← All projects
02 / 03

Nuzul Umrah

Multi-tenant SaaS · Web + Mobile · Solo-built · Arabic-first

Nuzul Umrah — Operations Platform for Umrah Companies

Try the live demo ↗

A subscription platform that runs an Umrah company end to end. Staff manage packages, departures and seats, bookings and payments, leads, trips, room assignments, tasks and documents from one Arabic-first dashboard. Pilgrims get a single companion app that follows them through the whole journey — a day-by-day programme, their miqat, their room and group, announcements and support. Nuzul is a technology provider only: pilgrims pay the company's own merchant account, and Nuzul never holds customer funds.

Architecture sketch

Company dashboardReact · InertiaPilgrim appFlutterStaff appFlutterLaravel 13tenant-isolated coreDatabaseMySQLLive updatesReverbSanctum
nuzul-umrah.app
Nuzul Umrah landing page — the Grand Mosque in Makkah and the Prophet's Mosque in Madinah behind the arch
nuzul-umrah.app/os/today
Nuzul Umrah Today board — departures, returns, overdue tasks and payments for the day, Arabic RTL
nuzul-umrah.app/os/trips
Trip page — pilgrim roster, rooms, itinerary and tasks for one departure
nuzul-umrah.app/os/leads
Leads board — five-stage pipeline with assignment and conversion to customers
Pilgrim app — home screen with the trip countdown and companion cards

Pilgrim — home

Pilgrim app — my trip with booking, room and miqat

Pilgrim — my trip

Pilgrim app — day-by-day programme with collapsible days

Pilgrim — day by day

Staff app — the company's trips in the field

Staff — trips in the field

Company dashboardLaravel 13, Inertia.js, React 19 + TS, Tailwind v4
Mobile appsFlutter / Dart — pilgrim + staff on a shared core package
Multi-tenancyFail-closed row-level isolation, tenant-isolation test gate
BookingsRace-proof seat locking, price snapshot, idempotent actions
MoneyInteger halalas; pilgrims pay the company directly
Real time & APIReverb live notifications, Sanctum mobile API
865Pest tests
58Flutter tests
3apps, one backend
Two staff booking the last seats at the same moment can never oversell: the departure row is locked and re-read before counting. · app/Services/Bookings/BookSeats.php
// Serialize concurrent bookings of the SAME departure and re-read
// the row so seatsRemaining can't act on a stale instance.
$fresh = PackageDeparture::allCompanies()->lockForUpdate()->findOrFail($departure->id);

// Computed on the LOCKED row — the whole point of the lock.
if ($fresh->seatsRemaining() < $seats) {
    throw new RuntimeException('Not enough seats remaining on this departure.');
}

// Halalas snapshot: later price changes never touch old bookings.
$booking->unit_price = $unitPrice;
$booking->total_price = $seats * $unitPrice;
→ كل المشاريع
٠٢ / ٠٣

نُزُل عمرة

SaaS متعدد الشركات · ويب + جوال · بناء فردي كامل · عربي أولًا

نُزُل عمرة — منصة تشغيل شركات العمرة

جرّب النموذج التفاعلي ↖

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

مخطط البنية

لوحة الشركةReact · Inertiaتطبيق المعتمرFlutterتطبيق الموظفFlutterLaravel 13عزل تام لكل شركةقاعدة البياناتMySQLالتحديث اللحظيReverbSanctum
nuzul-umrah.app
الصفحة الرئيسية لنُزُل عمرة — الحرم المكي والمسجد النبوي خلف القوس
nuzul-umrah.app/os/today
لوحة «اليوم» في نُزُل عمرة — المغادرون والعائدون والمهام المتأخرة والمدفوعات، عربي RTL
nuzul-umrah.app/os/trips
صفحة الرحلة — قائمة المعتمرين والغرف والبرنامج والمهام لموعد واحد
nuzul-umrah.app/os/leads
لوحة العملاء المحتملين — خمس مراحل مع الإسناد والتحويل إلى عملاء
تطبيق المعتمر — الرئيسية مع العدّ التنازلي وبطاقات «معك طوال الرحلة»

المعتمر — الرئيسية

تطبيق المعتمر — رحلتي مع الحجز والغرفة والميقات

المعتمر — رحلتي

تطبيق المعتمر — البرنامج يومًا بيوم بأيام قابلة للطي

المعتمر — يومًا بيوم

تطبيق الموظف — رحلات الشركة في الميدان

الموظف — الرحلات في الميدان

لوحة الشركاتLaravel 13 وInertia.js وReact 19 مع TypeScript وTailwind v4
تطبيقات الجوالFlutter وDart — المعتمر والموظف على حزمة مشتركة
تعدد الشركاتعزل تام على مستوى الصف، واختبار عزل شرط لأي دمج
الحجوزاتقفل المقاعد ضد التزامن، لقطة للسعر، عمليات بلا تكرار
المالبالهللات فقط، والدفع مباشرة لحساب الشركة
الوقت الحي والـ APIإشعارات لحظية عبر Reverb، وواجهة جوال عبر Sanctum
٨٦٥اختبار Pest
٥٨اختبار Flutter
٣تطبيقات بخادم واحد
موظفان يحجزان آخر المقاعد في اللحظة نفسها لا يمكن أن يتجاوزا العدد: صف الموعد يُقفل ويُعاد قراءته قبل العدّ. · app/Services/Bookings/BookSeats.php
// Serialize concurrent bookings of the SAME departure and re-read
// the row so seatsRemaining can't act on a stale instance.
$fresh = PackageDeparture::allCompanies()->lockForUpdate()->findOrFail($departure->id);

// Computed on the LOCKED row — the whole point of the lock.
if ($fresh->seatsRemaining() < $seats) {
    throw new RuntimeException('Not enough seats remaining on this departure.');
}

// Halalas snapshot: later price changes never touch old bookings.
$booking->unit_price = $unitPrice;
$booking->total_price = $seats * $unitPrice;