Skip to Content

البدء السريع

ينقلك هذا الدليل من خادم جديد تمامًا حتى أول طلب مُصادَق عليه. كل خطوة هي طلب حقيقي مقابل خادم apps/server قيد التشغيل. نفِّذها بالترتيب من الأعلى إلى الأسفل لتحصل على مسؤول أوّل، ورمز وصول، وبنية مستأجِرة، ومستخدم مُزوَّد.

المتطلبات المسبقة

  • نسخة apps/server قيد التشغيل. الخادم يعمل افتراضيًا على المنفذ 8787 (يمكن تغييره عبر متغير البيئة PORT). استبدل http://localhost:8787 أدناه بعنوانها. الواجهة الأمامية Next.js تعمل على المنفذ 3000؛ لا تخلط بينهما.
  • طرفية تحوي curl (واختياريًا jq لتنسيق مخرجات JSON).
  • إصدار Node 22 يهمّ فقط عند بناء الخادم، لا عند استدعائه.

الخطوة 1: تسجيل المسؤول الأوّل

التسجيل متاح للمستخدم الأول فقط. سجِّل مسؤولًا بنطاق SUPER بدون organizationId (الحالة الوحيدة التي يُحذف فيها):

curl -X POST http://localhost:8787/api/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "admin@school.edu.jo", "password": "your-strong-password", "fullNameAr": "أحمد العلي", "primaryPersona": "ADMIN" }'

الاستجابة: 201 Created (RegisterResponse):

{ "user": { "id": 1, "email": "admin@school.edu.jo", "primaryPersona": "ADMIN", "organizationId": null }, "tokens": { "accessToken": "eyJhbGci...", "refreshToken": "9f3c...e1", "expiresIn": 900, "tokenType": "Bearer" } }

يُغلَق التسجيل بعد المستخدم الأول. استدعاء POST /api/auth/register مرة ثانية يعيد 403 مع code: "PERMISSION_DENIED" («التسجيل مغلق»). بعد ذلك يُنشأ كل مستخدم آخر عبر إنشاء المستخدمين.

لديك مسبقًا زوج رموز من الاستجابة أعلاه، يمكنك تخطّي الخطوة 2 وإعادة استخدامه.

الخطوة 2: تسجيل الدخول

للحصول على زوج رموز جديد في أي وقت، سجّل الدخول بالبريد وكلمة المرور:

curl -X POST http://localhost:8787/api/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "admin@school.edu.jo", "password": "your-strong-password" }'

الاستجابة: 200 OK (AuthTokensResponse):

{ "accessToken": "eyJhbGci...", "refreshToken": "9f3c...e1", "expiresIn": 900, "tokenType": "Bearer" }

expiresIn هو عمر رمز الوصول بالثواني (900 = 15 دقيقة).

الخطوة 3: أول طلب مُصادَق عليه

مرّر رمز الوصول كترويسة Bearer. يؤكّد GET /api/auth/me هويتك ويعيد مجموعة صلاحياتك:

curl http://localhost:8787/api/auth/me \ -H "Authorization: Bearer eyJhbGci..."

الاستجابة: 200 OK (MeResponse، مختصرة):

{ "id": 1, "email": "admin@school.edu.jo", "primaryPersona": "ADMIN", "organizationId": null, "permissions": ["SUPER_ADMIN", "MANAGE_ORG", "..."], "classIds": [] }

مصفوفة permissions[] هي ما يحكم الوصول إلى نقاط النهاية فعليًا. انظر المفاهيم الأساسية ← التحكم بالصلاحيات.

الخطوة 4: إنشاء البنية المستأجِرة

يملك المسؤول الأول صلاحية SUPER_ADMIN، لذا يمكنه إنشاء قمة الشجرة. أنشئ مؤسسة، ثم مدرسة ضمنها، ثم صفًّا ضمن المدرسة.

# Organization curl -X POST http://localhost:8787/api/organizations \ -H "Authorization: Bearer eyJhbGci..." \ -H "Content-Type: application/json" \ -d '{ "name": "مدرسة النور الأساسية", "slug": "al-noor-school-jo", "country": "JO", "defaultLocale": "ar-JO" }'

تعيد 201 OrgResponse معرّفًا id (نصّ cuid، مثل clx4z2k0u0000xyz1234abcde). استخدمه كـ organizationId للمدرسة. يجب أن تطابق دولة المدرسة دولة مؤسستها، وعدم التطابق يعيد 422.

# School (organizationId = the org's id from above) curl -X POST http://localhost:8787/api/schools \ -H "Authorization: Bearer eyJhbGci..." \ -H "Content-Type: application/json" \ -d '{ "organizationId": "clx4z2k0u0000xyz1234abcde", "name": "مدرسة النور — عمان", "country": "JO" }' # Class (schoolId = the school's id; grade 1–4; academicYear "YYYY-YYYY") curl -X POST http://localhost:8787/api/classes \ -H "Authorization: Bearer eyJhbGci..." \ -H "Content-Type: application/json" \ -d '{ "schoolId": "clx4z2k0u0000xyz1234abcde", "name": "صف ثاني — أ", "grade": 2, "academicYear": "2026-2027" }'

الخطوة 5: تزويد مستخدم

يُنشأ كل المستخدمين عدا المسؤول الأول عبر نقطة نهاية واحدة، POST /api/users، وجسمها اتحاد مُميَّز مفتاحه primaryPersona:

curl -X POST http://localhost:8787/api/users \ -H "Authorization: Bearer eyJhbGci..." \ -H "Content-Type: application/json" \ -d '{ "primaryPersona": "TEACHER", "email": "teacher@school.edu.jo", "password": "teacher-strong-password", "fullNameAr": "سارة محمود", "organizationId": "clx4z2k0u0000xyz1234abcde" }'

تعيد 201 UserCreatedResponse المعرّف العددي id للمستخدم الجديد. انظر إنشاء المستخدمين لمصفوفة الحقول الكاملة لكل دور.

الخطوة 6: تجديد الرمز عند انتهائه

يعيش رمز الوصول 15 دقيقة. عند انتهائه، بادل رمز التجديد بزوج جديد:

curl -X POST http://localhost:8787/api/auth/refresh \ -H "Content-Type: application/json" \ -d '{ "refreshToken": "9f3c...e1" }'

رموز التجديد تتدوّر: رمز التجديد الذي استخدمته للتوّ صار ملغًى، وتحمل الاستجابة رمزًا جديدًا. إعادة استخدام رمز تجديد مُدوَّر تعيد 401 وتُلغي الجلسة (كشف السرقة).

عندما تسوء الأمور

كل إخفاق هو المغلَّف ذاته: { code, message, details?, retryAfter? }. فمثلًا، كلمة مرور خاطئة عند الدخول تعيد 401:

{ "code": "...", "message": "Invalid email or password." }

انظر الأخطاء لكامل دليل الحالات والرموز وإرشادات إعادة المحاولة.