دراسة حالة · البحرية والترفيه

رحلة صيد تُدار من أولها إلى آخرها — لصالح World Marine Center

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

نظرة سريعة.

العميل
World Marine Center، قطر
القطاع
البحرية والترفيه — رحلات صيد بالقوارب
الأسطول
٦ قوارب · رحلات مدتها ٣ ساعات · حتى ٦ ضيوف
ما بنيناه
تطبيق للعملاء، لوحة إدارة للفريق، وموقع حجز عام
التقنيات
Next.js وPostgres على Cloud Run · Flutter لنظامي iOS وAndroid
الاستضافة
Google Cloud منطقة me-central2 (الدوحة)
التحقّق
٩٨ اختباراً خلفياً · ٧٢ اختباراً للتطبيق · ٣٥ فحصاً يدوياً
الحالة
مبني ومختبَر وجاهز للنشر

ما الذي يوازنه مشغّل الرحلات فعلياً؟

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

القارب نفسه، محجوز مرّتين

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

كل ضيف يحتاج إلى أوراق

يجب تحديد هوية كل راكب يغادر مرسى قطرياً. ليس من قام بالحجز فحسب — بل كل ضيف على متن القارب. والحجز الذي يُؤخذ هاتفياً بعبارة «خمسة أشخاص، والأسماء لاحقاً» ليس حجزاً، بل مشكلة في صباح الرحلة.

مستندات لا تحتمل سوء التعامل

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

لا صورة واحدة شاملة

الحجوزات في واتساب، والتوافر في ذاكرة أحدهم، والصيانة على الورق، وشهادات الطاقم في ملف. وكل سؤال — هل يمكننا استقبال ستة أشخاص يوم الجمعة؟ — يحتاج إلى شخص للإجابة عنه.

نظام واحد، وثلاثة مداخل إليه.

بنينا منصّة واحدة بثلاثة واجهات، ليكون للأسطول مصدر حقيقة واحد أياً كان السائل.

تطبيق للعملاء

لنظامي iOS وAndroid، مبني بـFlutter. تصفّح الأسطول، واطّلع على التوافر الفعلي والأسعار الحقيقية، وارفع مستندات كل ضيف، وتابع حجزك برقمه المرجعي. والروابط العميقة تفتح قارباً أو باقة أو رحلة بعينها مباشرةً من رسالة.

لوحة إدارة للفريق

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

موقع حجز عام

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

واجهة برمجية موثّقة

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

القاعدة التي وُجد النظام كله لحمايتها.

لا شيء يفعله العميل يُنتج حجزاً مؤكّداً.

يصل الطلب برقم مرجعي وبحالة requested، ودون تخصيص أي قارب. ثم يؤكّده شخص من World Marine ويختار القارب. وحتى ذلك الحين لا يكون المقعد مُباعاً ولا القارب ملتزماً.

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

والرفض مقصود بالقدر نفسه. احجز دون بيانات الضيوف يُرفض الطلب. واحجز لخمسة ضيوف مع تقديم مستندات واحد فقط، فيُرفض مع بيان السبب صراحةً — “Identity details are required for all 5 guests — 1 supplied.” والحجز المرفوض لا يترك أثراً: لا رحلة نصف مكتوبة، ولا حجز وهمي على قارب.

لا يُوعَد بقارب مرّتين أبداً.

يُحسب التوافر من الساعات الثلاث التي تشغلها الرحلة فعلياً، لا من وقت انطلاقها.

  • الرحلة المتداخلة على القارب نفسه تُرفض“Fishing Boat 01 is already booked for part of that time.”
  • الرحلات المتتالية مسموحة. فرحلة التاسعة تُخلي القارب عند الثانية عشرة، ومن ثمّ فانطلاق الثانية عشرة سليم.
  • الإلغاء يحرّر الحجز فوراً، ويمكن إعادة حجز الموعد نفسه.
  • حجز القوارب الستة جميعاً في التاسعة يزيل الثامنة أيضاً من اليوم — فرحلة الثامنة ستظل بحاجة إلى قارب في التاسعة. والحالة الدقيقة هي الحالة المهمة.

مستندات الهوية، تُعامَل كما ينبغي.

جمع جواز السفر سهل. أما أن تكون أهلاً للثقة به فهو العمل الهندسي الحقيقي.

ليس للجميع أن يطّلع

يستطيع الموظفون إدارة الرحلات طوال اليوم دون رؤية رقم هوية واحد — فالقائمة تعرضه مُقنّعاً، ورابط التنزيل لا يظهر لهم أصلاً. والوصول إلى مستند بكتابة عنوانه مباشرةً يعيد 403، لا صفحة تسجيل دخول.

كل اطّلاع مسجَّل

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

الملفات تُفحص فحصاً حقيقياً

تُفحص الملفات بمحتواها لا باسمها. فملف نصي أُعيدت تسميته إلى .jpg يُرفض. وأي ملف يتجاوز ٨ ميغابايت يُرفض برسالة واضحة.

العملاء معزولون عن بعضهم

رحلات أي عميل غير مرئية لعميل آخر. وإلغاء حجز شخص آخر برقمه المرجعي يعيد 404 لا 403 — رفضٌ دون تأكيد وجود ذلك الرقم أصلاً.

البيانات تبقى في قطر — عن قصد.

تعمل المنصّة في منطقة me-central2 من Google Cloud، في الدوحة. وهذا قرار لا إعداد افتراضي.

المستندات التي يحفظها هذا النظام هي بطاقات هوية قطرية وتأشيرات وجوازات سفر. واستضافتها خارج البلاد كانت ستجعل كل حجز نقلاً عابراً للحدود لبيانات شخصية بموجب القانون رقم (١٣) لسنة ٢٠١٦. أما إبقاء قاعدة البيانات والحاوية وتخزين الملفات داخل الدولة فيُسقط هذا السؤال تماماً.

والمنطق نفسه حكم سياسة النسخ الاحتياطي. فـWorld Marine تحتفظ بمستندات الهوية إلى أجل غير مسمّى، ما يجعل قاعدة البيانات فهرساً لملفات لا يمكن إعادة إنتاجها — ولهذا فُعّلت الاستعادة إلى نقطة زمنية بدل الاكتفاء بنسخ ليلية.

اختُبر على النظام وهو يعمل، لا على الشيفرة.

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

٩٨

اختباراً خلفياً ناجحاً، مع خلوّ TypeScript وESLint من الملاحظات

٧٢

اختباراً ناجحاً لتطبيق Flutter

٣٥

فحصاً يدوياً على نسخة تعمل فعلياً — دون أي إخفاق حقيقي

٠

حجز مزدوج ممكن، وأُثبت ذلك بإنشاء تعارض متعمّد لا بانتظار العثور على واحد

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

أين يقف المشروع الآن.

المنصّة مبنية ومختبَرة وموثّقة إلى مستوى تسليم جاهز للنشر. وهي ليست منشورة بعد، وهذه هي العناصر التي تحتاج إلى بيئة إنتاج لا إلى مزيد من العمل الهندسي:

  • إرسال الرسائل النصية يحتاج إلى ربط مزوّد خدمة. أما مسار رمز التحقق ومسار رفضه فكلاهما مُتحقَّق منه على مسار التطوير.
  • الإشعارات الفورية تحتاج إلى مشروع Firebase في جانب التطبيق. وجانب الخادم مغطّى باختبارات آلية.
  • روابط Universal Links تحتاج إلى نطاق فعلي ونسخة إصدار موقّعة. ومسار الربط يعيد 503 صراحةً إلى أن يُضبط — فهو لا يتظاهر بالعمل.

أما الروابط العميقة بالمخطّط المخصّص فتعمل بالفعل: worldmarine:///fleet وworldmarine:///package وworldmarine:///trips/WM-2418 يفتح كلٌّ منها الشاشة الصحيحة على تثبيت جديد.

تدير أسطولاً عبر محادثة؟

إذا كان عملك يُحجز بالرسائل ويُتابَع على الورق، فنمط الإخفاق واحد دائماً — عميلان، وأصل واحد، ويُكتشف الأمر بعد فوات الأوان. نحن نبني النظام الذي يجعل ذلك مستحيلاً.