---
title: "التحفيز"
url: https://docs.growamal.com/ar/guides/gamification/
language: ar
---

# التحفيز

تربط وحدة التحفيز (WP-14-BE) كلَّ مكافأة مباشرةً بحدث تعلُّم قابل للقياس.
لا يُكتسب XP بمجرد تسجيل الدخول أو إتمام جلسات أو قضاء وقت في التطبيق. الشيء الوحيد
الذي يمكنه سكّ XP أو فتح وسام أو تقدُّم سلسلة مكافآت هو صف `mastery_event` تكتبه
قناة القياس (V-8). يضمن ذلك أن ما تعكسه قائمة المتصدرين هو نموٌّ حقيقي لا مجرد تفاعل.

> **ملاحظة:** يحمل ملف التحفيز للطالب XP الخاص به فحسب، إلى جانب الصورة الرمزية وسلسلة المكافآت
> والأوسمة. لا تصل أي بيانات عن الترتيب بين الأقران أو مجاميع الصف أو المقارنة بالمرجعية
> إلى أي سطح يراه الطالب (SPEC-GAM-10). تحصل رموز الطالب على `403` في كل مسار لقائمة
> المتصدرين؛ ولا توجد نقطة نهاية لقائمة متصدرين خاصة بالطلاب.

## المسارات

| الطريقة | المسار | من يمكنه الاستدعاء |
|---|---|---|
| `GET` | `/api/students/{id}/gamification/profile` | الطالب نفسه، المعلم الذي يدرّس الصف، وليّ الأمر، المدير، المسؤول |
| `GET` | `/api/leaderboards/class/{classId}` | المعلم، المدير، المسؤول (رمز الطالب: `403`) |
| `GET` | `/api/leaderboards/teacher/{teacherUserId}` | المعلم نفسه، المدير، المسؤول (رمز الطالب: `403`) |
| `GET` | `/api/leaderboards/school/{schoolId}` | المدير والمسؤول فقط (المعلم: `403`) |
| `POST` | `/api/teachers/badges/{studentBadgeId}/rescind` | المعلم (محدودًا بـ ClassTeacher) |
| `GET` | `/api/admin/gamification/audit` | المسؤول فقط |
| `POST` | `/api/admin/gamification/replay` | المسؤول فقط |

جميع معرّفات الطلاب والصفوف أعداد صحيحة موجبة. أي معرّف خارج النطاق أو ينتمي لمؤسسة
أخرى يُعيد `404` (عدم الكشف عن الوجود). يتطلب كل مسار رمز جلسة صالحًا وسياق
مستأجر `organizationId`.

## `GET /api/students/{id}/gamification/profile`

يُعيد رصيد XP للطالب وطبقة الصورة الرمزية وحالة سلسلة المكافآت وقائمة الأوسمة. بالنسبة
للمستدعين البالغين (المعلم، وليّ الأمر، المدير، المسؤول)، يحمل كل وسام أيضًا
`studentBadgeId` و`status` حتى يتمكن المعلم من استدعاء نافذة سحب الوسام. أما في
استجابة الطالب نفسه فيغيب هذان الحقلان؛ لا يرى الطالب إلا اسم الوسام وتاريخ منحه.

```bash
curl https://localhost:3000/api/students/42/gamification/profile \
  -H "Authorization: Bearer <accessToken>"
```

```json
{
  "studentId": 42,
  "xpBalance": 340,
  "avatarTier": 3,
  "streak": { "current": 4, "longest": 11, "lastTickDate": "2026-06-26" },
  "badges": [
    {
      "code": "BADGE_JOURNEY_START",
      "nameAr": "بداية الرحلة",
      "descriptionAr": "...",
      "awardedAt": "2026-06-10T08:00:00.000Z"
    }
  ]
}
```

`xpBalance` يُحسَب دائمًا عند القراءة (بعملية `SUM` على `xp_transaction`) ولا يُخزَّن
أبدًا كعمود (V-6). `avatarTier` عدد صحيح من 1 إلى 5. يظهر `studentBadgeId` و`status`
للمستدعين البالغين فقط.

## اشتقاق XP

لا يُخزَّن XP كرصيد متراكم قائم بذاته. كل استدعاء يُعيد `xpBalance` يحسبه من سجل
`xp_transaction` ذي الإلحاق فقط. تُكتب الرصيدات بواسطة المنسّق بعد كل حدث إتقان،
مع حدٍّ أقصى للجلسة (القيمة الافتراضية الهندسية: 200 XP للجلسة؛ هذا الحدّ قيمة في مجموعة
قواعد إصدار مُعيَّن لا ثابت مُضمَّن في الكود).

قيم `MasteryEventSourceKind` المغلقة الثماني التي يمكنها سكّ XP هي:

| النوع | الوصف |
|---|---|
| `subskill_state_up` | تنتقل مهارة فرعية إلى حالة أعلى في قناة SSE |
| `cbm_trend_above_goal` | يتجاوز اتجاه طلاقة CBM خط الهدف صعودًا |
| `bundle_step_goal_met` | تُكتمل خطوة فردية ضمن خطة الحزمة |
| `band_progression` | يتقدّم الطالب نطاقًا أو أكثر في مستوى الكفاءة على مجموعة عناصر |
| `skill_status_transition` | ينتقل وضع المهارة إلى حالة أكثر إيجابية |
| `domain_status_escalation` | ينتقل وضع المجال إلى حالة أكثر إيجابية |
| `bundle_completion` | تُكتمل خطة الحزمة بأكملها |
| `scaffold_tier_step_up` | ينتقل الطالب إلى طبقة دعم أقل ضمن الحزمة |

لا يوجد نوع حدث آخر. القائمة مغلقة؛ يرفض CI lint (‏`lint:gamification-award-rule`) أي
موقع استدعاء يحاول سكّ XP خارج هذه المجموعة. إشارة التوقف `do_not_decide_yet` أو
`partial_domain_profile` تقطع المنسّق كليًّا؛ لا يُكتب شيء.

## طبقات الصورة الرمزية

تتقدّم الصورة الرمزية عبر 5 طبقات مظهرية بناءً على عدد أحداث الإتقان التراكمية. الطبقات
مظهرية فقط؛ لا تحمل مضاعفًا ولا إشارة مقارنة بالأقران.

| الطبقة | تُبلَغ عندما يكون العدد التراكمي |
|---|---|
| 1 | أقل من 5 (طبقة البداية) |
| 2 | 5 أو أكثر |
| 3 | 15 أو أكثر |
| 4 | 35 أو أكثر |
| 5 | 75 أو أكثر |

العتبات قيم افتراضية هندسية عاملة (مُعلَّمة لتأكيد الشريك). يضع تقدّم الطبقة حدثًا
احتفاليًا غير حاجب للواجهة الأمامية؛ الحدث مثلي لكل `(student, tier)`.

## سلاسل المكافآت

تُحسَب سلسلة المكافآت مرة واحدة في كل يوم تقويمي يحقق فيه الطالب حدث إتقان واحدًا على
الأقل. الأيام التي تجري فيها جلسات دون أي حدث إتقان لا تُحسَب. الحساب مثلي داخل اليوم
التقويمي الواحد؛ إعادة التشغيل في اليوم ذاته بعد الحساب لا تُغيّر شيئًا.

**نافذة السماح.** عطلة نهاية الأسبوع (الجمعة والسبت) والإجازات المدرسية لا تُحتسَب في
غياب. لن يقطع النظام سلسلة بسبب يوم يصادف عطلة نهاية أسبوع أو إجازة مُعرَّفة. نافذة
السماح لأيام الدراسة العادية (غير عطل الأسبوع وغير الإجازات) التي لا تتضمن حدثًا تبلغ 7 أيام دراسية افتراضيًا.

**سلوك القطع.** عندما تتجاوز فجوة أيام الدراسة العادية (غير عطل الأسبوع وغير الإجازية) بلا أحداث نافذةَ
السماح، تنقطع السلسلة السابقة. يبدأ اليوم الذي تجاوز النافذة سلسلة جديدة بقيمة
`current = 1` (يوم القطع نفسه يُعدّ اليوم الأول للسلسلة الجديدة لا يومًا صفريًا).

معالم سلسلة المكافآت عند 5 و10 و20 يومًا متتاليًا، وتُرسَل إشعارات إلى الواجهة الأمامية.

## الأوسمة

تُبذَر 15 وسامًا من أحداث الإتقان حصرًا. كل وسام في الكتالوج له `awardRule` يستشهد
بنوع واحد على الأقل من `MasteryEventSourceKind`؛ لا يمكن تعريف وسام دون محفّز تعلُّم
قابل للقياس (V-8). يُقيِّم المنسّق كتالوج الأوسمة بعد كل حدث إتقان ويمنح وسامًا جديدًا
واحدًا كحدٍّ أقصى في كل تقييم، حفاظًا على إمكانية إدارة واجهة الاحتفال.

بالنسبة للمستدعين البالغين، يتضمن DTO الوسام `studentBadgeId` (معرّف صف قاعدة البيانات)
و`status` (‏`active` أو `rescinded`). هذان الحقلان غائبان في استجابة الطالب نفسه.

## قوائم المتصدرين

ثلاثة نطاقات لقوائم المتصدرين: الصف، والمعلم (تجميع متعدد الصفوف)، والمدرسة.
الثلاثة أسطح مخصصة للبالغين فقط.

> **تنبيه:** تحصل رموز الطالب على `403` في كل مسار لقائمة المتصدرين. لا توجد قائمة متصدرين يراها
> الطالب، ولا يُخطَّط لإتاحتها (V-8 / Vision §5 ميزة محظورة بشكل صارم).

**قائمة صف المتصدرين** (`GET /api/leaderboards/class/{classId}`) تُعيد مدخلات
لجميع الطلاب في الصف. يجب أن يكون المستدعي ClassTeacher لذلك الصف، أو مدير المدرسة،
أو مسؤولًا. يُعيد صف معلم آخر `404`.

**قائمة معلم المتصدرين** (`GET /api/leaderboards/teacher/{teacherUserId}`) تُعيد
تجميعًا متعدد الصفوف لجميع الصفوف التي يدرّسها المعلم، مع مجاميع لكل صف. يمكن للمعلم
طلب `teacherUserId` الخاص به فقط؛ ويمكن للمدير أو المسؤول طلب أي معلم ضمن نطاقه.

**قائمة مدرسة المتصدرين** (`GET /api/leaderboards/school/{schoolId}`) للمدير
والمسؤول فقط. يُعيد رمز المعلم `403` بصرف النظر عن انتمائه للمدرسة.

تقرأ جميع قوائم المتصدرين من `mastery_event` مباشرة. لا تقرأ `xp_balance` أو أعداد
الجلسات أو أي عداد تفاعل. تختار معامل الاستعلام `view` بين `by_mastery_events` (الافتراضي)
و`by_band_progression`. يُقيّد معامل `windowDays` (من 1 إلى 90، الافتراضي 14) العدد
لأحداث ضمن النافذة الزمنية.

تحمل الاستجابة `framing.topLabelAr` و`framing.bottomLabelAr`: نصوص عربية بلغة نموّ
تعرضها الواجهة الأمامية حرفيًّا. هذه النصوص تجتاز تصفية أمان اللغة ولا تستخدم لغة
مقارنة أو ترتيب (V-12).

```bash
curl "https://localhost:3000/api/leaderboards/class/cls_001?view=by_mastery_events&windowDays=14" \
  -H "Authorization: Bearer <accessToken>"
```

```json
{
  "scope": "class",
  "view": "by_mastery_events",
  "windowDays": 14,
  "framing": { "topLabelAr": "...", "bottomLabelAr": "..." },
  "entries": [
    {
      "studentId": 42,
      "masteryEventCount": 18,
      "bandProgressionCount": 3,
      "sourceKindBreakdown": { "subskill_state_up": 12, "band_progression": 3, "bundle_step_goal_met": 3 }
    }
  ]
}
```

## `POST /api/teachers/badges/{studentBadgeId}/rescind`

يمكن للمعلم سحب وسام إن مُنح خطأً. يحمل جسم الطلب `overrideCode` فحسب؛ لا يوجد حقل نص
حرّ في هذا المسار (B.3).

يجب أن يكون `overrideCode` هو `Gam_Award_Invalid_05`، الرمز الوحيد لسحب وسام التحفيز من
`OverrideCodeCatalog` ذي التسعة رموز. يُثبّت المعالج الرمز في النطاق
`applicableScope = 'gamification_rescind'` وقت التشغيل؛ رمز مفقود أو رمز من نطاق مختلف
(كرمز خروج حزمة) يُعيد `400`. يجب أن يكون المعلم ClassTeacher لطالب الوسام؛ أي معلم آخر
يحصل على `403`. وسام مسحوب مسبقًا يُعيد `409`.

```bash
curl -X POST https://localhost:3000/api/teachers/badges/8124/rescind \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "overrideCode": "Gam_Award_Invalid_05" }'
```

```json
{
  "studentBadgeId": 8124,
  "status": "rescinded",
  "compensatingXpTransactionId": 9201,
  "reversalDelta": -50
}
```

يُضيف السحب صف `xp_transaction` تعويضيًا (الرجوع). لا يُحذف شيء؛ يبقى السجل الكامل
بما فيه الرصيد الأصلي والرجوع مرئيًا في مسار التدقيق.

## المسؤول: التدقيق وإعادة الاشتقاق

### `GET /api/admin/gamification/audit`

يُعيد تدفقات أحداث الإتقان وعمليات XP والأوسمة الخام لطالب. يستخدمه المسؤولون لفحص
السجل الكامل قبل إعادة الاشتقاق أو بعدها. يقبل `studentId` (مطلوب) وفلتري `from`
و`to` لتاريخ ووقت.

```bash
curl "https://localhost:3000/api/admin/gamification/audit?studentId=42" \
  -H "Authorization: Bearer <adminAccessToken>"
```

### `POST /api/admin/gamification/replay`

يُعيد اشتقاق رصيد XP للطالب ومجموعة أوسمته وطبقة صورته الرمزية من تدفق `mastery_event`
غير المتغيَّر حتى نقطة زمنية محددة، ثم يقارن النتيجة بالقيم المخزَّنة (V-6). أي فارق
غير صفري يعني انزياح قيمة مخزَّنة عن السجل؛ يُعلّم الرد كل بُعد بشكل منفصل.

```bash
curl -X POST https://localhost:3000/api/admin/gamification/replay \
  -H "Authorization: Bearer <adminAccessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "studentId": 42, "asOf": "2026-06-27T00:00:00.000Z" }'
```

```json
{
  "studentId": 42,
  "asOf": "2026-06-27T00:00:00.000Z",
  "derived": { "xpBalance": 340, "badgeCodes": ["BADGE_JOURNEY_START"], "avatarTier": 3 },
  "stored":  { "xpBalance": 340, "badgeCodes": ["BADGE_JOURNEY_START"], "avatarTier": 3 },
  "drift": { "xpBalance": false, "badges": false, "avatarTier": false },
  "hasDrift": false
}
```

`hasDrift: true` يعني انزياح اللقطة المخزَّنة عن التدفق القابل للاشتقاق. هذه إشارة
تدقيق V-6؛ حلّها يتطلب تحقيقًا من المسؤول لا تصحيحًا تلقائيًا.

## الثوابت

- **V-8: كل مكافأة تعود لحدث مقيس.** يحوي قيد `MasteryEventSourceKind` تمامًا 8 قيم.
  `xp_transaction.masteryEventId` هو NOT NULL في كل صف رصيد؛ `student_badge.triggeringMasteryEventId`
  هو NOT NULL في كل صف وسام. يرفض CI lint (‏`lint:gamification-award-rule` / AC-GAM-1) أي
  مسار كتابة يتجاوز هذه القيود.
- **V-6: رصيد XP دائمًا مشتقّ.** `xp_balance` لا يُخزَّن أبدًا كعمود. إصدارات القواعد
  مُثبَّتة في كل صف رصيد حتى تُنتج إعادة الاشتقاق على نفس المدخلات نفس النتيجة.
- **إلحاق فقط (B.7).** جداول `mastery_event` و`xp_transaction` و`student_badge`
  و`student_badge_rescind` إلحاقية فقط باتفاقية التطبيق و CI lint. لا يوجد مشغّل
  Postgres من نوع `BEFORE` في الموجة الأولى؛ التطبيق هو طبقة الإنفاذ.
- **لا نص حرّ (B.3).** يقبل جسم السحب حقل `overrideCode` المُتحكَّم به فقط. لا يوجد
  حقل `reason` أو `note` أو `comment` في أي مسار كتابة للتحفيز.
- **لا قائمة متصدرين للطالب (SPEC-GAM-07).** تحصل رموز الطالب على `403` في المسارات
  الثلاثة لقوائم المتصدرين. هذه قاعدة منتج صارمة لا تهيئة صلاحية.
- **لا نموذج لغوي (V-5).** جميع منطق التحفيز حتمي ومكتوب بقواعد. لا تشارك أي نماذج
  لغوية في أي خطوة.
- **عزل المستأجر.** `organizationId` محوسب ومفهرس في كل جدول؛ معرّف من مؤسسة أخرى يُعيد `404`.
- **إشارة التوقف.** إشارة `do_not_decide_yet` أو `partial_domain_profile` من المحرك
  الأعلى تقطع المنسّق كليًّا؛ لا يُكتب حدث إتقان أو رصيد XP أو وسام أو حساب سلسلة.

## أدلة ذات صلة

- [ملفات الطلاب](https://docs.growamal.com/ar/guides/student-profiles/): دقة تحليل الملف التي تُغذّي قواعد الأوسمة المبنية على الملف
- [قرارات RTI](https://docs.growamal.com/ar/guides/rti-decisions/): مصدر لأحداث `bundle_completion` و`bundle_step_goal_met`
- [رصد التقدم](https://docs.growamal.com/ar/guides/progress-monitoring/): مصدر لأحداث `cbm_trend_above_goal`
- [محرك وضع المهارة](https://docs.growamal.com/ar/guides/skill-status-engine/): مصدر لأحداث `skill_status_transition` و`domain_status_escalation`
- [أمان اللغة](https://docs.growamal.com/ar/guides/language-safety/): الطبقة التي تصفّي ملصقات إطار قوائم المتصدرين بلغة النموّ
