١. نظرة عامة
الأكاديمية على إنجازيو نسختك الخاصة من المنصة: تعمل على نطاق فرعي من موقعك أنت (مثل board.example.com)، وتحمل اسمك وشعارك، ولها مديروها ومعلّموها وطلابها وحصصها وسبوراتها.
يدير مديرُ الأكاديمية كل شيء من لوحة التحكم على هذا النطاق. والربط يجيب عن ثلاثة أسئلة فقط:
- من هذا الشخص؟ — كيف يدخل المستخدم: بحسابه الموجود في منصتك، أو بجوجل، أو بمايكروسوفت، أو من منصة التعلّم، أو بحساب تنشئه له في إنجازيو.
- ما دوره؟ — مدير أكاديمية أو معلّم أو طالب، يُستنتج تلقائيًّا من البيانات التي ترجعها منصتك أصلًا.
- ما حصصه؟ — لتكون لكل حصة سبورتها، يفتحها معلّمها ويدخلها طلابها.
| منصتك | المسار المقترح | الكود المطلوب عندك |
|---|---|---|
| أي موقع، ولا يوجد مطوّر | أ · حسابات يديرها المدير (استيراد + روابط دعوة) | لا شيء |
| المستخدمون يدخلون بـ Google Workspace أو Microsoft 365 | ب · OpenID Connect | لا شيء — بضعة إعدادات |
| Keycloak أو Auth0 أو Okta أو Azure AD B2C أو ووردبريس بإضافة OIDC أو أي خادم OIDC | ب · OpenID Connect | لا شيء — تسجيل تطبيق واحد |
| Moodle أو Canvas أو Blackboard أو Brightspace أو Schoology أو Sakai | ج · LTI 1.3 | لا شيء — تسجيل أداة واحدة |
موقع خاص بكوكي جلسة وواجهة /me | د · الدخول بجلسة موقعك | غالبًا لا شيء |
| تريد إنشاء السبورات من صفحات حصصك أنت | هـ · واجهة الشركاء البرمجية | نداء واحد من خادمك |
| تريد مزامنة الأشخاص والحصص تلقائيًّا | و · Webhook أو تقويم iCal | بلا كود (Zapier أو Make أو n8n) |
٢. البدء السريع (١٥ دقيقة)
- اشترك في باقة أكاديمية على injazio.com فيصلك حساب مدير.
- أضف سجلّ DNS واحدًا:
board← CNAME ←board.injazio.com(القسم ٤). شهادة HTTPS تصدر تلقائيًّا. - افتح
https://board.example.com/admin/academyوادخل بحساب المدير. - اختر مسار الدخول من الأكاديمية ← الربط (الأقسام ٥ إلى ٨).
- اضبط قواعد الأدوار إن كانت منصتك ترسل الأدوار (القسم ٩).
- أضف الحصص، أو دعها تتزامن من منصة التعلّم أو التقويم أو الـWebhook (القسمان ١٠ و١١).
- راجع قائمة الإطلاق (القسم ١٦).
٣. المفاهيم الأساسية
- الأكاديمية (المستأجر)
- مساحتك المعزولة. لا تنتقل بيانات بين أكاديمية وأخرى أبدًا.
- نطاق الأكاديمية
- نطاقك الفرعي مثل
board.example.com، وعليه كل روابط الدخول. - مدير الأكاديمية
- يدير الأشخاص والحصص والنطاق والربط. ولا يصير مديرًا لمنصة إنجازيو أبدًا.
- المعلّم
- يملك السبورات وله كل أدوات الشرح: الرسم والمناهج والألعاب والاختبارات والتسجيل والشهادات. ويُحسب من مقاعد المعلّمين في باقتك.
- الطالب
- يدخل السبورات المدعوّ إليها، ويرى حصصه وسبوراتها في حصصي.
- المعرّف الخارجي
- معرّف المستخدم الثابت في منصتك (
subأوidأوuuid…). لا يتغيّر طوال عمر الحساب. البريد ليس معرّفًا. - الحصة
- موعد له معلّم وطلاب. تُنشأ سبورتها عند أول فتح من المعلّم، فالحصص التي لا تُفتح لا تستهلك من حصة السبورات.
أولوية الدور. الدور الذي يضبطه المدير يدويًّا يُقفَل، فلا تغيّره أي مزامنة. وإلا فقواعد الأدوار (القسم ٩) هي التي تقرّر، فإن لم تنطبق قاعدة طُبّقت خريطة مدمجة: admin ← مدير أكاديمية، و teacher أو instructor أو trainer ← معلّم، وما عداها ← طالب. ومالك الأكاديمية مدير دائمًا.
مقاعد المعلّمين. إن امتلأت مقاعد باقتك رُفضت الترقية اليدوية بالرمز teachers_limit_reached، ومن يصل بالدخول الموحّد معلّمًا يدخل طالبًا مع تنبيه، حتى يفرغ مقعد.
٤. الخطوة الأولى — ربط نطاقك
من الأكاديمية ← النطاق اكتب النطاق الفرعي الذي تريده (مثل board.example.com)، ثم أنشئ هذا السجلّ عند مزوّد DNS (Cloudflare أو GoDaddy أو Namecheap أو Route 53…):
board.example.com. CNAME board.injazio.com.- إن لم يسمح مزوّدك بـCNAME على هذا الاسم فاستعمل سجلّ A الظاهر في اللوحة.
- في Cloudflare اجعل السجلّ DNS only (السحابة الرمادية) حتى تصدر الشهادة.
- لا تستطيع توجيه الاسم الآن؟ أثبت الملكية بسجلّ TXT:
_injazio-verify.board.example.comبالقيمة الظاهرة في اللوحة، ثم حوّل الـCNAME لاحقًا. - اضغط تحقّق، فتنتقل الحالة من
waiting_dnsإلىready. شهادة HTTPS تصدر وتتجدّد تلقائيًّا. - بعد صدور الشهادة يمكنك جعل النطاق أساسيًّا. والحدّ ثلاثة نطاقات لكل أكاديمية.
٥. المسار أ — حسابات يديرها المدير (بلا كود)
ينشئ المدير الحسابات من الأكاديمية ← الأشخاص: واحدًا واحدًا، أو باستيراد ملف، أو بمشاركة رابط دعوة. مناسب إن لم يكن في منصتك دخول موحّد، أو لتبدأ اليوم.
استيراد جدول
ارفع ملف .xlsx أو .csv (بترميز UTF-8 أو UTF-16، والفاصل فاصلة أو فاصلة منقوطة أو Tab)، حتى ٥٬٠٠٠ صف. العناوين تُفهم بالعربية والإنجليزية. ابدأ دائمًا بـالمعاينة: تعرض نتيجة كل صف دون أن تكتب شيئًا.
| العمود | العناوين المقبولة | ملاحظات |
|---|---|---|
| الاسم * | الاسم، name، full name | إلزامي |
| البريد | البريد، البريد الإلكتروني، email | البريد أو اسم المستخدم — أحدهما إلزامي |
| اسم المستخدم | اسم المستخدم، username، login | حروف وأرقام و _ . - |
| الدور | الدور، النوع، role | مدير · معلم · طالب (أو admin · teacher · student). الأصل: طالب |
| كلمة المرور | كلمة المرور، password | إن تُركت فارغة تُولَّد كلمة سهلة القراءة من ٨ أحرف وتظهر مرة واحدة |
| الجوال | الجوال، الهاتف، phone | اختياري |
| المعرّف | المعرف، رقم الحساب، external_id | معرّفه في منصتك — ليجد الدخول الموحّد الحساب نفسه لاحقًا |
الاسم,البريد,الدور,المعرف
سارة علي,sara@example.com,معلم,1042
عمر خالد,omar@example.com,طالب,2210روابط الدعوة
أنشئ رابطًا لدور معيّن، مع وصف ومدة صلاحية وحدّ استعمال اختيارية. من يفتحه ينشئ حسابه بنفسه بهذا الدور:
https://board.example.com/join/inv_8fJ2kQ…(٣٢ حرفًا)- يمكن إبطال الرابط في أي وقت، والرابط المستنفَد أو المنتهي أو المُبطَل يتوقّف فورًا.
- دعوات المعلّمين تحترم مقاعد المعلّمين.
- لا نخزّن إلا بصمة الرمز — انسخ الرابط لحظة إنشائه.
٦. المسار ب — OpenID Connect (جوجل، مايكروسوفت، وأي مزوّد OIDC)
يظهر زر الدخول بـ… في صفحة دخول أكاديميتك. يصادق المستخدم عند مزوّد هويته، ثم تتحقّق إنجازيو من توقيع رمز الهوية وتُدخله. يعمل مع كل مزوّد OIDC قياسي.
القيم التي تسجّلها عند المزوّد
- نوع التطبيق
- تطبيق ويب (عميل سرّي)
- رابط إعادة التوجيه
https://board.example.com/sso/oidc/callback- النطاقات (Scopes)
openid email profile(وأضفgroupsأوrolesإن استعملتها في قواعد الأدوار)- نوع المنح
- Authorization Code مع PKCE (S256)
القيم التي تُدخلها في الأكاديمية ← الربط ← OIDC
| الحقل | Microsoft Entra ID | غيرهما (Keycloak و Auth0 و Okta…) | |
|---|---|---|---|
| المُصدِر (Issuer) | https://accounts.google.com | https://login.microsoftonline.com/{tenant-id}/v2.0 (أو common) | رابط المُصدِر عندك، مثل https://sso.example.com/realms/school |
| Client ID | من Google Cloud ← Credentials | Application (client) ID | من مزوّدك |
| Client secret | من Google Cloud | Certificates & secrets | من مزوّدك |
| حقل المعرّف | sub | sub (أو oid) | sub إلا إن فضّلت حقلًا ثابتًا آخر |
اضغط اختبار: تجلب إنجازيو /.well-known/openid-configuration وتؤكّد أن المزوّد متاح.
من يُسمح له بالدخول
| allow_mode | السلوك |
|---|---|
existing (الأصل) | من له حساب في أكاديميتك فقط (يُطابَق بالبريد الموثَّق أو بدخول OIDC سابق). الأكثر أمانًا. |
domains | كل من بريده الموثّق في النطاقات المذكورة، مثل school.edu, staff.school.edu. الجدد طلاب ما لم تقل قاعدة دور غير ذلك. |
any | أي حساب عند المزوّد. لا تستعمله إلا مع مزوّد خاص (Keycloak أو Entra الخاص بك). |
- يُربط الحساب أول مرة بالبريد الموثَّق، ثم بالمعرّف الثابت عند المزوّد.
- الحسابات الموقوفة تُرفض (
account_suspended). - السرّ يُخزَّن مشفّرًا ولا تعيده الواجهة أبدًا.
- الأمان: state و nonce و PKCE في كل دخول، والتوقيع يُتحقَّق منه بمفاتيح المزوّد العامة (RS*/ES* فقط)، مع فحص
issوaudوالصلاحية.
ملاحظات لكل مزوّد
- Google Workspace — Google Cloud Console ← APIs & Services ← Credentials ← OAuth client ID ← Web. أضف رابط إعادة التوجيه. واجعل شاشة الموافقة *Internal* لتقصرها على مؤسستك.
- Microsoft 365 / Entra ID — Entra admin center ← App registrations ← New ← Web ← رابط إعادة التوجيه. أضف Client secret. ضع معرّف مؤسستك في المُصدِر لتقصره عليها. وأضف حقل
groupsمن *Token configuration* إن كنت تستنتج الأدوار من المجموعات. - Keycloak — Clients ← Create ← OpenID Connect، مع تفعيل *Client authentication*، ورابط إعادة التوجيه كما سبق. أضف mapper لـ*realm roles* في رمز الهوية لتستعمل الأدوار.
- ووردبريس — ثبّت إضافة خادم OpenID Connect (مثل *OpenID Connect Server* أو *miniOrange OAuth Server*)، وسجّل إنجازيو عميلًا برابط إعادة التوجيه السابق.
- Auth0 / Okta / OneLogin / Cognito — أنشئ *Regular Web Application* وانسخ المُصدِر و Client ID والسرّ.
٧. المسار ج — LTI 1.3 (Moodle، Canvas، Blackboard، Brightspace…)
أضف سبورة إنجازيو أداةً خارجية في منصة التعلّم. يضيفها المعلّم نشاطًا داخل المقرّر، فإذا ضغطه المستخدم دخل بدوره الصحيح وفُتحت سبورة هذا النشاط — السبورة نفسها كل مرة. وطلاب المقرّر ينضمّون إليها تلقائيًّا.
قيم الأداة (انسخها من الأكاديمية ← الربط ← LTI)
- إصدار LTI
- LTI 1.3
- Tool URL / Target link URI
https://board.example.com/lti/launch- Initiate login URL
https://board.example.com/lti/login- Redirect URI(s)
https://board.example.com/lti/launch- Public keyset (JWKS) URL
https://api.injazio.com/api/lti/jwks- المفتاح العام
- يظهر أيضًا بصيغة PEM في اللوحة للمنصات التي تطلب مفتاحًا لا رابطًا
- طريقة الفتح
- نافذة جديدة (مستحسن — المتصفّحات تقيّد الكوكي داخل الإطارات)
- الرسائل
LtiResourceLinkRequest- الخصوصية
- شارك اسم المستخدم وبريده
ثم سجّل منصة التعلّم في إنجازيو
بعد حفظ الأداة تعرض منصتك قيمها. أدخلها في إضافة منصة:
| الحقل في إنجازيو | Moodle | Canvas | Blackboard Learn |
|---|---|---|---|
| Issuer | رابط Moodle عندك، مثل https://lms.example.com | https://canvas.instructure.com | https://blackboard.com |
| Client ID | يظهر في *Tool configuration details* | Developer Key ID | Application ID |
| Auth login URL | …/mod/lti/auth.php | https://sso.canvaslms.com/api/lti/authorize_redirect | https://developer.blackboard.com/api/v1/gateway/oidcauth |
| Keyset URL | …/mod/lti/certs.php | https://sso.canvaslms.com/api/lti/security/jwks | https://developer.blackboard.com/api/v1/management/applications/{id}/jwks.json |
| Access token URL | …/mod/lti/token.php | https://sso.canvaslms.com/login/oauth2/token | https://developer.blackboard.com/api/v1/gateway/oauth2/jwttoken |
| Deployment ID | يعرضه Moodle (اختياري — يُحفظ عند أول تشغيل) | من *Deployment ID* للتطبيق | من النشر |
Moodle خطوة بخطوة
- Site administration ← Plugins ← Activity modules ← External tool ← Manage tools ← *configure a tool manually*.
- Tool name: *Injazio Board*. و Tool URL: رابط launch السابق. و LTI version: LTI 1.3.
- Public key type: Keyset URL ← رابط JWKS السابق. و Initiate login URL و Redirection URI(s) كما سبق.
- Default launch container: New window. والخصوصية: مشاركة الاسم والبريد *Always*. ثم احفظ.
- اضغط أيقونة القائمة بجوار الأداة، وانسخ *Platform ID و Client ID و Deployment ID* والروابط الثلاثة إلى إنجازيو ← إضافة منصة.
- في المقرّر: Add an activity ← External tool ← *Injazio Board*. افتحه مرة بصفتك معلّمًا فتُنشأ السبورة.
Canvas خطوة بخطوة
- Admin ← Developer Keys ← + Developer Key ← LTI Key، واختر *Manual Entry*.
- Redirect URIs: رابط launch. و Target Link URI: رابط launch. و OpenID Connect Initiation URL: رابط login. و JWK Method: *Public JWK URL* ← رابط JWKS.
- Placements: *Course Navigation* و/أو *Link Selection*. و Privacy level: Public. احفظ وفعّل المفتاح ON.
- Admin ← Settings ← Apps ← + App ← *By Client ID* ← الصق معرّف المفتاح، وانسخ Deployment ID.
- في إنجازيو ← إضافة منصة: المُصدِر
https://canvas.instructure.com، و Client ID هو معرّف المفتاح، وروابط Canvas من الجدول.
ماذا يحدث عند التشغيل
- الأدوار:
InstructorوContentDeveloperوMentorوTeachingAssistantوAdministrator← معلّم، وما عداها ← طالب (وقواعد أدوارك مقدَّمة). - المستخدم يُعرَف بـ
iss + sub، فالشخص في مقرّرين حساب واحد. - كل رابط مورد (نشاط) = حصة واحدة وسبورة واحدة. أول معلّم يملكها، والمعلّمون الآخرون يدخلونها مشاركين في التدريس.
- الطلاب الذين يفتحون النشاط يصيرون مشاركين. وإن لم يفتح المعلّم السبورة بعد يرى الطالب شاشة *انتظار*.
- الأمان: state و nonce لمرة واحدة، والتوقيع يُتحقَّق منه بمفاتيح المنصة، مع فحص
issوaudوazpوdeployment_id، ورفض التشغيل المكرّر.
٨. المسار د — الدخول بجلسة موقعك
للمواقع الخاصة. لأن السبورة على نطاق فرعي من موقعك، يرسل المتصفّح كوكي جلستك إليها تلقائيًّا. يقرؤها خادمنا ويسأل واجهتك عن صاحبها. لا نستلم مفتاح التوقيع ولا كلمات مرور مستخدميك أبدًا.
المطلوب
- رمز الجلسة في كوكي على النطاق الأم:
Domain=.example.com; Secure; SameSite=Lax(و HttpOnly مقبول). أماlocalStorageفلا يصلح. - واجهة ترجع المستخدم الحالي مع
Authorization: Bearer <الرمز>، مثلGET https://example.com/api/me. - ترجع
200مع JSON للرمز الصالح، و401أو403للمنتهي أو غير الصالح أو الموقوف — لا200بجسم فارغ أبدًا. - تستجيب في أقل من ٦ ثوانٍ، وفيها حقل معرّف ثابت (
idأوuuid).
{
"id": 2481,
"name": "سارة علي",
"email": "sara@example.com",
"role": "trainer",
"capabilities": { "trainer": true, "admin": false }
}من الأكاديمية ← الربط ← الدخول بالجلسة اضبط اسم الكوكي ورابط /me ومسارات المعرّف والاسم والبريد والدور ومن يُسمح له. وزر فحص برمز حقيقي يعرض البيانات المقروءة والدور الذي سيأخذه. وإن لم يُضبط شيء لا يدخل أحد (يفشل مغلقًا).
الخروج من موقعك يحذف الكوكي، وإيقاف المستخدم يجعل /me تفشل — وكلاهما يسري عند أول تنقّل له في السبورة. العقد الكامل في docs/sso-partner-integration.md.
٩. قواعد الأدوار
القواعد تحوّل ما ترجعه منصتك (رمز هوية OIDC، أو ردّ /me، أو حقول LTI) إلى دور في الأكاديمية. تُفحص بالترتيب مدير ← معلّم ← طالب، وأول شرط ينطبق يفوز.
{
"admin": [ { "path": "groups", "op": "contains", "value": "academy-admins" } ],
"teacher": [ { "path": "role", "op": "in", "value": ["teacher", "trainer", "instructor"] },
{ "path": "capabilities.trainer", "op": "truthy" } ],
"student": [ { "path": "role", "op": "equals", "value": "learner" } ]
}| op | ينطبق حين |
|---|---|
equals | القيمة في path تساوي value (دون اعتبار حالة الأحرف) |
in | القيمة في path إحدى قيم القائمة value |
contains | المصفوفة (أو النص) في path تحتوي value |
truthy | القيمة في path صحيحة أو غير فارغة |
exists | المفتاح path موجود |
pathيستعمل النقطة للتداخل:user.profile.type. وحتى ٢٠ شرطًا لكل دور.- استعمل المعاينة في اللوحة: الصق ردًّا تجريبيًّا وانظر أي قاعدة تنطبق.
- الدور الذي يضبطه المدير يدويًّا مقفَل ويتقدّم على القواعد. افتح القفل لتعود المزامنة تقرّر.
١٠. الحصص والسبورات
لكل حصة معلّم وموعد اختياري وطلاب وصلاحية للطلاب (view مشاهدة أو edit تحرير). وتأتي الحصص من أي مصدر من هذه، ويمكن الجمع بينها:
| المصدر | الطريقة | المفتاح |
|---|---|---|
| اللوحة | ينشئها المدير أو المعلّم، مع تكرار أسبوعي اختياري (حتى ٥٢ أسبوعًا) | — |
| جدول | الأكاديمية ← الحصص ← استيراد (العنوان، المعلم، البداية، النهاية، الطلاب) | الصف |
| LTI | كل نشاط في منصة التعلّم | iss + deployment + resource link |
| Webhook | حدث lesson.upsert | معرّف حصتك id |
| تقويم iCal | رابط اشتراك تقويم، يُزامَن كل ساعة | UID الحدث (+ التاريخ للتكرار) |
| واجهة الشركاء | POST /partner/boards/resolve | context_type + context_id |
- السبورة تُنشأ حين يفتح المعلّم الحصة أول مرة — لا قبل ذلك، حفاظًا على حصة السبورات.
- يرى الطلاب حصصهم في حصصي ويدخلون بضغطة، وقبل أن يفتحها المعلّم يرون *في انتظار المعلّم*.
- داخل السبورة للمعلّم الأدوات كاملة: المناهج والألعاب والاختبارات والواجبات والتسجيل والشهادات والتحكّم في المشاركين.
- إلغاء الحصة يخفيها عن الطلاب، وتبقى السبورات ومحتواها.
١١. المسار و — الأتمتة: Webhook وتقويم iCal
Webhook وارد (Zapier أو Make أو n8n أو Power Automate أو خادمك)
من الأكاديمية ← الربط ← Webhook اضغط توليد، فيظهر رابط سرّي مرة واحدة:
POST https://api.injazio.com/api/hooks/academy/injwh_{academy-id}_{40 characters}أو أرسل الرمز في ترويسة X-Injazio-Webhook-Token إلى POST /hooks/academy. والجسم حدث واحد {event, data} أو دفعة {events: [...]} حتى ١٠٠ حدث.
curl -X POST "https://api.injazio.com/api/hooks/academy/injwh_124_…" \
-H "Content-Type: application/json" \
-d '{
"events": [
{ "event": "person.upsert", "data": { "external_id": "1042", "name": "سارة علي", "email": "sara@example.com", "role": "teacher" } },
{ "event": "person.upsert", "data": { "external_id": "2210", "name": "عمر خالد", "email": "omar@example.com", "role": "student" } },
{ "event": "lesson.upsert", "data": {
"id": "L-5531", "title": "الجبر — الأسبوع الثالث",
"starts_at": "2026-11-02T16:00:00+03:00", "ends_at": "2026-11-02T17:00:00+03:00",
"teacher_external_id": "1042",
"students": ["2210", "lina@example.com"]
} }
]
}'| الحدث | الحقول | الأثر |
|---|---|---|
person.upsert | external_id أو email (أحدهما إلزامي)، و name، و role | ينشئ الشخص أو يحدّثه. والأدوار اليدوية تبقى مقفلة. |
person.remove | external_id أو email | يوقف الحساب (ويبقى المحتوى). والمالك محميّ. |
lesson.upsert | id* و title* و starts_at و ends_at و teacher_external_id أو teacher_email و students (مصفوفة معرّفات أو بريد أو {external_id|email}، أو نص مفصول بفواصل) و replace_students (الأصل true) و cancelled | ينشئ الحصة أو يحدّثها بمفتاح id الخاص بك. |
lesson.cancel | id | يلغي الحصة. |
{ "success": true, "data": { "results": [
{ "event": "person.upsert", "ok": true, "user_id": 812 },
{ "event": "person.upsert", "ok": true, "user_id": 813, "created": true },
{ "event": "lesson.upsert", "ok": true, "lesson_id": 77, "students": 2, "teacher_found": true }
] } }- كل حدث يردّ
okوreasonالخاصين به، فالصف الخاطئ لا يوقف الدفعة. أرسل الأشخاص قبل الحصص التي تذكرهم. - تكرار الإرسال نفسه ينتج الحالة نفسها (idempotent).
- جدّد الرابط متى شئت فيتوقّف القديم فورًا، أو عطّله لإيقاف الـWebhook.
- Zapier: المُشغّل من تطبيقك (مثل *صف جديد في Google Sheets*) ← الإجراء *Webhooks by Zapier ← POST* ← الرابط السابق، ونوع الحمولة JSON. Make: وحدة HTTP ← *Make a request*، الطريقة POST، والجسم raw JSON.
رابط تقويم (iCal / ICS)
الصق رابط اشتراك تقويم (في Google Calendar: *العنوان السرّي بتنسيق iCal*، وفي Outlook: *رابط ICS للتقويم المنشور*، أو تصدير منصة التعلّم). و webcal:// مقبول. تُزامِن إنجازيو كل ساعة وعند الطلب، من ٧ أيام مضت إلى ١٢٠ يومًا قادمة.
SUMMARY← عنوان الحصة، وDTSTART/DTEND(مع احترام المنطقة الزمنية) ← الموعد، وUID← الهوية.- بريد
ORGANIZER← المعلّم (إن كان موجودًا)، وإلا فالمعلّم الافتراضي الذي تختاره. - بريد
ATTENDEEالمطابق لحسابات الأكاديمية ← طلاب. - التكرار اليومي والأسبوعي
RRULEيُفكّ، وSTATUS:CANCELLEDيلغي الحصة.
١٢. المسار هـ — واجهة الشركاء البرمجية
للمنصات التي تحتفظ بصفحات حصصها وتريد زر «افتح السبورة». خادمك ينادي نقطة واحدة بمعرّف الحصة ومعرّف المعلّم، فترجع رابط السبورة — تنشئها أول مرة وترجع السبورة نفسها بعد ذلك.
المصادقة
- الرابط الأساسي:
https://api.injazio.com/api - الترويسة:
X-Api-Key: injk_{academy-id}_{48 characters}— تُصدَر من الأكاديمية ← الربط ← مفاتيح API. - الصلاحيات:
boards:write(إنشاء السبورات وإدارة الوصول) وsubscription:read(قراءة الباقة والاستهلاك). استعمل مفتاحين منفصلين. - من الخادم فقط. لا نرسل ترويسات CORS، فلا تضع المفتاح في كود المتصفّح ولا في متغيّر
NEXT_PUBLIC_*. - الحدود: ٣٠ في الدقيقة لـ
resolve، و١٢٠ لمنح الوصول، و٦٠ لما عداها.
إنشاء السبورة أو فتحها — POST /partner/boards/resolve
POST /api/partner/boards/resolve
Host: api.injazio.com
X-Api-Key: injk_124_…
Content-Type: application/json
{
"context_type": "lesson",
"context_id": 4821,
"owner_external_id": "77",
"owner_name": "د. محمد أحمد",
"owner_email": "m@example.com",
"title": "المحاضرة الثالثة — النحو التطبيقي",
"student_permission": "view",
"teacher_permission": "edit",
"meta": { "course_id": 310 }
}{
"success": true,
"data": {
"uuid": "c67G7zwALS7",
"url": "https://board.example.com/waraqa/c67G7zwALS7",
"title": "المحاضرة الثالثة — النحو التطبيقي",
"created": true,
"owner_id": 5120
}
}| الحقل | إلزامي | المعنى |
|---|---|---|
context_type | نعم | lesson · course · consultation · live_class · session · workshop · assignment |
context_id | نعم | معرّفك الرقمي للحصة أو الحجز |
owner_external_id | نعم | معرّف المعلّم في منصتك — المعرّف نفسه الذي يرجعه دخولك الموحّد |
owner_name و owner_email | لا | يُستعملان عند إنشاء حساب المعلّم أول مرة |
title و description | لا | عنوان السبورة (الأصل: *سبورة الحصة #المعرّف*) |
student_permission | لا | view (الأصل) أو edit |
teacher_permission | لا | edit (الأصل) أو view |
meta | لا | أي JSON تريد حفظه مع السبورة |
created: true تعني أن السبورة أُنشئت الآن وحُسبت من حصتك، و false أنها كانت موجودة. نادِ هذه النقطة من زر افتح السبورة، لا عند حفظ الحصة.
النقاط الأخرى
| الطريقة والمسار | الجسم / الاستعلام | الغرض |
|---|---|---|
GET /partner/boards | ?context_type=&context_id= | هل لهذه الحصة سبورة؟ data: null إن لم تكن. لا تنشئ شيئًا. |
POST /partner/boards/access | context_type, context_id, viewer_external_id, viewer_name?, viewer_email?, viewer_role?, permission? (view|edit) | منح طالب الوصول إلى السبورة |
DELETE /partner/boards/access | context_type, context_id, viewer_external_id | سحب وصول هذا الطالب |
PATCH /partner/boards/access-policy | context_type, context_id, participant_permission (view|edit) | تغيير صلاحية كل المشاركين دفعة واحدة |
GET /partner/subscription | — | الباقة والحدود والاستهلاك الحالي (مفتاح subscription:read) |
أمثلة
// Laravel
$res = Http::timeout(10)
->withHeaders(['X-Api-Key' => config('services.injazio.board_key')])
->acceptJson()
->post('https://api.injazio.com/api/partner/boards/resolve', [
'context_type' => 'lesson',
'context_id' => $lesson->id,
'owner_external_id' => (string) $lesson->teacher_id,
'owner_name' => $lesson->teacher->name,
'title' => $lesson->title,
]);
if ($res->status() === 409) {
return back()->with('error', 'انتهت حصة السبورات لهذه الفترة.');
}
$lesson->update(['board_url' => $res->json('data.url')]);
return redirect()->away($res->json('data.url'));// Node.js (18+)
const res = await fetch("https://api.injazio.com/api/partner/boards/resolve", {
method: "POST",
headers: {
"X-Api-Key": process.env.INJAZIO_BOARD_KEY,
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
context_type: "lesson",
context_id: lesson.id,
owner_external_id: String(lesson.teacherId),
title: lesson.title,
}),
});
const { data } = await res.json();
res.redirect(data.url);# Python / Django
import os, requests
r = requests.post(
"https://api.injazio.com/api/partner/boards/resolve",
headers={"X-Api-Key": os.environ["INJAZIO_BOARD_KEY"], "Accept": "application/json"},
json={
"context_type": "lesson",
"context_id": lesson.id,
"owner_external_id": str(lesson.teacher_id),
"title": lesson.title,
},
timeout=10,
)
r.raise_for_status()
return redirect(r.json()["data"]["url"])١٣. واجهة الإدارة البرمجية (أتمتة اللوحة)
كل ما في لوحة الأكاديمية متاح بصيغة JSON. صادِق بحساب مدير الأكاديمية (Authorization: Bearer <access_token>) وحدّد الأكاديمية بـX-Tenant-Domain: board.example.com. الأساس: https://api.injazio.com/api/tenant.
| الطريقة | المسار | الغرض |
|---|---|---|
| GET | /admin/overview | الأعداد والمقاعد وحالة النطاق والربط |
| GET · POST | /admin/people | القائمة (مرشّحات: role و status و search و per_page) · إضافة شخص |
| PATCH · DELETE | /admin/people/{id} | تعديل (الاسم والبريد والدور والحالة و role_locked) · حذف |
| POST | /admin/people/{id}/reset-password | توليد كلمة مرور جديدة |
| POST | /admin/people/import | ملف file متعدد الأجزاء، و dry_run=1 للمعاينة |
| GET · POST · DELETE | /admin/invites[/{id}] | روابط الدعوة |
| GET · POST | /admin/domain | حالة النطاق · إضافة نطاق |
| POST | /admin/domain/{id}/verify · /primary | التحقّق من DNS · جعله أساسيًّا |
| GET | /admin/login | كل إعدادات الدخول (الأسرار لا تُرجع) |
| PUT · POST | /admin/login/roles · /roles/preview | حفظ قواعد الأدوار · تجربتها على ردّ نموذجي |
| PUT · POST | /admin/login/sso · /sso/probe | إعدادات الدخول بالجلسة · فحصها برمز |
| PUT · POST | /admin/login/oidc · /oidc/test | إعدادات OIDC · اختبار الاكتشاف |
| POST · PUT · DELETE | /admin/login/lti[/{id}] | منصات LTI |
| POST · DELETE | /admin/login/webhook | تجديد · تعطيل الـWebhook |
| PUT · POST | /admin/login/ical · /ical/sync | رابط التقويم · المزامنة الآن |
| POST · DELETE | /admin/login/api-keys[/{id}] | إصدار · إبطال مفاتيح الشركاء |
| POST | /admin/lessons/import | استيراد الحصص من ملف |
| GET · POST | /lessons | الحصص (المدير: الكل، والمعلّم: حصصه، والطالب: حصصه) · إنشاء |
| PATCH · DELETE | /lessons/{id} | تعديل · إلغاء |
| POST | /lessons/{id}/open | فتح سبورة الحصة ← { url } أو { waiting: true } |
١٤. مرجع الأخطاء
الأخطاء بصيغة JSON: { "success": false, "message": "<code>" }. وأخطاء التحقّق (422) فيها أيضًا كائن errors لكل حقل.
| الرمز | HTTP | المعنى / الحلّ |
|---|---|---|
invalid_or_unscoped_key | 401 | المفتاح خاطئ أو مُبطَل أو بلا الصلاحية المطلوبة |
invalid_webhook_token | 401 | رابط الـWebhook جُدّد أو عُطّل |
boards_limit_reached | 409 | انتهت حصة السبورات للفترة، و data فيه الحدّ والاستهلاك وموعد التجديد |
active_boards_limit_reached | 409 | عدد السبورات الموجودة معًا بلغ الحدّ؛ أرشِف القديم |
teachers_limit_reached | 422 | كل مقاعد المعلّمين مشغولة |
email_taken · username_taken | 422 | حساب آخر في الأكاديمية يستعمله |
owner_protected | 422 | مالك الأكاديمية لا يُخفَّض ولا يُوقف ولا يُحذف |
invite_not_found · invite_revoked · invite_expired · invite_full | 404/422 | رابط الدعوة لم يعد صالحًا |
domain_taken · domains_limit · invalid_domain · platform_domain | 422 | النطاق مستعمل، أو تجاوزت ٣، أو صيغته خاطئة، أو هو نطاق لإنجازيو |
oidc_not_configured · discovery_failed | 422 | أكمل إعدادات OIDC / المُصدِر غير متاح |
invalid_state · nonce_mismatch | 403 | انتهت مهلة الدخول (١٠ دقائق) أو تكرّر — ابدأ من جديد |
issuer_mismatch · audience_mismatch | 403 | المُصدِر أو Client ID في إنجازيو يخالف الرمز |
email_domain_not_allowed · not_registered_in_academy | 403 | منعه إعداد allow_mode |
account_suspended | 403 | الحساب موقوف في الأكاديمية |
platform_not_registered · deployment_not_registered | 403 | أضف منصة التعلّم (المُصدِر + Client ID) في إنجازيو، وراجع Deployment ID |
replayed_launch · unsupported_lti_version · unsupported_message_type | 403 | لا يُقبل إلا تشغيل LTI 1.3 جديد لرابط مورد |
not_a_participant | 403 | الطالب ليس في هذه الحصة |
unknown_event · id_and_title_required · external_id_or_email_required | 200 (لكل حدث) | صحّح حمولة الحدث |
ical_fetch_failed · ical_invalid | 422 | رابط التقويم غير متاح أو ليس تقويمًا صحيحًا |
429 | 429 | تجاوزت الحدّ — تمهّل وأعد المحاولة |
١٥. الأمان والخصوصية
- العزل — كل طلب محصور في أكاديمية واحدة بنطاقها، ومدير الأكاديمية لا يصل إلى أكاديمية أخرى ولا إلى المنصة أبدًا.
- لا أسرار تندم على مشاركتها — لا نطلب مفتاح توقيع JWT ولا الوصول إلى قاعدة بياناتك ولا كلمات المرور. و OIDC و LTI يعتمدان التوقيع بالمفتاح العام.
- الإعداد الافتراضي مغلق — OIDC يُدخل أصحاب الحسابات الموجودة فقط، والدخول بالجلسة لا يُدخل أحدًا حتى تُضبط القواعد.
- الأسرار مخزّنة بأمان — سرّ OIDC مشفّر، ومفاتيح API ورموز الـWebhook والدعوات تُخزَّن بصمةً بـSHA-256 وتظهر مرة واحدة.
- الطلبات الصادرة — نداءاتنا إلى
/meو JWKS والاكتشاف و iCal عبر HTTPS فقط، وترفض العناوين الداخلية والخاصة (حماية من SSRF). - نظافة الرموز — state و nonce و PKCE في كل دخول OIDC، و nonce الخاص بـLTI لمرة واحدة، ورمز الجلسة يضعه خادمنا في كوكي ولا يمرّ في الروابط.
- الإبطال فوري — جدّد الـWebhook، أو أبطل مفتاحًا أو دعوة، أو أوقف شخصًا: يسري في الحال.
- البيانات — نخزّن الاسم والبريد والدور ومعرّفك الخارجي. حذف الشخص يوقفه ويُبقي سبوراته، وطلبات الحذف من injazio.com/data-deletion.
١٦. قائمة الإطلاق
- ☐ حالة النطاق ready، ويفتح HTTPS بلا تحذيرات.
- ☐ مسار دخول واحد مضبوط ومجرَّب بحساب معلّم وحساب طالب.
- ☐ قواعد الأدوار جُرّبت ببيانات حقيقية، وحساب المدير مقفَل على دور المدير.
- ☐ مقاعد المعلّمين في باقتك تكفي معلّميك.
- ☐ حصة تجريبية: المعلّم يفتح السبورة، والطالب يراها في حصصي ويدخلها.
- ☐ لـLTI: التشغيل يفتح في نافذة جديدة، وطالب من المقرّر يصل إلى السبورة نفسها.
- ☐ للـWebhook والواجهة: المفاتيح في الخادم فقط، وتكرار الحمولة نفسها لا يغيّر شيئًا.
- ☐ أوقف مستخدمًا تجريبيًّا في منصتك وتأكّد أنه لم يعد يدخل.
تحتاج مساعدة؟ راسلنا من injazio.com/contact أو واتساب +20 155 544 9654 مع نطاق أكاديميتك ورمز الخطأ.