Case study: full stack build, booking and CRM
Savant, Dubai: a booking platform with a CRM for instructors
Savant is a multipurpose event space in Al Quoz, Dubai. It runs its own classes and events, and it rents the space to instructors who run theirs. I built the platform that handles all of it, alone, from the front end to the back end.

- Client
- Savant, Al Quoz, Dubai
- Built
- Booking, online payments, instructor CRM
- My role
- Everything, front end to back end
- Stack
- React, TypeScript, Laravel, MySQL, Stripe
Two kinds of customer, one system
A space that hosts other people's classes serves two groups at once: the guests who book, and the instructors who rent the room. Both work from the same schedule. Savant needed one platform for both, instead of bookings in one place and instructors' guest lists somewhere else.
For guests: find a class, book it, pay online
Guests browse the schedule of classes and events, filter it by class type and by instructor, and pick a day. Every class shows its time, its instructor and its price, with a button to book it. Payment happens online, as part of the booking.
For instructors: a CRM of their own
Instructors who rent the space run their classes from a dashboard built for them. It shows their bookings and the details of their guests, so each instructor has their schedule, their bookings and their people in one place.
Built end to end, by one person
I built all of it: the public site, the schedule, booking and online payment, the back end that ties it together, and the instructor dashboard. Because one person owns every layer, a change never has to be handed between a designer, a front end team and a back end team.
What it is built with
One repository holds two applications: the public website, and the Laravel application behind it that serves the API and the staff dashboard.
| Part | Built with |
|---|---|
| Public website | React 19 and TypeScript, built with Vite. Routing is hand written rather than a router library, and the styling is one plain CSS file, no framework. |
| API and dashboard | Laravel 13 on PHP 8.3, with Blade templates and Tailwind for the staff dashboard. |
| Accounts | Sanctum for customer logins, Breeze for staff logins. |
| Payments | Stripe hosted checkout through Laravel Cashier, and N-Genius (Network International) as a second option per product. |
| Data | MySQL with Eloquent and migrations. Money is stored in fils, as whole numbers. |
| Background work | A queue and scheduler for emails, reminders and expiring seat holds, driven by a single cron job. |
| Tests | 961 PHPUnit tests, all passing. |
| Deployment | Hosted in the UAE, deployed by pulling the repository over SSH. The built site is committed, so the server needs no build step. |
| Security | Payment keys encrypted in the database, HTTPS, caching and a Content Security Policy set at the server. |
Four decisions worth explaining
- Money is stored in fils, as whole numbers. Prices held as decimals drift by a fraction with every calculation, and on a platform that splits payments between a venue and its instructors, those fractions become an argument. Whole numbers cannot drift.
- Two payment providers, chosen per product. Stripe's hosted checkout and N-Genius from Network International, which some Gulf cards and banks prefer. Their keys are encrypted in the database rather than sitting in a configuration file.
- Seats are held, then released automatically. A queue and scheduler run the background work: confirmation emails, reminders, and seat holds that expire if a booking is never completed, so a class does not look full when it is not.
- 961 tests, all passing. A system that takes money and holds a schedule cannot be checked by clicking around. The tests are what make it safe to change a booking rule on a Tuesday afternoon.