المواصفة 02 — عقود واجهة API (NestJS، REST /api/v1)
الاصطلاحات: الصيغة JSON؛ التحقق من صحة كائنات النقل DTO عبر class-validator تحققاً صارماً — فالخصائص غير المعروفة تُرفض ولا تُحذف؛ وأحجام متون الطلبات محدودة؛ شكل الأخطاء { statusCode, code, message, messageAr }؛ التقسيم إلى صفحات ?page=1&limit=20 ← { items, total, page, limit }؛ المصادقة عبر كوكيز من نوع httpOnly هي nutqi_at / nutqi_rt؛ مُزخرِفات الحراسة @Roles(...)؛ وكل ذلك موصوف بتعليقات Swagger ولا يُقدَّم في الإنتاج إلا إذا فُعِّل صراحةً.
ومسارات القراءة تردّ صفوفاً مسطَّحة (D-26): الأسماء محلولةً في نص واحد، والتواريخ التقويمية بصيغة YYYY-MM-DD، والصور الرمزية روابط جاهزة للاستعمال، والعدّادات محسوبةً في الخادم، والعلاقات محذوفة — فلا يتسرّب تخطيط قاعدة البيانات إلى أي عميل.
وتحديد المعدّل يجري لكل عنوان شبكة، بميزانية أضيق بكثير على /auth/login ومسارات رمز التأكيد؛ وهو مكمِّل لقفل الحساب في G15 لا بديل عنه. والمتغيّران JWT_ACCESS_SECRET وCORS_ORIGIN مطلوبان في الإنتاج — فالتطبيق يرفض الإقلاع بدل الارتداد إلى قيمة افتراضية غير آمنة.
وحدة health#
GET /health(عام، بلا مصادقة) ← فحص حياة مع فحص قاعدة بيانات حقيقي. وهو خالٍ عمداً من أرقام الإصدارات وسلاسل الاتصال ونصوص الأخطاء؛ ويستهلكه الوسيط العكسي وفحص صحة الحاوية.
وحدة auth#
POST /auth/registerبحمولة{ role: PERSONAL_PATIENT|GUARDIAN|SPECIALIST|CENTER, firstName, lastName, email, phone, password, gender?, birthDate?, center? {nameAr, licenseNumber?, governorate?, city?, branchName?} }← تُنشئ مستخدماً (بالحالةPENDING_VERIFICATION)، ومعه مركز وأول فرع حين يكون الدورCENTERطبقاً لـG03؛ وتُرسل رمز تحقق للبريد والهاتف (المزوّد في بيئة التطوير هوconsole). تردّ 409 عند تكرار البريد أو رقم الهاتف.POST /auth/verify-otpبحمولة{ target, code, purpose: "verify" | "reset" }← عند التحقق: تُعلَّم الوسيلة كمُوثَّقة، وتتحول الحالة إلىACTIVE(للمريض وولي الأمر) أوPENDING_ACTIVATION(للأخصائي والمركز)؛ وتُضبط الكوكيز. وعند إعادة التعيين: تُعيد رمزresetTokenصالحاً لمرة واحدة.POST /auth/resend-otpبحمولة{ target, channel? }— محكومة بمهلة 60 ثانية (مطابقة للعدّاد التنازلي في الواجهة).POST /auth/loginبحمولة{ email, password }← تضبط الكوكيز؛ وكلمة السر الخطأ تزيد عدّاد المحاولات؛ وعند القفل تردّ 423 معlockedUntilطبقاً لـG15.POST /auth/forgotبحمولة{ email, phone }← رمز تحقق بغرضreset.POST /auth/reset-passwordبحمولة{ resetToken, password }.POST /auth/refreshوPOST /auth/logout.GET /auth/me← بيانات المستخدم + ملخص الملف الخاص بدوره + نسبة اكتمال التفعيل (وهي ما يحرّك حلقة البوابة).PATCH /auth/passwordبحمولة{ current, next }(من الإعدادات).
وحدة users#
PATCH /users/me(الأسماء بالعربية والإنجليزية،nationalId، تاريخ الميلاد، النوع، الصورة الشخصية، اللغة، وحقول العنوان).PUT /users/me/languagesبحمولة[{language, level}](اللغات المحكية،G13-b).GET/PUT /users/me/notification-channelsبحمولة[{channel, target, enabled}]؛ وPOST /users/me/notification-channels/:channel/verify(مسار رمز التحقق).
وحدة patients (بوابة ولي الأمر)#
GET /patients(الخاصة بي) /POST /patients(إضافة طفل،G09) /GET|PATCH /patients/:id.POST /patients/:id/documents(رفع متعدد الأجزاء، النوعDOC|VIDEO) /GET /patients/:id/documents/DELETE …/:docId.- التشخيص:
GET /forms/diagnosis-template← القالب النظامي؛ وPOST /patients/:id/diagnosis-response(تُنشئ الاستجابة أو تحدّثها عبر واجهة الإجابات الموصوفة أدناه).
وحدة specialists#
GET /specialists— الدليل العام (G12): المرشِّحاتqوgovernorateوspecialtyوsessionTypeوpriceMin/Maxوrating؛ ولا يظهر إلا من كان بالحالةACTIVE.GET /specialists/:id/profile← حمولة النظرة العامة (الإحصاءات: الخط الزمني للحجوزات، وتوزيع الأنواع، وأعلى البرامج — وكلها محسوبة)، والبيانات (الشهادات والتدريبات والفيديوهات)، والعيادات، وملخص التقييمات.GET /specialists/:id/schedule?weekStart=← شبكة الجلسات مع الأسعار؛ وGET /specialists/:id/slots?date=&clinicId?=← المواعيد المتاحة بفترات نصف ساعة (ساعات العمل − الحجوزات − أيام الراحة) طبقاً لـD-09.- مقصورة على الحساب نفسه:
GET/PUT /specialists/me/profile، وPOST/PATCH/DELETE /specialists/me/work-info، و…/certificates، و…/videos، و…/clinics، وPUT /specialists/me/schedule(كتل أيام الأسبوع)، وPOST /specialists/me/days-off. PUT /specialists/me/booking-settingsبحمولة{ availableForWork, acceptsOnline, acceptsOffline, acceptsConsultation }.GET/POST/DELETE /specialists/me/blocklist.GET /specialists/me/stats?period=all|year|month|week|day←{ dailyAvgCases, totalCases, earningsCents, pending: bool }.
وحدة bookings#
POST /bookingsبحمولة{ patientId, specialistId, clinicId?|type ONLINE, sessionType, date, startTime }← تُنشئ الحجز بالحالةPENDING؛ وتتحقق من أن الميعاد شاغر، وأن الأخصائي مفعَّل ومتاح، وأن الحاجز غير محظور؛ ويُحتسب السعر في الخادم. وتردّ 409 إذا كان الميعاد محجوزاً.GET /bookingsقائمة محدودة بنطاق الدور مع مرشِّحات (statusوtypeوqوdateRange) بالإضافة إلى?export=csv.PATCH /bookings/:id/statusبحمولة{ status, meetingUrl?, newDate?/newTime? for POSTPONED }— الانتقالات المسموح بها محكومة بآلة الحالات (المواصفةdocs-content/02§5)؛ ويجوز لولي الأمر إلغاء حجزه هو وهو بالحالةPENDING/WAITING.GET /bookings/upcoming← الحجز التالي لعرضه في الشريط طبقاً لـE10.
وحدة sessions#
POST /sessions(من حجز أو من حالة خاصة) /PATCH /sessions/:idبحمولة{ progressPercent, evaluation, notes }.GET /patients/:id/sessions، وGET /special-cases/:id/sessions.
وحدة special-cases (للأخصائي)#
- عمليات إنشاء وقراءة وتعديل وحذف على
/special-cases؛ والمرفقات على/special-cases/:id/attachments(المرحلةBEFORE|AFTER)؛ والملاحظات لها العمليات نفسها (حذف ناعم مع نافذة تراجع،G18).
وحدة forms (محرك الخطط والمقاييس)#
- القوالب:
GET/POST /forms/templates(الخاصة بي)، وGET/PATCH/DELETE /forms/templates/:id(مع حمولة متداخلة للصفحات والأسئلة، ومُدارة بالإصدارات). - الإسناد:
POST /forms/assignmentsبحمولة{ templateId, patientId|specialCaseId, dueDate? }← إشعار إلى ولي الأمر. GET /forms/assignments?role=guardian|specialist&status=← بيانات البطاقات (لم يتم / تم).- الإجابة:
GET /forms/assignments/:id/response(أو إنشاؤها)، وPUT /forms/responses/:id/answers/:questionIdبحمولة{ value }— حفظ تلقائي بالإدراج أو التحديث طبقاً لـE01، وPOST /forms/responses/:id/submit← يتحقق من الحقول المطلوبة ← يصبح الإسنادANSWERED. - النتائج:
GET /forms/assignments/:id/result(عرض للقراءة فقط للسؤال والإجابة).
وحدة reviews#
POST /reviewsبحمولة{ specialistId, bookingId?, stars, text, kind }(يشترط أن يكون لصاحب التقييم حجز بالحالةDONEمع الأخصائي حين يكون النوعSESSION).GET /specialists/:id/reviews?kind=&period=؛ وPATCH /reviews/:id/like، وPATCH /reviews/:id/reply(للأخصائي)، وPOST /reviews/:id/reportطبقاً لـG17.
وحدة payments#
GET /payments/mine(سجل مدفوعات ولي الأمر،G01) ← الصفوف مع الإجماليات.POST /bookings/:id/paymentبحمولة{ method, status }(تسجّله السكرتارية أو الأخصائي؛ ويُنشئ معاملة محفظة من نوعEARNINGعند الحالةPAID).GET /wallet(للأخصائي) ←{ balanceCents, withdrawnCents }؛ وGET /wallet/transactions.POST /wallet/withdrawalsبحمولة{ amountCents, method, target }طبقاً لـG19؛ وGET /wallet/withdrawals.
وحدة centers#
GET/PATCH /centers/me(للمالك والمدير)؛ والفروع لها العمليات الكاملة على/centers/me/branches.- الموظفون:
GET/POST /centers/me/staff(إنشاء مستخدم موظف مع الدور والفرع والراتب)، وPATCH/DELETE /centers/me/staff/:id. - مرضى المركز:
GET /centers/me/patients(مع تمرير طلبات الملفات الشخصية).
وحدة hr (للمركز)#
POST /hr/attendance/clock-in|clock-out(للموظف نفسه، بدورCENTER_SPECIALIST/SECRETARY) — وbranchIdاختياري طبقاً لـG20.GET /hr/attendance?staffId?&range(المالك والمدير يريان الجميع؛ والموظف يرى سجلّه هو).- عمليات شبه كاملة على
/hr/absences، و/hr/overtime، و/hr/penalties(معdeductionCents)، وهي للمالك والمدير فقط. - الطلبات:
POST /hr/requests(للموظف)، وGET /hr/requests(محدودة بالنطاق)، وPATCH /hr/requests/:id/decisionبحمولة{ status: APPROVED|REJECTED }(للمالك والمدير) ← إشعار.
وحدة jobs#
- للمركز:
GET/POST /jobs/postings، وPATCH /jobs/postings/:id(مسودة ← منشورة ← مغلقة)، والطلبات:GET /jobs/postings/:id/applications، وPATCH /jobs/applications/:id/decision← عند الحالةACCEPTEDتُعرض حمولة إنشاء سجلCenterStaff. - للأخصائي:
GET /jobs/market(المنشورة، مع مرشِّحات،G08)، وPOST /jobs/postings/:id/apply، وGET /jobs/applications/mine.
وحدة notifications#
GET /notifications?unread=، وPATCH /notifications/:id/read، وPATCH /notifications/read-all.GET /notifications/stream— بتقنيةSSEطبقاً لـE13.- خدمة إطلاق الأحداث تستعملها بقية الوحدات؛ وهي تُرسل دائماً عبر القناة
IN_APPإضافةً إلى القنوات المفعَّلة والمُوثَّقة (البريد عبرconsoleأوSMTPتطويري؛ وواتساب وتليجرام واجهتان صوريتان تسجّلان الحمولات فقط،D-17).
وحدة files#
POST /filesرفع متعدد الأجزاء (يتطلب المصادقة) ←StoredFile؛ وGET /files/:id(الصلاحية بحسب الملكية أو الارتباط)؛ مع حدود للحجم والنوع (الصور 5 ميجابايت، والمستندات 10 ميجابايت، والفيديو 100 ميجابايت).
وحدة admin (عبر واجهة API فقط في الإصدار الأول)#
GET /admin/activations(الأخصائيون والمراكز المعلَّقون)، وPATCH /admin/activations/:userIdبحمولة{ approve|reject }.GET /admin/withdrawals، وPATCH /admin/withdrawals/:idبحمولة{ TRANSFERRED|REJECTED }.GET /admin/reported-reviews.
الأحداث ← الإشعارات (الحد الأدنى)#
booking.created (← الأخصائي/السكرتارية)، و booking.status_changed (← ولي الأمر)، و assignment.created (← ولي الأمر)، و assignment.answered (← الأخصائي)، و application.decided (← الأخصائي)، و hr.request.decided (← الموظف)، و withdrawal.processed (← الأخصائي)، و activation.decided (← المستخدم).