مقال
مشاريع

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

5 أغسطس 2026Majed Alandajani

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

ما لا تصلح له

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

الخلاصة

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

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

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

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

الجداول الثلاثة والثلاثون: كيف تُقسَّم فعلاً

ليست 33 جدولاً عشوائياً، بل خمس مجموعات:

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

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

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

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

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

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

متى لا يصلح هذا الاختيار

كتابات متزامنة كثيفة جداً على نفس الصف. ومعالجة ثقيلة طويلة. وبيانات بمقياس لا يناسب SQLite.

وإن كان أحد هذه وصفك، فالاختيار خاطئ وليس التنفيذ.

اقرأ أيضاً

  • سجل تدقيق لا يستطيع التطبيق إعادة كتابته
  • العقد الموقّع يُقفل، وتعديله يعيده مسودة
  • استحالة الحجز المزدوج: قيد في القاعدة لا فحص في الكود
عندك مشروع في بالك؟
قل لي ما الذي تريد بناءه. أول 15 دقيقة استشارة مجانية.
احجز استشارة