Kako smo razvili višestruku aplikacijsku platformu iz jednog koda
Čitanje: 5 minMohammad Shaker

Kako smo razvili višestruku aplikacijsku platformu iz jednog koda

Alphazed koristi jednu kodnu bazu i Flutter okvir za više obrazovnih aplikacija s posebnim bazama podataka i sadržajem.

Engineering

Brzi odgovor

Alphazed koristi jednu kodnu bazu i Flutter okvir za više obrazovnih aplikacija s posebnim bazama podataka i sadržajem.

Alphazed upravlja sa više od 7 obrazovnih aplikacija (Amal, Thurayya, Qais, KidElite, Alphazed School, Alphazed Montessori i druge) koristeći jednu backend kodnu bazu i zajednički Flutter mobilni okvir. Svaka aplikacija ima svoje vlastite tablice u bazi podataka (s prefiksima), konfiguraciju, push notifikacije, email predloške i sadržaj — ali dijele autentifikaciju (AWS Cognito), analitičku infrastrukturu i osnovne algoritme učenja.

Backend: Izbor aplikacije u runtime-u

Kako to funkcioniše

Prilikom deploymenta, varijabla okruženja određuje koja se aplikacija koristi:

# Deploy Amal
export APP_NAME=amal
serverless deploy

# Deploy Thurayya
export APP_NAME=thurayya
serverless deploy

# Deploy Qais
export APP_NAME=qais
serverless deploy

Svaki deployment kreira nezavisne Lambda funkcije, API Gateway rute i monitoring — ali sve su povezane na istu backend kodnu bazu.

Prioritet konfiguracije u tri nivoa

# src/config.py
import os

app_name = os.getenv('APP_NAME', 'amal')

# Nivo 1: Tačno poklapanje aplikacije
config = load_json(f'config/{app_name}.json')

# Nivo 2: Poklapanje porodice aplikacija (ako tačan config ne postoji)
if not config:
    family = app_name.split('_')[0]  # 'amal_beta' → 'amal'
    config = load_json(f'config/{family}.json')

# Nivo 3: Podrazumevani config
if not config:
    config = load_json('config/default.json')

Konfiguracija po aplikaciji (config/amal.json)

{
  "app_name": "amal",
  "app_id": "com.alphazed.amal",
  "database": {
    "table_prefix": "amal_"
  },
  "email": {
    "template_dir": "templates/amal",
    "from_address": "amal@alphazed.com",
    "from_name": "Amal Team"
  },
  "push_notifications": {
    "firebase_project": "alphazed-amal",
    "apns_certificate": "certs/amal.pem"
  },
  "content": {
    "s3_bucket": "amal-content-production",
    "curriculum_id": "amal_v3_arabic"
  },
  "feature_flags": {
    "enable_tajweed_feedback": false,
    "enable_noorani_qaida": false,
    "enable_juz_amma": false,
    "enable_creature_building": true,
    "enable_physics_games": true
  },
  "pricing": {
    "monthly_usd": 6.99,
    "yearly_usd": 67.99,
    "trial_days": 14
  }
}

Zajednički vs. po aplikaciji resursi

ResursZajedničkiPo aplikacijiRazlog
Lambda kod✓ Da✗ NeJedna kodna baza, grane po APP_NAME
RDS instanca✓ Da✗ Ne (tablice sa prefiksima)Smanjenje troškova, jedinstvena rezerva
S3 sadržaj✗ Ne✓ DaSvaka aplikacija ima vlastiti kurikulum
AWS Cognito✓ Da✗ Ne (po app_id)Centralna autentifikacija, razlikovanje app_id
Analitika✓ Da✗ Ne (particionirano po aplikaciji)Jedinstven proces, odvojeni podaci
Firebase poruke✗ Ne✓ DaAPNs i FCM specifični za aplikaciju

Frontend: Flutter višestruka arhitektura aplikacija

Zajedničko jezgro (packages/alphazed_common)

  • Upravljanje stanje (Riverpod)
  • Obrada zvuka
  • Biblioteka animacija (Rive integracija)
  • Dizajn sistem (boje, tipografija, widgeti)
  • Autentifikacioni tokovi
  • Klijent za analitiku

Specifične aplikacijske slojeve (apps/amal, apps/thurayya itd.)

apps/
  ├── amal/
  │   ├── lib/
  │   │   ├── main.dart (ulazna tačka aplikacije)
  │   │   ├── config/
  │   │   │   ├── curriculum.json (struktura lekcija Amal)
  │   │   │   ├── colors.dart (tema Amal)
  │   │   │   └── characters.json (prilagođavanje avatara)
  │   │   └── screens/ (ekrani specifični za Amal)
  │   └── pubspec.yaml (Amal zavisnosti)
  │
  ├── thurayya/
  │   ├── lib/
  │   │   ├── main.dart (druga ulazna tačka)
  │   │   ├── config/
  │   │   │   ├── curriculum.json (struktura Juz Amma)
  │   │   │   ├── colors.dart (tema Thurayya)
  │   │   │   └── characters.json (prilagođavanje avatara)
  │   │   └── screens/ (specifični ekrani za Thurayya)
  │   └── pubspec.yaml (zavisnosti za Thurayya)
  │
  └── packages/
      └── alphazed_common/ (zajednički kod)

Konfiguracija u fazi build-a

# Build Amal
flutter build apk --dart-define=APP_NAME=amal --dart-define=CURRICULUM=amal_v3

# Build Thurayya
flutter build apk --dart-define=APP_NAME=thurayya --dart-define=CURRICULUM=thurayya_juzamma

Tokom build-a, svaka aplikacija prima svoj kurikulum, boje i konfiguraciju ugrađenu u binarni fajl. Jedan repozitorijum koda, više kompajliranih aplikacija.

Deployment: Nezavisni stackovi

Serverless Framework konfiguracija

# serverless.yml
service: alphazed-backend

custom:
  pythonRequirements:
    dockerizePip: true
  app_name: ${env:APP_NAME}

functions:
  # Funkcije se deployaju za svaku APP_NAME vrednost
  get_user:
    handler: src/handlers/user.get_user
    events:
      - http:
          path: app/{app_name}/user/{user_id}
          method: get
  
  content_duo:
    handler: src/handlers/content.generate_content_duo
    timeout: 20
    events:
      - http:
          path: app/{app_name}/content_duo
          method: post

resources:
  Resources:
    # Svaka aplikacija ima svoj CloudWatch log group
    ${self:custom.app_name}LogGroup:
      Type: AWS::Logs::LogGroup
      Properties:
        LogGroupName: /aws/lambda/alphazed-${self:custom.app_name}
        RetentionInDays: 30

Kada deployate sa APP_NAME=amal, CloudFormation kreira:

  • Lambda funkcije sa prefiksom alphazed-amal-*
  • API Gateway rute pod /amal/*
  • CloudWatch logove pod /aws/lambda/alphazed-amal
  • Nezavisno skaliranje i monitoring

Zašto je ovo važno

Za produkt timove

  • Brže lansiranje novih aplikacija: sedmice, a ne mjeseci (dijeljena infrastruktura)
  • Jednakost funkcionalnosti: popravljanje grešaka i unapređenja algoritama odmah u svim aplikacijama
  • A/B testiranje: lako testiranje novih funkcija na jednoj aplikaciji prije širenja

Za inženjere

  • Jedan kodni bazen: jedan skup testova, jedna CI/CD traka
  • Zajednički algoritmi učenja: ponavljanje u razmacima i miksanje sadržaja koristi svim aplikacijama
  • Operativna efikasnost: jedan tim upravlja kompletnom infrastrukturom

Za troškove

  • Zajednička RDS baza: djelić troška sedam nezavisnih baza
  • Zajednički Cognito: jedno autentifikaciono rješenje za sve aplikacije
  • Zajednička analiza: jedna pipelines za 7 aplikacija
  • Procijenjena ušteda: 40.000 do 60.000 USD godišnje u odnosu na odvojene backend-e

Izazovi i rješenja

Izazov 1: Sukobi u shemi baze podataka

  • Amal zahtijeva tablicu amal_user_memory
  • Thurayya zahtijeva thurayya_user_memory s drugačijim poljima za memorisanje Kur'ana
  • Rješenje: Migracije su svjesne aplikacije. migrations/001_amal_user_memory.sql se izvršava samo kad je APP_NAME=amal

Izazov 2: Različite funkcionalnosti

  • Thurayya ima povratne informacije o tajvidu, Amal nema
  • Amal ima igre fizike, Thurayya nema
  • Rješenje: Kontrola putem feature flagova u konfiguraciji (enable_tajweed_feedback, enable_physics_games)

Izazov 3: Nezavisno skaliranje

  • Amal ima veliki promet; Thurayya miruje
  • Zajednički Lambda pool znači konkurenciju za resurse
  • Rješenje: CloudWatch pravila za skaliranje po aplikaciji. Ako amal-* Lambda funkcije dostignu limit, automatski skaliraju

Često postavljana pitanja (FAQ)

P: Ne stvara li dijeljenje jedne kodne baze ovisnost između aplikacija?
A: Ne. Kod aplikacija je u zasebnim direktorijumima (apps/amal, apps/thurayya). Zajednički kod je u packages/alphazed_common i verzionisan je eksplicitno. Uska povezanost je loš dizajn koji hvatamo u kod reviziji.

P: Šta ako neka aplikacija treba prelomnu promjenu API-ja?
A: Verzije API-ja su po aplikaciji: /amal/v1/*, /thurayya/v1/*. Aplikacije se mogu nezavisno nadograditi. Stare verzije rade 12 mjeseci, dajući dovoljno vremena timovima.

P: Mogu li aplikacije dijeliti korisnike?
A: Po defaultu ne. Svaka aplikacija ima vlastitu korisničku tablicu (s prefiksom). Roditelji koji žele subscribati oba, Amal i Thurayya, kreiraju posebne naloge (ili možemo kasnije dodati rješenje za povezivanje „porodica“).

Povezani članci