The site and day book a Korean head spa runs its whole day on.
ginaskheadspa.com, top to bottom — the studio's public face.
TL;DR — A SCREENER CAN STOP HERE
Gina's K Head Spa is a real studio in Mineola, NY — run by Gina, whose English is limited, on a counter tablet. I built its marketing site, online booking, and the staff day book she runs the business on: appointments, comps and discounts, commissions, month-end books, gift cards with her own printed numbers. Live at ginaskheadspa.com, with real bookings on the calendar.
The owner runs the studio herself, her English is limited, and the whole operation lives on one tablet at the counter. Every feature had to survive a real day — walk-ins, comps for influencers, staff whose hours change, gift cards sold on paper.
✦ NORTH STAR
“Can Gina run the whole day from the counter tablet?”
The studio in Mineola — the software's only user sits at its front desk.
02 — SOLUTION
A public site that books, a day book that runs the studio
Guests book online; the desk runs everything else — arrivals and no-shows, editable prices with Free and Discount modes, split-staff add-on commissions, persistent customer notes, and month-end books without a spreadsheet.
The public side — picking a treatment, a specialist, and a time at ginaskheadspa.com.
Month-end books in one panel — income taken, value comped away, each specialist's commission, day by day.
INSIGHTCommission on list price, alwaysComps charge $0 and discounts charge less — but the specialist did the work, so commission is always on the list price. Only the day's takings read the charged price.
INSIGHTThe studio's own numbersGift cards are her printed cards — 001, 002… typed in at sale, duplicates rejected, balances drawn down until $0.
03 — UNDER THE HOOD
The same screens, flipped over
The rules that keep a real business honest live in the database — row locks, exclusion constraints, atomic RPCs — not in the interface. Toggle any screen below to see the code behind it.
FRONTENDNext.js 14 · TypeScript · Tailwind
BACKENDSupabase — Postgres · RLS · RPCs
HOSTINGNetlify — auto-deploy from main
DISCIPLINEMigration before push — a hard rule
KEY SCREEN A · GIFT CARDS
UNDER THE HOOD · THIS EXACT SCREEN
select * into c from public.gift_cards
where upper(trim(code)) = upper(trim(p_code)) for update; -- lock the row
if c.balance_cents <= 0 then raise exception 'gift_card:used_up'; end if;
insert into public.gift_card_redemptions (gift_card_id, amount_cents, booking_ref)
values (c.id, p_amount_cents, p_booking_ref);
update public.gift_cards
set balance_cents = balance_cents - p_amount_cents,
status = case when balance_cents - p_amount_cents <= 0
then 'used_up' else 'active' end
where id = c.id;
The row is locked, every draw is logged, and a card only dies at $0 — atomic in one RPC.
Same screen, both faces — her printed card numbers, with running balances.
KEY SCREEN B · THE DAY GRID
UNDER THE HOOD · THIS EXACT SCREEN
create or replace function slot_overlap_window(p_starts timestamptz, p_ends timestamptz)
returns tstzrange language sql immutable as $$
select tstzrange(p_starts, greatest(p_ends - interval '15 minutes', p_starts));
$$;
alter table booking_slots add constraint booking_slots_no_overlap
exclude using gist (
staff_id with =,
slot_overlap_window(starts_at, ends_at) with &&
) where (status <> 'cancelled');
Two same-specialist slots may overlap by 15 minutes — enforced by the database, not the UI.
Same screen, both faces — comps in sage, deals in blue, no double-booking by construction.
04 — DECISIONS
What I said no to
✕ REJECTEDGenerated gift-card codesv1 generated codes; the studio sells printed cards. v2 uses her numbers, typed in — the software bent to the business.
✕ REJECTEDAuto-replying to every reviewThe AI drafter answers 4–5★ automatically; 1–3★ are held for a human. Apologies shouldn't come from a robot on autopilot.
✕ REJECTEDCommission on the charged priceA comp charges $0, but the specialist still worked — commission stays on list price.
✕ REJECTEDPushing before migratingA migration that silently didn't apply forced a live rollback — now every migration ends with a confirmation SELECT and is verified before deploy.
A NOTE ON HONESTY
“The screenshots use seeded test data — real customers' names and bookings stay off the internet. Everything else is the live product exactly as Gina runs it.”
05 — REFLECTION
The software bends to the business
Every rework went the same direction: toward how the studio actually runs — her printed gift cards over generated codes, list-price commissions over charged-price math, a 15-minute grace window because real appointments breathe. The deploy discipline came the hard way: verify the database saw the migration before the code that needs it goes live.