مرجع واجهة API
كل مسار تقدّمه واجهة API في Learnio، ومن يحق له استدعاؤه، وكيف يعمل تسجيل الدخول والصلاحيات والأخطاء والتقسيم إلى صفحات.
لحزمة الحزمة الكاملة
العنوان الأساسي وصيغة الاستجابة
يُقدَّم كل مسار تحت البادئة /api. محليًا، العنوان الأساسي هو http://localhost:8000/api. وعلى الخادم، هو عنوان واجهة API الخاصة بك متبوعًا بـ /api، وهي القيمة نفسها التي تقرؤها الواجهتان الأماميتان من NEXT_PUBLIC_API_BASE_URL (متغيرات البيئة).
تخدم واجهة API جمهورين لا يتشاركان رمزًا أبدًا. يستخدم الطلاب المسارات تحت /api/users/<area> و/api/shop، المذكورة في أقسام الطلاب أدناه. وتستخدم لوحة الإدارة كل المسارات الأخرى، بما فيها /api/users نفسه و/api/users/<username>، اللذان يديران حسابات الطلاب.
أجسام الطلبات بصيغة JSON، باستثناء رفع الملفات. وتأتي كل إجابة في الغلاف نفسه:
{
"success": true,
"data": { },
"message": ""
}يحمل data النتيجة. وmessage جملة قصيرة تملؤها بعض عمليات الكتابة، مترجمة إلى لغة الطلب، وتكون فارغة في غير ذلك. لا يحتاج فحص السلامة إلى رمز، ويُظهر الغلاف:
curl http://localhost:8000/api/health{"success":true,"data":{"status":"ok"},"message":""}يجيب بـ 503 ما دام الوصول إلى قاعدة البيانات متعذرًا أو كانت خالية من الجداول، لذا يمكن لموازن الأحمال استخدامه كفحص للجاهزية.
الأخطاء
يُجاب الطلب الفاشل برمز حالة HTTP المناسب وبالغلاف نفسه، مع success: false وdata: null، ومع المشكلات لكل حقل عند التحقق، مفهرسةً باسم الحقل (والحقل داخل كائن متداخل بمساره المنقّط):
curl -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"not-an-email","password":"x"}'{
"success": false,
"data": null,
"message": "Enter a valid email address (example@domain.com).",
"errors": {
"email": ["Enter a valid email address (example@domain.com)."]
}
}| الحالة | متى |
|---|---|
400 | فشل حقل في التحقق، أو قيمة استعلام غير صالحة، أو يحتوي الجسم على حقل لا يقبله المسار. تُرفض الحقول غير المعروفة، ولا تُتجاهل. |
401 | الرمز مفقود، أو منتهي الصلاحية، أو يخص الجمهور الآخر. وكذلك تسجيل الدخول الفاشل، سواء لم يكن للبريد حساب أو كانت كلمة المرور خاطئة. |
403 | أدوار المسؤول لا تمنح صلاحية المسار، أو حاول حساب مدرّس الوصول إلى ما هو خارج دوراته. |
404 | لا يوجد سجل كهذا. |
409 | تتعارض عملية الكتابة مع سجل موجود، مثل بريد إلكتروني أو slug مستخدم بالفعل. |
429 | محاولات كثيرة جدًا من عنوان واحد على مسار تسجيل دخول أو إنشاء حساب أو كلمة مرور. ترويسة Retry-After تحدد عدد الثواني التي يجب انتظارها. |
500 | فشل غير متوقع. تبقى الرسالة عامة وتذهب التفاصيل إلى سجل واجهة API. |
تجيب عمليات الكتابة الناجحة بـ 201 مع POST وبـ 200 مع الطرق الأخرى.
التقسيم إلى صفحات والترتيب
تأتي القوائم بشكلين، واحد لكل جمهور. تجيب مسارات الطلاب بالشكل الذي يقرؤه موقع الطلاب؛ وتجيب مسارات الإدارة بالشكل الذي تقرؤه لوحة الإدارة.
| قوائم الطلاب والقوائم العامة | قوائم الإدارة | |
|---|---|---|
| الصفحة | page، بدءًا من 1 | page، بدءًا من 1 |
| حجم الصفحة | page_count (الدورات، والمدونة، والتسجيلات، والتقييمات) أو per_page (المدرّسون). حجم صفحة الدورات افتراضيًا هو الإعداد courses_per_page، والتسجيلات 100. | page_count، وهو 15 افتراضيًا (10 للمسؤولين). وتستخدم الطلبات limit. |
| الترتيب | للدورات فقط: sort_by وsort_dir (asc أو desc) | sort وorder (asc أو desc). وتستخدم الطلبات sort_by وsort_order. |
| الترتيب الافتراضي | الدورات حسب الأحدث تحديثًا أولًا، والمدونة حسب الأحدث نشرًا أولًا | الأحدث تحديثًا أولًا، ويُفصل في التساوي بواسطة id. وتحتفظ الفئات والمدرّسون بترتيبهم المنسَّق. |
| الإجابة | data، وcurrent_page، وlast_page، وper_page، وtotal، وfrom، وto، إضافة إلى روابط الصفحات | data, page, limit, total, totalPages |
تضم الصفحة 100 صف على الأكثر: حجم الصفحة الأكبر يُقرأ 100، والحجم المفقود أو غير المقروء يعود إلى القيمة الافتراضية للقائمة. وينطبق الأمر نفسه على page، التي تعود إلى 1.
لا يقبل sort إلا الأعمدة التي تسمح بها كل قائمة. ويعود المفتاح غير المعروف إلى الترتيب الافتراضي بدلًا من الفشل، فتظل الإشارة المرجعية القديمة تعمل.
ترتَّب قائمة الدورات العامة حسب id أو price أو discount_percentage أو rating أو duration أو level أو language أو created_at أو updated_at، وتُرشَّح حسب title وcategory_id وinstructor_id وtype (live أو recorded).
اللغة
أرسل لغة القارئ في ترويسة Accept-Language. تتحدث واجهة API اللغات المسرودة في back-end/src/i18n/locales.ts، وهي en وar كما تُشحن. تقرأ الوسم الأول، فيكون ar-SA عربية، والطلب الذي لا يحدد لغة مدعومة يُجاب بلغة الإعداد default_locale. لا يوجد معامل استعلام للغة.
- تُترجم رسائل الخطأ و
messageالخاصة بعمليات الكتابة الناجحة. - النص المخزّن باللغتين، مثل عناوين الدورات وأوصافها، يُعاد بالشكل
{ "en": "...", "ar": "..." }ويختار العميل أحدهما. - تجيب بعض مسارات الطلاب باللغة المطلوبة فقط: قائمة التسجيلات، ومحتوى الدورة، والبحث.
- يأخذ الدفع اللغة من جسم الطلب (
locale، إحدى اللغات المدعومة)، فيطابق الإيصال الصفحة التي اشترى منها الطالب.
المصادقة
يسجّل الطلاب والمسؤولون الدخول عبر نقاط نهاية مختلفة، ومقابل جداول مختلفة، ويحصلون على رموز لا تقبلها إلا مساراتهم الخاصة.
| الجمهور | تسجيل الدخول | الرمز في الإجابة | مقبول على |
|---|---|---|---|
| الطالب | POST /api/users/auth/login | data.token، مع data.user | مسارات الطلاب |
| لوحة الإدارة | POST /api/auth/login | data.access_token، مع data.admin (الأدوار والصلاحيات) | مسارات الإدارة |
- كلاهما رمز JWT موقّع بـ
JWT_SECRET. أرسلهما بالشكلAuthorization: Bearer <token>. - يدوم الرمز طوال
JWT_EXPIRATION، و7dافتراضيًا (متغيرات البيئة). ويعيد تسجيل دخول المسؤول القيمة نفسها فيexpires_in. - لا توجد نقطة نهاية للتجديد. عندما تنتهي صلاحية الرمز، يجيب الطلب التالي بـ
401ويسجّل العميل الدخول من جديد. - تسجيل الخروج (
POST /api/users/auth/logout) يطلب من العميل فقط التخلص من رمزه. لا يُلغى أي شيء على الخادم، لذا يبقى الرمز صالحًا حتى تنتهي صلاحيته. - يُرفض رمز الطالب على مسارات الإدارة، ورمز المسؤول على مسارات الطلاب، رغم أن كليهما يستخدم المفتاح السري نفسه.
- يُجاب تسجيل الدخول الفاشل بالرمز
401وبرسالة واحدة، سواء لم يكن للبريد حساب أو كانت كلمة المرور خاطئة، فلا يمكن استخدام النموذج لمعرفة من يملك حسابًا. - تقبل مسارات تسجيل الدخول وإنشاء الحساب وكلمة المرور 10 محاولات في الدقيقة من عنوان واحد، تُحسب لكل مسار على حدة. وبعدها تُجيب بالرمز
429مع ترويسةRetry-After. يُحفظ العدّ في ذاكرة واجهة API، فيبدأ من جديد عند إعادة التشغيل ويُحسب منفصلًا في كل نسخة.
سجّل الدخول بحساب المدير العام التجريبي
الطرفيةcurl -X POST http://localhost:8000/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"admin@learnio.com","password":"Admin@123"}'الاستجابة{ "success": true, "data": { "access_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_in": "7d", "admin": { "id": 1, "email": "admin@learnio.com", "instructor_id": null, "roles": [{ "id": 1, "name": "Super Admin", "guard_name": "web" }], "permissions": ["admins.view", "admins.create", "..."] } }, "message": "Signed in successfully." }استدعِ مسارًا محميًا بالرمز
الطرفيةcurl "http://localhost:8000/api/courses?page=1&page_count=5" \ -H "Authorization: Bearer <access_token>"النتيجة المتوقعة: أول خمس دورات، بشكل قائمة الإدارة.
سجّل الدخول بحساب الطالب التجريبي
تحتوي البيانات النموذجية أيضًا على طالب،
demo@learnio.comبكلمة المرورDemo@123:الطرفيةcurl -X POST http://localhost:8000/api/users/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"demo@learnio.com","password":"Demo@123"}'ثم مرّر
data.tokenبالطريقة نفسها، على سبيل المثال إلىGET /api/users/enrollments.
غيّر كلمات المرور التجريبية
تستخدم حسابات البيانات النموذجية كلمات مرور منشورة: Admin@123 للمدير العام، وadmin123 لبقية الطاقم، وDemo@123 للطالب التجريبي. غيّرها، أو ابدأ بجداول فارغة، قبل إطلاق الموقع.
الصلاحيات
يتحقق كل مسار إداري من الرمز أولًا، ثم من الصلاحية التي يحددها. تُسمّى الصلاحيات بالشكل <module>.<action>، ويملك المسؤول كل صلاحيات كل دور لديه. وحيث يحدد المسار عدة صلاحيات، تكفي أي واحدة منها. في جداول الإدارة أدناه، يعني اسم الصلاحية في عمود من يحق له استدعاؤه مسؤولًا تمنحه أدواره تلك الصلاحية.
تشغيل أداة البذر مجددًا ينشئ الأدوار الناقصة ويترك صلاحيات الأدوار الموجودة كما هي، فتبقى التغييرات التي أجريتها في لوحة الإدارة. والاستثناء هو المدير العام: يحصل على أي صلاحية لا يملكها بعد.
| الوحدة | الصلاحيات |
|---|---|
| المسؤولون | admins.view, admins.create, admins.edit, admins.delete, admins.assign_roles |
| الأدوار | roles.view, roles.create, roles.edit, roles.delete, roles.assign_permissions |
| الإعدادات | settings.view, settings.edit |
| الطلاب | students.view, students.create, students.update, students.delete, students.restore, students.verify |
| الفئات | categories.view, categories.create, categories.edit, categories.delete, categories.restore |
| الدورات | courses.view, courses.create, courses.edit, courses.delete, courses.restore |
| المناهج | curriculum.view, curriculum.create, curriculum.edit, curriculum.delete |
| المدرّسون | instructors.view, instructors.create, instructors.edit, instructors.delete, instructors.restore |
| التسجيلات | enrollments.view, enrollments.create, enrollments.edit, enrollments.delete |
| الطلبات | orders.view, orders.create, orders.edit, orders.delete |
| التقييمات | reviews.view, reviews.edit, reviews.delete, reviews.restore |
| الحصص المباشرة | live_sessions.view, live_sessions.create, live_sessions.edit, live_sessions.delete |
| الواجبات | assignments.view, assignments.create, assignments.edit, assignments.delete |
| المدونة | blog.view, blog.create, blog.edit, blog.delete, blog.restore |
| المساعد الذكي | ai_chat.use, ai_chat.view_models |
كل صلاحية قراءة تنتهي بـ .view ولا تنتهي بها أي صلاحية أخرى: دور المشاهد (Viewer) التجريبي مبني على هذه القاعدة. الأدوار التي تنشئها البيانات النموذجية:
| الدور | يمنح |
|---|---|
| المدير العام (Super Admin) | كل شيء |
| لوحة الإدارة | كل شيء باستثناء roles.* وadmins.* وsettings.edit |
| المدير (Manager) | الدورات، والمناهج، والفئات، والمدرّسون، والتسجيلات، والطلبات من دون الحذف، إضافة إلى students.view وreviews.view وreviews.edit |
| المحرر (Editor) | blog.*, reviews.view, reviews.edit, categories.view, courses.view, instructors.view |
| المشاهد (Viewer) | كل صلاحية .view |
| المدرّس | الحصص المباشرة، والواجبات، والمناهج، وcourses.view، وcourses.create، وcourses.edit، وقراءة الطلاب والتسجيلات والتقييمات |
يحمل حساب المسؤول المرتبط بمدرّس الحقل instructor_id في إجابة تسجيل الدخول، ويُقيَّد بدوراته الخاصة إضافة إلى صلاحياته: لا تعرض القوائم إلا تلك الدورات وطلابها، وأي عملية كتابة خارجها تجيب بـ 403.
عندما تتغير أدوار مسؤول، تُبلَّغ لوحة الإدارة عبر مقبس /auth (الحدث permissions-updated) لتعيد تحميل GET /api/auth/me. ولا يقبل هذا المقبس إلا رموز المسؤولين.
الكتالوج العام
لا حاجة إلى رمز. هذه هي المسارات التي تستدعيها الصفحات العامة في موقع الطلاب.
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/health | أي شخص | فحص الجاهزية |
GET | /api/users/courses | أي شخص | يسرد الدورات العامة المنشورة، مقسّمة إلى صفحات (page_count، والإعداد courses_per_page افتراضيًا)، مع عوامل التصفية والترتيب |
GET | /api/users/courses/categories | أي شخص | التصنيفات التي تضم دورة عامة واحدة على الأقل، مع أعدادها |
GET | /api/users/courses/:slug | أي شخص | دورة عامة منشورة واحدة مع أقسامها ودروسها. والمسودة تُجاب بالرمز 404. ولا تحمل محتواها وفيديوها إلا دروس المعاينة المجانية. |
GET | /api/users/courses/:slug/reviews | أي شخص | التقييمات المنشورة للدورة، الأحدث تحديثًا أولًا، مقسّمة إلى صفحات (page_count، و5 افتراضيًا) |
GET | /api/users/Instructors | أي شخص | دليل المدرّسين، مقسّم إلى صفحات (per_page، وهو 8 افتراضيًا)، مع التصفية حسب specialty |
GET | /api/users/Instructors/:username | أي شخص | مدرّس واحد مع دوراته العامة |
GET | /api/users/blog | أي شخص | المقالات المنشورة، الأحدث أولًا، مقسّمة إلى صفحات (page_count، وهو 9 افتراضيًا)، مع التصفية حسب tag |
GET | /api/users/blog/tags | أي شخص | كل وسم مستخدم، مع عدد المقالات التي تحمله |
GET | /api/users/blog/:slug | أي شخص | مقالة منشورة واحدة |
GET | /api/users/platform/figures | أي شخص | أرقام الصفحة الرئيسية: الطلاب، والدورات، والمدرّسون، والدول، ونسبة الرضا |
GET | /api/categories | أي شخص | قائمة التصنيفات، مقسّمة إلى صفحات، مع search وis_active وparent_id وhas_courses |
GET | /api/categories/roots | أي شخص | التصنيفات الرئيسية |
GET | /api/categories/slug/:slug | أي شخص | تصنيف واحد حسب المعرّف النصي (slug) |
GET | /api/categories/:id | أي شخص | تصنيف واحد حسب المعرّف (id) |
GET | /api/helpers/countries | أي شخص | الدول لحقل اختيار، بلغة الطلب |
GET | /api/shop/payment-methods | أي شخص | طرق الدفع التي يجب أن تعرضها صفحة الدفع، وأيها مستضافة |
الحرف الكبير I في /api/users/Instructors هو المسار الذي يستدعيه موقع الطلاب؛ والمطابقة لا تميّز بين الأحرف الكبيرة والصغيرة.
تسجيل الطلاب وتسجيل دخولهم
يستخدم موقع الطلاب المسارات تحت /api/users/auth. يسجّل إنشاء الحساب دخول الطالب مباشرة ويرسل إليه رابط تأكيد بالبريد؛ ويظل بإمكان الحساب غير المؤكد التصفح والشراء.
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
POST | /api/users/auth/register | أي شخص | ينشئ الحساب (first_name وlast_name وemail وpassword من 8 أحرف أو أكثر، وphone اختياريًا) ويسجّل الدخول. يوضح data.verification_email_sent ما إذا كانت الرسالة قد أُرسلت. |
POST | /api/users/auth/login | أي شخص | يسجّل الدخول بـ email وpassword، ويجيب بـ token وuser |
POST | /api/users/auth/logout | أي شخص | لا شيء يُلغى؛ يتيح للعميل مسح الرمز المميز الخاص به |
POST | /api/users/auth/resend | أي شخص | يعيد إرسال رابط التأكيد إلى email |
POST | /api/users/auth/verify-email | أي شخص | يؤكد العنوان باستخدام token من الرابط (صالح لمدة 24 ساعة) |
POST | /api/users/auth/forgot-password | أي شخص | يرسل رابط إعادة تعيين إلى email (صالح لمدة ساعة واحدة) |
POST | /api/users/auth/reset-password | أي شخص | يضبط password جديدة باستخدام token من الرابط |
GET | /api/users/auth/me | الطالب | الطالب المسجّل دخوله |
يُجيب resend وforgot-password بالطريقة نفسها سواء كان للعنوان حساب أم لا، فلا يمكن استخدامهما لمعرفة من المسجّل. وتسجيل الدخول وإنشاء الحساب وresend وforgot-password وreset-password محدودة المعدّل (المصادقة).
تعمل مجموعة ثانية من مسارات الطلاب تحت /api/students/auth على الحسابات نفسها، وتجيب أيضًا بـ token وuser. لا يستخدمها موقع الطلاب؛ فضّل /api/users/auth.
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
POST | /api/students/auth/register | أي شخص | ينشئ حساب طالب ويسجّل الدخول، دون رسالة تأكيد |
POST | /api/students/auth/login | أي شخص | يسجّل الدخول |
GET | /api/students/auth/me | الطالب | الملف الشخصي للطالب المسجّل دخوله |
PATCH | /api/students/auth/me | الطالب | يحدّث الاسم أو البريد الإلكتروني أو الهاتف |
PATCH | /api/students/auth/me/password | الطالب | يغيّر كلمة المرور |
POST | /api/students/auth/forgot-password | أي شخص | يرسل رابط إعادة تعيين إلى email، ويُجيب بالطريقة نفسها سواء كان للعنوان حساب أم لا |
POST | /api/students/auth/reset-password | أي شخص | يضبط كلمة مرور جديدة باستخدام رمز إعادة التعيين |
الملف الشخصي للطالب ودوراته وتقدّمه
تحتاج كل المسارات هنا إلى رمز طالب. يُشار إلى الدورات والدروس بقيمة code الخاصة بها، لا بمعرّفها الرقمي.
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/users/profile | الطالب | الطالب المسجّل دخوله |
PATCH | /api/users/profile | الطالب | يحدّث first_name أو last_name أو email أو phone |
PATCH | /api/users/profile/password | الطالب | يغيّر كلمة المرور (الحالية وجديدة من 8 أحرف أو أكثر) |
GET | /api/users/dashboard/overview | الطالب | كل ما تعرضه الشاشة الرئيسية للوحة الطالب، في استدعاء واحد |
GET | /api/users/dashboard/kpis | الطالب | الأرقام الرئيسية للطالب |
GET | /api/users/dashboard/radar | الطالب | مخطط المهارات، من الإعداد dashboard_radar_metrics |
GET | /api/users/enrollments | الطالب | دورات الطالب، مقسّمة إلى صفحات (page_count، و100 افتراضيًا)، مع التصفية حسب type وsearch وstatus |
GET | /api/users/enrollments/courses/:code | الطالب | المحتوى الكامل لدورة يملكها الطالب، مع حالة كل درس والتقدّم |
PATCH | /api/users/enrollments/courses/:code | الطالب | يسجّل آخر درس فُتح (last_accessed_lesson_id) |
POST | /api/users/enrollments/lessons/:lessonCode/complete | الطالب | يحدّد الدرس كمكتمل ويحدّث تقدّم الدورة |
GET | /api/users/enrollments/lessons/:lessonCode/note | الطالب | ملاحظة الطالب على درس |
PUT | /api/users/enrollments/lessons/:lessonCode/note | الطالب | يحفظ الملاحظة (body) |
GET | /api/users/search | الطالب | بحث شامل (q، وlimit لكل نوع): دورات الطالب، والكتالوج، والمدرّسون، وغير ذلك |
GET | /api/users/courses/:courseId/review | الطالب | تقييم الطالب نفسه للدورة، أو null إذا لم يقيّمها |
PUT | /api/users/courses/:courseId/review | الطالب | يكتب تقييم الطالب أو يستبدله: rating من 1 إلى 5، وcomment اختياري حتى 2,000 حرف |
DELETE | /api/users/courses/:courseId/review | الطالب | يسحب تقييم الطالب |
تأخذ مسارات التقييم المعرّف الرقمي للدورة، ولكل طالب تقييم واحد لكل دورة. ولا يكتبه إلا طالب مسجّل في الدورة؛ والتسجيل الملغى يُجاب بالرمز 403.
- يكون التقييم
publishedفورًا، أوpendingإلى أن يعتمده مشرف عندما تكون قيمة الإعدادreviews_require_approvalهيtrue. وتعديل تقييم أخفاه مشرف يعيده إلىpending. - التقييم الذي حذفه مشرف يعود بالحالة
status: removedولا يمكن تعديله ولا سحبه (403). - كل كتابة تعيد حساب تقييم الدورة وعدد تقييماتها، وكذلك تقييم مدرّسها وعدده.
- التقييم الجديد، والتعديل الذي ينتظر الموافقة، يُشعِران الطاقم الذي يملك
reviews.view.
الاختبارات والواجبات والتقويم
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/users/quizzes?course_id= | الطالب | اختبارات دورة يملكها الطالب |
GET | /api/users/quizzes/:id | الطالب | اختبار واحد بأسئلته، دون الإجابات |
GET | /api/users/quizzes/:id/attempts | الطالب | محاولات الطالب السابقة |
POST | /api/users/quizzes/:id/attempts | الطالب | يرسل answers (معرّف السؤال مقابل معرّفات الخيارات المختارة) ويعيد النتيجة |
GET | /api/users/dashboard/calendar | الطالب | الحصص ومواعيد تسليم الواجبات بين from وto (تواريخ ISO، 7 أيام افتراضيًا، و92 يومًا كحد أقصى) |
POST | /api/users/dashboard/calendar/assignments/:id/submit | الطالب | يسلّم واجبًا (body) |
DELETE | /api/users/dashboard/calendar/assignments/:id/submit | الطالب | يسحب تسليمًا |
مسارات الحصص المباشرة في التقويم موصوفة في الحصص المباشرة.
رسائل الطلاب وإشعاراتهم
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/users/conversations | الطالب | محادثات الطالب مع مدرّسيه |
POST | /api/users/conversations | الطالب | يفتح المحادثة مع مدرّس course_id، أو يعيدها إن كانت موجودة |
GET | /api/users/conversations/:id/messages | الطالب | الرسائل في محادثة واحدة |
POST | /api/users/conversations/:id/messages | الطالب | يرسل رسالة: body، أو صورة (attachment_url، attachment_name، attachment_type)، أو كليهما |
PATCH | /api/users/conversations/:id/read | الطالب | يحدّد المحادثة كمقروءة |
PATCH | /api/users/conversations/:id/unread | الطالب | يحدّدها كغير مقروءة |
GET | /api/users/notifications | الطالب | إشعارات الطالب |
PATCH | /api/users/notifications/:id/read | الطالب | يحدّد إشعارًا واحدًا كمقروء |
PATCH | /api/users/notifications/read-all | الطالب | يحدّد الكل كمقروء |
DELETE | /api/users/notifications/:id | الطالب | يحذف إشعارًا واحدًا |
تُدفع الإشعارات الجديدة أيضًا عبر Socket.IO، على مساحة الأسماء /notifications على عنوان واجهة API من دون /api. مرّر الرمز المميز في auth.token أثناء المصافحة واستمع إلى notification:created. يستخدم المسؤولون المقبس نفسه برموزهم الخاصة.
الدفع والمدفوعات
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/shop/payment-methods | أي شخص | طرق الدفع methods التي تعرضها صفحة الدفع وأيها hosted |
POST | /api/shop/checkout | الطالب | يشتري course_id، أو ما يصل إلى 50 من course_ids في عملية دفع واحدة، مع payment_method (card أو paypal) وlocale |
POST | /api/shop/orders/:reference/settle | الطالب | يُكمل الدفع المستضاف عند عودة المشتري. مطلوب لـ PayPal؛ ولا يفعل شيئًا مع Stripe. |
GET | /api/shop/orders | الطالب | طلبات الطالب |
POST | /api/webhooks/payments/stripe | Stripe، موقَّع | يُتمّ الطلبات أو يُفشلها أو يستردّها بناءً على أحداث Stripe |
POST | /api/webhooks/payments/paypal | PayPal، موقَّع | يُتمّ الطلبات أو يُفشلها أو يستردّها بناءً على أحداث PayPal |
عندما تجيب صفحة الدفع بـ redirect_url، وجّه المشتري إليه واعتبر الطلب pending: يُمنح المقعد عندما يؤكد الـ webhook الخاص بمعالج الدفع العملية، لا عند العودة. يتحقق كل webhook من توقيع معالج الدفع ويجيب بـ 401 عند عدم التطابق. تُطبَّق الأحداث مرة واحدة، مهما كرّر معالج الدفع المحاولة.
تمر الدورة المجانية (السعر 0) عبر المسار نفسه ولا تصل إلى أي معالج دفع، فتعمل دون أي مفاتيح دفع. يُكتب الطلب بالحالة paid مع gateway: "free" وredirect_url: null، ويُمنح المقعد فورًا، ويتلقى الطالب رسالة التسجيل دون إيصال. وتُحسب الطلبات المجانية تسجيلات لا مبيعات: فهي مستبعدة من متوسط قيمة الطلب.
إعداد معالجات الدفع واشتراكات الـ webhook الخاصة بها: المدفوعات.
تسجيل دخول المسؤولين وحسابات الطاقم
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
POST | /api/auth/login | أي شخص | يسجّل دخول مسؤول، ويُجيب بـ access_token والأدوار والصلاحيات. محدود المعدّل. |
GET | /api/auth/me | أي مسؤول مسجّل دخوله | المسؤول المسجّل دخوله مع أدواره وصلاحياته |
GET | /api/admins | admins.view | قائمة الطاقم، مع التصفية حسب email وname وphone وrole_id |
GET | /api/admins/statistics | admins.view | أعداد الطاقم |
GET | /api/admins/:id | admins.view | مسؤول واحد |
POST | /api/admins | admins.create | ينشئ مسؤولًا |
PATCH | /api/admins/:id | admins.edit | يحدّث مسؤولًا |
PATCH | /api/admins/:id/roles | admins.assign_roles | يستبدل أدوار المسؤول (role_ids) |
DELETE | /api/admins/:id | admins.delete | يحذف مسؤولًا |
PATCH | /api/admins/profile | أي مسؤول مسجّل دخوله | يحدّث اسم المسؤول المسجّل دخوله وبيانات الاتصال به وصورته |
PATCH | /api/admins/profile/password | أي مسؤول مسجّل دخوله | يغيّر كلمة مرور المسؤول المسجّل دخوله الخاصة به |
عنوان البريد يخص مسؤولًا واحدًا، حتى لو كان محذوفًا: إنشاء مسؤول، أو تغيير بريد إلى عنوان مستخدم، يُجاب بالرمز 409.
الأدوار
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/roles | roles.view | الأدوار، مقسّمة إلى صفحات عند إرسال page، مع التصفية حسب name وguard_name وcreated_from وcreated_to |
GET | /api/roles/statistics | roles.view | أعداد الأدوار |
GET | /api/roles/select | roles.view | كل الأدوار، لأداة اختيار |
GET | /api/roles/permissions | roles.view | كل الصلاحيات، مجمّعة حسب الوحدة |
GET | /api/roles/:id | roles.view | دور واحد بصلاحياته |
POST | /api/roles | roles.create | ينشئ دورًا (name) |
PUT | /api/roles/:id | roles.edit | يعيد تسمية دور |
POST | /api/roles/:id/permissions | roles.assign_permissions | يستبدل صلاحيات الدور بـ permissions، وهي قائمة أسماء |
DELETE | /api/roles/:id | roles.delete | يحذف دورًا |
الطلاب
يُشار إلى حسابات الطلاب بقيمة username. حذف أحدها حذف مؤقت يمكن التراجع عنه.
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/users | students.view | الطلاب، مع search وemail وphone وcountry_id وusername وfirst_name وlast_name وfrom_date وto_date وverified |
GET | /api/users/statistic | students.view | أعداد الطلاب |
GET | /api/users/:username | students.view | طالب واحد |
POST | /api/users | students.create | ينشئ طالبًا |
PATCH | /api/users/:username | students.update | يحدّث طالبًا |
PATCH | /api/users/:username/change-password | students.update | يضبط كلمة مرور طالب |
POST | /api/users/:username/resend-verification-email | students.update | يرسل رابط التأكيد مجددًا. تكون data.sent بقيمة false وdata.simulated بقيمة true عندما لا يكون هناك مزوّد بريد وذهب الرابط إلى السجل. 409 إذا كان مؤكَّدًا، و429 عندما تلقى العنوان رسائل كثيرة، و503 عندما رفض المزوّد. |
POST | /api/users/:username/make-verified | students.verify | يحدّد البريد الإلكتروني كمؤكَّد |
POST | /api/users/:username/make-unverified | students.verify | يحدّد البريد الإلكتروني كغير مؤكَّد |
DELETE | /api/users/:username | students.delete | ينقل الطالب إلى سلة المحذوفات |
GET | /api/users/deleted | students.view أو students.delete أو students.restore | الطلاب المحذوفون |
GET | /api/users/deleted/:username | students.view أو students.delete أو students.restore | طالب محذوف واحد |
POST | /api/users/deleted/:username/restore | students.restore | يستعيد طالبًا محذوفًا |
المدرّسون
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/instructors | instructors.view | المدرّسون، مع search وspecialty وstatus وis_featured |
GET | /api/instructors/statistic | instructors.view | أعداد المدرّسين |
GET | /api/instructors/username/:username | instructors.view | مدرّس واحد حسب اسم المستخدم |
GET | /api/instructors/:id | instructors.view | مدرّس واحد |
POST | /api/instructors | instructors.create | ينشئ مدرّسًا |
PATCH | /api/instructors/:id | instructors.edit | يحدّث مدرّسًا |
DELETE | /api/instructors/:id | instructors.delete | ينقل مدرّسًا إلى سلة المحذوفات |
GET | /api/instructors/deleted | instructors.view أو instructors.delete أو instructors.restore | المدرّسون المحذوفون |
POST | /api/instructors/deleted/:id/restore | instructors.restore | يستعيد واحدًا |
يراسل حساب المدرّس طلابه عبر هذه المسارات، التي تجيب بـ 403 للمسؤول غير المرتبط بمدرّس:
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/conversations | حساب المدرّس | محادثات المدرّس |
GET | /api/conversations/with/:userId | حساب المدرّس | الدورات المشتركة بين المدرّس وطالب ما، لبدء محادثة منها |
POST | /api/conversations | حساب المدرّس | يفتح محادثة مع user_id، أو يعيدها إن كانت موجودة، اختياريًا حول course_id |
GET | /api/conversations/:id/messages | حساب المدرّس | الرسائل في محادثة واحدة |
POST | /api/conversations/:id/messages | حساب المدرّس | يرسل رسالة |
PATCH | /api/conversations/:id/read | حساب المدرّس | يحدّدها كمقروءة |
PATCH | /api/conversations/:id/unread | حساب المدرّس | يحدّدها كغير مقروءة |
الفئات
القراءات متاحة للجميع ومدرجة مع الكتالوج العام. أما الكتابة فتحتاج إلى صلاحية:
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/categories/statistic | categories.view | أعداد التصنيفات |
POST | /api/categories | categories.create | ينشئ تصنيفًا |
PATCH | /api/categories/:id | categories.edit | يحدّث تصنيفًا |
DELETE | /api/categories/:id | categories.delete | ينقل تصنيفًا إلى سلة المحذوفات |
GET | /api/categories/deleted | categories.delete أو categories.restore | التصنيفات المحذوفة |
POST | /api/categories/deleted/:id/restore | categories.restore | يستعيد واحدًا |
الدورات
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/courses | courses.view | الدورات، مع search وcategory_id وinstructor_id وstatus وtype وis_public وis_featured |
GET | /api/courses/statistic | courses.view | أعداد الدورات |
GET | /api/courses/slug/:slug | courses.view | دورة واحدة حسب المعرّف النصي (slug) |
GET | /api/courses/:id | courses.view | دورة واحدة |
POST | /api/courses | courses.create | ينشئ دورة |
PATCH | /api/courses/:id | courses.edit | يحدّث دورة |
DELETE | /api/courses/:id | courses.delete | ينقل دورة إلى سلة المحذوفات |
GET | /api/courses/deleted | courses.delete أو courses.restore | الدورات المحذوفة |
POST | /api/courses/deleted/:id/restore | courses.restore | يستعيد واحدًا |
المنهج: الأقسام والدروس والموارد
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/courses/:courseId/sections | curriculum.view | أقسام دورة |
POST | /api/courses/:courseId/sections | curriculum.create | يضيف قسمًا |
POST | /api/courses/:courseId/sections/reorder | curriculum.edit | يضبط ترتيب الأقسام من ids |
GET | /api/sections/:id | curriculum.view | قسم واحد |
PATCH | /api/sections/:id | curriculum.edit | يحدّث قسمًا |
DELETE | /api/sections/:id | curriculum.delete | يحذف قسمًا |
GET | /api/sections/:sectionId/lessons | curriculum.view | دروس قسم |
POST | /api/sections/:sectionId/lessons | curriculum.create | يضيف درسًا |
POST | /api/sections/:sectionId/lessons/reorder | curriculum.edit | يضبط ترتيب الدروس من ids |
GET | /api/lessons/:id | curriculum.view | درس واحد |
PATCH | /api/lessons/:id | curriculum.edit | يحدّث درسًا |
DELETE | /api/lessons/:id | curriculum.delete | يحذف درسًا |
GET | /api/lessons/:lessonId/resources | curriculum.view | الموارد القابلة للتنزيل في درس |
POST | /api/lessons/:lessonId/resources | curriculum.edit | يرفق موردًا |
PATCH | /api/lesson-resources/:id | curriculum.edit | يحدّث موردًا |
DELETE | /api/lesson-resources/:id | curriculum.edit | يزيل موردًا |
الاختبارات والواجبات
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/quizzes?course_id= | courses.view | اختبارات دورة (course_id مطلوب) |
GET | /api/quizzes/:id | courses.view | اختبار واحد بأسئلته وإجاباته |
POST | /api/quizzes | courses.create | ينشئ اختبارًا |
PATCH | /api/quizzes/:id | courses.edit | يحدّث اختبارًا |
DELETE | /api/quizzes/:id | courses.delete | يحذف اختبارًا |
POST | /api/quizzes/:id/questions | courses.edit | يضيف سؤالًا |
PATCH | /api/quizzes/:id/questions/:questionId | courses.edit | يحدّث سؤالًا |
DELETE | /api/quizzes/:id/questions/:questionId | courses.edit | يحذف سؤالًا |
GET | /api/assignments | assignments.view | الواجبات، مع search وcourse_id وlesson_id وstatus وfrom وto |
GET | /api/assignments/:id | assignments.view | واجب واحد |
GET | /api/assignments/:id/submissions | assignments.view | التسليمات التي تنتظر التصحيح |
PATCH | /api/assignments/submissions/:submissionId/grade | assignments.edit | يصحّح تسليمًا |
POST | /api/assignments | assignments.create | ينشئ واجبًا |
PATCH | /api/assignments/:id | assignments.edit | يحدّث واجبًا |
DELETE | /api/assignments/:id | assignments.delete | يحذف واجبًا |
التسجيلات والطلبات
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/enrollments | enrollments.view | التسجيلات، مع search وcourse_id وuser_id وstatus وdate_from وdate_to |
GET | /api/enrollments/statistic | enrollments.view | أعداد التسجيلات |
GET | /api/enrollments/:id | enrollments.view | تسجيل واحد |
POST | /api/enrollments | enrollments.create | يسجّل طالبًا يدويًا |
PATCH | /api/enrollments/:id | enrollments.edit | يحدّث تسجيلًا |
DELETE | /api/enrollments/:id | enrollments.delete | يزيل تسجيلًا |
GET | /api/orders | orders.view | الطلبات، مع search وstatus وpayment_method وcourse_id وuser_id وdate_from وdate_to وpage وlimit وsort_by وsort_order |
GET | /api/orders/revenue | orders.view | الإيرادات بين date_from وdate_to. ويستبعد متوسط قيمة الطلب الطلبات المجانية. |
GET | /api/orders/revenue/series | orders.view | الإيرادات اليومية لآخر days يومًا (30 افتراضيًا، و365 كحد أقصى) |
GET | /api/orders/:id | orders.view | طلب واحد |
POST | /api/orders | orders.create | يسجّل مقعدًا دُفع ثمنه في مكان آخر |
PATCH | /api/orders/:id | orders.edit | يحدّث طلبًا |
DELETE | /api/orders/:id | orders.delete | يحذف طلبًا |
حالة الطلب status هي pending أو paid أو failed أو refunded. ويذكر gateway معالج الدفع الذي حصّل المبلغ، أو demo للمحاكي المدمج، أو free لدورة لم تكلّف شيئًا.
التقييمات
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/course-reviews | reviews.view | التقييمات، مع search وcourse_id وuser_id وrating وstatus |
GET | /api/course-reviews/statistic | reviews.view | أعداد التقييمات |
GET | /api/course-reviews/:id | reviews.view | تقييم واحد |
PATCH | /api/course-reviews/:id | reviews.edit | يراجع تقييمًا: قيمة status هي published أو pending أو hidden |
DELETE | /api/course-reviews/:id | reviews.delete | ينقل تقييمًا إلى سلة المحذوفات |
GET | /api/course-reviews/deleted | reviews.delete أو reviews.restore | التقييمات المحذوفة |
POST | /api/course-reviews/deleted/:id/restore | reviews.restore | يستعيد واحدًا |
يكتب الطلاب تقييماتهم عبر مسارات الطالب، وتقرأ صفحة الدورة المنشور منها من الكتالوج العام. كل تغيير إشرافي يعيد حساب تقييم الدورة وتقييم المدرّس.
المدونة
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/blog | blog.view | المقالات بكل حالاتها، مع search وcategory_slug وstatus وtag |
GET | /api/blog/statistic | blog.view | أعداد المقالات |
GET | /api/blog/slug/:slug | blog.view | مقالة واحدة حسب المعرّف النصي (slug) |
GET | /api/blog/:id | blog.view | مقالة واحدة |
POST | /api/blog | blog.create | ينشئ مقالة |
PATCH | /api/blog/:id | blog.edit | يحدّث مقالة |
DELETE | /api/blog/:id | blog.delete | ينقل مقالة إلى سلة المحذوفات |
GET | /api/blog/deleted | blog.delete أو blog.restore | المقالات المحذوفة |
POST | /api/blog/deleted/:id/restore | blog.restore | يستعيد واحدًا |
الإعدادات
تُخزَّن إعدادات المنصة كأزواج من المفاتيح والقيم، ويُشار إليها بقيمة key.
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/settings | settings.view | الإعدادات، مع search وcategory وtype |
GET | /api/settings/:key | settings.view | إعداد واحد |
PATCH | /api/settings/:key | settings.edit | يغيّر قيمة إعداد |
DELETE | /api/settings/:key | settings.edit | يحذف إعدادًا |
تنشئ أداة البذر هذه الإعدادات الستة، ويقرأ كلًّا منها واجهة API أو لوحة الطالب:
| المفتاح | القيمة الأولية | وظيفته |
|---|---|---|
site_name | Learnio | اسم المنتج المكتوب في كل رسالة بريد ترسلها واجهة API |
default_locale | en | اللغة المستخدمة عندما لا يحدد الطلب لغة مدعومة. والقيمة التي ليست لغة مدعومة تُرفض بالرمز 400. |
support_email | support@learnio.com | عنوان الرد لكل رسالة بريد، فيصل الرد إلى شخص حقيقي |
courses_per_page | 12 | حجم صفحة الكتالوج العام عندما لا يحدد الطلب حجمًا (من 1 إلى 100) |
reviews_require_approval | false | عند true، ينتظر تقييم الطالب بالحالة pending حتى ينشره مشرف |
dashboard_radar_metrics | خريطة JSON من المقياس إلى الدرجة | مخطط المهارات في لوحة الطالب |
يسري التغيير على الطلب التالي أو الرسالة التالية، دون إعادة تشغيل. وتشغيل أداة البذر مجددًا يضيف الإعداد الناقص لكنه لا يستبدل قيمة محفوظة أبدًا.
رفع الوسائط
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
POST | /api/helpers/upload | أي مسؤول مسجّل دخوله، أو طالب | يرفع ملفًا واحدًا إلى مخزن الوسائط ويجيب بعناوينه |
أرسل multipart/form-data مع الملف في file، بحجم يصل إلى 150 ميغابايت، واختياريًا path (المجلد، وهو uploads افتراضيًا)، وfor (إعداد مسبق لحجم الصورة)، وtype (القيمة video لتخطي معالجة الصور). يُعاد تحجيم الصور إلى عدة نسخ؛ أما الفيديو (mp4، webm، mov، m4v) فيُخزَّن كما هو. يحتاج إلى إعدادات المخزن في تخزين الوسائط.
يحتاج المسار إلى رمز مسؤول أو طالب، ويُتحقق منه قبل قراءة الملف. ويجب أن تكون path أحد المجلدات المسرودة في back-end/src/modules/helpers/upload/upload-folders.constants.ts؛ وأي مجلد آخر يُجاب بالرمز 400. يستطيع المسؤول الرفع إلى uploads وadmins/profile وadmins/profiles وusers/profiles وblog وcategories وcourses وinstructors وmessages وai-chat. ولا يستطيع الطالب الرفع إلا إلى messages، للصور التي يرفقها بمحادثة. والشاشة الجديدة التي ترفع إلى مجلد خاص بها تحتاج إلى إضافة ذلك المجلد إلى القائمة.
curl -X POST http://localhost:8000/api/helpers/upload \
-H "Authorization: Bearer <access_token>" \
-F "file=@cover.jpg" -F "path=courses"الإشعارات والبحث والإحصاءات
| الطريقة | المسار | من يحق له استدعاؤه | وظيفته |
|---|---|---|---|
GET | /api/notifications | أي مسؤول مسجّل دخوله | إشعارات المسؤول المسجّل دخوله وعدد غير المقروء منها |
PATCH | /api/notifications/read-all | أي مسؤول مسجّل دخوله | يحدّد الكل كمقروء، ويجيب بالقائمة كاملة |
PATCH | /api/notifications/:id/read | أي مسؤول مسجّل دخوله | يحدّد إشعارًا واحدًا كمقروء، ويجيب بالقائمة كاملة |
DELETE | /api/notifications/:id | أي مسؤول مسجّل دخوله | يحذف إشعارًا واحدًا، ويجيب بالقائمة كاملة |
GET | /api/search | أي مسؤول مسجّل دخوله | بحث شامل (q، وlimit لكل نوع). لا يُبحث إلا في الأنواع التي تسمح بها صلاحيات المسؤول. |
GET | /api/statistics/trends | courses.view | الأرقام التي تقف خلف كل بطاقة إحصائية، في استدعاء واحد |
GET | /api/statistics/overview | courses.view | النظرة العامة للصفحة الرئيسية في لوحة الإدارة، خلال days، مع limit صفًا لكل قائمة |
لا يقرأ المسؤول ولا يغيّر إلا إشعاراته: تأخذ المسارات المسؤولَ من الرمز. وتكتب واجهة API إشعارًا لكل حدث من هذه الأحداث، لكل مسؤول يملك الصلاحية التي تحتاجها الشاشة المرتبطة:
| النوع | متى | من يتلقاه |
|---|---|---|
enrollment_created | يُمنح طالب مقعدًا، بالشراء أو بدورة مجانية أو من الطاقم | enrollments.view |
course_completed | يُنهي طالب دورة | enrollments.view |
course_review_submitted | يترك طالب تقييمًا، أو يعدّل تقييمًا ينتظر الموافقة | reviews.view |
course_published | تُنشر دورة | courses.view |
student_registered | ينشئ طالب حسابًا | students.view |
حساب المسؤول المرتبط بمدرّس لا يُشعَر إلا بما يخص دورات ذلك المدرّس، ولا يُشعَر بالحسابات الجديدة. ويُدفع كل إشعار أيضًا عبر مقبس /notifications لحظة حفظه.
الحصص المباشرة
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
مسارات الحصص المباشرة: جدولة الجلسات، ورموز الدخول التي يتلقاها الطلاب والمضيفون لغرفة Jitsi Meet.
الشهادات
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
مسارات الشهادات: كيف يطلب الطالب شهادة لدورة أنهاها، وعنوان التحقق العام.
المساعد الذكي
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
مسارات المساعد الذكي: بث الرد، وقائمة النماذج، وجلسات المحادثة المحفوظة.
سجل محادثات المساعد
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
حفظ محادثات المساعد وعرضها وإعادة تسميتها.
خادم MCP
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
وحدة MCP التي تقدّم بيانات لوحة الإدارة كأدوات للمساعد.
مسارات وضع العرض التجريبي
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
المسارات التي يستخدمها العرض التجريبي العام: مفتاح العرض التجريبي وحسابات الزوار.
بوابات دفع مخصّصة
مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.
كيف بُنيت طبقة الدفع: واجهتا البوابة والـ webhook، والـ webhook الخاص بالمحاكي، وإضافة معالج دفع.