Files
saqel/docs/MEDIUM_EXECUTION_TASKS.md
T

136 lines
17 KiB
Markdown

# قائمة تنفيذ صَقِل — جلسات Medium قابلة للاستئناف
هذه القائمة هي سجل التشغيل العملي للمحادثات القادمة. النموذج الافتراضي لكل مهمة هو **GPT-5.6 Terra على Medium**. لا تفتح أكثر من مهمة تنفيذية واحدة في المحادثة الواحدة إلا إذا كانت الثانية لا تمس الملفات أو قاعدة البيانات نفسها. استخدم Sol/Astra للمراجعة النهائية للمال والأمن فقط، بعد اكتمال الاختبارات.
## طريقة الاستئناف
في أي جلسة جديدة ابدأ بالنص التالي، ثم نفذ أول مهمة `planned` اكتملت متطلباتها:
```text
اقرأ AGENTS.md وdocs/MEDIUM_EXECUTION_TASKS.md وملفات المهمة المحددة.
نفذ المهمة فقط، واحفظ تغييرات المستخدم. لا تنشر ولا تتصل بخدمة دفع حية.
حدّث حالة المهمة إلى implemented_unverified أو verified فقط بدليل فعلي.
```
| الترتيب | المهمة | النموذج/الجهد | يعتمد على | الحالة |
|---:|---|---|---|---|
| 00 | تثبيت بيئة الاختبار والأوامر الفعلية | Medium | — | implemented_unverified |
| 01 | إيقاف النجاح المالي والمحتوى البديل الوهمي | Medium | 00 | implemented_unverified |
| 02 | هوية المنهج والأصول المنشورة | Medium | 01 | implemented_unverified |
| 03 | حصة المعلم والإصدار والاستبدال الذري | Medium | 02 | implemented_unverified |
| 04 | تدقيق الفيديو والأسئلة من الأدلة | Medium | 02, 03 | planned |
| 05 | API صفر/واحد/متعدد واختيار المعلم | Medium | 02, 04 | planned |
| 06 | دفتر الحسابات وحجز الرصيد | Medium ثم Sol review | 00, 01 | planned |
| 07 | جلسات المشاهدة والدقائق المؤهلة | Medium | 02, 05, 06 | planned |
| 08 | تسوية صندوق المعلمين وكشف الحساب | Medium ثم Sol review | 06, 07 | planned |
| 09 | مزود الدفع والبصمة والتحويل | Medium ثم Sol/Astra review | 06 | blocked: مزود دفع/سياسة متجر |
| 10 | الإنجليزية: حزمة الدرس والصوت الموحد | Medium | 01, 02 | planned |
| 11 | موارد الدرس وحلقة العلاج وولي الأمر | Medium | 02, 04, 05, 10 | planned |
| 12 | المؤسسات والتقييمات والتلعيب | Medium | 02, 05, 07, 11 | planned |
| 13 | إثبات الصف العاشر وقرار الإطلاق | Medium ثم Astra review | كل ما يلزم | planned |
## قاعدة تحديث قاعدة البيانات
شغّل من جذر المشروع فقط: `php backend/scripts/run_migrations.php --status` ثم `--dry-run`، وبعد نسخة احتياطية وstaging نفّذ الأمر دون خيارات. يسجل المشغّل اسم كل migration وSHA-256؛ يرفض تشغيل ملف تغيّر بعد تسجيله. لا تستخدم `migrate.php fresh` لهذا المسار لأنه قد يحذف قاعدة البيانات.
## بطاقات التسليم
### 00 — خط الأساس
اقرأ `backend/public/index.php` و`backend/cron/run_scheduled_tasks.php` و`backend/composer.json` وملفات الاختبار قبل تشغيل أي منها. أنشئ سجلاً لأوامر الفحص الآمنة، ولا تستخدم `artisan`. أنجز harness اختبارات PHP محلياً لا يحتاج قاعدة إنتاج أو Gemini.
### 01 — الصدق أولاً
نفذ NP-01 من `NEXT_PHASE_EXECUTION_BACKLOG.md`: لا تفعيل وصول من صورة إيصال، لا إكمال سحب دون مزود، لا تحويل أرقام المنصة إلى دخل معلم، ولا مستند أو IPA أو درس بديل عند فشل المصدر. أضف migration رسمية لما كان ينشأ وقت الطلب. اختبر فشل الخدمات وحالات عدم توفر الدفع.
### 02 — هوية المحتوى
نفذ migration لـ`curriculum_lesson`, `content_asset`, وإصدار الحزمة. اعتمد IDs ثابتة ولا تطابق بالعنوان أو LIKE. أنشئ endpoint يطلب asset ID فقط ويعيد الأصل المنشور الموافق أو خطأ. اكتب backfill dry-run مع تقرير تعارضات.
### 03 — نشر واستبدال الحصة
نفذ `teacher_submission` و`video_version` وقيد حصة أساسية واحدة لكل معلم/درس. أضف Idempotency-Key وقفل/transaction للنشر. البديلة تبقى مرشحة حتى يجتاز فحصها ولا توقف النسخة القديمة.
### 04 — الفحص السقراطي
طبق `VIDEO_REVIEW_AND_SOCRATIC_PROMPTS.md`: لا توليد في GET، ولا fallback أسئلة. job يجمع تفريغاً وأدلة وصوراً وMarkdown بإصدارات، ويخضع لـschema validation ومراجعة بشرية. ابن regression fixtures معزولة لا تستدعي AI.
### 05 — اختيار المعلم
اعرض حصصاً منشورة ومصرحاً بها للدرس المحدد فقط: صفر موارد صادقة، واحد تشغيل مباشر، متعدد قائمة paginated مرتبة بتقييم موثق. المشغل يعمل بـvideo_version ID وليس عنواناً.
### 06–08 — المال بالدقائق
لا تبدأ قبل تثبيت policy تجارية موقعة. نفذ دفتر الفلس، ثم أحداث مشاهدة غير موثوقة من العميل، ثم توزيع صندوق الفترة وإشعارات معلم تفسيرية. كل تعديل قيد عكسي، وكل سحب حجز ذري. راجع Sol قبل تشغيل أي رصيد حقيقي.
### 09 — الدفع والبصمة
مهمة محجوبة حتى يحدد المستخدم مزود تحصيل/تحويل حقيقي وقناة التوزيع وسياسة المتاجر. عندها نبني intents، webhooks موقعة، sandbox، تأكيد بصمة مرتبط بتحدٍ، وتسوية. لا يتم تخزين بصمة.
### 10–12 — تجربة الطالب والمعلم
أعد بناء الإنجليزية من الحزمة المنشورة، لا من قوائم ثابتة. وحّد الصوت ولا تولد IPA/ترجمة. أضف PDF وورقة وخريطتي صور، ثم الحلقة العلاجية، ثم تنظيم المؤسسات والتقييمات.
### 13 — الإطلاق
اختبر 12 درساً حقيقياً للصف العاشر على staging مع بيانات محكومة. لا توسع قبل دليل مصادر، صحة أسئلة، عودة الطالب بعد أسبوع، ومساهمة تشغيل موجبة. هذه بوابة مراجعة Astra النهائية.
## قاعدة التحديث
بعد كل مهمة اكتب في آخر هذه الوثيقة: المهمة، commit/diff، الاختبارات الفعلية، ما لم يختبر، والقرار التالي. لا تحوّل `blocked` إلى `planned` دون القرار أو الخدمة المطلوبة.
## سجل التنفيذ
### 2026-09-09 — 00 و01 (implemented_unverified)
- أضيفت `backend/migrations/20260909_payment_safety_hold.sql` لنقل تعريف جداول كليك وطابور السحب من وقت الطلب إلى migration واضحة لا تحذف أدلة مالية عند التراجع.
- واجهات كليك والسحب والتسوية المجدولة تعيد حالة عدم توفر ولا تنشئ إيصالاً أو حركة أو وصولاً أو سحباً. لوحة المعلم لا تستنتج دخلاً أو رصيداً من عدد المشتركين أو أسعار الدورات.
- حذف مصدر Markdown التجريبي؛ طلب المستند يحتاج مسار Markdown دقيقاً داخل تخزين المنهج، وفشل المصدر يعرض حالة صادقة. تشغيل الفيديو أصبح للقراءة فقط ولا يولد نقاط فحص من العنوان أو المنهج العام.
- فحوص شُغلت: `php -l` للملفات PHP المعدلة، و`git diff --check`، و`flutter analyze` للتطبيقين. لم يظهر خطأ في الملفات المعدلة؛ توجد تحذيرات قديمة غير مانعة في المشروعين.
- لم تُنفذ migration على قاعدة بيانات، ولم تُشغّل اختبارات تكامل بقاعدة معزولة أو مزود دفع؛ لا تنشر هذه الدفعة قبل تنفيذ ذلك.
- الخطوة التالية: ابدأ 02 بهوية محتوى وأصول منشورة؛ بعدها فقط ابدأ 03 و04.
### 2026-09-09 — 02 (implemented_unverified)
- أضيفت migration `20260909_curriculum_publication_identity.sql` لجداول هوية الدرس، bundle النشر، الأصل ذي checksum، وربط الأصول بالحزمة. الاستيراد لا ينشر شيئاً تلقائياً.
- أضيف `GET /api/curriculum/assets/{assetId}` للطالب المصرح؛ يقبل UUID فقط ويقرأ أصلاً محلياً approved من bundle منشور فقط. لا يستقبل مسار ملف من المستخدم.
- أضيف `backend/scripts/backfill_curriculum_identity.php`: افتراضياً dry-run بلا اتصال DB، و`--apply` ينشئ طابور مراجعة draft/unverified ضمن transaction فقط بعد تطبيق migration وحل التعارضات.
- نتيجة dry-run المحلية: 74 سجل manifest، 55 ملفاً محلياً قابلاً لطابور المراجعة، و19 مرجعاً بلا ملف. لا يوجد تعارض هوية تلقائي؛ المراجع الناقصة مدرجة في تقرير الأمر.
- فحوص شُغلت: PHP lint للخدمة/المتحكم/route/script و`git diff --check`. لم تطبق migration ولم يشغّل `--apply`.
- الخطوة التالية: 03، بناء حصة المعلم ونسخة الفيديو والاستبدال الذري فوق `curriculum_lessons`.
### 2026-09-09 — 03 (implemented_unverified)
- أضيفت migration `20260909_teacher_submission_versions.sql`: قيد فريد للمعلم والدرس المنهجي، نسخ فيديو مرشحة مرقمة، مؤشر منفصل للنسخة المنشورة، ومفاتيح idempotency.
- أضيف مسار `POST /api/teacher/submissions/preflight` مع `Idempotency-Key`. الحصة الثانية تعيد `409 existing_submission`؛ الاستبدال يتطلب هدف الحصة الحالية وينشئ candidate جديداً فقط.
- رفع الفيديو المباشر صار يتطلب `video_version_id` من preflight ويحجز النسخة atomically من draft إلى uploading قبل تخزين الفيديو. بعد الرفع ترتبط بالدرس القديم بوصفها `review`؛ لا تنشر ولا تستبدل النسخة الحالية تلقائياً.
- فحوص شُغلت: PHP lint للخدمة والمتحكم والـroute و`git diff --check`.
- لم تطبق migration ولم ينفذ اختبار تزامن أو transaction على MySQL. تطبيق المعلم لا يمرر بعد `curriculum_lesson_id`/`video_version_id` لأنه يحتاج تشغيل backfill ومراجعة/نشر هوية الدروس أولاً؛ لذلك الرفع القديم يرفض صراحة بدلاً من تجاوز القيد.
- الخطوة التالية: 04، job تدقيق الفيديو من التفريغ وMarkdown وإصدار النسخة، ثم نشر ذري للنسخة التي اجتازت المراجعة.
### 2026-09-09 — إدارة migrations و04 (in_progress)
- أضيف `backend/scripts/run_migrations.php` كمشغل موحد للمجلد `backend/migrations` مع أوضاع status وdry-run وapply وسجل checksum.
- أضيفت migration `20260909_video_review_jobs.sql` لسجل job وتقرير مراجعة بشرية؛ لا يوجد فيها نشر آلي أو توليد أسئلة تلقائي.
### 2026-09-09 — 04 و05 (implemented_unverified، تكامل الواجهة مؤجل)
- أضيفت `video_review_evidence` مع مسار إداري `POST /api/admin/video-review/evidence`. لا ينتقل job إلى مراجعة بشرية قبل تفريغ زمني معتمد ودليل بصري معتمد وسجل تغطية متصل؛ ولا يقبل قرار الموافقة أو النشر من دون هذا السجل.
- أضيفت `GET /api/curriculum/lessons/{lessonId}/videos`: يعتمد UUID الدرس، يعرض النسخ المنشورة فقط، ويرشح كل صف بصلاحية الطالب قبل كشف الاسم أو التقييم أو العدد. لا يحدث هذا الاستعلام بيانات الطالب أو تصريحاته أثناء التصفح.
- نقطة التشغيل الجديدة `GET /api/video-versions/{versionId}/playback` تتحقق من صلاحية النسخة المنشورة والصلاحية الدراسية قبل توقيع البث. أسئلة الفيديو تبقى فارغة إلى أن تنشر من مسار الأدلة والمراجعة.
- أزيل DDL من طلبات المعلم والمنهج والامتحان؛ أصبحت hooks التوافقية no-op وتحتاج البيئة إلى `run_migrations.php` قبل الخدمة. أزيلت قيم السمعة والإنجاز الافتراضية من واجهات المعلم والطالب وولي الأمر ومن HDDL، مع migration تصحح defaults للبيئات الموجودة.
- فحوص شُغلت: `php -l` على كل PHP في `backend/app` و`backend/scripts` و`backend/cron` (ناجح)، و`git diff --check` (ناجح). محاولة `php backend/scripts/run_migrations.php --dry-run` لم تبدأ لأن البيئة المحلية بلا `.env` و`ENCRYPTION_KEY`.
- لم يكتمل بعد: Flutter ما زال يستدعي `/api/lessons/playback` لأن شجرة المنهج الحالية لا تحمل UUID الدرس المنشور. لا تربطه بالـAPI الجديد إلا بعد تطبيق migrations وbackfill ومراجعة/نشر bundles حقيقية؛ عندها نفذ حالة صفر/واحد/متعدد في `subject_hub_screen.dart` ثم مرر `video_version_id` إلى المشغل.
- الخطوة التالية: 06 بعد سياسة دخل موقعة، أو تنفيذ واجهة اختيار المعلم فور توافر UUIDs منشورة على شجرة المنهج.
### 2026-09-09 — 05 و07 و10 (implemented_unverified)
- شجرة المنهج تثري الدروس من قاعدة البيانات بعد migrations/backfill فقط بـ`curriculum_lesson_id` و`has_video` المنشور. لا تعيد مساراً بديلاً عندما لا تكون الهوية منشورة.
- تطبيق الطالب يستخدم `/api/curriculum/lessons/{lessonId}/videos` ثم `/api/video-versions/{versionId}/playback`: حصة واحدة تفتح مباشرة، وأكثر من حصة يظهر لها اختيار معلم صريح بالتقييم الموثق وعدد التقييمات. أزيل استدعاء `/api/lessons/playback` القائم على العنوان من التطبيق.
- أضيفت جلسة المشاهدة: `POST /api/video-versions/{id}/watch-sessions` ثم أحداث متسلسلة. يحتسب الخادم interval متصلاً من heartbeat فقط، بمقارنة زمن الخادم وموضع العميل وحدود صارمة؛ لا ينشئ ذلك رصيداً أو تسوية أو دخل معلم.
- أضيف `TeacherLedgerService` لعرض الرصيد بالفلس وحجز السحب idempotently من رصيد دفتر قائم فقط. لا توجد واجهة حجز أو تسوية مفعلة ولا أي سياسة سعر/صندوق مختلقة.
- أزيل مختبر الإنجليزية الثابت وما فيه من IPA ومفردات وصوت غير موثقين. أضيف `GET /api/curriculum/lessons/{lessonId}/english-package` الذي يقرأ حزمة إنجليزية منشورة فقط ومفرداتها وصوتها approved؛ الواجهة تعرض حالة انتظار صادقة إلى أن تُزرع الحزم المعتمدة.
- فحوص شُغلت: PHP lint كامل لـ`backend/app` و`backend/scripts` و`backend/cron`، و`git diff --check`، وFlutter analyze لملفات الطالب المعدلة؛ كلها ناجحة.
- لم تُطبق migrations أو تختبر المعاملات على MySQL لأن `.env` و`ENCRYPTION_KEY` غير متاحين محلياً. كما أن 06–08 لا يجوز تفعيلها أو حساب توزيع مالي قبل سياسة دخل موقعة، و09 ما زالت محجوبة بتحديد مزود دفع/تحويل فعلي.
- الخطوة التالية تلقائياً: نفذ migrations على staging مع backup، شغّل backfill dry-run ثم راجع الـ19 مرجعاً الناقصاً، وانشر bundles وحزم إنجليزية حقيقية للصف العاشر. بعدها اختبر مسارات صفر/واحد/متعدد وجلسات المشاهدة بتكامل MySQL قبل أي نشر.