سجل تطوير KuroCMS ج5: تنفيذ نوع الوصفة
قمنا بتنفيذ ميزة بطاقة الوصفة الجديدة في KuroCMS بناءً على التعليقات. اقرأ عن البنية التقنية وتوليد JSON-LD وتفاصيل تكامل المحرر.
في نظام "KuroCMS" ومحرر "KuroEditor"، اللذين تم تطويرهما كجيل جديد من أنظمة إدارة المحتوى بدون رأس (headless CMS) للعمل عند الحافة (edge)، تم تنفيذ "بطاقة وصفة" جديدة رسميًا في أحدث إصدار. بينما ركزت الإصدارات السابقة من KuroCMS على التعبير العام للمستندات باستخدام markdown وHTML القياسي، فإن إدخال بطاقة الوصفة هذه يسمح بالتعامل الصارم مع البيانات الوصفية مثل وقت الطهي، وقوائم المكونات، والحصص، والخطوات، مما يضمن إخراجًا متسقًا كـ بيانات منظمة يمكن لمحركات البحث مثل Google فهمها بسهولة (Schema.org Recipe). في هذه المقالة، نوضح بالتفصيل التصميم الفني لبطاقة الوصفة هذه ونوضح كيف يتم فرض التحقق من الصحة عبر طبقات المحرر وAPI والواجهة الأمامية.
فلسفة التصميم والتصميم الأساسي: نموذج بيانات ذكي يقتصر على مستند واحد = وصفة واحدة
عند تنفيذ بطاقة الوصفة، كان التحدي الأكبر الذي واجهه فريق التطوير هو "اتساق البيانات والقضاء على التكرار". بينما تحتوي مواقع الوصفات العامة غالبًا على بطاقات وصفات متعددة مبعثرة داخل مقال واحد، فإن هذا يميل إلى إنتاج بنية تالفة من منظور البيانات المنظمة لمحركات البحث (JSON-LD). إذا تم إخراج أطباق أو خطوات متعددة مختلفة بالتوازي لعنوان URL واحد (مقال)، يصبح الارتباط بين الخصائص المشتركة (مثل اسم الطبق والصورة النهائية والوصف وتاريخ النشر) وبطاقات الوصفات الفردية غامضًا.
لذلك، يفرض KuroCMS قيدًا يستند إلى القواعد وهو "مستند واحد = وصفة واحدة". الـ RecipeCard مسؤول فقط عن "الأجزاء المتغيرة الخاصة بالوصفة"—الحصص ووقت الطهي والمكونات والخطوات—بينما يتم إعادة استخدام المعلومات المشتركة مثل اسم الطبق والوصف والصورة النهائية وتاريخ النشر من خصائص المستند (العنوان والملخص وصورة الغلاف وتاريخ الإنشاء وما إلى ذلك). هذا يتجنب المدخلات المتكررة ويمنع المشاكل حيث تتكرر أسماء الوصفات المتطابقة في تنسيق تالف داخل نفس البيانات المنظمة.
بصراحة، من منظور تصميم محرر KuroEditor، لم نكن نريد قبول قيد مستند واحد = وصفة واحدة لأنه يحد من مرونة التخطيط. ومع ذلك، لأن صفحات وصفات المستخدمين تحصل على تقييمات SEO أعلى وتكون أسهل في القراءة والرجوع إليها، فإننا نطبق بصرامة قاعدة بطاقة وصفة واحدة لكل مقال في الإصدار الحالي.
ضمان الاتساق من خلال الوظائف النقية المشتركة
في نظام إدارة المحتوى بدون رأس، ليس من السهل تنفيذ نفس التحقق من بنية البيانات في المحرر الغني (KuroEditor) وAPI الحفظ وعملية البناء الثابتة للصفحات العامة. إذا كتبت منطق التحقق بشكل منفصل باستخدام لغات أو أطر عمل مختلفة في كل طبقة، فإن الفجوات في التنفيذ ستؤدي حتمًا إلى حدوث مشكلات، مثل "تم الحفظ في المحرر ولكنه فشل في خادم API"، أو "تم الحفظ في قاعدة البيانات ولكنه فشل في بناء الواجهة الأمامية، مما أدى إلى كسر موقع الويب".
لحل هذه المشكلة بشكل جذري، اعتمد KuroCMS نمط تصميم "الوظيفة النقية المشتركة" (Shared Pure Function). على وجه التحديد، نقوم بدمج "dist/kuro-recipe.js" (المبني في مستودع KuroEditor الرئيسي) في جوهر KuroCMS كـ "src/kuro-recipe.js"، إلى جانب ملف تعريف النوع "kuro-recipe.d.ts". يضمن هذا أن نفس رمز JavaScript تمامًا يفحص بيانات الوصفة في نص HTML أثناء تحرير المحرر واستدعاءات API للحفظ وعمليات البناء الثابتة. هذا التصميم ذو المصدر الواحد للحقيقة (Single Source of Truth) يقلل من الأخطاء.
*بما أن كلاً من KuroEditor وKuroCMS هما "برمجيات مفتوحة المصدر" تم تطويرها بواسطة Kuroboo، فإن الرجوع إلى سجل GitHub معًا سيجعل الفهم أسهل.
التحقق الصارم في API الحفظ: مواصفات recipe-guard.ts
عند حفظ مقال (PUT) في KuroCMS، لا يقوم API لجانب الخادم بتخزين السلسلة فحسب. بل يفحص بصرامة ما إذا كانت بيانات الوصفة مدمجة بشكل صحيح داخل نص HTML المرسل. يتم التعامل مع هذا الدور بواسطة وظيفة "checkRecipeCards(bodyHtml, isRecipeType)" في "src/recipe-guard.ts" في الخلفية.
الجانب الأكثر أهمية في هذا التحقق هو توقيته. يأخذ KuroCMS في الاعتبار التحرير التعاوني متعدد المستخدمين، وتتم كتابة البيانات المحفوظة النهائية في قاعدة البيانات بعد "دمج ثلاثي الاتجاهات" (3-way merge) للإصدارات المتعددة. إذا تم تشغيل التحقق قبل الدمج، فلا يمكننا منع الحالات التي يؤدي فيها الدمج بطريق الخطأ إلى تكرار بطاقات الوصفات أو إدخال بيانات تالفة. لذلك، يتم تنفيذ الفحص دائمًا على النص النهائي بعد الدمج. إذا فشل التحقق، يعيد API خطأً واضحًا إلى العميل، مما يؤدي إلى حظر عملية الحفظ.
| عنصر الفحص | التفاصيل وتدابير السلامة |
|---|---|
| عدد البطاقات | تأكد من وجود بطاقة واحدة بالضبط في مقال الوصفة، ووجود 0 بطاقة بالضبط في المقالات غير المخصصة للوصفات. |
| فك تشفير data-recipe | قم بفك تشفير بيانات JSON للوصفة المشفرة والمدمجة في علامة HTML وتحقق مما إذا كانت تتوافق مع المخطط. |
| قائمة المسموحات (allowlist) للسمات | افحص بدقة سمات HTML غير المعروفة. هذا يزيل الثغرات الأمنية حيث يقوم المستخدمون الخبيثون بحقن نصوص XSS مثل "onclick" عبر نص HTML. |
| فحص الإصدار | تحقق من توافق إصدار مخطط الوصفة لمنع حفظ إصدارات البطاقات القديمة أو التنسيقات التالفة. |
مخرجات JSON-LD: التوليد التلقائي لبنية Recipe للـ SEO
هذه هي القيمة الأساسية لإضافة بطاقة الوصفة. عادةً، يولد KuroCMS بيانات "Article" كبيانات منظمة للصفحة، ولكن عندما يحتوي المستند على بطاقة وصفة، فإنه يستبدلها تلقائيًا ويولد "Recipe" كبيانات منظمة رئيسية.
يقرأ سمة "data-recipe" من HTML المحفوظ ويمرر البيانات التي تم تحليلها كـ "article.recipe" و"page.isRecipe" إلى قالب HTML. لتجنب "التحقق من النوع عن طريق مقارنة السلاسل" في القالب، فإنه يستخدم فرعًا منطقيًا بسيطًا (#if page.isRecipe) لتبديل القوالب. يتم تحويل بيانات الوقت تلقائيًا داخليًا إلى تنسيق المدة القياسي الدولي ISO-8601 duration (على سبيل المثال، "PT25M" لمدة 25 دقيقة). نظرًا لأن عرض HTML والبيانات المنظمة لـ JSON-LD يتم إنتاجهما من نفس مصدر البيانات الوحيد، فلا يوجد خطر من عدم تطابق المعلومات لمحركات البحث.
تكامل الإدارة: منطق إعادة إنشاء المحرر الديناميكي
تم أيضًا دمج منطق التكامل في منطقة المحرر بلوحة الإدارة. في KuroEditor، يتم التحكم في تمكين أو تعطيل "زر القدر" لإنشاء الوصفات بواسطة خيار "recipeUi" الذي يتم تمريره عند التهيئة. نظرًا لأن السلوك الافتراضي لمحرر KuroEditor هو إظهار الزر (true)، فإن KuroCMS لا يحتاج إلى تحديده عادةً، ولكن إذا تم تعيينه على false، فإنه يظهر دون تغيير للمستخدمين الذين لا يستخدمون محرر KuroEditor لتحرير الوصفات، مما يقلل من تأثير التغيير.
علاوة على ذلك، على مستوى KuroEditor، تم قفل بطاقات الوصفات الآن بوصفة واحدة لكل مقال (الزر الثاني غير نشط ولا يمكن النقر عليه). هذا يحافظ على القاعدة الأساسية لمقالات الوصفات. يقوم KuroCMS أيضًا بإجراء فحص مزدوج عند الحفظ لضمان تشغيل الفحوصات الخاصة بالوصفات بشكل صحيح لمقالات الوصفات.
بناءً على ذلك، تم إضافة مجموعة اختبار خاصة بالوصفات "npm run test:recipe" (src/recipe-guard.test.ts، 12 حالة اختبار إجمالاً)، للتحقق من كل شيء من عدد البطاقات إلى ترميز الأحرف في السمات.
المهام المتبقية وخارطة الطريق المستقبلية
مع هذا التحديث، أصبح "النظام الأساسي" لمقال الوصفة و"التحقق من الحفظ" قيد التشغيل بالكامل. ومع ذلك، لا يقدم KuroCMS حتى الآن تخطيط صفحة وصفات كامل مثل البوابات الكبيرة. كان هدفنا هو السماح بنشر الوصفات بسهولة على المواقع الشخصية، وتوليد بيانات SEO تلقائيًا دون الحاجة إلى قيام المستخدم بكتابتها. الآن يمكن لأي شخص إطلاق موقع طهي بسهولة.
أيضًا، نظرًا لأن KuroCMS يتميز بنظام قوالب، يمكن للمستخدمين الاستمرار في تحسين التصميم بأنفسهم (انظر المصدر 3 للحصول على التفاصيل). لجعل KuroCMS أسهل في الاستخدام، سيستمر فريق التطوير في تنفيذ التحديثات بناءً على ملاحظاتكم، شكرًا لكم على دعمكم!