مقال
مشاريع

نظام أعمال كامل على Cloudflare D1: خمس خدمات وقاعدة واحدة

5 أغسطس 2026Majed Alandajani

معظم ما يُكتب عن Cloudflare D1 يقف عند "كيف تبدأ": أنشئ قاعدة واكتب استعلاماً يطبع نتيجة، وانتهى الدرس. لم أجد شيئاً يجيب السؤال الذي واجهني فعلاً: هل تصلح لتشغيل أعمال حقيقية فيها عقود وفواتير وبيانات عملاء؟

هذا ما بنيته، وهذه إجابتي بعد تشغيله.

ما الذي يعمل فعلاً

خمس خدمات مستقلة تتشارك قاعدة بيانات واحدة:

  • موقع ثابت ثنائي اللغة
  • متجر خدمات
  • مدونة تُعرض من قاعدة البيانات
  • واجهة برمجية تستقبل الطلبات والمدفوعات
  • لوحة تشغيل خلف بوابة هوية

القاعدة نفسها: 33 جدولاً بُنيت عبر 18 هجرة مرتبة، وفيها 7 مشغّلات تفرض قيوداً لا يستطيع التطبيق تجاوزها.

خمس مجموعات تحمل 33 جدولاً

الجداول الثلاثة والثلاثون تنتظم في خمس مجموعات. التجارة: الطلبات والعروض والعقود والفواتير والأقساط والمدفوعات. العلاقة: العملاء وسجلاتهم وروابطهم الخاصة. التشغيل: الحجوزات وقواعد التوفر واستثناءاتها. المراسلات: البريد الوارد والصادر وسجل الإشعارات. الحوكمة: سجل التدقيق وسجل الموافقات وإعدادات النظام.

مجموعة الحوكمة تحديداً هي ما يحوّل النظام من تطبيق إلى نظام أعمال، لأنها تجيب سؤال «من فعل ماذا ومتى» بعد شهور.

القرار الأول: قاعدة واحدة للخدمات كلها

البديل المعتاد أن تحمل كل خدمة قاعدتها الخاصة. رفضته لسبب واحد: الحقيقة تتشظّى. يتبعثر الطلب والعميل والعقد على قواعد متفرقة، ثم تحتاج مزامنة بينها، والمزامنة تفشل بصمت.

بقاعدة واحدة تصبح حالة العميل حقيقة واحدة تقرأها كل خدمة. ودفعت الثمن المقابل: كل خدمة تستطيع تقنياً قراءة كل شيء، فصارت بوابة الوصول وحدها مسؤولة عن الحماية بعد غياب عزل القواعد.

القرار الثاني: الضمانات تعيش في القاعدة

سجل التدقيق عندي لا يقبل تعديلاً ولا حذفاً، ليس لأن الكود يمتنع عن ذلك، بل لأن مشغّلاً في قاعدة البيانات يرفض العملية نفسها. شرحت التفاصيل في سجل تدقيق لا يستطيع التطبيق إعادة كتابته، والفكرة أن المشغّل يلغي أي تعديل أو حذف على السجل.

الفرق هنا جوهري. القيد المكتوب في الكود يسقط مع أول خطأ برمجي، والقيد المكتوب في القاعدة يبقى حتى لو أخطأ التطبيق فوقه بالكامل.

القرار الثالث: الفهرس الفريد الجزئي

بعض الصفوف تحمل مفتاحاً خارجياً وبعضها يتركه فارغاً. الفهرس الفريد العادي سيرفض الصف الثاني الذي يحمل NULL في بعض المحركات. الحل:


CREATE UNIQUE INDEX ux_posts_sheet_key ON posts(sheet_key) WHERE sheet_key IS NOT NULL;

فيتعايش عدد غير محدود من NULL، ويبقى المفتاح فريداً حين يوجد.

المصائد التي كلّفتني وقتاً

لا تخلط ? و?1 في جملة واحدة. SQLite يعيد استخدام الفهرس 1 فتحصل على ربط خاطئ بلا أي خطأ يدلك عليه.

صيغتا الوقت مختلفتان بين أوامر الطرفية وجداول الأدلة، والمقارنة بينهما تجري على النص كما هو، فتأكد من تطابق الصيغة قبل أن تقارن.

كيف تُدار 18 هجرة بلا كارثة

كل هجرة ملف مرقّم بأصفار بادئة، فيعطيك الترتيب الأبجدي الترتيب الزمني نفسه.

لا تُعدَّل هجرة طُبّقت. التصحيح يكون بهجرة جديدة، وإلا اختلفت قاعدتك عن قاعدة أي بيئة أخرى.

وكل هجرة تمر أولاً على قاعدة تجريبية بنفس المخطط وبلا بيانات عملاء، ويُفحص المخطط بعد التطبيق قبل أن يُطلب تأكيد الإنتاج، لأن الهجرة قد تنجح وتترك خلفها قاعدة لا تجيب.

اختيار قاعدة على الحافة

في هذا القرار جانب يتجاوز التقنية. قاعدة على الحافة تعني أنك لا تدير خادماً، وهذا يزيل من جدولك الترقيات والتصحيحات الأمنية ومراقبة القرص وحجز السعة، ويزيل معها فاتورة شهرية ثابتة تدفعها سواء استُعملت أو لا.

وللأمر ثمنه: تعمل داخل قيود لا تتحكم فيها. مهلة التنفيذ محددة، ولا نظام ملفات، وبيئة التشغيل ليست كاملة، وبعض المكتبات لن تعمل. تحقق من هذا كله قبل أن تبني.

ما لا تصلح له

D1 في جوهرها قاعدة SQLite. الكتابات المتزامنة الكثيفة جداً على نفس الصف ستؤذيها، والمعالجة الثقيلة الطويلة كذلك، ومثلهما البيانات بمقياس يتجاوز ما يناسب SQLite، والاستعلامات التحليلية الثقيلة. إن كان أحد هذه وصف نظامك فالاختيار هو الخاطئ وليس التنفيذ.

أما ما تصلح له فهو ما تصلح له SQLite نفسها: قراءات كثيرة مع كتابات معقولة على بيانات منظمة، وهذا وصف دقيق لمعظم أنظمة الأعمال.

الخلاصة

نعم، تصلح لتشغيل أعمال حقيقية. بشرط أن تكتب ضماناتك في المخطط نفسه، وأن تجرّب كل هجرة على قاعدة تجريبية قبل الإنتاج.

اقرأ أيضاً

عندك مشروع في بالك؟
قل لي ما الذي تريد بناءه. أول 15 دقيقة استشارة مجانية.
احجز استشارة