لماذا متحف، ولماذا «العربية أولًا»؟
أنا أحمد عبد العال، مطوّر مقيم في أونتاريو، كندا. في أغسطس 2025 بدأت مشروعًا شخصيًا غير تجاري: متحف رقمي يوثّق التاريخ الإسلامي، أطلقتُه في 11 أكتوبر 2026 باسم islam.museum. قرار التصميم الأول كان لغويًا: أغلب المحتوى المرجعي على الإنترنت إنجليزي البنية حتى حين يُترجم إلى العربية؛ أردت أن تكون العربية هي الأصل الذي تُبنى عليه البيانات، لا طبقة ترجمة فوقها. هذا المقال عن الهندسة: كيف تُمثَّل أربعة عشر قرنًا من التاريخ في نموذج بيانات يستطيع مطوّر آخر البناء عليه — بصدق كامل حول طريقة البناء، بما فيها أن خط الإنتاج عندي أسطول من وكلاء الذكاء الاصطناعي يعملون تحت إدارتي ومراجعتي. المكدّس باختصار: Astro 5 بإخراج ثابت بالكامل، ومكوّنات Svelte للمقاطع التفاعلية، وTailwind CSS 4 — أما المحتوى كله ففي Git، كما سترى.
نموذج البيانات: التاريخ كرسم كيانات
المحتوى عندي ليس صفحات مستقلة، بل entity graph: عقدٌ من خمسة أنواع رئيسية — أشخاص، أماكن، أحداث، مخطوطات، عمارة — وحوافّ تربطها بعلاقات موثّقة بالمصادر. اليوم يضم الرسم 47,889 مدخلًا موثّقًا، تُشتق منه 96,000 صفحة و301 مسار موضوعي يرشد القارئ عبر سلاسل مترابطة.
والتخزين مملّ عن قصد: كل كيان ملف YAML واحد في data/<class>/<slug>.yaml، محايد لغويًا — الاسم وصيغه حقل موثّق بنوع كل صيغة (names)، والتواريخ بصيغة EDTF مع مقابلها الهجري، والعلاقات بداخله بنوعها ومصادرها. أنواع العلاقات نفسها مضبوطة في schema/predicates.yaml، ومخططات JSON Schema لكل صنف مولّدة آليًا من قوائم القيم في schema/enums/. والنصوص السردية ملفات Markdown في content/<lang>/<class>/<slug>.md. خط أنابيب TypeScript يجمّع هذا كله في رسم graphology واحد، ومن ذلك الرسم الواحد تُشتق الصفحات وواجهة API معًا.
أهم درس في النمذجة: القيد الحقيقي ليس شكل السجل الواحد، بل اتساق المجموعة. حين يرتبط شخص بحدث، يجب أن تتسق تواريخ حياته مع تاريخ الحدث؛ وحين يقع مكان في مسارين، يجب أن تكون هويته واحدة. لذلك صار عندي تمييز صارم بين طبقة البيانات (الحقائق والعلاقات والمصادر) وطبقة العرض (الصفحات والمسارات): أصلح الحقيقة مرة واحدة في مصدرها، فينعكس الإصلاح على كل صفحة تلمسها.
تفصيلان آخران أثّرا في كل شيء لاحقًا. الأول: المصدر يعيش داخل السجل نفسه، لا في قائمة مراجع عامة بعيدة عنه؛ فكل واقعة تُقرأ مع دليلها، وأي مراجع يستطيع أن يبدأ من الادعاء وينتهي إلى مصدره مباشرة. الثاني: المسارات (pathways) ليست روابط يدوية بين صفحات، بل سلاسل مُنتقاة فوق الرسم نفسه؛ فإذا تغيّرت علاقة في البيانات، تغيّر ما يمرّ به القارئ في المسار. معنى ذلك عمليًا أن سلامة المسارات نفسها جزء من سلامة البيانات، لا عمل تحريري منفصل — وهو قيد إضافي على كل تعديل، لكنه ثمن مقبول مقابل ألا تتعارض رواية الموقع مع بياناته.
النشر الصحيح: CC0 وإصدارات موثّقة
من اليوم الأول نشرتُ مجموعة البيانات برخصة CC0، والنصوص بـCC BY-SA، والكود بـMIT. البيانات متاحة على Zenodo بإصدارات مرقّمة وDOI ثابت (10.5281/zenodo.23692511)، بحيث يستطيع أي باحث الاستشهاد بإصدار بعينه لا بـ«الموقع كما هو اليوم». وفوق البيانات واجهة API عامة (api.islam.museum) تجعل إعادة الاستخدام برمجيًا لا نسخًا يدويًا: JSON ثابت يولّده سكربت تصدير عند البناء — ملف كامل لكل كيان (/api/v1/<class>/<slug>.json)، وفهرس مضغوط لكل صنف، والرسم كاملًا في nodes.ndjson وedges.ndjson، ومواصفة OpenAPI منشورة في /openapi/v1.json.
لماذا CC0 لا رخصة «غير تجارية» مثلًا؟ لأن كل قيد إضافي يقلّل من يُبنى فوق البيانات فعليًا، وهدفي بنية تحتية معرفية عربية يبني عليها غيري بحرية. الثمن معلوم وقاسٍ: الخطأ المنشور بـCC0 لا يُسترد. هذا الثمن هو ما يفسّر بقية المقال.
وللإصدارات المرقّمة وظيفة ثانية غير الأرشفة: إنها تجعل البيانات قابلة للاستشهاد العلمي. الباحث الذي يبني على «الموقع كما وجده اليوم» يبني على رمل؛ أما من يستشهد بإصدار محدد بـDOI فيستطيع غيره إعادة إنتاج نتيجته على البيانات نفسها. وبالمثل تعاملت مع واجهة API كعقد لا كوسيلة عرض: ما تعد به الواجهة اليوم يجب أن يبقى صحيحًا غدًا، لأن كسره يكسر عمل من بنى عليه. الانضباط هنا مملّ ظاهريًا — تثبيت، توثيق، إصدارات — لكنه الفرق كله بين «موقع جميل» و«بنية تحتية».
العربية وRTL على نطاق 96,000 صفحة
الاتجاه RTL ليس قلبًا لخاصية CSS وانتهى؛ إنه قرار في كل طبقة: ترتيب عناصر الواجهة، اتجاه الجداول الزمنية، سلوك البحث. تقنيًا، تعدّد اللغات مدمج في Astro نفسه: العربية هي الافتراضية وبادئة في كل المسارات، ثم الإنجليزية والأردية، ونصوص الواجهة في ملفات i18n/{ar,en,ur}.yaml بمجموعات مفاتيح متطابقة يفرضها اختبار آلي. والبحث Pagefind: سكربت البناء يولّد فهرسًا مستقلًا لكل لغة (pagefind-ar وpagefind-en وpagefind-ur)، تسنده ملفات مرادفات منسّقة للعربية والإنجليزية. والبحث العربي تحديدًا أصعب ما واجهنا: اسم تاريخي واحد قد يظهر بصيغ متعددة (كنية، لقب، نسبة)، والتشكيل غائب غالبًا، والتصرّف الصرفي يفرّع الكلمة الواحدة إلى صور كثيرة. تعاملنا مع ذلك في طبقة البيانات نفسها — ضبط الأسماء وصيغها البديلة كحقول موثّقة، لا كحيل لاحقة في واجهة البحث. لا أدّعي أن المشكلة حُلّت؛ أقول إن مكان حلّها الصحيح هو البيانات لا العرض.
التحقق هو المنتج الحقيقي
سأكون مباشرًا: مسودّات سجلّات المتحف يكتبها وكلاء ذكاء اصطناعي يعملون بالتوازي. من جرّب ذلك يعرف أن الكتابة ليست المشكلة؛ المشكلة أن تجعل المخرجات جديرة بالنشر. لذلك صارت بوّابات التحقق عندي هي «المنتج» الذي أبنيه فعلًا:
- Zero-error builds: فحص آلي شامل للمخطط والاتساق قبل أي دمج؛ خطأ واحد يوقف الخط كله. عندنا هذا هو تسلسل البناء نفسه: validate ← graph ← derive ← api ← astro ← pagefind؛ أي مرحلة تفشل توقف ما بعدها، واختبارات Vitest تعيد التحقق من المستودع كله.
- قاعدة المصدرين المستقلين: الواقعة المتنازع عليها لا تُعتمد إلا بمصدرين مستقلين فعلًا؛ من نقل عن غيره لا يُعدّ مصدرًا ثانيًا.
- Schema checks صارمة: حقول وقيم مضبوطة؛ ما لا يطابق المخطط لا يدخل أصلًا إلى طابور المراجعة. المخططات مولّدة من قوائم القيم المضبوطة نفسها، فتوسيع قيمة مسموحة قرار موثّق في ملف واحد، لا تعديلات مبعثرة.
- Cite-check: كل استشهاد داخل سجل يجب أن يحلّ آليًا إلى كيان مصدر مسجّل عندنا؛ الفحص يجري على كل دفعة قبل دمجها، واستشهاد لا يحلّ يعني فشل الدفعة.
لهذه البوّابات سبب بشري أيضًا: المراجع النهائي إنسان واحد. لو وصلته المسودّات بأخطاء بنيوية وتنسيقية، لاستهلك وقته في الصيد السطحي ولما بقي له جهد للحكم الحقيقي — هل الواقعة موثّقة فعلًا؟ هل العلاقة صحيحة الاتجاه؟ البوّابات الآلية تتكفل بكل ما يمكن ضبطه بقاعدة، فتصلني المراجعة وقد صارت الأسئلة المتبقية أسئلة حكمٍ لا أسئلة تنسيق. بهذا المعنى لا «تسرّع» البوّابات العمل فحسب؛ إنها تجعل مراجعة إنسان واحد لـ47,889 مدخلًا أمرًا ممكنًا أصلًا.
أعطال حقيقية وما غيّرته
ثلاثة أعطال شكّلت النظام الحالي. أولًا: وكلاء يعملون على المستودع نفسه كتبوا فوق تعديلات بعضهم وضاع عمل سليم؛ العلاج كان انضباط 3-way merge لا يُستثنى منه أحد. ثانيًا: استشهاد مختلق بالكامل أنتجه وكيل بثقة تامة؛ منذ ذلك اليوم يُتحقق من كل مرجع عند مصدره قبل الاعتماد. ثالثًا: أخطاء اتساق عبر الرسم (تواريخ لا تتسق بين سجلّين مرتبطين) لا تراها مراجعة الصفحة الواحدة؛ لذلك صار فحص الاتساق على مستوى المجموعة كلها بوّابة مستقلة، لا خطوة ضمن فحص السجل.
ماذا كنت سأفعل مختلفًا؟
كنت سأبني بوّابات التحقق قبل أول سجل، لا بعد أول ألف. وكنت سأعامل «الاتساق عبر المجموعة» كمتطلب تصميم منذ نموذج البيانات الأول، لأن إضافته لاحقًا أصعب بكثير. وكنت سأوثّق قرارات الترخيص والنشر مبكرًا كما أفعل الآن: المشروع قُبل في نطاق الحفظ الرقمي لدى مكتبة وأرشيف كندا، وطلب انضمامه إلى Digital Public Goods Alliance قيد المراجعة — وهذه خطوات كان يجب أن تبدأ مع الإطلاق لا بعده.
البيانات مفتوحة، وواجهة API عامة، والموقع https://islam.museum. إن بنيتَ شيئًا فوق البيانات، أو وجدت خطأ يستحق التصويب، فهذا بالضبط ما نُشرت من أجله.
![How to Use shadcn/ui in React Native Applications [Full Handbook]](https://cdn.hashnode.com/uploads/covers/5e0f2c2e490269cb30227a2b/a30e05d8-efcb-41ed-ad2c-fd22763d7ea2.png)

