Plateforme multi-apps avec une seule codebase
6 min de lectureMohammad Shaker

Plateforme multi-apps avec une seule codebase

Alphazed s appuie sur une base backend commune et Flutter pour faire tourner plus de 7 apps educatives avec efficacite.

Engineering

Réponse rapide

Alphazed s appuie sur une base backend commune et Flutter pour faire tourner plus de 7 apps educatives avec efficacite.

Comment nous avons construit une plateforme multi-apps avec une seule codebase

Alphazed exploite plus de 7 applications éducatives (Amal, Thurayya, Qais, KidElite, Alphazed School, Alphazed Montessori, et plus) à partir d'une seule base de code backend et d'un cadre mobile Flutter partagé. Chaque application dispose de ses propres tables de base de données (préfixées), configuration, notifications push, modèles d'email, et contenu — mais partage l'authentification (AWS Cognito), l'infrastructure d'analytique et les algorithmes d'apprentissage de base.

Backend : Sélection d'application à l'exécution

Comment ça marche

Lors du déploiement, une variable d'environnement sélectionne l'application :

# Déployer Amal
export APP_NAME=amal
serverless deploy

# Déployer Thurayya
export APP_NAME=thurayya
serverless deploy

# Déployer Qais
export APP_NAME=qais
serverless deploy

Chaque déploiement crée des fonctions Lambda indépendantes, des routes API Gateway, et une surveillance — mais elles se connectent toutes à la même base de code backend.

Priorité de configuration à trois niveaux

# src/config.py
import os

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

# Niveau 1 : Correspondance exacte de l'application
config = load_json(f'config/{app_name}.json')

# Niveau 2 : Correspondance de la famille d'applications (si la configuration exacte n'existe pas)
if not config:
    family = app_name.split('_')[0]  # 'amal_beta' → 'amal'
    config = load_json(f'config/{family}.json')

# Niveau 3 : Défaut
if not config:
    config = load_json('config/default.json')

Configuration par application (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": "Équipe Amal"
  },
  "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
  }
}

Ressources partagées vs par application

Ressource Partagée Par application Raison
Code Lambda ✓ Oui ✗ Non Codebase unique, bifurcation par APP_NAME
Instance RDS ✓ Oui ✗ Non (tables préfixées) Réduction des coûts, sauvegarde unique
Contenu S3 ✗ Non ✓ Oui Chaque app a son propre programme
AWS Cognito ✓ Oui ✗ Non (via app_id) Authentification centrale, différenciation par app_id
Lac d'analytique ✓ Oui ✗ Non (partitionné par app) Pipeline unifié, données séparées
Messagerie Firebase ✗ Non ✓ Oui APNs spécifiques à l'app + FCM

Frontend : Architecture multi-apps Flutter

Noyau partagé (packages/alphazed_common)

  • Gestion d'état (Riverpod)
  • Gestion audio
  • Bibliothèque d'animation (intégration Rive)
  • Système de design (couleurs, typographie, widgets)
  • Flux d'authentification
  • Client d'analytique

Couches spécifiques aux applications (apps/amal, apps/thurayya, etc.)

apps/
  ├── amal/
  │   ├── lib/
  │   │   ├── main.dart (point d'entrée de l'app)
  │   │   ├── config/
  │   │   │   ├── curriculum.json (structure des leçons d'Amal)
  │   │   │   ├── colors.dart (thème d'Amal)
  │   │   │   └── characters.json (personnalisation d'avatar)
  │   │   └── screens/ (écrans spécifiques à Amal)
  │   └── pubspec.yaml (dépendances d'Amal)
  │
  ├── thurayya/
  │   ├── lib/
  │   │   ├── main.dart (point d'entrée différent)
  │   │   ├── config/
  │   │   │   ├── curriculum.json (structure de Juz Amma)
  │   │   │   ├── colors.dart (thème de Thurayya)
  │   │   │   └── characters.json (personnalisation d'avatar)
  │   │   └── screens/ (écrans spécifiques à Thurayya)
  │   └── pubspec.yaml (dépendances de Thurayya)
  │
  └── packages/
      └── alphazed_common/ (code partagé)

Configuration au moment de la construction

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

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

Au moment de la construction, chaque application reçoit ses propres données de programme, couleurs et configuration intégrées. Un seul dépôt de code, plusieurs binaires compilés.

Déploiement : Piles indépendantes

Configuration du Framework Serverless

# serverless.yml
service: alphazed-backend

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

functions:
  # Ces fonctions sont déployées pour chaque valeur APP_NAME
  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:
    # Chaque application reçoit son propre groupe de logs CloudWatch
    ${self:custom.app_name}LogGroup:
      Type: AWS::Logs::LogGroup
      Properties:
        LogGroupName: /aws/lambda/alphazed-${self:custom.app_name}
        RetentionInDays: 30

Lorsque vous déployez avec APP_NAME=amal, CloudFormation crée :

  • Fonctions Lambda préfixées alphazed-amal-*
  • Routes API Gateway sous /amal/*
  • Logs CloudWatch sous /aws/lambda/alphazed-amal
  • Évolutivité et surveillance indépendantes

Pourquoi c'est important

Pour les équipes produits

  • Lancement de nouvelle app : semaines au lieu de mois (infrastructure partagée)
  • Parité de fonctionnalités : corrections de bugs et améliorations d'algorithmes appliquées instantanément à toutes les apps
  • Test A/B : tester facilement des fonctionnalités sur une app avant de les déployer sur d'autres

Pour l'ingénierie

  • Codebase unique : un seul ensemble de tests, un seul pipeline CI/CD
  • Algorithmes d'apprentissage partagés : la répétition espacée et le mixage de contenu profitent à toutes les apps
  • Efficacité opérationnelle : une équipe gère toute l'infrastructure

Pour les coûts

  • RDS partagé : une fraction du coût de 7 bases de données indépendantes
  • Cognito partagé : un fournisseur d'authentification pour toutes les apps
  • Analytique partagée : un pipeline desservant 7 apps
  • Économies estimées : 40 000 à 60 000 $/an par rapport à des backends séparés

Défis et solutions

Défi 1 : Conflits de schéma de base de données

  • Amal nécessite la table amal_user_memory
  • Thurayya nécessite la table thurayya_user_memory (champs différents pour la mémorisation du Coran)
  • Solution : les migrations tiennent compte des apps. migrations/001_amal_user_memory.sql ne s'exécute que lorsque APP_NAME=amal

Défi 2 : Différents ensembles de fonctionnalités

  • Thurayya a des retours de tajweed ; Amal non
  • Amal a des jeux de physique ; Thurayya non
  • Solution : drapeaux de fonctionnalités dans la configuration (enable_tajweed_feedback, enable_physics_games)

Défi 3 : Évolutivité indépendante

  • Amal voit un pic de trafic ; Thurayya est calme
  • Piscine Lambda partagée signifie qu'elles se disputent la concurrence
  • Solution : politiques de mise à l'échelle CloudWatch par application. Si les Lambdas amal-* atteignent la limite de concurrence, mise à l'échelle automatique indépendamment

FAQ

Q : Le partage d'une seule base de code ne crée-t-il pas de couplage entre les apps ? R : Non. Le code de chaque app est dans des répertoires séparés (apps/amal, apps/thurayya). Le code partagé est dans packages/alphazed_common et est explicitement versionné. Le couplage fort est une mauvaise odeur de conception que nous détectons lors de la revue de code.

Q : Que se passe-t-il si une app nécessite un changement d'API incompatible ? R : Nous versionnons les APIs par app : /amal/v1/*, /thurayya/v1/*. Les apps peuvent évoluer indépendamment. Les anciennes versions fonctionnent pendant 12 mois, ce qui laisse le temps aux équipes d'apps de se mettre à jour.

Q : Les apps peuvent-elles partager des utilisateurs ? R : Pas par défaut. Chaque app a sa propre table utilisateur (préfixée). Si un parent veut s'abonner à la fois à Amal et Thurayya, il crée des comptes séparés (ou nous pourrions ajouter une fonctionnalité de liaison "familiale" plus tard).

Articles connexes