Auto Detailing SaaS — Multi-tenant booking platform
From manual estimating and double-bookings to 1,000 daily appointments — fully automated.

The problem
A multi-location auto detailing chain was losing money to three things:
- Manual quoting. Customers waited 1–2 days for estimates while staff inspected vehicle photos by hand. Most never came back.
- Double-booked bays. Spreadsheet-based scheduling across 4 locations meant the same bay was booked twice multiple times a week.
- Payment friction. Cash and card-on-file with no recurring billing, no upsells, and no refund flow.
The owner had tried two off-the-shelf booking tools — both buckled under the multi-tenant + multi-bay rules. He needed a custom build, fast, but didn't want to spend $50k on a v1.
The obvious answer was "build a SaaS in NestJS." But a 4-month build was the wrong tool — the business needed traction in weeks, and most of the complexity was in business rules (bay availability, location-specific pricing), not in scaling.
The approach
I built the entire backend on Xano to compress the timeline, and pushed the heavy reasoning (vehicle photo analysis, scheduling logic) into custom function stacks and AI Vision calls.
Why Xano (and when I'd have skipped it)
Xano made sense because:
- Single-tenant data shape. Each location was a tenant, but the data model was the same — Xano's tenant filters do this cleanly.
- Stripe + webhooks built in. Saved 1–2 weeks of plumbing.
- Owner could read the visual function stacks. Critical for trust.
I would have skipped Xano if the platform needed real-time bay tracking via WebSockets (it didn't — polling every 30s was fine), or if we needed sub-100ms response times for a mobile app (we didn't).
Architecture
The bay solver
This was the trickiest piece. Each location has 2–6 bays, each bay has a service-type whitelist (some can't do interior detailing), and bookings have variable duration. I modeled it as:
- Block ingestion — every booking creates a
bay_blockrow with(bay_id, start, end, service_type). - Availability query — given a service type and duration, find bays where
start..enddoesn't overlap any existing block. - Hold + confirm — a 90-second optimistic hold prevents the classic "two customers click confirm at the same time" race.
AI photo quoting
Customer uploads 4 photos → Xano sends them to a vision model with a prompt seeded with the location's price book → returns an estimate with a confidence score. Below 70% confidence, a human reviews. 80% of quotes never need review.
Outcomes
What I'd do differently
Two things I'd change on a v2:
- Move the bay solver to a typed function — by month 3 the visual function stack was getting long. Not unmaintainable, but a pure function in a worker would test better.
- Add a soft-launch tenant — we cut over all 4 locations on day 1 because the owner was confident. It worked, but I'd ship to one location first now.
“One of the best backend devs I've worked with. Exceptional developer with clear communication. You'll be fortunate to have him on your team!
”
Building something similar?
Send a quick note — happy to compare notes on the architecture.