All work
TSOffline-First · Multi-TenantMobile AppsCase study

Technaut Salon — Offline-First Salon MS

Books, serves and bills a salon client with the internet completely down, then reconciles the moment it returns.

Offline-first salon and beauty-parlour management: advance booking with a slot engine that understands staff shifts, resources and colour-processing gaps, a walk-in queue, per-staff service attribution, GST billing with offline-safe invoice numbering, backbar inventory, commissions and payroll.

Source private
Industry
Salon & Beauty
Role
Architect & Full-Stack Engineer
Type
Mobile App
Year
2026
Status
Delivered
Works offline
Reception
Android · iOS · Windows
Platforms
Salons → branches
Tenancy

Overview

Technaut Salon is built for reception desks that cannot stop when the connection does. The Flutter app — Android, iOS and Windows, plus web for the public booking page — keeps a local SQLite database via Drift as its own source of truth, and reconciles with a NestJS API on MariaDB as soon as a connection returns.

The scheduling is the hard part. A salon slot is not a fixed block: a colour service has a processing gap in the middle during which the chair is occupied but the stylist is free, an assistant may cover part of a service, and some services need a resource — a basin, a steamer — that is shared across staff. The slot engine models shifts, resources and processing gaps together, so the calendar offers times that can actually be honoured.

Two constraints follow from working offline. Invoice numbering has to be safe when several terminals are issuing bills with no server to arbitrate, and inventory has to deduct backbar product automatically as services are performed rather than at a stocktake. Both are handled locally and reconciled on sync.

The platform is multi-tenant across many salons, each with many branches, and covers commissions and payroll, packages, memberships and loyalty, campaign messaging, and staff, sales, client and financial reporting.

The problem

Salon software assumes a fixed appointment block and a live connection. Neither holds: a colour service frees the stylist mid-treatment while the chair stays busy, assistants cover parts of services that commission has to account for, and a reception desk that cannot bill during an outage sends clients away.

Discovery

Modelled a real day at the chair rather than a calendar grid — shifts, shared basins and steamers, processing gaps, assistant hand-offs — and found the scheduling constraint, not the billing, was what generic tools got wrong.

The solution

Made the device authoritative: a Flutter app over a local Drift/SQLite database that books, serves and bills with no network, reconciling with a NestJS API on MariaDB when a connection returns. The slot engine reasons about shifts, resources and processing gaps together so offered times can actually be honoured.

Technical stack

Frontend

  • Flutter
  • TypeScript

Backend

  • NestJS

Data

  • SQLite
  • Redis

Infrastructure

  • Docker

Also used

  • Drift
  • Prisma
  • MariaDB 11.8

System architecture

  1. 1

    Flutter app (Android, iOS, Windows; web for public booking) with Drift/SQLite as the local source of truth

  2. 2

    NestJS + Prisma API over MariaDB 11.8, with Redis alongside

  3. 3

    Multi-tenant model: many salons, each with many branches

  4. 4

    Slot engine combining staff shifts, shared resources and per-service processing gaps

  5. 5

    Offline-safe invoice numbering reconciled on sync across concurrent terminals

  6. 6

    Backbar inventory deducted automatically as services are performed

Engineering challenges

Challenge

Treating a service as one contiguous block either blocked the stylist through a colour processing gap or double-booked the chair, so the calendar offered slots the salon could not honour.

How I solved it

Modelled a service as segments with an explicit processing gap, and made the slot engine reason about staff, chair and shared resources separately — freeing the stylist during processing while the chair stays occupied.

Challenge

Several terminals issuing GST invoices offline cannot ask a server for the next number, and duplicate or gapped invoice numbers are a compliance problem, not a cosmetic one.

How I solved it

Gave each terminal an offline-safe numbering scheme reconciled on sync, so bills can be raised during an outage without colliding when the branch comes back online.

Challenge

Commission was computed per service, which quietly underpaid assistants who covered part of a treatment and overpaid the lead stylist.

How I solved it

Made attribution per-staff with explicit assistant splits at the service level, so commissions and payroll fall out of what was actually performed.

Core features

  • Offline-first — the local SQLite database is the app's source of truth
  • Slot engine aware of staff shifts, shared resources and colour-processing gaps
  • Advance booking plus a walk-in queue
  • Per-staff service attribution including assistant splits
  • GST billing with offline-safe invoice numbering across terminals
  • Inventory with automatic backbar deduction as services are performed
  • Commissions and payroll derived from attributed services
  • Packages, memberships and loyalty
  • WhatsApp, SMS and email campaigns
  • Staff, sales, client and financial reporting
  • Multi-tenant — many salons, each with many branches
  • Android, iOS and Windows from one codebase, plus a web public booking page

Results & impact

Reception books, serves and bills through an outage and reconciles automatically afterwards. The calendar stops offering impossible slots, backbar stock reflects services performed rather than a monthly count, and commissions match the work each person actually did.

What I learned

  • The scheduling model, not the billing, is what generic salon software gets wrong — and it is the one that decides whether staff trust the calendar.
  • Offline invoice numbering has to be designed in; retrofitting it onto a server-issued sequence is not possible.

Related work

All projects
Next step

Have a system like this to build?

I take projects from the first conversation through to production, and stay on for the support that follows.