feat: N1d/N2/N3 + قانون فلاتر وإعادة ضبط تطبيق السائق

الباك إند:
- تعيين أول أدمن صار يُنشئ المستخدم إن لم يوجد — كان يشترط دخولاً سابقاً،
  وهي بيضة ودجاجة تمنع الدخول إلى لوحة أي مستأجر جديد أصلاً.
- OTP_DEV_MODE كان يفشل مفتوحاً (`!== 'false'`): غياب المتغيّر أو خطأ مطبعي
  يترك الإنتاج برمز ثابت يفتح كل حساب، ويحرس السحب المالي كذلك. صار
  `=== 'true'` في الإعداد وفي قارئَيه، مع تحذير عند الإقلاع.
- N2: التحقّق من اللوغو عند الرفع (PNG/JPEG · 512+ · مربّع · سقف 5MB) عبر
  قراءة الترويسة بلا اعتمادية — بدل اكتشاف أيقونة ممطوطة بعد النشر.

N3: السكربت يولّد build_config.dart بأعلام const (طبقات docs/22 §1.5)،
ويضبط bundle IDs واسم التطبيق والأيقونات/splash، و--build يشغّل Shorebird.

فلاتر:
- docs/23: قانون مُلزِم للتطبيقين (البنية · Cubit · طبقة الشبكة · الأعلام).
- السائق: أُزيل Dart القديم (GetX) مع الإبقاء على الأصيل والإضافات وشهادات
  التوقيع وShorebird وFirebase الخاص به، وأُعيد هيكلته مطابقاً للراكب.
- طبقة الشبكة ترسل x-device-id وتجدّد التوكن عند 401 مرة واحدة فقط.
- الحزم موحّدة بين التطبيقين، والـAPI https حصراً في الاثنين.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-07-18 13:06:46 +03:00
co-authored by Claude Fable 5
parent 3ab74a13a8
commit de4bbd00ac
271 changed files with 1333 additions and 81068 deletions
+6 -2
View File
@@ -110,8 +110,9 @@ Shorebird يرقّع Dart فقط. بتوحيد Kotlin/الصلاحيات/NDK ت
| N1a | **تعليق المستأجر يسري فعلياً** (2026-07-18). | ✅ كان `tenant.status` يُكتب ويُعرض **بلا أي فرض** — أي أن «تعطيل المستأجر» زخرفة والمستأجر غير الدافع يظل يشتغل. الفرض الآن في `JwtStrategy` (نقطة واحدة، نفس حجّة ربط الجهاز D2) + `AuthService.resolveTenant` (يخنق `sendOtp` و`verifyOtp` معاً). القراءة مكيَّشة (Redis أولاً) والإبطال يجعل التعليق فورياً؛ وتعذّر القراءة **يمرّر** لا يقطع المنصة كلها (G). |
| N1b | **النظرة الشاملة**: `GET /admin/overview?days=` — رحلات · GMV · **إيراد المنصة (العمولة)** لكل مستأجر. | ✅ استعلام واحد مجمَّع لكل المستأجرين (لا N+1). `revenue` = مجموع العمولة وهو الرقم الذي يهمّ عند التسعير، لا الـGMV. |
| N1c | **خدمة اللوحات الثلاث على الإنترنت**. | ✅ تُخدم من **نفس أصل الـAPI** عبر `useStaticAssets`: `/panel/superadmin` · `/panel/admin` · `/panel/service` — بلا CORS وبلا دومين/شهادة ثانية، وترث TLS القائم (docs/20). المجلد مربوط bind من compose فتعديل HTML يظهر بتحديث الصفحة بلا إعادة بناء. |
| N2 | **رفع اللوغو + توليد الأيقونات/splash**. | 🔵 الباك إند ✅ (`POST /admin/tenants/:id/logo` + `GET /tenant/logo/:slug` **عام لأصل الهوية فقط** — لا يخدم مجلد التخزين كاملاً حتى لا تُسرَّب صور الوثائق). توليد الأيقونات نفسه في N3. |
| N3 | **سكربت توليد التطبيق الواحد**: bundle ID · أيقونات/splash من اللوغو · FCM · **إضافات Kotlin/C++ الأصيلة** (overlay · method channels · NDK) · بناء · **Shorebird**. | 🔵 `scripts/generate-tenant-app.sh` — يجلب المانيفست ويضبط الهيكل؛ خطوات فلاتر موسومة [Q] تُوصَل عند بناء المجموعة Q (المشروع غير موجود بعد). **يجب أن يولّد `BuildConfig` بأعلام `const` حسب §1.5** — هذا ما يجعل الطبقات حقيقية لا تجميلية. |
| N1d | **تعيين أول أدمن للمستأجر**. | ✅ `POST /platform/users/role` صار **يُنشئ المستخدم إن لم يوجد**. كان يشترط دخولاً سابقاً، وهذه بيضة ودجاجة: مستأجر مزوَّد حديثاً بلا مستخدمين، فلا سبيل لصنع أول أدمن — أي أن لوحته لا يمكن الدخول إليها إطلاقاً. زر «تعيين أدمن» في لوحة السوبر-أدمن. |
| N2 | **رفع اللوغو + توليد الأيقونات/splash**. | ✅ الرفع **مع تحقّق** (`image-meta.ts`: PNG/JPEG · حدّ أدنى 512×512 · مربّع ±5٪ · سقف 5MB) — لوغو صغير أو مستطيل كان يُنتج أيقونة ممطوطة في كل تطبيقات المستأجر ولا يُكتشف إلا بعد بناءٍ ونشر. لم نُدخل `sharp`: التوليد نفسه شغل `flutter_launcher_icons` في N3، والباك إند لا يحتاج إلا التحقّق (قراءة ترويسة بلا اعتمادية). زر رفع في اللوحة. |
| N3 | **سكربت توليد التطبيق الواحد**: bundle ID · أيقونات/splash من اللوغو · FCM · **إضافات Kotlin/C++ الأصيلة** (overlay · method channels · NDK) · بناء · **Shorebird**. | 🔵 `scripts/generate-tenant-app.sh` — يجلب المانيفست ويضبط الهيكل؛ خطوات فلاتر موسومة [Q] تُوصَل عند بناء المجموعة Q (المشروع غير موجود بعد). ✅ يولّد الآن `lib/core/build_config.dart` بأعلام `const` (§1.5) · يضبط `applicationId` و`PRODUCT_BUNDLE_IDENTIFIER` و`android:label` · يجلب اللوغو ويكتب إعدادات `flutter_launcher_icons`/`flutter_native_splash` · و`--build` اختياري يشغّل Shorebird. |
| N4 | **لوحة أدمن المستأجر (ويب)**: سائقون (اعتماد) · رحلات · مراجعة وثائق · سحوبات (تحويل/فشل). | ✅ `dashboards/admin-web/index.html` + نقاط سرد إدارية (`/drivers/admin/list` · `/trips/admin/list` · `/payouts/admin/list` خلف RolesGuard admin/dispatcher). التعرفة والتقارير تُضاف مع L. |
| N5 | **لوحة خدمة العملاء (ويب)**: بحث مستخدم برقمه (فهرس أعمى) · رحلاته · تفاصيل رحلة بالمعرّف. | ✅ `dashboards/service-web/index.html` + `GET /admin/users/search` · `/trips/admin/list?rider=`. الشكاوى تحتاج وحدة complaints (لا توجد بعد — بند لاحق). |
@@ -138,6 +139,9 @@ Shorebird يرقّع Dart فقط. بتوحيد Kotlin/الصلاحيات/NDK ت
### المجموعة Q — تطبيق فلاتر (إعادة بناء كاملة) 📱
> **إعادة استعمال الأصيل الثابت** (Kotlin/iOS من التطبيق القديم Ride/Tripz)، **وإعادة بناء Dart من الصفر** بـCubit+Bloc (لا GetX).
> راجع [[tripz-mobile-store-identity]] لمعرّفات المتاجر التي يجب الحفاظ عليها.
>
> 📜 **القانون المُلزِم: [23-flutter-conventions](23-flutter-conventions.md)** — يُقرأ كاملاً قبل أي كود Dart.
> **الحالة (2026-07-18)**: هيكل التطبيقين متطابق حرفياً (`core/` + `features/auth` + `features/home`)؛ Dart القديم (GetX) أُزيل من السائق مع **الإبقاء على** الأصيل والإضافات وشهادات التوقيع وShorebird وFirebase. طبقة الشبكة تُرسل `x-device-id` وتجدّد التوكن عند 401 مرة واحدة. الحزم موحّدة بين التطبيقين والـAPI صار https حصراً (`usesCleartextTraffic=false` في الاثنين).
| # | البند |
|---|-------|