چگونه با یک کدبیس چندین اپ آموزشی ساختیم
5 دقیقه مطالعهMohammad Shaker

چگونه با یک کدبیس چندین اپ آموزشی ساختیم

Alphazed بیش از ۷ اپ آموزشی (از جمله Amal و Thurayya) را با یک کدبیس و فریم‌ورک Flutter مشترک مدیریت می‌کند.

Engineering

پاسخ سریع

Alphazed بیش از ۷ اپ آموزشی (از جمله Amal و Thurayya) را با یک کدبیس و فریم‌ورک Flutter مشترک مدیریت می‌کند.

شرکت Alphazed بیش از ۷ اپ آموزشی (Amal, Thurayya, Qais, KidElite, Alphazed School, Alphazed Montessori و غیره) را از طریق یک کدبیس بک‌اند یکپارچه و فریم‌ورک موبایل مشترک Flutter مدیریت می‌کند. هر اپ دارای جداول بانک اطلاعاتی (با پیشوند مخصوص)، تنظیمات، اعلان‌های پوش، قالب‌های ایمیل و محتوای خاص خود است اما احراز هویت (AWS Cognito)، زیرساخت تحلیل داده‌ها و الگوریتم‌های اصلی یادگیری بین همه مشترک است.

بک‌اند: انتخاب اپ در زمان اجرا

چگونه کار می‌کند

در زمان استقرار (deployment)، یک متغیر محیطی اپ مورد نظر را تعیین می‌کند:

# Deploy Amal
export APP_NAME=amal
serverless deploy

# Deploy Thurayya
export APP_NAME=thurayya
serverless deploy

# Deploy Qais
export APP_NAME=qais
serverless deploy

هر استقرار توابع Lambda مستقل، مسیرهای API Gateway و مانیتورینگ جداگانه ایجاد می‌کند ولی همه به یک کدبیس واحد متصل‌اند.

اولویت‌های سه‌گانه تنظیمات

# src/config.py
import os

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

# اول: تطابق دقیق با نام اپ
config = load_json(f'config/{app_name}.json')

# دوم: تطابق خانواده اپ (اگر تنظیمات دقیق نباشد)
if not config:
    family = app_name.split('_')[0]  # 'amal_beta' → 'amal'
    config = load_json(f'config/{family}.json')

# سوم: تنظیمات پیش‌فرض
if not config:
    config = load_json('config/default.json')

تنظیمات مخصوص هر اپ (مثال 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
  }
}

منابع مشترک و اختصاصی هر اپ

منبعمشترکمخصوص اپدلیل
کد Lambda✓ بله✗ خیریک کدبیس با شاخه‌بندی بر اساس APP_NAME
نمونه RDS✓ بله✗ خیر (جداول پیشونددار)کاهش هزینه، بکاپ یکپارچه
محتوای S3✗ خیر✓ بلههر اپ برنامه آموزشی خود را دارد
AWS Cognito✓ بله✗ خیر (بر اساس app_id)احراز هویت مرکزی و تمایز توسط app_id
تالاب تحلیل✓ بله✗ خیر (بخش‌بندی شده بر اساس اپ)خط لوله داده یکپارچه اما جداسازی داده‌ها
ارسال پیام Firebase✗ خیر✓ بلهAPNs و FCM مخصوص هر اپ

فرانت‌اند: معماری چند اپ در Flutter

هسته مشترک (packages/alphazed_common)

  • مدیریت وضعیت (Riverpod)
  • پخش صدا
  • کتابخانه انیمیشن (ادغام Rive)
  • سیستم طراحی (رنگ‌ها، قلم‌ها، ویجت‌ها)
  • روندهای احراز هویت
  • کلاینت تحلیل

لایه‌های اختصاصی هر اپ (apps/amal, apps/thurayya و غیره)

apps/
  ├── amal/
  │   ├── lib/
  │   │   ├── main.dart (ورودی اپ)
  │   │   ├── config/
  │   │   │   ├── curriculum.json (ساختار درس Amal)
  │   │   │   ├── colors.dart (تم Amal)
  │   │   │   └── characters.json (شخصیت‌ها)
  │   │   └── screens/ (صفحه‌های مختص Amal)
  │   └── pubspec.yaml (وابستگی‌های Amal)
  │
  ├── thurayya/
  │   ├── lib/
  │   │   ├── main.dart (ورودی متفاوت)
  │   │   ├── config/
  │   │   │   ├── curriculum.json (ساختار جزء عمّا)
  │   │   │   ├── colors.dart (تم Thurayya)
  │   │   │   └── characters.json (شخصیت‌ها)
  │   │   └── screens/ (صفحه‌های مختص Thurayya)
  │   └── pubspec.yaml (وابستگی‌های Thurayya)
  │
  └── packages/
      └── alphazed_common/ (کد مشترک)

تنظیمات زمان ساخت

# ساخت Amal
flutter build apk --dart-define=APP_NAME=amal --dart-define=CURRICULUM=amal_v3

# ساخت Thurayya
flutter build apk --dart-define=APP_NAME=thurayya --dart-define=CURRICULUM=thurayya_juzamma

در زمان ساخت، هر اپ داده‌های برنامه آموزشی، رنگ‌ها و تنظیمات مخصوص به خود را دریافت می‌کند. یک مخزن کد، چند باینری مختلف.

استقرار: استک‌های مستقل

پیکربندی Serverless Framework

# serverless.yml
service: alphazed-backend

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

functions:
  # این توابع برای هر مقدار 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:
    # هر اپ گروه لاگ جداگانه در CloudWatch دارد
    ${self:custom.app_name}LogGroup:
      Type: AWS::Logs::LogGroup
      Properties:
        LogGroupName: /aws/lambda/alphazed-${self:custom.app_name}
        RetentionInDays: 30

با استقرار برای APP_NAME=amal، CloudFormation موارد زیر را ایجاد می‌کند:

  • توابع Lambda با پیشوند alphazed-amal-*
  • مسیرهای API Gateway زیر /amal/*
  • لاگ‌های CloudWatch در /aws/lambda/alphazed-amal
  • مقیاس‌پذیری و مانیتورینگ مستقل

چرا این مهم است

برای تیم محصول

  • زمان راه‌اندازی اپ جدید: هفته‌ها به جای ماه‌ها به دلیل اشتراک زیرساخت
  • تطابق امکانات: رفع اشکال و بهبود الگوریتم‌ها بلافاصله در همه اپ‌ها اعمال می‌شود
  • تست A/B آسان: آزمایش ویژگی‌ها در یک اپ پیش از انتشار به بقیه

برای تیم مهندسی

  • یک کدبیس واحد: یک مجموعه تست و یک خط تولید CI/CD
  • الگوریتم‌های یادگیری مشترک: تکرار فاصله‌ای و ترکیب محتوا برای همه اپ‌ها
  • کارایی عملیاتی: مدیریت تمام زیرساخت توسط یک تیم

برای هزینه‌ها

  • رایگان‌تر بودن RDS مشترک نسبت به ۷ پایگاه جداگانه
  • یک ارائه‌دهنده احراز هویت AWS Cognito برای همه اپ‌ها
  • یک خط لوله تحلیل داده برای همه ۷ اپ
  • صرفه‌جویی تخمینی ۴۰ تا ۶۰ هزار دلار در سال نسبت به بک‌اندهای جداگانه

چالش‌ها و راه‌حل‌ها

چالش ۱: تداخل در ساختار دیتابیس

  • Amal به جدول amal_user_memory نیاز دارد
  • Thurayya به جدول thurayya_user_memory نیاز دارد با فیلدهای متفاوت برای حفظ قرآن
  • راه‌حل: مهاجرت‌ها با آگاهی از اپ اجرا می‌شوند. اسکریپت migrations/001_amal_user_memory.sql تنها برای APP_NAME=amal اجرا می‌شود

چالش ۲: مجموعه امکانات متفاوت

  • Thurayya بازخورد تجوید دارد؛ Amal ندارد
  • Amal بازی‌های فیزیک دارد؛ Thurayya ندارد
  • راه‌حل: استفاده از پرچم‌های ویژگی در تنظیمات enable_tajweed_feedback و enable_physics_games

چالش ۳: مقیاس‌پذیری مستقل

  • Amal افزایش ترافیک دارد؛ Thurayya کم است
  • استخر Lambda مشترک باعث رقابت برای همزمانی می‌شود
  • راه‌حل: سیاست‌های مقیاس‌گذاری CloudWatch برای هر اپ. اگر توابع amal-* به حد همزمانی برسند، به طور مستقل مقیاس می‌شوند

پرسش‌های متداول

Q: آیا اشتراک یک کدبیس باعث وابستگی زیاد بین اپ‌ها نمی‌شود؟
A: خیر. کد هر اپ در دایرکتوری‌های جداگانه (apps/amal, apps/thurayya) است. کد مشترک در packages/alphazed_common و نسخه‌بندی شده است. وابستگی شدید نشانه طراحی بد است و در بازبینی کد پیدا می‌شود.

Q: اگر یک اپ نیاز به تغییر شکسته در API داشته باشد چه؟
A: ما APIها را بر اساس اپ نسخه‌بندی می‌کنیم: /amal/v1/, /thurayya/v1/. اپ‌ها می‌توانند مستقل به‌روزرسانی شوند. نسخه‌های قدیمی تا ۱۲ ماه اجرا می‌شوند تا فرصت بروزرسانی باشد.

Q: آیا کاربران بین اپ‌ها مشترک اند؟
A: به طور پیش‌فرض خیر. هر اپ جدول کاربران جداگانه دارد (با پیشوند). اگر والدین بخواهند هر دو اپ Amal و Thurayya را داشته باشند، باید حساب‌های مجزا بسازند (یا می‌توان ویژگی لینک «خانواده» افزود).

اشتراک‌گذاریTwitterLinkedInWhatsApp

مقالات مرتبط