All case studies
Bookra · SaaS · Booking · 2025

Bookra — Salon & Coaching Booking SaaS

A multi-tenant booking platform with an availability engine, payments, payouts, and revenue reporting — kept consistent with a transactional outbox and background queues.

3 min read
NestJSNext.jsPrismaPostgreSQLStripeWhatsAppGoogle Calendar
Bookra — Salon & Coaching Booking SaaS
Multi-tenant
Platform
Stripe
Payments
Outbox + queues
Reliability

The problem

Salons and coaches don't just need a calendar — they need money to move correctly. A booking touches availability, staff schedules, payments, invoices, refunds, commissions, and payouts, and every one of those has to stay consistent even when a third party (Stripe, Google, WhatsApp) is slow or fails mid-flow.

The platform is multi-tenant: each business runs on its own branded space, with its own staff, services, and revenue — isolated from every other tenant.

The architecture

NestJS + Prisma on PostgreSQL owns the domain; Next.js serves the booking flow and the operator dashboard. The two things that keep it honest are the availability engine and a transactional outbox.

Booking → payment → side effects

The availability engine

Slots are computed from each staff member's working hours, service duration, and existing bookings. Reservations are written inside a transaction so two customers can't claim the same slot — the conflict is impossible at the database level, not patched up afterward.

Why a transactional outbox

When a booking is paid, several external things must happen — invoice, calendar event, WhatsApp message, commission split. If those run inline, a flaky Google or WhatsApp call can fail a paid booking. Instead, the booking and an outbox row are committed in the same transaction, and a background worker drains the outbox with retries. The payment and the side effects can never disagree.

Money math lives server-side

Commissions, refunds, and payouts are derived from the ledger, not the UI. Revenue reporting reads the same source of truth, so the numbers an owner sees always reconcile with what Stripe actually moved.

Outcomes

Multi-tenant
Branded per business
Isolated staff, services, revenue
No double-booking
Availability engine
Enforced in the database, not the UI
Outbox + queues
Consistent side effects
Payments and integrations never drift

What this taught me

Booking software lives or dies on consistency. The availability engine and the outbox were the two decisions that turned "usually works" into "correct under failure" — which is exactly what a business trusting you with payouts needs.

Building something similar?

Send a quick note — happy to compare notes on the architecture.