1eb79fee99ee4584164bb4824f68ae43f212e56d
D1 — تطبيع أرقام الهاتف (JO/EG/SY): - common/phone/phone.service.ts: مفتاح قانوني واحد لكل رقم حقيقي — يقبل صفراً محلياً/دولياً/+/00/بلا صفر ويرجع صيغة دولية موحّدة بلا + - يعالج لبس مصر تحديداً الذي ذكره المالك: "01012345678" يُطبَّع بمفتاح 20 الصحيح لا "2" — الخوارزمية عامة فلا تحتاج معرفة اللبس، فقط تحذف الصفر البادئ وتضيف مفتاح الدولة الحقيقي - send-otp و verify-otp و platform/users/role تمرّ كلها بالتطبيع الآن؛ كانت تخزّن/تبحث بالرقم الخام كما كُتب — رقم واحد بصيغتين = حسابان - هجرة NormalizePhones تُصحّح حسابات الاختبار الموجودة على السيرفر، بحذر: تتخطّى أي تصادم بدل كسر القيد الفريد (tenant_id, phone) - أُزيل config.callingCodes المكرّر — مصدر واحد للحقيقة D2 — ربط الجلسة بالجهاز (نمط سيرو): **مبنيّ ومطفأ** (AUTH_REQUIRE_DEVICE_BINDING=false) حتى يرسل فلاتر x-device-id. منفَّذ داخل JwtStrategy.validate نفسها (passReqToCallback) لا كحارس يُضاف يدوياً لكل متحكّم — فلا نقطة محميّة يمكن نسيانها. التوكن يحمل hash(deviceId) لا القيمة الخام. verifyOtp/refresh يمرّران x-device-id من المتحكّم عند إصدار التوكن. D3 — HMAC: منفَّذ فعلاً ضمن I6 (SigningService/SignatureGuard)، لا تكرار. خطأ ضبطته قبل الدفع: كتبت مفتاح `auth:` ثانياً في configuration.ts — كائنات JS تسمح بمفاتيح مكرّرة والأخير يطغى، فكان سيمحو otpDevMode/otpTtl/ otpLength بالكامل. دُمج في الكتلة الأصلية بدل مفتاح جديد. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tripz — منصة نقل ذكي متعددة المستأجرين (White-Label)
منصة SaaS لتأجير تطبيقات نقل بعلامة تجارية خاصة لكل مستأجر (مكتب تكسي / أسطول / مشغّل مرخّص) في دول متعددة. تُبنى لتكسر نموذج Onde عبر أربع فجوات: الشفافية السعرية، الاستضافة داخل الدولة (السيادة)، خرائط انطلق الذاتية (بلا فاتورة خرائط)، والعربية أولاً.
هذا الفولدر هو حجر الأساس التخطيطي للمشروع قبل كتابة أي كود. كل ملف هنا يجيب عن سؤال واحد: ماذا نبني، وكيف، وبأي ترتيب.
القرارات المحسومة (لا نقاش فيها عند البناء)
| الطبقة | القرار | لماذا |
|---|---|---|
| الباك إند | NestJS 11 + TypeORM + PostgreSQL/PostGIS + Redis | باك إند انطلق مبني به أصلاً وفيه Tenant + Usage جاهزان |
| الـ Realtime | Socket.IO Gateway (@nestjs/websockets) + redis-adapter | لغة واحدة، فريق واحد، توسّع أفقي |
| الموبايل | Flutter + flutter_bloc (Cubit افتراضياً، Bloc لدورة الرحلة والعروض) | قابلية اختبار وتدقيق لمنتج يُرخّص + قرب من عقلية GetX |
| التوجيه/الحقن | go_router + get_it | معيار صناعي مقبول |
| الخرائط | انطلق (Martin tiles + geocoding + routing ذاتي) | الخندق التنافسي: بلا اعتماد على Google |
| الاستئجار | قاعدة واحدة + tenant_id (قياسي)، ونسخة معزولة (وضع سيادة) | أرخص تشغيلاً + منتج مضاد لثغرة Onde |
تفاصيل كل قرار في docs/02-backend-plan.md وdocs/03-mobile-plan.md.
خريطة الوثائق
ابدأ من الأعلى للأسفل. كل ملف مستقل لكنه يشير للبقية.
| # | الملف | يجيب عن |
|---|---|---|
| 00 | نظرة عامة | الرؤية، الجمهور، التمايز، ما ليس ضمن النطاق |
| 01 | البنية | كيف تتحدث الأنظمة معاً (مخطط عام) |
| 02 | الباك إند | وحدات NestJS، الطبقات، الحرّاس |
| 03 | الموبايل | هيكل فلاتر، الحالة، الشاشات، الـ flavors |
| 04 | محرك التعرفة | كيف نسعّر الرحلة (JSON قواعد) |
| 05 | تسعير المنتج والفوترة | الباقات وخوارزمية فاتورة المستأجر |
| 06 | نموذج الاستئجار | tenant_id، وضع السيادة، حزم الدول |
| 07 | التكاملات | الدفع، OTP/SMS، واجهة المنظّم، Webhooks |
| 08 | نموذج البيانات | الجداول الأساسية والعلاقات |
| 09 | الطبقة الحية | قنوات Socket، الحضور، الإسناد |
| 10 | خطة التنفيذ | P0→P3 بالأسابيع وشروط الخروج |
| 11 | النشر والأتمتة | CI، flavors، fastlane، البيئات |
| 12 | اللاندنج والبيع | الموقع، قنوات البيع بلا إعلانات |
| 13 | المخاطر والقرارات المفتوحة | ما يحتاج حسم المالك |
| 14 | اصطلاحات السيرفر والعزل | قرارات تشغيلية محسومة: البادئة، Redis DB، سيرفر مشترك، سيرو |
| 🌳 | شجرة المستودع | البنية الكاملة للمجلدات والملفات |
البدء السريع (عند جهوزية القرار)
- اقرأ 00-overview → 01-architecture.
- احسم القرارات المفتوحة (الاسم، سوق الانطلاق، دور سيرو).
- نفّذ P0 — تأسيس الـ Monorepo.
- تابع الشجرة المرجعية في project-tree.
الحالة: تخطيط · آخر تحديث: 2026-07-16 · الاسم المؤقت: Tripz
Languages
Dart
56.8%
JavaScript
21.3%
PHP
12.3%
TypeScript
4%
Kotlin
1.8%
Other
3.5%