
عن المشروع
منظومة نقاط بيع للمطاعم والتجزئة والبقالة، مبنية حول مركز محلي يبقي الصندوق يبيع حتى عند انقطاع الإنترنت. وأي قطاع جديد ملف إعدادات لا نسخة كود منفصلة.
دوري: مهندس ومطوّر full stack للتطبيقات الثلاثة، ولنموذج المزامنة دون اتصال، وللنشر السحابي.
بنيت هذه المنظومة حول قيد تتجاهله بهدوء معظم منتجات نقاط البيع السحابية: لا يمكن لمتجر أن يتوقف عن البيع لأن الاتصال انقطع. في تونس هذه ليست حالة نادرة بل يوم عادي. لذلك تضع البنية مركزًا محليًا بين الصناديق والسحابة، بدل أن تجعل كل عملية بيع رهينة رحلة ذهاب وإياب إلى مركز بيانات.
المنظومة عبارة عن مستودع أحادي بـTurborepo يضم ثلاثة تطبيقات. يعمل الصندوق والمكتب الخلفي كتطبيق ويب تقدّمي بـReact 19، مع Zustand لإدارة الحالة وWorkbox للتخزين المؤقت دون اتصال. أما الواجهة البرمجية فهي Express 5 مع Drizzle فوق PostgreSQL 18 على Cloud SQL، منشورة على Cloud Run. وبينهما يقف مركز مكتبي مبني بـElectron، يضمّ خادم Express خاصًا به وقاعدة better-sqlite3، يخدم كل صناديق الشبكة المحلية ويسوّي بياناته مع السحابة فور عودة الاتصال.
كان على منتج واحد أن يغطي خدمة المطاعم والتجزئة العامة والبقالة، وهي ثلاث طرق مختلفة للبيع. وبدل تشعيب الكود لكل قطاع، صغت الفروق على شكل إعدادات وأبقيت على كتالوج واحد ومحرك تسعير واحد ودفتر مبيعات واحد. وتعتمد المصادقة على Firebase مع بيانات تعريف تحمل المستأجر والدور، فيدير صاحب عدة متاجر كل شيء من حساب واحد دون تسرّب أي بيانات بينها. وتعمل المنظومة اليوم في الإنتاج لدى مشغّل واحد، واستقبال ثانٍ يعني إنشاء مستأجر واختيار ملف قطاع، لا إقامة نظام آخر.
أهم الميزات
- 🔌 بيع يعمل دون اتصال أولًا: مركز Electron محلي بقاعدة SQLite مدمجة يبقي كل الصناديق تعمل عند فقدان الاتصال.
- 🍽️ تعدّد القطاعات بالإعدادات: تعمل خدمة المطاعم والتجزئة العامة والبقالة على قاعدة كود واحدة، وتُعبَّر فروقها كإعدادات.
- 📱 واجهة صندوق قابلة للتثبيت: شاشة الكاشير تطبيق ويب تقدّمي مخزّن عبر Workbox، فيُفتح كتطبيق أصلي.
- 🏪 تعدّد المستأجرين بالتصميم: تحمل بيانات Firebase المستأجر والدور، فيدير المالك عدة متاجر من حساب واحد دون اختلاط البيانات.
- 🔄 تسوية ثنائية الاتجاه: تُعاد المبيعات المحلية إلى السحابة عند عودة الاتصال، وتنزل تغييرات الكتالوج إلى المركز المحلي.
- ⚡ واجهة برمجية بلا خوادم على Cloud Run: يتقلّص Express 5 مع Drizzle فوق PostgreSQL 18 إلى الصفر بين أوقات الذروة ويعود عند الخدمة.
- 🧾 دفتر مبيعات واحد: يغذّي كتالوج واحد ومحرك تسعير واحد كل القطاعات، فلا تحتاج التقارير إلى دمج مصادر متنافرة.
- 🚦 الحالة اليوم: يشغّل مشغّل واحد المنظومة في الإنتاج. والثاني مستأجر يُنشأ وملف قطاع يُختار، لا نظام آخر يُقام.
مشكلات وحلول
المشكلة: تتوقف أنظمة نقاط البيع السحابية عن تحصيل المدفوعات لحظة انقطاع الإنترنت، ما يعني عمليًا توقف المتجر. أما الأنظمة المحلية بالكامل فتتفادى ذلك لكنها تحرم المالك من رؤية موحّدة عبر متاجره.
الحل: وضعت مركزًا محليًا بين الاثنين. تتحدث الصناديق إلى مركز على شبكة المتجر يملك قاعدة SQLite مدمجة، فلا يعتمد البيع على الإنترنت إطلاقًا. ويسوّي المركز بياناته مع PostgreSQL على Cloud SQL فور عودة الاتصال، ما يحفظ الرؤية الموحّدة لعدة متاجر.
المشكلة: تبيع المطاعم والتجزئة العامة والبقالة بطرق مختلفة فعلًا، والجواب المعتاد منتج منفصل أو نسخة كود مستقلة لكل منها. ثم تنحرف كل نسخة، ويجب نقل أي إصلاح كُتب لقطاع إلى البقية يدويًا.
الحل: صغت فروق القطاعات كإعدادات فوق كتالوج ومحرك تسعير ودفتر مبيعات مشتركة. تخدم قاعدة كود واحدة القطاعات الثلاثة، ويصبح أي قطاع جديد ملف إعدادات لا نسخة منفصلة. وهذا أيضًا ما يجعل المنظومة قابلة للبيع لمشغّل ثانٍ دون قاعدة كود ثانية تُصان.

