كل المشاريع/HAKEEM JAN TRAVELS

نظرة عامة

Hakeem Jan Travels منتج لحجز رحلات السفر والحج لصالح وكالة سفر عاملة. يعرض الموقع العام الوجهات وباقات الجولات والعمرة ومدوّنة سفر؛ ومن خلفه، تسجّل خدمة Django الحجوزات والاستفسارات وتدفعها إلى Google Calendar وGoogle Sheets. وهو يخدم جمهورين في آنٍ واحد — المسافرين المحتملين الذين يتصفّحون الباقات، وموظّفي الوكالة الذين يحتاجون أن يصل كل استفسار إلى مكان يطالعونه أصلًا.

التحدي

معظم أنظمة الحجز تطالب الوكالة بالتخلّي عن سير عملها القائم. كانت Hakeem Jan Travels تدير جدولتها عبر Google Calendar وتحتفظ بسجلات الحجوزات في Google Sheets، ولم تكن لديها رغبة في مصدر حقيقة ثانٍ يضطر أحدهم إلى مطابقته يدويًا. لذلك كان التكليف أضيق وأصعب من «بناء موقع حجز»: كان على مسار الحجز الإلكتروني أن ينتهي داخل أدوات الوكالة القائمة، لا بجوارها. فالحجز المُرسَل يجب أن يصبح موعدًا في التقويم وصفًّا في الجدول دون أن يعيد أحد الموظّفين كتابته، وكان على الواجهة التسويقية — الوجهات والباقات والمدوّنة — أن تكون قابلة للتحرير من غير المهندسين عبر واجهة يتعلّمونها في بعد ظهر واحد.

تصميم النظام

يتوزّع النظام على مستودعين. الواجهة الأمامية تطبيق صفحة واحدة بـ React 18 مبني بـ Vite 4 وTypeScript 5، ومنسّق بـ Tailwind CSS وPostCSS/Autoprefixer. يتولّى react-router-dom v6 التوجيه، وlucide-react الأيقونات، وSwiper شرائح الوجهات والباقات. وهي بناء ثابت (tsc && vite build) منشور على Vercel — يتكفّل vercel.json بإعادة كتابة مسارات تطبيق الصفحة الواحدة، ويحمل .env.production العنوان الأساسي لواجهة البرمجة حتى تتمكّن الحزمة نفسها من الإشارة إلى نظام خلفي محلي أو منشور. وإبقاء الواجهة الأمامية ثابتة بالكامل يعني أن تبقى الواجهة التسويقية سريعة وزهيدة التقديم، مع وصول كل المحتوى الديناميكي عبر HTTP من واجهة Django البرمجية.

النظام الخلفي مشروع Django 5.2 منظَّم في تطبيقات مركّزة تنعكس بوضوح على المجال: destinations للكتالوج، وblogs للمحتوى التحريري، وbook_services لنماذج الحجز والاستفسار، وapis كواجهة HTTP التي يستهلكها تطبيق الصفحة الواحدة، وتطبيقان مخصّصان للتكامل — google_calender وgoogle_sheet — يملكان كل حركة الخروج إلى Google. وعزل التكاملات في تطبيقات خاصة بها بدلًا من تناثر استدعاءات الواجهة البرمجية داخل كود العروض يعني أن معالجة بيانات اعتماد Google وبناء العملاء ومسارات الأخطاء تعيش في مكان واحد، وأن نماذج الحجز تبقى غير معنيّة بكيفية حفظها لاحقًا في الوجهات النهائية. يسمح django-cors-headers للمصدر المستضاف على Vercel باستدعاء واجهة البرمجة؛ ويقدّم whitenoise الملفات الثابتة للوحة الإدارة والقوالب؛ ويدعم Pillow حقول الصور في الوجهات ومقالات المدوّنة.

الوصول إلى Google من خادم إلى خادم عبر حساب خدمة بدلًا من OAuth لكل مستخدم، فلا يحتاج أي موظّف إلى الاحتفاظ بجلسة كي تُزامَن الحجوزات. تستخدم المنظومة google-api-python-client مع google-auth وgoogle-auth-oauthlib لواجهة Calendar، وgspread كعميل أعلى مستوى لـ Sheets — وهو تقسيم منطقي، فالعمل في Sheets إضافة صفوف وقراءتها، بينما تحتاج Calendar إلى نموذج الموارد الكامل. تعيش بيانات الاعتماد في مجلّد credentials/، وتُحمَّل الإعدادات من البيئة عبر python-dotenv. والنشر يجري بالحاويات: يُشغّل Dockerfile وdocker-compose.yml التطبيق خلف وكيل عكسي nginx، ويُنفّذ entrypoint.sh الترحيلات ويجمع الملفات الثابتة عند الإقلاع، ويقدّم gunicorn خدمة WSGI، ويقود .gitlab-ci.yml خط الإنتاج. أما التفاصيل التشغيلية فموثّقة داخل المستودع (RUN_MIGRATIONS.md وHERO_SECTION_API.md)، وتقوم سكربتات إدارية لمرة واحدة — seed_enquiry.py وupdate_enquiry_colors.py — بتهيئة بيانات الاستفسارات المستخدَمة في لوحة الإدارة وتعبئتها بأثر رجعي.

كيف يعمل

01/03
01

تسليم المحتوى

يتصفّح الزائر الوجهات والباقات ومقالات المدوّنة المقدَّمة من واجهة Django البرمجية إلى تطبيق React الثابت أحادي الصفحة.

  1. 1يفتح الزائر تطبيق الصفحة الواحدة المستضاف على Vercel؛ تُقدَّم حزمة Vite الثابتة ويحسم React Router المسار داخل المتصفّح.
  2. 2يستدعي مكوّن الصفحة تطبيق `apis` في Django عبر HTTPS باستخدام العنوان الأساسي المضمَّن وقت البناء من `.env.production`.
  3. 3يوجّه Django الطلب إلى تطبيق `destinations` أو `blogs`، فيُسلسِل مدخلات الكتالوج أو تفاصيل الباقة أو مقالات المدوّنة.
  4. 4يتحقّق `django-cors-headers` من مصدر الطلب قبل إعادة الاستجابة.
  5. 5يعرض React المحتوى؛ ويشغّل Swiper شرائح الوجهات والباقات، وتُقدَّم الصور من حقول الوسائط في Django المدعومة بـ Pillow.
02

التقاط الحجوزات والاستفسارات

يُتحقَّق من طلب الحجز الذي يرسله المسافر، ويُحفَظ في نماذج book_services، ويظهر لموظّفي الوكالة في لوحة إدارة Django.

  1. 1يختار الزائر باقة عمرة أو جولة سياحية ويُكمل نموذج الحجز في واجهة React الأمامية.
  2. 2يرسل تطبيق الصفحة الواحدة حمولة الحجز عبر POST إلى نقطة `apis` التي يوفّرها نظام Django الخلفي.
  3. 3يتحقّق Django من الحمولة ويحفظها في نماذج `book_services`، منشئًا سجلّ الحجز أو الاستفسار.
  4. 4تُسلّم طبقة `book_services` السجلّ المحفوظ إلى تطبيقات التكامل لمزامنته لاحقًا.
  5. 5يصبح السجلّ ظاهرًا فورًا في لوحة إدارة Django، حيث يديره موظّفو الوكالة — وتحمل حالات الاستفسار الترميز اللوني الذي أضافه `update_enquiry_colors.py`.
03

المزامنة مع Google Calendar وSheets

ينتقل كل حجز محفوظ إلى Google Calendar وGoogle Sheets القائمَين لدى الوكالة عبر مصادقة حساب خدمة من خادم إلى خادم.

  1. 1يحمّل تطبيقا `google_calender` و`google_sheet` بيانات اعتماد حساب الخدمة من مجلّد `credentials/`، مع تحديد المسارات والمعرّفات من متغيّرات البيئة عبر python-dotenv.
  2. 2يُنشئ `google-auth` طبقة نقل مُصرّحًا بها، تُستخدم لبناء عميل Calendar عبر `google-api-python-client` وعميل Sheets عبر `gspread`.
  3. 3يُترجَم الحجز إلى حدث في Calendar — التواريخ والباقة وبيانات المسافر — ويُدرَج في تقويم الوكالة.
  4. 4ويُضاف الحجز نفسه صفًّا في Google Sheet الخاص بالوكالة، فيحصل الموظّفون على سجلّهم الجدولي المعتاد دون إدخال يدوي.
  5. 5ولأن المزامنة تجري بعد الكتابة في قاعدة البيانات، يبقى سجلّ Django مصدر الحقيقة الخاص بالنظام مستقلًّا عن استدعاء Google.

أبرز الميزات

  • تصفّح الوجهات والباقات
  • مسار حجز العمرة والجولات
  • الجدولة عبر Google Calendar
  • حفظ السجلات في Google Sheets
  • مدوّنة سفر
  • لوحة إدارة Django الخلفية

Outcomes

  • الحجوزات تتدفّق إلى أدوات Google القائمة
  • حفظ يدوي أقل للسجلات
  • موقع تسويقي غني بالمحتوى

أعمال أخرى