Brendon Rice
Back end projects

Case study · Foxera

The whole salon,on one platform.

Foxera is booking software for salons, spas and clinics. Every salon that signs up gets its own calendar, payments, text messages and staff tools, kept apart from every other salon but running on one system. I built the platform underneath: the data, the money, the texts, the calendar rules and the jobs that keep running while the salon is busy.

Glow Hair StudioText message
Illustration · no one at the salon touched this

The brief

Every salon on its own. All on one system.

A booking app for one salon is a calendar and a form. A platform sold to salon after salon is a different job. Each salon has its own locations, staff, prices, policies, bank account and phone number, and none of it can leak into anyone else's.

On top of that, clients book across salons from a public app, staff work from a dashboard and a clock-in kiosk, and card payments are taken on an iPhone at the counter. Everything had to run from one codebase and one database.

ClientsBooking app: search, book, pay deposits, waitlist, gift cards, reviews
Salon staffDashboard, calendar, checkout, reports, PIN kiosk
The counterTap to Pay on iPhone companion app
Foxera platformOne codebase
  • 210 API routes
  • Signed sessions · owner, manager, staff
  • Every query scoped to the salon and location
  • Plan limits enforced on the server
Per salon LocationsStaff & rostersServices & pricesPayment policyStripe accountMobile number
PostgreSQL62 tables · 43 migrations
  • StripeConnect & Terminal
  • TwilioTwo-way SMS
  • OpenAI& Deepgram voice
  • SendGrid& Brevo email
  • SpacesBackups & files

Payments · Stripe Connect

Paid to the salon. Never charged twice.

Clients pay the salon, not Foxera, and Foxera still needs its cut. Salons also lose money every time someone doesn't turn up. Both problems are handled in the same payment model.

  • Each salon onboards to Stripe Connect and is paid directly. Every card payment goes to the salon's account with Foxera's commission taken in the same charge.
  • A salon can't take card payments until onboarding is finished, and Stripe's webhook keeps that status in sync.
  • At booking, the deposit is taken and the card saved for later. If the salon doesn't take deposits, the card is saved without charging anything.
  • Late cancels and no-shows are charged to the saved card by the salon's own time-based policy, with any deposit already taken netted off.
  • The charge engine skips anything already charged or waived, so it's safe to run again. An hourly job retries cards that failed.
  • In the salon: invoices, refunds, split payments, gift cards, client credit and a daily cash-up.

Two-way SMS · Twilio

Texts that understand the reply.

Reminders cut no-shows, but only if the reply does something. The hard part is knowing when a reply means yes, when it means no, and when it's a person asking a question.

  • Reminders go out with a tap-to-confirm link, and clients can also just reply.
  • A reply only counts against the last question the salon asked. "Y" on its own is noise. "Y" after "can you still make 2pm?" is a yes.
  • Matching is strict on purpose: short answers only, nothing hedged, no questions. Everything else goes to the salon's inbox.
  • A "no" gets up to three new times from the next 14 days, from the same availability engine as online booking. The time is checked again when they pick it.
  • If that time has just gone, they get one fresh set, then staff take over. No answer in 24 hours, and the booking is flagged for a phone call.

A mobile number for every salon.

Australian mobile numbers can't be bought until the business using them is approved, and that review is done by people at Twilio, so it can take more than a day. Foxera registers each salon once and reuses the approval for every number after. Twilio calls back the moment it's approved, and an hourly check catches anything that call missed.

  1. Salon detailsThe business, not Foxera, is the sender
  2. Address checkedValidated before it's sent
  3. DocumentsBundled into one application
  4. ReviewedCan take more than a day
  5. Number boughtAn Australian mobile, ready for replies

The calendar · scheduling rules

A calendar that checks every move.

Salon bookings aren't single blocks. A colour might be three services with two staff and a processing gap in the middle. Drag one piece and the rest can quietly break, so every move goes through a set of rules first.

  • Day, week, month and list views with a column per staff member. Bookings drag between times and between staff.
  • While dragging, columns for staff who can't do that service dim, and a drop there is refused.
  • Moving one service in a multi-service booking asks whether to move the whole booking, just that service, or line the rest back up behind it.
  • Pushing a booking back checks everything chained behind it and offers a free, qualified staff member or the next gap.
  • When someone calls in sick, their day is shared out with a suggested replacement for each booking. The salon approves each one, and affected clients are texted.
  • The suggestions use AI when it's available and fall back to plain rules when it isn't, so the button always works.

Waitlist

Cancelled slots fill themselves.

A cancellation used to mean an empty chair unless someone rang around. Now the slot goes looking for a client on its own.

  1. A slot frees upA client cancels or moves
  2. MatchedService, staff, date or days, time window, first in line
  3. Held & offeredA text with a one-tap confirm link
  4. Next in lineNo answer in time? It moves on, or the slot is released

Scheduled jobs

Nine jobs that run on their own.

Most of what makes Foxera useful happens when nobody is looking at a screen. Reminders, offers, fees, follow-ups and backups all run on a schedule.

Each one is built to be run twice without doing anything twice. Every outgoing message is written to a log before it's sent, so a server restart mid-send can't lose it: a job picks up anything still waiting after two minutes. Fees that are already charged are skipped. There's one switch to pause them all, and each job needs a secret key to run.

AI tools

AI that shows its work before it saves.

AI is useful at a busy front desk, but it can't be trusted to change bookings on its own. So it looks things up freely and proposes changes, and a person confirms them.

  • A chat and voice assistant with 16 tools: find clients, check availability, find the next free slot, pull revenue figures, and import a client list pasted in any format.
  • Lookups run straight away. Anything that would change data comes back as a preview card for staff to confirm.
  • The model is tested like code. Real requests run through the live endpoint many times, reworded each time, and report a pass rate, because one good answer proves nothing.
  • Photo booking: a client uploads a selfie and the look they want, and it's matched to that salon's own menu. It can only suggest services the salon offers, and low-confidence matches go to a stylist instead of being quoted.
  • Rebooking and product suggestions based on each client's history.

And a few more

The parts nobody sees until they need them.

Built to Apple's review rules

Tap to Pay on iPhone

A companion iPhone app takes contactless cards at the counter. The dashboard queues the payment, the iPhone picks it up and reports back. Every transaction gets a receipt, and if a card is declined after the app is closed, a push notification says so.

Every night

Backups

At 2 am the live database is dumped and stored off-site in DigitalOcean Spaces. The same code runs from a "Back up now" button in the admin, so every backup shows up in one list.

Subscriptions

Plans and limits

Each plan caps how many staff and locations a salon can add, checked on the server. Limits are edited in the admin, and downgrading never deletes anything. It only stops new ones past the cap.

Testing

Tested like money depends on it.

Because it does. A wrong rule here charges a client, cancels a booking or texts the wrong person, so the rules are tested on their own and the whole system is tested end to end.

Unit tests cover the logic that decides money and time: availability, waitlist matching, reschedules, cash-up, stock and reports. Browser tests click through the admin. And twenty end-to-end flows can be run from the super-admin against a dedicated test business, from sign-up and booking through to payments, receipts, SMS campaigns and plan limits.

  • 295unit tests
  • 102browser tests
  • 20end-to-end flows
  • 12AI probe cases

Where it landed

Booked, paid, reminded and refilled.

Built with Next.js · React · TypeScript · PostgreSQL · Prisma · Stripe Connect & Terminal · Twilio · OpenAI · Deepgram · SendGrid · Brevo · DigitalOcean Spaces · Jest · Playwright

If you can describe it,
I can build it.