Control Panel Specifications
Update
Field editability matrix per status. Strict re-review rule (any edit on published → needs-updates). PDF replacement flow + version history.
شاشة التعديل بتشترك في نفس مجموعة الحقول مع شاشة Create. الفرق الهيكلي الوحيد هو مصفوفة قابلية التعديل الحسّاسة للصلاحيات (بعض الحقول تُقفل بعد خروج الملف من draft) + قاعدة إعادة المراجعة الصارمة (أي تعديل على ملف منشور يبدّله لـ needs-updates). Form preview أسفل الصفحة يعرض بالضبط كيف تظهر شاشة Edit.
موارد فرعية خاصّة بـ Edit
Edit يضيف تبويبَين مش موجودَين في Create — الاتنين بيستعلموا عن سجلّات موجودة، مش بيُنشئوا سجلّات جديدة.
تبويب Leads (مورد فرعي للقراءة فقط)
- الغرض — يدرج كل صفّ DownloadLead متّصل بهذا الملف. بيسمح للأدمن يتحقّق من قمع العملاء + يفحص التقاط الموافقة بالعيّنة.
- نوع DB — قراءة `DownloadLead WHERE FounderFileId = @fileId ORDER BY CreatedAt DESC`. ترجع: createdAt, leadEmail, leadRole, leadCountry, langDelivered, consentMarketing, consentPartners, deliveredAt.
- التحقّق — اختبارات QC: قدّم تحميل بموافقة من الجانب العام → الصفّ يظهر خلال 5 ثوانٍ؛ تأكّد إن `langDelivered` يطابق اللغة اللي كان عليها المستخدم.
تبويب History (سجلّ التدقيق)
- الغرض — timeline لكل انتقال حالة + كل تغيير حقل قابل للتعديل على هذا الملف. تُستخدم لمراجعة الحوادث ولإثبات الالتزام بالـ workflow التحريري.
- نوع DB — قراءة `FounderFileAuditLog WHERE FounderFileId = @fileId ORDER BY OccurredAt DESC`. كل صفّ: occurredAt, actorId (→AdminUser join), eventType (status-transition / field-change), fromValue, toValue, reason.
- التحقّق — اختبارات QC: غيّر عنوان الملف واحفظ → صفّ يظهر بـ eventType=field-change وقيم fromValue/toValue معبَّأة؛ ارفض الملف → صفّ يظهر بـ eventType=status-transition وتعليق المراجِع الإلزامي في `reason`.
مصفوفة قابلية التعديل
قابل للتعديل في أي حالة
- العنوان (لكل لغة) · الـ tagline (لكل لغة)
- الوصف الكامل (لكل لغة)
- نقاط التعلّم (لكل لغة، 3–5)
- الموضوعات، وقت القراءة
- ربط الراعي (يخضع لفحص سريان العقد)
- الـ flags التحريرية (IsFeatured، IsGated، IsDownloadable)
قواعد القفل
- الفئة، صورة الغلاف، استبدال الـ PDF → قابلة للتعديل فقط في `draft` أو `needs-updates`
- `Id` → مقفول دائماً بعد INSERT (PK في قاعدة البيانات)
- `Slug` → مقفول دائماً لحظة خروج Status من `draft`
- `FileNumber` → مقفول دائماً بعد INSERT (تسلسل)
- `PublishedAt` → لا يُعدَّل أبداً (تلقائي وغير قابل للتغيير)
تدفّق استبدال الـ PDF
- الغرض — استبدال الـ PDF المنشور بدون فقدان سجلّ النسخ. النسخ السابقة تبقى في التخزين عشان Lead تسلَّم أمس يقدر يوصل لنفس البايتات اللي وُعد بيها.
- نوع DB — `FounderFileLang.PdfUrl` يُحدَّث ليشير لـ `founder-files/{slug}/{lang}/v{N+1}.pdf`. `FounderFileLang.FileSizeBytes` و `.PageCount` يعيد حسابهما خدمة الرفع ويُحدَّثا. لا يُدخَل صفّ جديد.
- التحقّق — آخر 5 نسخ محفوظة لكل لغة. اختبارات QC: استبدل 6 مرات → تأكّد إن النسخ v2–v6 فقط موجودة في التخزين (v1 محذوفة)؛ عميل تسلَّم وقت v3 لازم يظل يحلّ لمّا نشوف صفّ التدقيق (PdfVersionDelivered=3 → قابل للقراءة من Azure رغم إن المؤشّر الحالي v6).
الآثار الجانبية عند الحفظ
- `FounderFile.LastUpdatedAt` يُحدَّث لـ GETUTCDATE().
- `FounderFile.LastUpdatedBy` يُحدَّث من جلسة الأدمن الموثَّقة.
- صفّ يُدخَل في `FounderFileAuditLog` لكل حقل اتغيّر (صفّ لكل diff حقل).
- لو `SponsorId` اتغيّر: الراعي السابق يتوقّف فوراً عن استلام العملاء؛ حدث `founder-file.sponsor-changed` يُطلق؛ تعديل فوترة proportional يُجدَّل.
- لو كان `published` وأي حقل قابل للتعديل اتغيّر: `Status` يُحدَّث لـ `needs-updates`؛ حدث `founder-file.content-updated` يُطلق؛ Editorial Lead يستلم إيميل.
معاينة الفورم — شاشة Edit
Edit بيعيد استخدام فورم Create حرفياً (Metadata · EN · AR · FR · Sponsor) ويضيف تبويبَين على اليمين: Leads و History. الحقول المقفولة تظهر كـ inputs بـ `disabled` ومعها أيقونة قفل. المثال أدناه ملف `published` على تبويب Metadata — لاحظ إن الـ Slug + Category + Cover مقفولين، والحقول القابلة للتعديل لسّه تفاعلية.
