ian.hwang / portfolio
available · full-stack roles
case · 02
~/cases/kauboi-bbq
← back to all work
case study · hospitality & growth · 2024—2025

Kauboi BBQ — a restaurant digital platform that turned 73 reservation clicks into 40 bookings.

Marketing site, menu, reservations, and a QR-based Easter campaign with one-time token redemption — three separate flows for customers, staff, and admins, all designed around the day-to-day of running a restaurant.

role
full-stack lead
timeline
2025 — present
surfaces
customer · staff · admin
stack
next.js · supabase · resend
channel
web · qr · email
01 / overview

The problem

Kauboi BBQ had a strong in-restaurant brand and zero digital infrastructure. Reservations went through Instagram DMs, marketing was reactive, and there was no way to measure whether a campaign actually drove bookings versus just impressions.

What we built

A single Next.js platform with three distinct surfaces: a marketing & reservation site for customers, a staff console for managing bookings & campaigns, and an admin layer for menu, pricing, and audit. Plus a one-shot Easter QR campaign with token redemption — built end-to-end in three days.

Kauboi Easter QR draw — egg cracking animation
Kauboi Easter QR result — Free SODA prize claim
02 / outcomes

Measurable growth.

930/wk
weekly visitors
post-launch · 8-wk avg
40/73
reservation conversion
55% click → booking
494redeemed
easter qr campaign
one-time tokens · 0 double-redeems
160signups
email list grown from
qr opt-in flow
03 / surfaces

Three flows, one system.

Restaurant software fails when it tries to be one app for everyone. The customer flow has to be glanceable on a phone in 8 seconds. The staff flow is an iPad on the host stand, used at speed during a rush. The admin flow is desktop, used weekly by ownership for menu and reporting.

customer
marketing · menu · reserve · qr
staff (host stand)
today · seating · check-in · waitlist
admin (ownership)
menu · pricing · campaigns · audit
↓ shared core ↓
api
Next.js route handlers · TS · zod
primary store
Postgres · prisma · resend · vercel
04 / qr campaign

QR campaign · one-time token redemption.

Easter weekend ran a city-wide promo: scan a QR on the table, get a free side on the next visit. The hard problem isn't generating QRs — it's making sure a token can only be redeemed once, even if a guest scans it twice, on two phones, while staff is mid-rush and our API is briefly slow.

Solved with a Postgres unique constraint on (token, redeemed_at), a server-side SELECT ... FOR UPDATE at redemption, and an idempotency key on the staff confirm. Out of 494 redemptions, 0 doubles.

# campaign · easter-2025 · 494 redemptions · 0 doubles POST /api/promo/redeem token=KB-7Q3F-9X2A staff=host_03 ↳ tx begin SELECT * FROM promo_token WHERE code = $1 FOR UPDATE → status=unredeemed UPDATE promo_token SET redeemed_at=now(), redeemed_by=$2 → 1 row INSERT INTO promo_audit (token, action, actor) ... ↳ commit 204ms ok # duplicate scan attempt — same token, 80ms later POST /api/promo/redeem token=KB-7Q3F-9X2A staff=host_03 ↳ SELECT ... FOR UPDATE blocks 12ms · sees redeemed_at NOT NULL ↳ 409 already_redeemed · idempotent response ✓ 0 double-redeems across 494 events
easter.kauboibbq.com / admin
Kauboi Easter QR admin dashboard — generate QR codes with prize allocation per type
05 / funnel

Reservation funnel.

Eight-week window, post-launch. The reservation page does one job: collect intent and confirm a booking via email + SMS without making the guest re-type anything they already gave Instagram.

visits
7,440
reserve clicks
73
bookings
40
click → book
54.8%
06 / reflection

What worked, what didn't.

  • Three surfaces, one codebase & data model — the right call. Staff and admin shared 80% of components.
  • Idempotency keys + DB-level locks beat queueing for redemption; simpler to reason about under rush.
  • SMS confirmation drove the 54% reservation conversion; pure-email confirm tested at ~30%.
  • Wish I'd shipped a tiny analytics endpoint earlier — spent a week reverse-engineering Plausible exports.
next case · 01

ProjectsToBid — construction bidding SaaS