This is the booking and dispatch workflow behind Lux4Rides, a licensed Los Angeles black-car operation run by the same person who founded Limoform. It is the system that produced most of what we publish about transportation software. The six decisions that shaped it were: freeze quotes with their inputs, make assignment constraints refusals rather than warnings, treat monitoring as notification rather than display, close trips at the kerb, keep the booking experience on the operation's own domain, and record attribution from the start.
Disclosure, and what this case study does not contain
Limoform and Lux4Rides share a founder, Sam Altabbaa. Lux4Rides operates the vehicles and holds the transportation authority (California TCP #40987); Limoform built and maintains the software. This is a case study of our own work for our own operation, which is the only reason it can be this specific — and a reason to read it with the relationship in mind.
Two things you will not find below. There are no performance metrics: the system was built incrementally while volume, staffing and pricing were all changing, and we have no clean measurement to attribute to the software. And there are no screenshots of live reservations, because they contain passenger data.
What is here is the architecture and the reasoning, including the parts we got wrong first.
What it replaced
The starting arrangement was the one most small operators run: a website enquiry form, a shared inbox, a spreadsheet schedule, rates held in one person's head, and a phone.
It worked, in the sense that trips happened. The failures were the ones that arrangement always produces, and they are worth naming because they are the actual requirements:
- Quotes varied depending on who answered the phone.
- Nothing objected to an impossible schedule. The spreadsheet accepted two trips on one vehicle without comment.
- Flight changes depended on someone remembering to look. At 3am, nobody looks.
- Trip details were reconstructed later, which meant wait time and extras were approximate.
- Revenue was known; its source was not. No way to tell which channels produced work.
Those five map almost exactly onto the seven-stage model in how a chauffeur booking system actually works — which is not a coincidence. The model came out of this build rather than preceding it.
Six decisions that shaped the build
| Decision | The alternative we rejected | Why |
|---|---|---|
| Freeze quotes with their inputs stored. | Recalculate from current rates when asked. | A price you cannot reproduce is a dispute you cannot win. |
| Assignment constraints refuse, not warn. | Warn and let the dispatcher decide. | A warning at 4am is a warning that gets clicked through. |
| Monitoring notifies a person. | Show live status on a dispatch screen. | Nobody is watching the screen at 3am. |
| Trips close at the kerb, on a phone. | Close trips at end of shift. | Detail captured later is approximate; approximate detail is unbillable. |
| Booking runs on the operation's own domain. | Redirect to a third-party booking domain. | Customers drop at the domain change, and the accumulated value is not yours. |
| Attribution recorded from the first trip. | Add reporting later, once there is volume. | Attribution cannot be backfilled — the data simply does not exist. |
Quoting: freezing the number
Rates live in editable tables rather than in code: routes, zones, vehicle classes, time bands, wait allowances and surcharges, all changeable without a developer. That was a deliberate choice, and the reason is behavioural — pricing that requires an engineer stops being adjusted, and we have seen operators running two-year-old rates for exactly that reason.
The more important decision was that a quote, once issued, is frozen with its inputs. The stored record holds the resolved number and the values that produced it: the distance used, the time band applied, the vehicle class, the wait allowance, the surcharges. A rate table change afterwards cannot alter a quote already given.
This came directly from getting it wrong. Quotes initially stored references to the rate table rather than resolved values, so a mid-week rate change silently altered prices customers had already been sent. The fix is now the first thing we build on any pricing engine.
The second quoting rule is that the engine is allowed to refuse. Trips the table does not genuinely cover return "needs a human" rather than falling through to a default. A system that always produces a number always produces a number for the trips it does not understand — the tariff-gap problem in the booking and pricing errors that cost operators the most.
Assignment: making the system say no
Assignment is where this build differs most from the spreadsheet it replaced, and the difference is one word: refuse.
Four constraints are hard blocks, not warnings:
- The vehicle is not committed to an overlapping trip.
- The chauffeur is not committed to an overlapping trip, including travel time from the previous drop-off.
- The vehicle class matches the class that was sold. A different class forces a re-quote rather than a silent substitution.
- The vehicle can physically access both the pickup and the drop-off — which in Los Angeles rules out larger vehicles on hillside addresses, gated complexes and height-restricted structures.
The second is the one that earns its place. Conflicts on this route are rarely head-on; they are created by transit time between jobs. A 14:00 drop-off in Santa Monica and a 14:30 pickup at LAX do not overlap on any calendar and are impossible in practice.
Making these refusals rather than warnings was contentious internally, and the argument that settled it was simple: there is no situation in which a physically impossible assignment is correct. The cost of a block is a dispatcher spending ten seconds choosing a different vehicle.
The fourth constraint was added after the fact, and it is the one most systems lack. Access is a capacity problem that does not look like one — see matching the vehicle to the job.
Monitoring: from screen to notification
The first version displayed live flight status on a dispatch view. It was, in hindsight, a demo rather than a feature: technically correct and operationally inert, because the screen is not being watched at 3am.
The current model is a chain that ends at a person:
- Flight data is polled, more aggressively as the arrival window approaches.
- A change beyond a threshold is treated as an event, not a refresh.
- Affected live reservations are identified.
- The responsible person is notified through a channel that interrupts, with a message stating what changed and what decision is needed.
- Their response is recorded against the trip, so the next person to look knows it was handled.
Two details matter more than the mechanism. The thresholds are asymmetric — early arrivals trigger far sooner than delays, because a delay grants time and an early arrival removes it. And step five, recording the response, was added because without it two people handled the same exception twice, or each assumed the other had.
The limit of all of this is covered honestly in what flight tracking really does: the feed describes the aircraft, and the operation is waiting for a person. The gap between the gate and the kerb is closed by the passenger's own signal, which is why the vehicle is released on a message from the passenger rather than a clock.
The chauffeur side
Everything a chauffeur does happens on a phone, outdoors, frequently one-handed, sometimes in the dark. That is the whole design constraint, and it produced three rules.
Closing a trip takes about fifteen seconds. Actual times, wait time, extras, tolls — because detail captured at the kerb is accurate and detail captured at the end of a shift is a reconstruction.
Notifications state the decision, not the data. "Flight now 40 minutes early — acknowledge?" can be absorbed at a traffic light. A status change cannot.
Nothing important requires typing. Taps and confirmations, with free text reserved for the genuinely unusual.
The same reasoning governs the customer-facing booking flow, at greater length, in building a booking flow that works on a phone at the curb.
What we got wrong
Four things, all of which changed how we build:
- Quotes referenced the rate table instead of freezing values. A rate change altered prices already sent to customers. The most expensive mistake on this list.
- Deadhead was priced as a citywide average. It looked fine in aggregate and quietly lost money on a specific cluster of routes. Only visible by comparing quoted price against actual trip cost and examining the outliers — which is the entire argument for building the reconciliation stage early.
- Monitoring displayed rather than notified. The information was present and no human was told, which is a worse position than not having it.
- Access was not a constraint at booking. We checked vehicle access at dispatch, which is too late: the vehicle that fits the group cannot reach them, and the one that can reach them cannot take the group.
Three of the four were invisible without measurement. That is the main lesson of this build, and it is why reconciliation is no longer treated as reporting to add later.
What transfers to another operator
Being direct about this, since we sell software: most of the value here is not the code.
What transfers is the set of decisions — frozen quotes, hard assignment constraints, notification rather than display, kerbside trip closing, attribution from day one. Those apply whether an operator builds, buys, or runs on a general-purpose tool, and any decent platform can be configured towards most of them.
What does not transfer is the rate structure, the vehicle classes and the workflow specifics. Those are properties of one operation in one city.
For most operators, the honest recommendation is a good off-the-shelf platform tested against the six behavioural checks in how to choose software for a limousine or black-car company. A custom build becomes rational when the pricing model genuinely does not fit, or when the booking experience needs to be strategically yours — which were the two reasons here.
Sources
Questions we actually get asked
Why is there no before-and-after metric in this case study?
Because we do not have measurements clean enough to publish. The system was built incrementally over a period in which trip volume, staffing and pricing all changed, so any percentage we quoted would be attributing a mixed outcome to one cause.
We would rather describe the architecture and the reasoning accurately than publish a number that looks authoritative and is not defensible. Our editorial policy covers why.
Is this the same system Limoform sells?
It is the same architecture, not the same instance. The seven-stage structure, the hard assignment constraints and the notification model are what we carry into other builds; the rate tables, vehicle classes and workflow details are specific to one operation.
What we would not claim is that another operator can install this. The value that transfers is the set of decisions, which is why they are spelled out here rather than summarised.
Could an off-the-shelf platform have done this?
Most of it, yes — and for many operators that is the right answer, which we say plainly in how to choose software for a limousine company.
The parts that pushed towards building were the pricing structure and having the booking experience on the operation's own domain. Neither is a reason for a typical operator to commission a custom build.