البدء السريع
ينقلك هذا الدليل من خادم جديد تمامًا حتى أول طلب مُصادَق عليه. كل خطوة هي طلب حقيقي مقابل خادم
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
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." }انظر الأخطاء لكامل دليل الحالات والرموز وإرشادات إعادة المحاولة.