0%
balqalam Logo
بالقلم
المميزاتالمجتمعالتسعيرالوثائق
تسجيل الدخول
  • مقدمة
  • العرض
  • MVP
  • خارطة الطريق
  • متطلبات المنتج
  • ابدأ الآن
  • البيئة المحلية
  • البنية المعمارية
  • الهيكل
  • الأنماط
  • الحزمة التقنية
  • قاعدة البيانات
  • تعدّد المستأجرين
  • الفهرس (Catalog)
  • العمل دون اتصال
  • المصادقة
  • التهيئة (Onboarding)
  • تدفق التكامل (Integration Flow)
  • التهيئة (Provision)
  • القبول
  • الحضور
  • الامتثال التنظيمي
  • الملف الشخصي
  • الاجتماعات
  • إدارة الرسوم
  • الفاتورة
  • التدويل
  • الترجمة
  • دليل الترجمة
  • أمان قاعدة البيانات
  • المساهمة
  • هَوْغوارتس
  • عرض حي
  • الإلهام
المبيعات والانتشار
  • المبيعات
  • الذهاب إلى السوق
  • التسويق
  • القبول — تسليط الضوء
  • البرنامج التجريبي
  • العملاء المحتملون
  • العرض التجاري
  • قوالب التواصل
  • دراسة الحالة
  • المنافسون
  • نموذج العمل
  • الاقتصاد المشترك
  • الجذب والنمو
التمويل والشراكات
  • الحصول على الدعم
  • عرض المستثمر
  • غرفة البيانات
  • المستثمرون
  • المُسرِّعات
  • الحاضنات
  • المنح
  • الرعاة
  • الشركاء
  • المسابقات والهاكاثونات
  • الجامعات ومراكز التدريب

الفهرس (Catalog)

السابقالتالي

العمود الفقري للمنهج على مستوى المنصّة — جداول محتوى عامة، وجسور مُنطَقة بـ schoolId، والتهيئة، وتدفّق الاقتراح-والموافقة، والمحتوى المدفوع، ومحرّك المنهج، وتغطية كل منهج.

الفهرس هو مخزن المنهج المشترك للمنصّة. توجد نسخة واحدة من كل مادة وفصل ودرس داخل جداول عامة بلا schoolId؛ وكل مدرسة تشير إلى نفس المحتوى عبر صفوف جسر (bridge) صغيرة بدل استنساخه. والمحتوى الذي يساهم به المعلّمون والمدارس (فيديوهات، مواد، أسئلة، كتب) يمرّ بمراجعة فريق SaaS ثم يُثري الفهرس للجميع.

هذه الصفحة هي المرجع الموحّد للفهرس. المرجع الكامل لشبكة التوصيل (CDN) والأصول يوجد منفصلاً في CDN & Assets.

نظرة عامة

يقوم النظام كلّه على نموذج ذهني واحد: هناك جداول فهرس عامة (مشتركة، بلا مستأجر) وصفوف جسر مُنطَقة بـschoolId تربط المستأجر بذلك المحتوى المشترك. لا تستنسخ المدرسة الفهرس قطّ — بل تشير إليه.

prisma/models/— catalog data model
catalog.prisma— Subject — content root
chapter.prisma— Chapter
lesson.prisma— Lesson
curriculum.prisma— Curriculum
video.prisma— Video, VideoPurchase, Attachment
qbank.prisma— Question, ExamQuestion
exam.prisma— Exam, ExamTemplate
material.prisma— Material
assignment.prisma— Assignment
book.prisma— Book
textbook.prisma— Textbook
document.prisma— Document
proposal.prisma— Proposal
bridge.prisma— SubjectSelection, ContentOverride, InstructorPreference, BookSelection
enrollment.prisma— Enrollment, LessonProgress, SubjectCertificate
academic.prisma— AcademicLevel, AcademicGrade, AcademicStream
prisma/seeds/catalog/— load content into the DB
index.ts— orchestrator: seedCatalog (US + full SD) + seedFullCatalog
engine.ts— syncCurriculumTree (deep) + seedSubjectsOnly (shallow) — shared seeder
registry.ts— all 12 Curriculum records + curriculumId backfill
us.ts— US — the US-curriculum source backbone
sd.ts— Sudan — subjects + chapters + lessons, from curriculum/sd/
gb.ts— England (GB) — deep, from curriculum/uk
cbse.ts— Indian CBSE — deep, from curriculum/in
caie-igcse.ts— Cambridge IGCSE — deep, from curriculum/caie-igcse
ib.ts— IB Diploma — deep, from curriculum/ib
sa.ts · eg.ts · ae.ts · qa.ts · kw.ts · jo.ts— subjects-only nationals (split from world.ts; graduate to deep trees)
concepts.ts— concept images to S3
banners.ts— concept banners to S3 (owned, shared)
lesson-covers.ts— per-lesson/chapter covers to S3 (US, legacy)
books.ts— global catalog books
content.ts— materials, exams, questions
videos.ts— lesson videos
exam-templates.ts— exam blueprints + templates
demo.ts— demo-school structure + bridges
src/components/catalog/— shared core — every surface imports from here
concepts-data.ts— 23 concepts, colors, nearestConcept, exact-match maps + pools — single source
setup.ts— provisions a school onto the catalog
provision.ts— schedule/sections/timetable/library provisioning + the repair doctor
image.ts— Sharp pipeline + S3 upload
image-url.ts— resolve image URLs (CloudFront)
src/components/saas-dashboard/catalog/— platform authoring (DEVELOPER)
src/components/school-dashboard/listings/subjects/catalog/— school adoption + contribution
src/components/lumos/data/catalog/— LMS read queries
curriculum/— on-disk content source
sd/— Sudan — read by sd
uk/— British → GB (read by gb)
in/— Indian CBSE (read by cbse)
caie-igcse/— Cambridge IGCSE (read by caie-igcse)
ib/— IB Diploma (read by ib)
us/— Aldar American — unread (US uses the master inventory)
fr/— French — image-only
_build_tools/— engine.py — generates the trees
public/subjects/concepts/— 23 source concept images
scripts/
us-curriculum/us-inventory.json— US source data
sudan-data/— Sudan source data + TOC + PDFs
upload-textbooks-all.ts— upload textbook PDFs to S3 (all curriculum trees)
gen-curriculum-structure.ts— spec JSON → structure.json tree
  • الفهرس العام (جداول catalog_*، بلا schoolId) — هرم المنهج (Subject → Chapter → Lesson) إضافةً إلى المحتوى المرتبط به (Exam، Question، Material، Assignment، Video، Book، Quiz، Document، Image، Textbook) وسجلّات Curriculum.
  • صفوف الجسر (جداول school_*، تحمل schoolId) — SubjectSelection، ContentOverride، InstructorPreference، BookSelection. تربط المستأجر بالمحتوى المشترك؛ وكل ما يخصّ المدرسة يقرأ من خلالها.
  • لماذا — عند 1,000 مدرسة يخزّن النموذج المشترك ~240 مادة بدل 220k، وكل مساهمة تُثري كل المدارس.
الأسلوببيانات 1,000 مدرسة × ~240 مادةالمشاركة
نسخة لكل مدرسة220k مادة، 800k فصل، 4M درسلا شيء
فهرس مشترك~240 مادة، ~800 فصل، ~4k درس + سجلّات الجسركل مساهمة تُثري كل المدارس

الحالة باختصار

القدرةالحالة
نموذج الفهرس العام + الجسرموصول — في الإنتاج
اتّساع المناهج12 منهجاً عرضاً، 6 بعمق (US، SD، GB، CAIE-IGCSE، IB-DP، CBSE)
البنية الأكاديمية لكل منهجموصولة — academic-config.ts (ثغرة "السوداني-للجميع" القديمة أُصلِحت)
التهيئة (setupCatalogForSchool)موصولة — استنتاج + تراجع 4 خطوات + إصلاح ذاتي كسول
الاقتراح → الموافقة (اختياري)موصول هذه الجلسة — اقتراح، طابور المُشغِّل، نشر، إشعار، مُنتقي مُثبَّت
الموافقة تنشر المحتوىمُصلَح — الموافقة تضبط الآن status: PUBLISHED (كانت ثغرة DRAFT غير مرئية)
الفيديوهات المدفوعةموصولة — VideoPurchase، CloudFront مُوقَّع، حجب الرابط null
الاختبارات/الأسئلة المدفوعةمؤجّل — الحقول موجودة، تدفّق الشراء غير مبني
مصغّرات الموادمكتملة — كل المناهج الـ12 عبر المفاهيم المشتركة
البانرات / أغلفة الكتبجزئي / مفقود (راجع CDN & Assets)
تكرارية بذرة المحتوى (idempotency)مُصلَحة هذه الجلسة — إعادة التشغيل تتخطّى الصفوف الموجودة

المعمارية

نماذج الفهرس تستخدم أسماء مجرّدة مربوطة بجداول catalog_*؛ ونماذج الجسر مربوطة بجداول school_*. مُوصِّل عميل Prisma هو صيغة camelCase من اسم النموذج (db.subject، db.subjectSelection).

نماذج الفهرس العام

النموذجالجدول (@@map)المُوصِّليحمل
Subjectcatalog_subjectsdb.subjectجذر الهرم؛ slug (فريد)، curriculum، concept، أعداد مُزال تطبيعها
Chaptercatalog_chaptersdb.chapterمفتاح أجنبي subjectId، sequenceOrder
Lessoncatalog_lessonsdb.lessonمفتاح أجنبي chapterId، sequenceOrder، durationMinutes
Videolesson_videosdb.videovideoUrl، provider، visibility، price، الموافقة
Examcatalog_examsdb.examاختبار الفهرس (≠ SchoolExam المدرسي)
ExamQuestioncatalog_exam_questionsdb.examQuestionجدول وصل Exam ↔ Question مع order/points
Questioncatalog_questionsdb.questionبنك أسئلة الفهرس (≠ QuestionBank المدرسي)
Materialcatalog_materialsdb.materialكتب/مناهج/أوراق عمل على أي مستوى
Assignmentcatalog_assignmentsdb.assignmentقوالب واجبات/مشاريع قابلة لإعادة الاستخدام
Bookcatalog_booksdb.bookكتب المكتبة (≠ SchoolBook المدرسي)
Quizcatalog_quizzesdb.quizمُعرَّف؛ لا يُبذَر
Documentcatalog_documentsdb.documentسجلّ ملفات موحّد (PDF/PPTX/DOCX/صوت)
Imagecatalog_imagesdb.imageنسخ صور المفاهيم (راجع المفاهيم)
Textbookcatalog_textbooksdb.textbookبيانات الكتاب الوصفية (مفتاح S3 لملف PDF على Subject.pdf)
Curriculumcatalog_curriculadb.curriculumسجلّات المناهج الـ12؛ هدف مفتاح curriculumId

نماذج الجسر (تحمل schoolId)

النموذجالجدول (@@map)المُوصِّلالغرض
SubjectSelectionschool_subject_selectionsdb.subjectSelectionصفّ لكل مادة+صفّ مُتبنّى؛ isActive يُفعّل/يُعطّل المادة
ContentOverrideschool_content_overridesdb.contentOverrideتجاوز فصل/درس/فيديو لكل مدرسة؛ isHidden يُخفي المحتوى
InstructorPreferenceschool_instructor_preferencesdb.instructorPreferenceترتيب معلّم/فيديو لكل مدرسة
BookSelectionschool_book_selectionsdb.bookSelectionيجسر Book من الفهرس إلى مكتبة مدرسة

مرايا المدرسة (مفتاح أجنبي للفهرس → catalogXxxId)

نموذج الفهرس ونظيره المُنطَق للمدرسة هما نموذجان مختلفان. عند قراءة Exam راجع الجدول لتعرف أيّهما المقصود. مرآة المدرسة ترتبط بالفهرس عبر مفاتيح أجنبية اختيارية catalogSubjectId / catalogChapterId / catalogLessonId.

الفهرس (عام)مُنطَق للمدرسة (لكل مستأجر)
Exam → catalog_examsSchoolExam → exams
Book → catalog_booksSchoolBook → books
Assignment → catalog_assignmentsSchoolAssignment → assignments
Question → catalog_questionsQuestionBank → question_bank
ExamTemplate → catalog_exam_templatesSchoolExamTemplate → exam_templates
// QuestionBank, SchoolExam — link to catalog hierarchy
catalogSubjectId  String?
catalogChapterId  String?
catalogLessonId   String?
 
// SchoolAssignment — link to catalog lesson
catalogLessonId   String?

التعدادات (Enums)

ContentStatus      DRAFT, REVIEW, PUBLISHED, ARCHIVED, DEPRECATED
ApprovalStatus     PENDING, APPROVED, REJECTED
ContentVisibility  PRIVATE, SCHOOL, PUBLIC, PAID
SchoolLevel        ELEMENTARY, MIDDLE, HIGH
StreamType         GENERAL, SCIENCE, ARTS, COMMERCE, TECHNICAL, RELIGIOUS
MaterialType       TEXTBOOK, SYLLABUS, REFERENCE, STUDY_GUIDE, PROJECT, WORKSHEET,
                   PRESENTATION, LESSON_NOTES, VIDEO_GUIDE, LAB_MANUAL, OTHER
QuestionType       MULTIPLE_CHOICE, TRUE_FALSE, SHORT_ANSWER, ESSAY, FILL_BLANK,
                   MATCHING, ORDERING, MULTI_SELECT
QuestionSource     MANUAL, AI, IMPORTED
DifficultyLevel    EASY, MEDIUM, HARD
BloomLevel         REMEMBER, UNDERSTAND, APPLY, ANALYZE, EVALUATE, CREATE
ProposalType       SUBJECT, CHAPTER, LESSON, VIDEO
ProposalStatus     DRAFT, SUBMITTED, IN_REVIEW, APPROVED, REJECTED, PUBLISHED
EnrollmentStatus   PENDING, ACTIVE, COMPLETED, CANCELLED, EXPIRED

ContentVisibility هو البوّابة التي يحملها كل عنصر مُساهَم به: PRIVATE (مدرسة المُنشئ فقط)، SCHOOL (المدارس التي تستخدم تلك المادة، مجاناً)، PUBLIC (أي شخص، مجاناً)، PAID (أي شخص، محجوب بالشراء). راجع الرؤية والمحتوى المدفوع.

تفصيل نماذج المحتوى

Material (الجدول catalog_materials) — كتب ومناهج وأوراق عمل على أي مستوى:

الحقلالنوعملاحظات
catalogSubjectId / catalogChapterId / catalogLessonIdString?أحدها مضبوط (مفتاح أجنبي إلى هرم الفهرس)
title / langStringlang افتراضي "ar"
typeMaterialTypeTEXTBOOK، SYLLABUS، WORKSHEET، …
fileUrl / fileKey / fileSize / mimeType / pageCountمتنوّعمُخزَّن على S3
externalUrlString?للموارد غير المرفوعة
contributedBy / contributedSchoolIdString?النسب
approvalStatus / visibilityتعداداتالمراجعة + الحجب

Assignment (الجدول catalog_assignments) — نفس بنية Material بالإضافة إلى instructions/rubric (String?)، وtotalPoints (Decimal?)، وestimatedTime (Int?، بالدقائق)، وassignmentType (homework/project/lab/essay/presentation).

ExamQuestion (الجدول catalog_exam_questions) — جدول وصل يربط Exam ↔ Question مع order وتجاوز points لكل اختبار. الفهارس: @@unique([catalogExamId, order])، @@unique([catalogExamId, catalogQuestionId]). يحلّ محلّ حقل JSON القديم Exam.questions.

Video، Attachment — المخطّطات الكاملة في prisma/models/video.prisma (lesson_videos، lesson_attachments). أهم حقول Video: videoUrl، provider (youtube/vimeo/self-hosted)، visibility، price، approvalStatus، إضافةً إلى التفاعل (viewCount، likeCount، averageRating، isFeatured). الفيديوهات المدفوعة تُحجَب عبر VideoPurchase.

التهيئة (Provisioning)

لا تستنسخ المدرسة الفهرس قطّ. عند انتهاء الإعداد، يستدعي completeOnboarding (src/components/onboarding/legal/actions.ts) الدالة setupCatalogForSchool (src/components/catalog/setup.ts): فهي تستنتج المنهج، وتجد المواد المطابقة عبر تراجع تدريجي، وتبني المراحل/الصفوف/المسارات الأكاديمية من إعدادات المنهج، وتكتب صفّ جسر SubjectSelection واحداً لكل مادة وصفّ مُتبنّى.

import { setupCatalogForSchool } from "@/components/catalog/setup"
 
await setupCatalogForSchool(schoolId, { country: "US", curriculum: "US" })
await setupCatalogForSchool(schoolId, { country: "AE", curriculum: "IB-DP" })
await setupCatalogForSchool(schoolId, { country: "GB", curriculum: "GB" })

inferCurriculum + تراجع findSubjects

صفّ المدرسة لا يخزّن رمز المنهج — inferCurriculum() يشتقّه من البلد + النوع وقت التشغيل. ثم يحلّ findSubjects() المواد عبر تراجع تدريجي من 4 خطوات، فتحصل المدرسة دوماً على شيء ما:

الخطوةالمُرشِّح
1country + curriculum + schoolType
2country + curriculum
3country="*" + curriculum (عالمي)
4US (تراجع أساسي)

المواد المخصّصة لصف بعينه تُنتج ربطاً 1:1 — "Math Grade 3" يُربَط مباشرةً بالصف الثالث في المدرسة.

ensureSubjectSelections — إصلاح ذاتي كسول

تعمل التهيئة بأسلوب fire-and-forget عبر after() في Next.js. إن غابت صفوف الجسر، يُصلِحها ensureSubjectSelections بشكل كسول عند أول قراءة، فيُصحَّح فشل التهيئة الجزئي ذاتياً — لاختيارات المواد فقط.

طبيب التهيئة — repairProvisioning

كانت الاختيارات هي المرحلة الوحيدة التي تُصلَح ذاتياً؛ انقطاع serverless كان لا يزال قادراً على ترك مدرسة بلا حصص أو شُعَب أو خانات جدول. الطبيب في src/components/catalog/provision.ts يغلق هذه الثغرة:

  • getProvisioningStatus(schoolId) — جولة عدّ واحدة مُجمَّعة عبر كل مرحلة (الافتراضات، البنية الأكاديمية، الاختيارات، الجدول الزمني، الشُّعَب، خانات الجدول، رمز الانضمام) مع تقارير إضافية للعرض فقط (المسارات، كتب المكتبة).
  • repairProvisioning(schoolId) — يشغّل المراحل الناقصة فقط بترتيب الاعتمادية، وكل مرحلة معزولة بحيث لا يُوقف فشلُ واحدة البقيةَ. كل خطوة أساسية قابلة لإعادة التنفيذ — إعادة تشغيله على مدرسة سليمة لا تفعل شيئاً.

ثلاثة مستدعين يلتقون عليه: خطّاف after() في الإعداد الأولي، ومسار publishSchool اليدوي، وجدول مدارس المُشغِّل (إجراء Repair Provisioning). applyTimetableStructureForNewSchool صار هو الآخر قابلاً لإعادة التنفيذ — إعادة تشغيله لم تعد تكرّر حصص المدرسة.

البنية الأكاديمية لكل منهج (الثغرة المُصلَحة)

كان setup.ts القديم يُضمِّن النموذج السوداني — مراحل عربية 6+3+3، أسماء صفوف عربية، مسارات علمي/أدبي مفروضة على الصفوف 10–12 — ويطبّقه على كل مدرسة، فكانت مدرسة أمريكية/بريطانية/IB تحصل على أسماء صفوف عربية ومسارات لا تخصّها. هذا مُصلَح الآن. التهيئة تحلّ رمز منهج المدرسة إلى CurriculumAcademicConfig في src/components/catalog/academic-config.ts (CURRICULUM_ACADEMIC_CONFIG، يُختار عبر getAcademicConfig). مدخل SD يحفظ الثوابت الأصلية بايتاً ببايت، فتُهيَّأ المدارس السودانية تماماً كما كانت.

رمز/رموز المنهجالبنيةتسمية الصفوفالمسارات
SD، SA، EG، AE، QA، KW، JOعربي 6+3+3الصف الأول …علمي / أدبي من الصف 10
US، CAIE-IGCSE، IB-DPإنجليزي 5+3+4Grade Nلا شيء
GBمراحل رئيسية (خريطة 6+3+3)Year Nلا شيء
CBSE5+3+4 (ابتدائي/متوسط/ثانوي)Class Nلا شيء
(غير معروف)إنجليزي عام 6+3+3Grade Nلا شيء (GENERIC_FALLBACK)

معرّفات (slugs) الصفوف غير قابلة للضبط عمداً — تبقى grade-${n} في كل مكان لأن ربط YearLevel في setup.ts يطابق على شكل ذلك المعرّف. الاسم المعروض، وحدود المراحل، وسياسة المسارات فقط هي ما يتغيّر لكل منهج.

الاقتراحات والموافقة

يمكن للمدرسة أن تقترح محتوى فهرس جديداً، وعند الموافقة تتبنّاه اختيارياً. هذا هو تدفّق الطلب الذي شُحِن هذه الجلسة — لاحظ أن الموافقة تنشر إلى الفهرس فقط؛ لا جسر تلقائي (المدرسة تضيفه صراحةً).

School proposes a subject/chapter/lesson
  → Proposal { status: SUBMITTED }      (requireProposer: ADMIN / DEVELOPER / TEACHER)
Operator queue at /catalog/proposals      (sidebar badge shows SUBMITTED count)
  → approveProposal → creates Subject/Chapter/Lesson (status PUBLISHED) in the catalog
                      → proposal PUBLISHED, catalogEntityId set
                      → NO auto-bridge (opt-in)
  → notifies proposer + school ADMINs     (in_app + email, school-language aware)
School catalog picker pins the new subject ("Requested by your school — now ready")
  → one-time reminder dialog + Add CTA
  → pin clears once the subject is added (SubjectSelection exists)
  → rejectProposal → notifies proposer + ADMINs with the rejection reason

الاقتراح (جانب المدرسة)

تكتب submitSubjectProposal / submitChapterProposal / submitLessonProposal (src/components/school-dashboard/listings/subjects/catalog/proposal-actions.ts) صفّ Proposal (catalog_proposals) بحالة status: SUBMITTED. مُصرَّح به عبر requireProposer — ADMIN أو DEVELOPER أو TEACHER ممّن لديه schoolId. حقل Proposal.data (JSON) يحمل حقول الكيان؛ واقتراحات الفصل/الدرس تشير إلى parentSubjectId / parentChapterId. يمكن تحرير اقتراح DRAFT أو REJECTED وإعادة إرساله (updateProposal).

طابور المُشغِّل

/catalog/proposals (لـDEVELOPER فقط) يسرد الاقتراحات عبر getProposalsForReview، مع ضبط المُرشِّح افتراضياً على SUBMITTED. يحسب تخطيط الفهرس أعداد الشارة — db.proposal.count({ where: { status: "SUBMITTED" } }) — ويعرض تسمية التنقّل بصيغة Proposals (N) عند وجود معلّق.

الموافقة → الفهرس فقط

تُشغِّل approveProposal التدفّق كاملاً في معاملة واحدة (فحص حالة متفائل داخل المعاملة، وإعادة محاولة عند تضارب المعرّف، والأسماء العربية تحصل على لاحقة معرّف عشوائية). تُنشئ Subject/Chapter/Lesson بحالة status: PUBLISHED، وتعلّم الاقتراح PUBLISHED مع catalogEntityId، ولا تُنشئ SubjectSelection — المدرسة تتبنّاه اختيارياً. تنطلق الإشعارات بعد المعاملة (فشل الإشعار لا يتراجع عن الموافقة أبداً):

  • لغة المدرسة تُحلّ عبر resolveSchoolLang(schoolId) (عنوان/متن ثنائي اللغة).
  • يُعاد استخدام NotificationType document_shared للموافقة، و**system_alert** للرفض.
  • metadata يحمل { entityType: "proposal", kind: "proposal_approved" | "proposal_rejected", catalogEntityId, url: "/subjects/catalog" }.
  • يُسلَّم إلى المقترِح (يُتخطّى إن كان المقترِح ADMIN — توزيع الجمهور حسب الدور يغطّيه أصلاً، تفادياً للتكرار) وكل ADMIN في المدرسة، على in_app + email.
  • rejectProposal يتطلّب سبباً ويضمّنه في الإشعار.

مُثبَّت في مُنتقي المدرسة

مُنتقي فهرس المدرسة (subject-picker.tsx) يأخذ pinnedSubjectIds — المواد المُوافَق عليها التي طلبتها هذه المدرسة ولم تُضِفها بعد. تُعرَض في قسم مُثبَّت "Requested by your school — now ready" مع زرّ Add، ويعلن عنها مرّةً واحدة حوار CatalogReadyReminder (يُخزَّن الصرف في localStorage تحت catalog-ready-dismissed:${schoolId}). يُرشِّح التثبيت أي مادة لها اختيار بالفعل، فيُمسَح تلقائياً بمجرّد إضافة المادة.

الرؤية والمحتوى المدفوع

كل عنصر مُساهَم به يحمل ContentVisibility إضافةً إلى price/currency اختيارية. دورة حياة المساهمة:

Teacher/School creates content
  → approvalStatus: PENDING, visibility: PRIVATE, status: DRAFT
SaaS admin reviews (/catalog/approvals)
  → APPROVED → status set to PUBLISHED, visibility set by reviewer
       PRIVATE  — only creator's school
       SCHOOL   — schools using that subject (free)
       PUBLIC   — anyone (free)
       PAID     — anyone, gated by purchase (priceable types only)
  → REJECTED → reason sent to creator

الموافقة تنشر الآن (الثغرة المُصلَحة)

مساهمات المدرسة المُوافَق عليها تُنشأ بحالة status: DRAFT، لكن مسارات تصفّح المدرسة لا تُظهر إلا الصفوف PUBLISHED + APPROVED — فكانت المساهمة المُوافَق عليها تبقى سابقاً DRAFT غير مرئية. الآن تضبط approveContent (saas-dashboard/catalog/approval-actions.ts) أيضاً status: PUBLISHED لـ Question وMaterial وAssignment (لا ContentStatus لـVideo؛ والكتاب يُنشَر + يُختار تلقائياً في مكتبة المساهِم).

الفيديوهات المدفوعة (موصولة)

الفيديوهات محجوبة بالكامل عبر Stripe: صفّ VideoPurchase يسجّل الشراء، والرابط يُقدَّم عبر CloudFront مُوقَّع، والفيديو PAID غير المُشترى يُعيد رابطاً null فلا يستطيع المشغّل جلبه. ضبط فيديو على PAID عند الموافقة يتطلّب سعراً موجباً وعملة من 3 أحرف.

الاختبارات / الأسئلة المدفوعة (مؤجّل)

يحمل Question وExam حقلَي price/currency ويقبلان رؤية PAID، لكن تدفّق الشراء غير مبني — الحقول موجودة لمتجر اختبارات/أسئلة مدفوع مستقبلاً.

إدارة أعلام المُشغِّل

updateContentFlags (+ الحوار content-flags-dialog) يتيح لـDEVELOPER ضبط الرؤية / الحالة / السعر لكل نوع محتوى، مستقلاً عن الموافقة/الرفض. يفرض الحوار قائمة بيضاء لكل نوع:

الحقلمسموح على
visibilityكل نوع
statusكل نوع عدا Video (لا ContentStatus)
price / currencyQuestion، Video، Exam فقط
PAIDالأنواع القابلة للتسعير فقط — تتطلّب سعراً + عملة 3 أحرف

ضوابط جانب المدرسة

  • SubjectSelection.isActive — يُفعّل/يُعطّل مادة مُتبنّاة للمدرسة.
  • ContentOverride.isHidden — يُخفي فصلاً/درساً/فيديو. هذا الآن يُرشِّح فعلاً صفحة تفاصيل المادة للأدوار غير الإدارية (get-course.ts يقرأ ContentOverride ويُسقِط العُقَد المخفيّة؛ وإن فشل استعلام التجاوز يُظهر كل شيء بدل خطأ 500). الإداريون يستخدمون admin-get-course.ts الذي يُعيد كل المحتوى موسوماً بـ _isHidden فيستطيع لوح Customize إدارة الرؤية.
  • البحث العام يُرشِّح الآن إلى المواد المنشورة فقط (atom/generic-command-menu/server/global-search.ts) — تسريب سابق لمحتوى غير منشور أُصلِح.

هندسة المنهج

هرم الفهرس ثلاثة جداول عامة، كلّها بلا نطاق؛ والمدارس تشير إليها عبر الجسر. slug هو مفتاح الـupsert الأساسي — يُرمِّز البلد + الصفّ + المادة (sd-g5-math، us-g5-math)، فلا حاجة لقيد فريد مركّب على (country, curriculum, grade, name).

model Subject {                                    // table catalog_subjects
  country      String        @default("SD")        // ISO 3166-1 alpha-2
  curriculum   String        @default("SD")        // canonical code: bare ISO (US, SD, GB) or BODY-PROGRAMME (IB-DP, CAIE-IGCSE, CBSE)
  curriculumId String?                             // optional FK → Curriculum
  concept      String?                             // shared image key
  thumbnail    String?       @map("thumbnailKey")  // S3 key for WebP variants
  grades       Int[]         @default([])          // [5] = grade 5 only
  levels       SchoolLevel[]                       // [ELEMENTARY]
  slug         String        @unique               // sd-g5-math, us-g5-math
  totalChapters Int                                // denormalized counts
  totalLessons  Int
}

أشجار المحتوى على القرص — curriculum/

دليل curriculum/ هو مصدر الحقيقة للمحتوى للمناهج العميقة. أداة البناء (curriculum/_build_tools/engine.py) تكتب، ومحرّك البذرة يقرأ، هذا الشكل:

curriculum/<dir>/
  g{N}/                       # grade
    <subject>/                # e.g. math, science
      structure.json          # { subject, chapters: [{ name, slug, lessons: [...] }] }
      textbook.pdf            # optional — merged free official PDF

scripts/gen-curriculum-structure.ts يحوّل مواصفة قائمة فصول مُوجزة إلى شجرة structure.json؛ وscripts/upload-textbooks-all.ts يدفع كتب أي شجرة (PDF) إلى S3. الصيغ القديمة (us-inventory.json، sudan-curriculum.json) تحتفظ ببذورها الخاصّة — والمناهج الجديدة وحدها تمرّ عبر محرّك الشجرة.

syncCurriculumTree (محرّك الشجرة)

التكرار لكل بذرة (upsert، تحديث الأعداد، حلقة الفصل/الدرس، إسناد المفهوم) مُجمَّع في مساعد واحد syncCurriculumTree (prisma/seeds/catalog/engine.ts). المنهج العميق الجديد ملفّ مصدر بـ~20 سطراً:

// prisma/seeds/catalog/gb.ts
import { syncCurriculumTree } from "./engine"
 
export async function seedGbCurriculum(prisma: PrismaClient) {
  return syncCurriculumTree(prisma, {
    dir: "uk", // curriculum/uk/
    country: "GB",
    code: "GB", // canonical curriculum code
    slugPrefix: "gb", // gb-g{N}-{subject}
    name: "British (England)",
    lang: "en",
    gradeRange: [1, 12],
    sortBase: 20000,
  })
}

يقرأ أي شجرة curriculum/<dir>/g{N}/<subject>/structure.json، ويُحدِّث/يُدرِج (upsert) Subject/Chapter/Lesson بالرمز/البلد القانوني، ويُرفق مفتاح S3 لكتاب PDF عند وجوده، ويُدوِّر مصغّر المفهوم المشترك عبر الفصول. وهو قابل لإعادة التنفيذ بأمان (upsert للمادة حسب slug؛ والفصول/الدروس تُستبدَل). تحمل المواد رمز المنهج فقط — registry.ts يملك صفّ Curriculum ويملأ curriculumId. المستدعون الأربعة الأحياء هم gb.ts، وcbse.ts، وcaie-igcse.ts، وib.ts. والمناهج العربية الستة مواد-فقط (sa.ts…jo.ts) تتشارك seedSubjectsOnly.

المناهج والرموز

المناهج الوطنية تستخدم رمز دولة ISO 3166-1 المجرّد — البلد هو المُعرِّف؛ والبرامج الدولية تستخدم رمز {body}-{programme}. الصفوف الموجودة رُحِّلت من الرموز القديمة (national / us-k12 / ib) عبر ترحيل canonicalize_curriculum_codes (المُفعَّل الآن). يحتفظ Curriculum.slug بقيمه الخاصّة (sd-national، ib-diploma).

المنهجالرمزالنوع
السودانSDوطني
السعوديةSAوطني
مصرEGوطني
الولايات المتحدةUSوطني
إنجلتراGBوطني
الإماراتAEوطني
قطرQAوطني
الكويتKWوطني
الأردنJOوطني
بكالوريا IBIB-DPدولي
كامبريدج IGCSECAIE-IGCSEدولي
الهندي CBSECBSEدولي

التغطية

كل المناهج الاثني عشر لها مواد. ستة بعمق (فصول ودروس حقيقية) — US، والسودان، وإنجلترا (curriculum/uk)، وكامبريدج IGCSE، وIB-DP، والهندي CBSE. أما المناهج العربية الوطنية الستة فتبقى مواد فقط حتى تُؤلَّف بنية كتبها الوزارية.

المنهجالرمزالصفوفموادفصولدروسالمصدرالبذرة
الولايات المتحدةUS1–12~240~750~3,993US-inventoryus
السودانSD1–121258642,937curriculum/sdsd
إنجلتراGB1–12184363730curriculum/ukgb
كامبريدج IGCSECAIE-IGCSE1087676curriculum/caie-igcsecaie-igcse
بكالوريا IBIB-DP1294949curriculum/ibib
الهندي CBSECBSE1075858curriculum/incbse
السعوديةSA1–12~132——sa.ts المضمّنsa
مصرEG1–12~140——eg.ts المضمّنeg
الإماراتAE1–12~144——ae.ts المضمّنae
قطرQA1–12~122——qa.ts المضمّنqa
الكويتKW1–12~139——kw.ts المضمّنkw
الأردنJO1–12~150——jo.ts المضمّنjo

المناهج العابرة للحدود العميقة (كامبريدج، IB، CBSE) تغطّي صفّاً تمثيلياً حتى الآن؛ وتوسعتها لكل صفّ آليّة (تأليف مزيد من structure.json). أما curriculum/us على القرص (Aldar American، 128/266/535) فهي غير مُدمَجة — تتصادم على فضاء المعرّف us-g{N}-* وهي أقلّ عمقاً؛ تبقى طبقة مرجعية. لا دمج مخطّط له.

المحتوى الحقيقي — السودان (كل الصفوف)

catalog/sd-content.ts يُدمِج بنوك الأسئلة والامتحانات النهائية المؤلَّفة الموجودة بجوار كل كتاب مدرسي سوداني (curriculum/sd/g{1–12}/<subject>/{qbank,exams}.json) في Question/Exam/ExamQuestion: ‏102 مادة، ~2,700 سؤال (100% مربوطة بالفصول؛ منها 405 مربوطة بالدروس أيضاً — وهي ما يُغذّي اختبار التدريب في صفحة الدرس)، وامتحان نهائي مرتبط لكل مادة. بوّابة جودة تتخطّى 22 ملفاً في الصفّين 11–12 مولَّدة قالبياً (>50% علامات حشو) — تلك المواد تُبقي المحتوى الاصطناعي بدلاً منه. الصفوف موسومة "sd"؛ والدمج حذفٌ-وإعادة-إنشاء لكل مادة ويعمل محلياً (pnpm db:seed:single sd-content) لأن curriculum/ لا يُنشر.

دروس السودان بلا صفوف Video عمداً — مشغّل الدرس في lumos يعود إلى مقطع story.mp4 المشترك في كل درس سوداني، فلا يظهر مشغّل فارغ ولا رابط لكائن مفقود على CDN.

المحتوى المُولَّد

catalog/content.ts يقرأ الهرم المنشور ويُولِّد صفوفاً اصطناعية بالجملة: اختبارات (لكل مادة/فصل/درس)، وبنك أسئلة (~10/مادة، 6/فصل، 4/درس)، ومواد (بيانات وصفية فقط — fileUrl يكون null)، وواجباً واحداً لكل درس. المنهج مواد-فقط يحصل على صفوف لكل مادة فقط. المواد التي تحمل محتوى حقيقياً مُدمَجاً (أسئلة موسومة "sd") تُتخطّى، والصفوف الاصطناعية اليتيمة (مفاتيح نطاق أفرغتها إعادة بناء الفصول) تُحذَف في كل تشغيل. والاستثناء هو catalog/exam-templates.ts الذي يكتب مخطّطات + قوالب حقيقية مؤلَّفة يدوياً (قابلة لإعادة التنفيذ، لكل مادة). نموذج Quiz لا يُبذَر. content.ts قابل لإعادة التنفيذ — راجع العمليات.

جودة استخراج جدول المحتويات

كثير من ملفات السودان (خاصّةً الصفوف 6–8 و10–12) أنتجت مخرجات pdftotext مشوّهة أو فارغة، فبقيت فصول بـ0 دروس:

نطاق الصفوفبدروسبـ0 دروس
1–531 (89%)4 (11%)
6–98 (40%)12 (60%)
10–1214 (29%)34 (71%)

الأولويات: تمريرة OCR (Tesseract عربي) على الملفات الممسوحة، ثم إدخال يدوي للصفوف 10–12 عبر طبقة المحتوى / تدفّق الاقتراح.

خريطة الملفات

prisma/
  models/catalog.prisma              # Subject, Chapter, Lesson + shared enums
  seeds/catalog/
    engine.ts                        # syncCurriculumTree + seedSubjectsOnly (shared)
    registry.ts                      # 12 Curriculum records + curriculumId backfill
    index.ts                         # seedCatalog + seedFullCatalog
    us.ts                            # US (240, us-inventory.json)
    sd.ts                            # Full Sudan from curriculum/sd/ (125)
    sd-content.ts                    # SD real qbank+exams ingest, g1–g12
    gb.ts / cbse.ts / caie-igcse.ts / ib.ts   # deep tree callers
    {sa,eg,ae,qa,kw,jo}.ts           # 6 subjects-only nationals
    concepts.ts / banners.ts         # shared image upload + backfill
    content.ts / books.ts / videos.ts / exam-templates.ts / demo.ts
    single.ts                        # CLI registry
curriculum/
  <dir>/g{N}/<subject>/structure.json   # on-disk content trees
  _build_tools/engine.py             # writes the trees
src/components/catalog/
  setup.ts                           # findSubjects(), inferCurriculum()
  academic-config.ts                 # per-curriculum CurriculumAcademicConfig
  image.ts / image-url.ts            # Sharp pipeline + URL resolution
  concepts-data.ts                   # single source of concepts + nearestConcept

منهج الولايات المتحدة

مصدر US هو جرد محتوى K-12: scripts/us-curriculum/us-inventory.json. تتوسّع 62 مادة أساسية إلى ~240 صفّ Subject مخصّص لصف عبر بذرة us. تصنيف US وصوره بذرا أصول المفاهيم المشتركة، وهو المرجع الذي تُحسَّن منه بقية المناهج.

المقياسالعدد
المواد62
مجموعات المواضيع201
المواضيع الفرعية986
الفيديوهات22,289
الموارد43,075
المستوىموادمجموعاتمواضيعفيديوهاتمواردالصفوف
Elementary18493468,13017,233K-5
Middle21732765,49010,7546-8
High23793648,66915,0889-12

كل موضوع فرعي في الجرد مفتاحه slug:

type SourceTopic = {
  slug: string // kebab-case identifier
  name: string // display name
  videos: number
  resources: number
  coverId: string
  subject: string
  topicGroup: string
}
# list every sub-topic for a tier
jq '.tiers.elementary.subjects[] | .topics[]' scripts/us-curriculum/us-inventory.json
jq '.tiers.middle.subjects[]     | .topics[]' scripts/us-curriculum/us-inventory.json
jq '.tiers.high.subjects[]       | .topics[]' scripts/us-curriculum/us-inventory.json

منهج السودان

يغطّي السودان الصفوف 1–12 في بنية 6+3+3 (Elementary، Middle، Secondary)، مُستخرَجة من ملفات الكتب المدرسية المنشورة من المركز القومي للمناهج والبحث التربوي (بخت الرضا). المواد والفصول والدروس تعيش في الفهرس بـcountry: "SD" وcurriculum: "SD". نمط المعرّف sd-g{N}-{subject} (مثل sd-g5-math)؛ بادئة المعرّف تجميلية، ورمز curriculum هو مفتاح الربط القانوني.

الصفالمستوىموادفصولدروسملاحظات
1Elementary417112Arabic, Math, Islamic, English
2Elementary736195+ Science, Arts, History
3Elementary635212+ Geography
4Elementary52455+ Computer
5Elementary1253222+ Earth Environment, Resources, Clothing
6Elementary5100Scanned PDFs — chapters only
7Middle110English activity book only
8Middle———No textbooks available
9Middle93440+ Technical Education, Communication Tech
10Secondary114980+ Physics, Chemistry, Biology, French
11Secondary197177Full catalog including streams
12Secondary187656Shahada year — all streams

مسارات الثانوي (10–12) تُوجَّه بأنماط في setup.ts:

const SCIENCE_ONLY_PATTERNS = [
  "physics",
  "chemistry",
  "فيزياء",
  "كيمياء",
  "أحياء",
]
const ARTS_ONLY_PATTERNS = [
  "philosophy",
  "فلسفة",
  "أدب",
  "بلاغة",
  "مطالعة",
  "نحو",
  "عربية خاصة",
  "رياضيات أساسية",
]

خطّ معالجة البيانات

~/SD/*.pdf (260 raw, ~112 unique textbooks)
  → organize        → scripts/sudan-data/pdfs/grade-{N}/sd-g{N}-{subject}.pdf
  → pdftotext       → raw Arabic TOC text
  → parse TOC       → scripts/sudan-data/toc/sd-g{N}-{subject}.json (97 files)
  → assemble-sudan-curriculum.ts → scripts/sudan-data/sudan-curriculum.json (master)
  → prisma/seeds/catalog/sd.ts   → Subject + Chapter + Lesson (upsert)

ثغرات معروفة: ملفات الصف 6 صور ممسوحة (فصول فقط، 0 دروس)، والصف 7 له كتاب واحد، والصف 8 بلا كتب، وعدّة ملفات ثانوية مشوّهة — يُعالَج بـOCR، أو بجلب الكتب المتبقّية، أو بمساهمة المجتمع.

إضافة منهج وطني

السودان يسبق الخطّ العام (بذرة مُحرَّكة بجدول المحتويات). المنهج الوطني الجديد (مثل مصر EG) يمرّ عبر محرّك الشجرة:

  1. ألِّف curriculum/eg/g{N}/<subject>/structure.json.
  2. أضف ملفّاً بسطر واحد prisma/seeds/catalog/eg.ts يستدعي syncCurriculumTree بـcountry: "EG", code: "EG"، وسجّله في prisma/seeds/single.ts.
  3. أضف EG → "EG" إلى inferCurriculum() وCOUNTRY_CURRICULUM (src/lib/timetable-reference.ts).
  4. أضف الأسماء العربية إلى SUBJECT_CONCEPT_BY_NAME في concepts-data.ts.
  5. (اختياري) أضف مدخل EG إلى CURRICULUM_ACADEMIC_CONFIG إن اختلف عن الافتراضي العربي المشترك 6+3+3.
  6. شغّل pnpm db:seed:single eg ثم pnpm db:seed:single concepts.

المفاهيم (Concepts)

المفهوم (concept) مُعرِّف مستقلّ عن المنهج يربط كل مادة بأصول بصرية مشتركة. العربية (السودان) واللغات العالمية (US) تتشاركان نفس مفهوم languages ونفس صور S3. كانت الرسومات تُشار إليها أصلاً من مكتبة خارجية أثناء النمذجة الأوّلية؛ وتلك الأصول الآن مملوكة، ومُعاد رسمها، ومشتركة عبر كل منهج — راجع الأصول.

Subject (any curriculum)
  └── concept: "math"
        ├── thumbnail: catalog/concepts/g{grade}-math/thumbnail-{size}.webp
        ├── banner:    catalog/concepts/g{grade}-math/banner-{size}.webp
        └── cover:     catalog/concepts/math/cover

المفاهيم الـ23

arts، biology، career-tech، celebrations، chemistry، civics، computer-science، earth-science، economics، english، geography، health، history، languages، life-skills، math، pe، physics، psychology، religion، science، sociology، teacher-pd.

صور المصدر تعيش في public/subjects/concepts/{concept}.jpg. بذرة concepts تعالج كلاً منها إلى 4 نسخ WebP (sm/md/lg/original) وترفعها إلى S3 لكل الصفوف الـ12. كل المناهج الـ12 تربط موادها بأحد هذه المفاهيم الـ23؛ ونموذج Image (catalog_images) يخزّن السجلّات لكل نسخة.

مصدر واحد للحقيقة — concepts-data.ts

كل ما يخصّ المفاهيم يعيش في src/components/catalog/concepts-data.ts: المفاهيم الـ23 وألوانها، وخرائط المطابقة الدقيقة (SUBJECT_CONCEPT_BY_SLUG، SUBJECT_CONCEPT_BY_NAME)، وأحواض التدوير (CONCEPT_POOL)، وخوارزمية كلمات مفتاحية nearestConcept() (إنجليزي + عربي) كي لا تبقى أي مادة بلا صورة (اللون المسطّح هو الملاذ الأخير). كل بذرة (us.ts، sd.ts، engine.ts، concepts.ts) تستورد منه — ولا تبقى نسخ لكل بذرة.

أحواض تدوير الفصول

الفصول داخل المادة تدور عبر حوض من 5 مفاهيم مرتبطة للتنوّع البصري (تُدوَّر بـ sequenceOrder % poolSize): مثلاً math → math، science، computer-science، physics، economics؛ وscience → science، biology، chemistry، physics، earth-science. البذور العميقة وsyncCurriculumTree ترث هذا؛ وللمناهج مواد-فقط، تأتي صور الفصل/الدرس مجاناً بمجرّد توفّر العمق.

النسخ (Variants)

النسخةالعرضالجودةالاستخدام
-sm.webp200px95مصغّرات الشبكة
-md.webp600px97صور البطاقات
-lg.webp1200px100بانرات البطل
-original.webpكاملبلا فقدالدقّة الكاملة

image.ts (خادم فقط — processAndUploadCatalogImage، deleteCatalogImage) يشغّل Sharp؛ وimage-url.ts (آمن للعميل — getCatalogImageUrl) يبني {key}-{size}.webp وقت القراءة. حلّ الرابط: CloudFront من thumbnailKey → تراجع ثابت قائم على المفهوم → null (خلفية لونية).

CDN والأصول

أصول الفهرس تتبع اصطلاح مفاتيح صارماً وتُقدَّم من S3 عبر CloudFront. المرجع الكامل لشبكة توصيل المنصّة (الحاوية، مساعد asset()، أدلّة أصول الواجهة المسطّحة الخمسة) يوجد في CDN & Assets — هذا القسم يغطّي قصّة الأصول الخاصّة بالفهرس فقط.

يحمل Subject أربعة حقول مفاتيح S3 — thumbnail (@map("thumbnailKey"))، banner (@map("bannerUrl"))، cover (غلاف الكتاب)، pdf (ملف الكتاب). يميّز الاصطلاح بين *Key (مفتاح S3 خام، تُلحَق النسخ وقت القراءة) و***Url** (رابط كامل التكوين، مثل أغلفة الكتب الخارجية). تخطيط S3:

catalog/concepts/g{n}-{concept}/thumbnail-{sm,md,lg,original}.webp
catalog/concepts/g{n}-{concept}/banner-{sm,md,lg,original}.webp
catalog/concepts/{concept}/cover
catalog/textbooks/{slug}/textbook.pdf
catalog/subjects/{slug}/…/thumbnail-{size}.webp     # US lesson/chapter covers

جدول ثغرات الأصول الصادق

الأصليُنتجهالحالة
مصغّرات الموادconcepts.tsمكتمل — كل المناهج الـ12، كل الصفوف الـ12
البانراتbanners.tsمُغطّى ذاتياً — ~10 من 23 مفهوماً لها بانر خاص؛ البذرة تستعير الآن بانر أقرب جار في CONCEPT_POOL للبقية (23/23 بعد التشغيل القادم)
أغلفة الكتب—مفقود — مفتاح cover مضبوط على كل مادة، لكن الكائن لم يُرفَع قطّ (تتراجع البطاقة إلى أيقونة)
ملفات الكتب (PDF)upload-textbooks-all.tsالسودان فقط — 118 textbook.pdf؛ لا منهج آخر
مصغّرات الدروس / الفصولlesson-covers.tsUS فقط — تُسحَب من CDN وقت البذرة
الفيديوهاتvideos.ts / مُساهَم بهمُتحقَّق بالفحص — البذرة تفحص كل .mp4 برأسية HEAD ولا تسجّل إلا الصفوف ذات الكائن الموجود (وتحذف الصفوف القديمة)؛ الرفع الفعلي ما زال معلّقاً
الكتبbooks.tsخارجي — 51 كتاباً على covers.openlibrary.org؛ السكربت scripts/snapshot-book-covers.ts يوطّنها إلى CDN لدينا (يعمل ببيانات AWS الإنتاج)
الموادcontent.tsبيانات وصفية فقط — fileUrl يكون null؛ بطاقات المواد تصبح قابلة للنقر تلقائياً فور وصول fileUrl/externalUrl

العمليات

أوامر البذر

seedFullCatalog (بذرة full) يشغّل كل شيء بالترتيب القانوني — كل المناهج الـ12 → registry → صور المفاهيم. وبذرة catalog الافتراضية هي المجموعة الفرعية السريعة: US

  • السودان الكامل، مُسجَّلة. كل منهج آخر هو تشغيل صريح خاصّ به. استخدم دوماً pnpm db:seed:single <name> — لا البذرة الكاملة قطّ (فهي يدوية فقط؛ راجع القاعدة أدناه).
البذرة (pnpm db:seed:single …)المحتوى
fullseedFullCatalog — كل المناهج الـ12 → registry → صور المفاهيم (قاعدة جديدة)
catalogالافتراضي السريع: US (~240) + السودان الكامل + registry
us / sdUS (الجرد) / السودان الكامل من curriculum/sd/
gb / cbse / caie-igcse / ibالمناهج العميقة عبر syncCurriculumTree من curriculum/<dir>/
sa / eg / ae / qa / kw / joالمناهج الوطنية الستة مواد-فقط (seedSubjectsOnly)
registryكل سجلّات Curriculum الـ12 + ملء Subject.curriculumId
concepts / bannersمصغّرات المفاهيم والبانرات → Sharp → S3/CloudFront
lesson-coversمصغّرات دروس/فصول US (تعتمد على CDN)
books / content / videos / exam-templatesكتب، محتوى مُولَّد، فيديوهات، مخطّطات/قوالب اختبارات
demoالبنية الأكاديمية + صفوف الجسر للمدرسة التجريبية
pnpm db:seed:single --list        # list available seeds
pnpm db:seed:single catalog       # fast default: US + full Sudan + registry
pnpm db:seed:single gb            # England — deep, from curriculum/uk
pnpm db:seed:single sa            # Saudi Arabia — subjects-only national
pnpm db:seed:single registry      # (re)link all 12 Curriculum records
pnpm db:seed:single concepts      # thumbnails → S3/CDN
pnpm tsx scripts/upload-textbooks-all.ts   # Sudan textbook PDFs → S3

التكرارية (Idempotency)

أغلب البذور آمنة للـupsert (بذور الصور تعيد الرفع إلى مفاتيح ثابتة، آمنة أيضاً). بذرة المحتوى الآن قابلة لإعادة التنفيذ كذلك (مُصلَحة هذه الجلسة): content.ts يحسب seedKey حتمياً من نطاق كل صفّ + عنوانه، ويحمّل المفاتيح الموجودة مسبقاً، ويُسقِط المرشّحين الموجودين بالفعل — فإعادة تشغيله لم تعد تكرّر الاختبارات/الأسئلة/المواد/الواجبات. نموذج Quiz ما زال لا يُبذَر.

مزامنة قاعدة البيانات الحيّة المؤجّلة للنشر

الرموز القانونية حيّة، لكن اتّساع المناهج العميقة مشحون في الكود وليس في قاعدة البيانات الحيّة بعد. الدليل التشغيلي كله صار أمراً واحداً:

pnpm tsx scripts/catalog-deploy-sync.ts            # خطة — تقرير للقراءة فقط
pnpm tsx scripts/catalog-deploy-sync.ts --execute  # تطبيق (مرهون بالنشر)

يجرد السكربت صفوف مواد-فقط القديمة التي حلّت محلّها الأشجار العميقة (gb-national-g* ~156 وib-diploma-g* ~114)، ويحذف فقط ما لا تشير إليه أي مدرسة — لأن SubjectSelection/Enrollment تُحذَف تتابعياً مع حذف المادة، فالصفوف المُشار إليها تُدرَج للترحيل اليدوي بدل حذفها — ثم يبذر registry → gb → cbse → caie-igcse → ib → concepts → banners. (كامبريدج IGCSE وCBSE بلا صفوف في قاعدة البيانات الحيّة بعد.) شغّله فقط بعد أن يصبح نشر الكود حيّاً، مع فرع Neon احتياطاً. ومعه في البيئة نفسها: scripts/snapshot-book-covers.ts (أغلفة OpenLibrary → S3 لدينا) و scripts/snapshot-covers.ts (مصادر أغلفة دروس US).

لا تشغّل البذرة الكاملة قطّ

وفق قاعدة المشروع، لا تشغّل pnpm db:seed قطّ — البذرة الكاملة يدوية فقط. استخدم دوماً pnpm db:seed:single <name>. العمليات المدمّرة لقاعدة البيانات (إعادة تشغيل SQL الترحيل، وdb push --accept-data-loss، وmigrate reset) ممنوعة بلا موافقة صريحة.

الأصول (Origins)

تصنيف منهج US (مواد → فصول → دروس) ورسومات المفاهيم الأصلية استُلهِما من ClickView، نظام التعلّم الأمريكي الذي أُشير إليه أولاً. تلك الأصول الآن مملوكة، ومُعاد رسمها، ومشتركة عبر كل منهج، وفهرس US هو المرجع الذي تُحسَّن منه البقية — ClickView يُنسَب إليه الفضل هنا مع الشكر؛ وهو لم يعد اعتمادية وقت تشغيل.

اطّلع أيضاً

  • CDN & Assets
  • Library
  • Multi-Tenancy
تعدّد المستأجرينالعمل دون اتصال

On This Page

نظرة عامةالحالة باختصارالمعماريةنماذج الفهرس العامنماذج الجسر (تحمل schoolId)مرايا المدرسة (مفتاح أجنبي للفهرس → catalogXxxId)التعدادات (Enums)تفصيل نماذج المحتوىالتهيئة (Provisioning)inferCurriculum + تراجع findSubjectsensureSubjectSelections — إصلاح ذاتي كسولطبيب التهيئة — repairProvisioningالبنية الأكاديمية لكل منهج (الثغرة المُصلَحة)الاقتراحات والموافقةالاقتراح (جانب المدرسة)طابور المُشغِّلالموافقة → الفهرس فقطمُثبَّت في مُنتقي المدرسةالرؤية والمحتوى المدفوعالموافقة تنشر الآن (الثغرة المُصلَحة)الفيديوهات المدفوعة (موصولة)الاختبارات / الأسئلة المدفوعة (مؤجّل)إدارة أعلام المُشغِّلضوابط جانب المدرسةهندسة المنهجأشجار المحتوى على القرص — curriculum/syncCurriculumTree (محرّك الشجرة)المناهج والرموزالتغطيةالمحتوى الحقيقي — السودان (كل الصفوف)المحتوى المُولَّدجودة استخراج جدول المحتوياتخريطة الملفاتمنهج الولايات المتحدةمنهج السودانخطّ معالجة البياناتإضافة منهج وطنيالمفاهيم (Concepts)المفاهيم الـ23مصدر واحد للحقيقة — concepts-data.tsأحواض تدوير الفصولالنسخ (Variants)CDN والأصولجدول ثغرات الأصول الصادقالعملياتأوامر البذرالتكرارية (Idempotency)مزامنة قاعدة البيانات الحيّة المؤجّلة للنشرلا تشغّل البذرة الكاملة قطّالأصول (Origins)اطّلع أيضاً

من تطوير Databayt ·

مرحباً بك في بالقلم.

رحلة عظيمة على وشك أن تبدأ.