المشكلة
التنقل في جورجيا كعائلة زائرة أصعب مما ينبغي. المواصلات العامة لا تصل حيث يريد السياح، وتطبيقات النقل تتلاشى سريعًا خارج تبليسي، والسوق غير الرسمي — سائق يرشّحه ابن عم أحدهم عبر واتساب — بلا أسعار قابلة للمقارنة ولا مساءلة ولا لغة مشتركة. وفي المقابل هناك عرض حقيقي من سائقين محليين محترفين بلا وسيلة للوصول إلى المسافرين الباحثين عنهم تحديدًا.
وُجدت سفرة لتجعل هذا السوق مقروءًا: سائقون موثّقون، وأسعار يومية شفافة، وتقييمات يمكن قراءتها، وحجز يمكن محاسبة أحد عليه.
البنية
تطبيق الويب مبني بـ Next.js 16 على App Router مع React 19. ويوفر Supabase أربعة أشياء من مزوّد واحد — Postgres والمصادقة واللحظية والتخزين — والقرار الذي يشكّل كل ما عداه هو أن الأمان على مستوى الصف داخل Postgres هو الحد الأمني، لا شيفرة التطبيق. تعمل استعلامات الميزات عبر Drizzle داخل غلاف يبدّل الاتصال إلى دور `authenticated` أو `anon` ويحقن مطالبات JWT لكل معاملة، فيصبح التحقق من الملكية خاصية في قاعدة البيانات لا أمرًا على المطور تذكّره.
الشيفرة مقسّمة إلى شرائح رأسية. التوجيه في `app/`، ومنطق الأعمال في شرائح تحت `features/`، وواجهات المستخدم العامة في `components/`، والبنية التقنية في `lib/`. ويُمنع استيراد الشرائح من بعضها؛ وحين تحتاج شريحتان الشيء نفسه يُرفع إلى طبقة أعلى بدل مشاركته جانبيًا. وهناك قائمة قصيرة من الشرائح العابرة المعتمدة صراحةً — يسجّل كل مدخل فيها تاريخ إضافته وسببها، لأن قاعدة معمارية تتآكل بصمت أسوأ من قاعدة لم تُكتب أصلًا.
- ٢١ شريحة ميزات رئيسية، و٩٧ مجلدًا عند احتساب الشرائح الفرعية
- ١١٥ مسار صفحة عبر خمس بوابات حسب الدور: العام والمصادقة والعميل والسائق والإدارة
- ٣٤٩ معالج مسار REST — الواجهة الرسمية للويب والموبايل معًا
- ٦٦ جدولًا في Postgres و٥٢ نوعًا معدودًا، تحكمها نحو ٢٣٢ سياسة أمان على مستوى الصف
- ٢٢١ ترحيل SQL، وهي المصدر الوحيد للحقيقة في المخطط والسياسات والمشغّلات
واجهة واحدة، عميلان
تطبيق Flutter ليس غلافًا حول الموقع — بل عميل أصلي يخاطب واجهة REST نفسها. وهذا مفروض بقاعدة لا بحسن النية: كل دالة خادم يجب أن تكون قابلة للوصول عبر معالج مسار HTTP، والميزة لا تكتمل قبل وجود تلك النقطة. تبقى Server Actions لسهولة الويب، لكن المنطق المشترك يعيش في وحدات خدمة تستقبل مقبض قاعدة البيانات كوسيط، فيستدعي كلٌّ من الإجراء والمعالج الدالة ذاتها بمقبض مبني من كوكي أو من رمز Bearer على التوالي.
والنتيجة أن الويب والموبايل لا يمكن أن يتباعدا. يحمل عميل الموبايل نحو ١٠٠ ألف سطر Dart مكتوبة يدويًا عبر ٢٢ شريحة، وفيه تعيش مجموعة الاختبارات الآلية للمشروع كاملة — ٨٨ ملف اختبار بـ ٧٦٣ حالة و١٥٢٥ تأكيدًا، يشغّلها التكامل المستمر مع كل دفعة. أما في الويب فيقوم بهذا الدور ٢٤ سكربت حراسة مخصصًا، يعمل ٢٢ منها في التكامل المستمر إلى جانب الفحص والأنواع والبناء، مؤكدةً ما لا يستطيع نظام الأنواع تأكيده: أن صلاحيات قاعدة البيانات مطابقة للمتوقع، وأن لا جدول شُحن بلا أمان على مستوى الصف، وأن مجمّع الاتصالات مضبوط بشكل صحيح.
ثلاث لغات بلا ثغرات
العربية والإنجليزية والجورجية كلها من الدرجة الأولى. تحمل كل حزمة لغة ٦٧١٩ مفتاحًا بالضبط، وفرق مسارات المفاتيح بين الإنجليزية وأي لغة أخرى يساوي صفرًا — فلا مسار احتياطي يرى فيه المستخدم مفتاحًا خامًا. وتقود العربية اتجاهًا كاملًا من اليمين إلى اليسار، منفّذًا بخصائص منطقية بدل نسخة أنماط معكوسة، فيصير الاتجاه خاصية تخطيط لا تصميمًا ثانيًا يجب صيانته. وتغلق المحادثة الفجوة المتبقية وقت التشغيل: تُترجم الرسائل بين مسافر عربي وسائق جورجي تلقائيًا فور وصولها.
الكلفة بوصفها مسألة هندسية
بعد شهرين تحولت فاتورة البنية التحتية إلى تمرين في التشخيص، وتبيّن أن نصفيها معماريان لا مسألة ضبط إعدادات.
كانت قاعدة البيانات ترسل ٣٥٤٫٩٤ جيجابايت شهريًا لـ ٧٦٣ مستخدمًا نشطًا — نحو ٤٦٥ ميجابايت لكل مستخدم مقابل قاعدة حجمها ١٥٤ ميجابايت، أي أن البيانات كلها تغادر المنصة ٦٧ مرة تقريبًا. والسبب أن الصور كانت في مخزن خاص خلف روابط يعاد توقيعها كل ساعة، فكان كل طلب إخفاقًا في التخزين المؤقت بحكم التصميم. نقلها إلى مخزن عام وإنشاء نسخ WebP بعرض ٨٠٠ بكسل أصغر بنحو ٩ أضعاف مع تعبئة رجعية للمكتبة عالج معظم المشكلة؛ وأتمّ الباقي تقليصُ حجم الصفوف ودمجُ عمليات الاستطلاع.
وبشكل منفصل، كشف بيان البناء عن ٥ مسارات ثابتة فقط من أصل ١٢٦ — كانت كل صفحة تُعرض في المصدر، فتنفخ أربعة عدّادات فوترة دفعة واحدة. والمسؤول ثلاثة استدعاءات مستقلة لـ `headers()` يتساهل معها البناء بصمت. وأكثرها إفادةً صفحة «غير موجود» الجذرية وهي تقرأ الترويسات لتحديد اللغة: يُدرج Next هذا الحد في شجرة عرض كل مسار، فألغى استدعاءٌ واحد في ملف لا يفكر فيه أحد تحسينَ الموقع بأكمله.
لم تكن أي من المشكلتين ظاهرة من سلوك التطبيق. اكتُشفت كلتاهما بقراءة فاتورة سطرًا سطرًا والسؤال عمّا يجب أن يكون صحيحًا فيزيائيًا كي يظهر ذلك الرقم.