Skip to content
georgepuma.dev

projectsronatello

Mini-case · Direct client · 12 days to production

Ronatello

Production site for a newly opened neighborhood liquor store in Arequipa: promotions with validity dates, bookings with capacity limits and its own admin panel. From brief to deployment in 12 days.

problem
A newly opened liquor store needs to publish promotions that expire, take bookings without exceeding capacity and manage all of it from its own panel.
role
Direct client: from brief to deployment in 12 days, reusing the starter kit extracted from Cleo Spa. In production.
scope
24 routes (9 public + admin panel) · business rules in Postgres with RLS · CI that spins up a real Supabase stack.
result

12 days

brief → production

24 routes

9 public + admin panel

Next.js 16 · React 19 · TypeScript · Tailwind v4 · Supabase · Vitest · GitHub Actions

The product, unretouched

Promotions table in the panel: each row with the combo, price, validity range, capacity and status — active or ended — and actions to edit and unpublish.
Promotions: validity dates and capacity in plain view. The ended one stays in the table — history, not deletion.
Bookings table: code, promotion, customer with buttons to call or open WhatsApp, delivery and status; expired ones show a final-status note kept as history.
Bookings: an expired one becomes a record only — kept as history, with the phone number still visible in case the customer needs a call.
Home panel with four cards: bookings awaiting a reply, promotions closing soon, products published on the site versus those not, and access to the public site.
The panel opens with what is actionable: what awaits a reply, what closes soon and what the customer sees — or does not see.

Three decisions that hold up the rest

  1. A promotion knows when it's live

    Every promotion carries a validity range and a capacity, and its status is read from there: active or ended. It can be unpublished early, but an ended one does not disappear — it stays in the table as a history of what was offered.

  2. An expired booking is a record, not a to-do

    Bookings deduct capacity from their promotion and expire if nobody replies in time. An expired, delivered or cancelled booking moves to a final status: it is kept as history, no longer accepts actions, and the customer's phone stays visible in case they need to be contacted.

  3. The rules live in Postgres, and CI tests them for real

    Business rules live in Postgres with RLS and CI spins up a real Supabase stack — the same skeleton of roles, RLS and CI extracted from Cleo Spa. Reusing decisions already argued through once is what made it possible to go from brief to deployment in 12 days.

What it left behind

The proof that the starter kit extracted from Cleo Spa works: the same skeleton of roles, RLS and CI, from brief to production in 12 days. There it was extraction work; here it was a deadline.

The system's most delicate rule — an expired booking giving its capacity back — has a pgTAP test that covers it end to end, and CI doesn't run it yet: a green build that doesn't check what matters most. It's one workflow step, and it's next.