Files
tripz-llc/scripts/generate-tenant-app.sh
T
Hamza-AyedandClaude Opus 4.8 c93be38622 feat: المجموعة N (طبقة الـSaaS) — تزويد المستأجر + مانيفست التطبيق + لوحة سوبر-أدمن
الهدف الأساسي: السوبر-أدمن ينشئ مستأجراً كاملاً (اسم/لوغو/دولة/دفع/باقة/
ميزات/bundle IDs) ويولّد تطبيقه.

الباك إند (خلف PlatformGuard):
- POST /admin/tenants/provision — تزويد بضربة واحدة
- GET /admin/tenants/:id/summary + /app-manifest (يستهلكه سكربت البناء)
- PATCH .../branding + .../payment-methods
- POST /admin/tenants/:id/logo (رفع) + GET /tenant/logo/:slug عام
  **يخدم أصل الهوية فقط لا مجلد التخزين كاملاً** — وإلا سُرّبت صور وثائق
  الهوية الحساسة بمفاتيحها
- كتالوج payment-methods.ts (cash/wallet/cliq/zaincash/paymob/mtn/
  syriatel/shamcash حسب الدولة) + تصفية المخترع
- GET /admin/features يرجع الميزات ووسائل الدفع للكتالوج

الواجهة: dashboards/superadmin-web/index.html — SPA مكتفية ذاتياً (vanilla
JS، بلا خطوة بناء)، سرّ المنصة في sessionStorage، RTL. تُخدَم كملف ثابت.

سكربت التوليد: scripts/generate-tenant-app.sh — يجلب المانيفست ويضبط
الهيكل؛ خطوات فلاتر موسومة [Q] تُوصَل عند بناء مشروع فلاتر.

اختبار: provision-test.mjs (يثبت الحارس + التزويد + تصفية الدفع +
الاستحقاقات + المانيفست). لا هجرة — settings/branding jsonb موجودان.

القرار: اللوحات ويب (لا فلاتر) — تحديث فوري، سطح مكتب، معيار الصناعة.
البدء بـN (طبقة الـSaaS) قرار المالك.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 03:39:02 +03:00

79 lines
5.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# ==========================================================================
# توليد تطبيق مستأجر واحد من مانيفست الباك إند (docs/22 — N3).
#
# سكربت واحد يأخذ slug المستأجر → يجلب مانيفسته → يضبط bundle ID والأيقونات
# والـsplash من اللوغو، يحقن FCM، يربط إضافات Kotlin/C++ الأصيلة (overlay ·
# method channels · NDK) المبنية على bundle ID، يبني، ويسجّل/يدفع عبر Shorebird.
#
# الاستعمال:
# PLATFORM_SECRET=xxx API=https://tripz-api.intaleqapp.com/api \
# ./scripts/generate-tenant-app.sh <slug> <rider|driver>
#
# ⚠️ الخطوات الموسومة [Q] تعتمد على مشروع فلاتر (المجموعة Q) الذي لم يُبنَ بعد.
# البنية والعقد (المانيفست) جاهزان الآن؛ تُوصَل هذه الخطوات عند وصول Q.
# ==========================================================================
set -euo pipefail
SLUG="${1:?الاستعمال: generate-tenant-app.sh <slug> <rider|driver>}"
APP_KIND="${2:-rider}" # rider | driver
API="${API:?اضبط API=https://tripz-api.intaleqapp.com/api}"
SECRET="${PLATFORM_SECRET:?اضبط PLATFORM_SECRET}"
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
APP_DIR="$ROOT/apps/$APP_KIND" # [Q] مشروع فلاتر لكل نوع
WORK="$ROOT/.build/$SLUG-$APP_KIND"
echo "▶ توليد تطبيق [$APP_KIND] للمستأجر [$SLUG]"
# ── 1. جلب المانيفست من الباك إند (جاهز الآن) ──────────────────────────
echo " • جلب المانيفست…"
# نحصل على tenant id من القائمة ثم المانيفست
TENANT_ID="$(curl -fsSL -H "x-platform-secret: $SECRET" "$API/admin/tenants" \
| node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const t=JSON.parse(s).find(x=>x.slug==='$SLUG');if(!t){console.error('مستأجر غير موجود: $SLUG');process.exit(1)}process.stdout.write(t.id)})")"
MANIFEST="$(curl -fsSL -H "x-platform-secret: $SECRET" "$API/admin/tenants/$TENANT_ID/app-manifest")"
echo "$MANIFEST" | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const m=JSON.parse(s);console.log(' الاسم:',m.app_name,'| bundleAndroid:',m.bundle_id_android,'| دولة:',m.country_pack)})"
val() { echo "$MANIFEST" | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{process.stdout.write(String(JSON.parse(s).$1 ?? ''))})"; }
APP_NAME="$(val app_name)"
BID_ANDROID="$(val bundle_id_android)"
BID_IOS="$(val bundle_id_ios)"
COUNTRY="$(val country_pack)"
[ -z "$BID_ANDROID" ] && { echo " ✗ bundle_id_android غير مضبوط في المانيفست — اضبطه من لوحة السوبر-أدمن أولاً"; exit 1; }
# ── 2. تحضير نسخة عمل من مشروع فلاتر ───────────────────────────────────
if [ ! -d "$APP_DIR" ]; then
echo " ⚠️ [Q] مشروع فلاتر $APP_DIR غير موجود بعد — تخطّي خطوات البناء."
echo " المانيفست جاهز؛ تُوصَل خطوات فلاتر عند بناء المجموعة Q."
exit 0
fi
rm -rf "$WORK"; mkdir -p "$(dirname "$WORK")"; cp -r "$APP_DIR" "$WORK"
# ── 3. ضبط bundle ID (أندرويد + iOS) ───────────────────────────────────
echo " • ضبط bundle ID…"
# [Q] applicationId في build.gradle، و PRODUCT_BUNDLE_IDENTIFIER في iOS.
# الإضافات الأصيلة (overlay/NDK/method-channel) مبنية على bundle ID —
# تُحدَّث مراجعها هنا. راجع apps/*/android و apps/*/ios.
# sed -i "s/applicationId \".*\"/applicationId \"$BID_ANDROID\"/" "$WORK/android/app/build.gradle"
# ── 4. الأيقونات و splash من اللوغو ────────────────────────────────────
echo " • توليد الأيقونات و splash من اللوغو…"
curl -fsSL "$API/tenant/logo/$SLUG" -o "$WORK/assets/logo.png" 2>/dev/null || echo " (لا لوغو مرفوع — يُستعمل الافتراضي)"
# [Q] flutter_launcher_icons + flutter_native_splash من assets/logo.png
# ── 5. حقن FCM + إعداد المستأجر ────────────────────────────────────────
echo " • حقن إعداد المستأجر ($COUNTRY)…"
# [Q] نسخ google-services.json / GoogleService-Info.plist الخاص بالمستأجر.
# BASE_URL و TENANT عبر --dart-define عند البناء.
# ── 6. البناء + Shorebird ──────────────────────────────────────────────
echo " • البناء وتسجيل Shorebird…"
# [Q] أول مرة: shorebird init (يسجّل app_id لهذا bundle ID في حساب Shorebird).
# التحديثات: shorebird release / shorebird patch.
# ( cd "$WORK" && shorebird release android \
# --dart-define=BASE_URL=${API} --dart-define=TENANT=$SLUG )
echo "✅ اكتمل توليد [$APP_KIND] لـ[$SLUG] (الخطوات الموسومة [Q] معلّقة حتى مشروع فلاتر)."