حوكمة النظام البيئي
شام باص ليس تطبيقاً واحداً، بل نظاماً بيئياً كاملاً يشمل:
- بوابة العملاء
- لوحة الشركات
- لوحة الإدارة
- تطبيق العميل للموبايل
- تطبيق السائق
- الحزم المشتركة
- قاعدة البيانات والترحيلات والدوال
- التوثيق الداخلي والعام
- CI/CD والنشر والمراقبة
الهدف من هذه الصفحة هو تقليل الازدواجية وتوضيح المكان الصحيح لأي تغيير جديد.
الحدود الافتراضية للمسؤوليات
| المجال | المصدر المعتمد | ملاحظات |
|---|---|---|
| إنشاء عملاء Supabase وإدارة الجلسات والكوكيز | packages/database | الأغلفة داخل التطبيقات يجب أن تبقى خفيفة ومخصصة للتهيئة فقط. |
| أدوات المصادقة و CSRF والصلاحيات المشتركة | packages/auth | سياسات كل تطبيق قد تغلف هذه الأدوات لكنها لا تنسخها. |
| الأنواع المشتركة و Zod schemas وعقود الطلب/الاستجابة | packages/types | لا تكرر الأنواع نفسها داخل عدة تطبيقات. |
| التحقق المشترك والتنسيق والتطبيع | packages/utils | تطبيع أرقام الهواتف وقواعد التحقق العامة يجب أن تكون مركزية. |
| مكونات UI المشتركة للويب | packages/ui | المكونات المحلية داخل التطبيق تبقى للتجميع أو السلوك الخاص بالمنتج. |
| الثوابت والتوكنات المشتركة بين الويب والموبايل | packages/shared و packages/config | أي قيمة يفترض أن تتطابق بين المنصات يجب أن تبدأ هنا. |
| الخدمات المشتركة مثل الإشعارات و rate limiting ومزودي الدفع | packages/services | يجب فصلها عن imports المحلية من نوع @/lib/*. |
| التحقق من طلبات HTTP وتحويل أخطاء Zod إلى responses موحدة | packages/services/utils/validate | تستخدمه مسارات Next كطبقة موحدة فوق packages/types. |
| منطق السياسات الخاصة بكل تطبيق ومسارات API | داخل التطبيق نفسه | طبقات BFF تبقى في التطبيقات لكنها تعتمد على الخدمات المشتركة. |
| مخطط البيانات و RLS و RPCs و triggers | infrastructure/supabase/migrations | هذا هو المصدر المعتمد لسلوك قاعدة البيانات. |
| الدوال الطرفية Edge Functions | infrastructure/supabase/functions | يجب توثيق العلاقة بينها وبين كود التطبيقات بوضوح. |
| التوثيق الداخلي والتشغيلي | apps/docs/docs/internal | يجب تحديثه بعد أي تغيير معماري أو تشغيلي مهم. |
| CI/CD والنشر والفحوص الأمنية | .github/workflows | يجب أن تعكس المسارات والأوامر الحالية في المستودع. |
قواعد العمل
- إذا كان السلوك مشتركاً بين تطبيقين أو أكثر، ابدأ من الحزم المشتركة.
- إنشاء عملاء Supabase على الخادم، جلسات SSR، إعادة كتابة عناوين Docker، وقراءة التوكن من
Authorizationأو الكوكيز المخصصة يجب أن يتم من خلالpackages/database. - تطبيع أرقام الهواتف، تنسيقها، وتوحيد قواعد كود الحجز يجب أن يتم من خلال
packages/utilsمع استخدامpackages/typesكطبقة العقود والتحقق وقت التشغيل. - لا تضف منطقاً جديداً مكرراً داخل
apps/*/src/libإذا كان له مكان واضح داخلpackages/*. - أي route handler جديد يحتاج قراءة
bodyأوquery paramsيجب أن يبدأ منvalidateBodyأوvalidateQueryبدلاً من تكرارrequest.json()وsafeParse()يدوياً. - حافظ على عقود API الحالية للمستهلكين، خصوصاً تطبيقات Flutter، أثناء نقل المنطق إلى الحزم المشتركة.
- اعتبر الترحيلات المصدر الأول للحقيقة عند توثيق مخطط البيانات أو سلوك القاعدة.
- لا تترك فحوص CI الأساسية في وضع fail-open:
pnpm auditو Semgrep و Patrol/Playwright يجب أن تفشل عند وجود مشكلة حقيقية، لا أن تمر عبرcontinue-on-errorأو|| true. - أي تغيير مهم في المعمارية أو الإعداد أو التشغيل يجب أن يصاحبه تحديث توثيقي.
ما الذي أصبح مركزياً الآن؟
- إنشاء عملاء Supabase على الخادم والكوكيز متعددة التطبيقات يبدأ من
packages/database. - تطبيع الهاتف وتوليد/تطبيع كود الحجز يبدأ من
packages/utils. - عقود الحجز المشتركة مثل
createRoundTripBookingSchemaوbulkBookingActionSchemaوbookingPaginationQuerySchemaتبدأ منpackages/types. - توجد الآن عقود نظام بيئي صريحة داخل
packages/types/src/ecosystem.tsلحالات مثل تفاصيل الحجز، المسارات الشائعة، قائمة الانتظار، وضع الصيانة، وإعدادات الشركة، ويجب أن تبقى هذه العقود هي المرجع عند تعديل المسارات أو مستهلكي Flutter/Next. - توسعت هذه العقود لتشمل أيضاً طبقة "ثقة الرحلة" المعيارية عبر
TripStatusSnapshotوBookingTicketStateوJourneyUpdateوSupportTicketState، إضافة إلى سجل 2FA للإدارة عبرAdminTwoFactorState. - إدارة أعلام الميزات داخل لوحة الإدارة يجب أن تمر الآن عبر مسارات
app/api/feature-flags/*فقط، بما في ذلك التبديل والتعديل والاستثناءات، حتى تبقى الصلاحيات و CSRF و سجل التدقيق موحدة ولا تنتقل الكتابة المباشرة إلى Supabase من المتصفح. - مسارات الويب التي تحتاج parsing و validation للطلبات تبدأ من
packages/services/utils/validateثم تمرر البيانات النظيفة إلى الخدمات المحلية أو المشتركة. routes.serviceوdrivers.serviceوcheck-permissionأصبحت تعمل كطبقات مشتركة قابلة للحقن من داخل الحزم، بينما تبقى الملفات داخلapps/*/src/lib/...مجرد adapters خفيفة لربطcreateClientأوcreateAdminClientالمحليين.- يوجد الآن فحص تكاملي في
tests/integration/system/shared-package-boundaries.test.tsيمنع إضافة imports جديدة من نوع@/lib/*أو@/types/*داخل الحزم المشتركة خارج الاستثناءات المؤقتة الموثقة.
متى يبقى التغيير محلياً داخل التطبيق؟
التغيير يبقى داخل التطبيق عندما يكون:
- متعلقاً بسياسة وصول أو صلاحيات خاصة بذلك التطبيق
- متعلقاً بتجميع واجهة أو UX محلي
- متعلقاً بتشكيل response خاص بمستهلك محدد
- غلافاً صغيراً فوق طبقة مشتركة لأغراض التهيئة فقط
مسار التنفيذ الموصى به
- عدل المصدر المعتمد أولاً.
- اجعل الطبقات المحلية مجرد adapters أو wrappers خفيفة.
- حدث الاختبارات الأقرب للسلوك المتغير.
- حدث التوثيق المرتبط بالمعمارية أو التشغيل أو قاعدة البيانات.
- اجعل الـ commits مقسمة حسب النظام الفرعي لتسهيل المراجعة.