E — اتصال ثم إلغاء (من driver_ride_scam عند سيرو): - E1: driver_called_passenger + last_call_at/by/count على الرحلة نفسها لا Redis فقط — حقيقة دائمة تفيد التحقيق بعد انتهاء الرحلة وزوالها من الكاش. يُسجَّل عند call:offer (بدء المكالمة الفعلي) في RealtimeGateway عبر Repository<Trip> مباشرة — لا استيراد TripsModule كاملاً (يستورد RealtimeModule أصلاً، فدورة استيراد) - E2: FraudService.recordCallThenCancel — عدّاد يومي منفصل عن عدّاد الإلغاء العام بالساعة. 3/يوم = إنذار لا يمنع الإلغاء، 6/يوم = حظر مؤقت (طلب المالك حرفياً). يرتبط فقط إن كانت المكالمة خلال 30 دقيقة من الإلغاء تشفير الهاتف at-rest (ملاحظة المالك) — بفهرس أعمى منفصل، لا تشفير ساذج: - AES-256-GCM عشوائي IV يمنع WHERE phone = :x من المطابقة أصلاً (كل تشفير مختلف شكلاً حتى لنفس الرقم) — لو طُبِّق التشفير مباشرة بلا هذا لكسر تسجيل الدخول بالكامل بصمت - users.phone_bidx = HMAC-SHA256(الرقم المطبَّع) — حتمي، يصلح للبحث وللقيد الفريد. القيد انتقل من (tenant_id, phone) إلى (tenant_id, phone_bidx) — القديم كان سيقبل تكرار نفس الرقم الحقيقي فعلياً - findByPhone/create يحسبان البصمة؛ لا نقطة أخرى تقرأ phone بمساواة خام - هجرة EncryptPhone تُشفّر الصفوف القائمة فوراً وتبني البصمة بأثر رجعي — استثناء متعمَّد من تسامح decrypt() المعتاد (الهاتف عمود بحث يومي، خطره كنص صافٍ أعلى من name) - يعتمد على تطبيع D1: بصمة حتمية لنفس *النص*، فلا بد أن يصل الرقم مطبَّعاً قبلها وإلا عاد نفس الرقم بصيغتين ليصير رقمين مرة أخرى هجرات: TripCallSignal · EncryptPhone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tripz Backend — NestJS (Docker فقط)
لا تثبيت محلي على الماك. الكود يُكتب محلياً، والبناء والتشغيل والهجرات كلها داخل Docker على السيرفر.
التشغيل على السيرفر
cd backend
cp .env.example .env # ثم عدّل كلمات المرور والأسرار
docker compose up -d --build # يبني ويشغّل: postgres/postgis, redis, martin, api, worker
الهجرات (داخل حاوية الـ api)
docker compose exec api npm run migration:run
الهجرات تعمل على النسخة المترجمة
dist/config/data-source.js(صورة الإنتاج بلا ts-node). لو ما رفعت آخر نسخة بعد، شغّل مباشرة:docker compose exec api node_modules/.bin/typeorm migration:run -d dist/config/data-source.js
فحص سريع
curl http://<server>:4010/api/health # {"status":"ok",...}
# توثيق Swagger: http://<server>:4010/api/docs
العزل على السيرفر المشترك (راجع docs/14)
- Postgres: قاعدة
tripz، بادئة جداولtripz_(مثال:tripz_tenants). - Redis: DB رقم 3 غير الافتراضي + بادئة مفاتيح
tripz:. - منافذ مضيف غير قياسية (API 4010، Postgres 55432) لتفادي التصادم.
- أسماء حاويات/شبكة/فوليوم ببادئة
tripz-.
البنية الحالية (P0)
src/
├── main.ts # bootstrap API (+ Swagger)
├── worker.ts # نقطة دخول BullMQ (هيكل)
├── app.module.ts # ConfigModule + TypeORM(entityPrefix) + Throttler + TenantMiddleware
├── config/ # configuration.ts + data-source.ts (هجرات)
├── common/
│ ├── tenant/ # context (AsyncLocalStorage) + middleware + @Tenant()
│ └── usage/ # UsageInterceptor (أساس الفوترة)
├── database/
│ ├── entities/ # tenant.entity.ts
│ └── migrations/ # InitTenants
└── modules/
├── health/ # GET /api/health
└── tenants/ # GET /api/tenant/config/:slug ، admin/tenants
التالي (P1)
users · auth(OTP) · drivers · trips(★ آلة حالة) · matching(Redis GEO) · tariff · realtime(Socket.IO) · maps(وكيل انطلق).