Sajjad Mahessar Good Merch Group Free audit
~/sajjad $ cat projects/qr-hardened ← cd ../projects Systems

QR ordering, rebuilt hardened for a second venue

Live · Oct 202648 of 49 checks passed

The QR order-and-pay platform redeployed for another venue — and rebuilt to a much stricter security standard, because the database it had to live in was shared with a staff app. No database key in any page, locked tables, server-side prices, passcode lockouts and payment checks, tested against 49 attacks before launch.

Type
Payments platform
Category
Systems
Built with
Supabase · Netlify Functions · Stripe · bcrypt · RLS · Security headers
Project
11 of 37
FIRST VERSION → THIS VERSION KEY IN PAGE SOURCEfine on its own database NO KEY ANYWHEREshared database, open tables PHONE /api/ SERVER FUNCTIONS TABLES: SECURITY ON, NO POLICIES, PUBLIC GRANTS REVOKED FUNCTIONS: CALLABLE BY THE SERVER ROLE ONLY SETUP SQL CHECKS ITS OWN LOCKDOWN AND PRINTS OK
The pages only know one address — everything else is behind the server

Why it couldn’t just be copied

The first deployment runs on its own database, so its public key in the page source exposes nothing else. This venue’s system had to live in a database shared with a staff app whose tables were open to that same public key — staff, takings and timesheets included.

Copying the first version would have handed that key to anyone who scanned a table. So the second deployment was rebuilt so that no page ever holds a key, and the exposure in the staff app was written up separately as its own fix.

How it’s locked down

  • Pages talk only to the site’s own /api/ address, forwarded to two server functions.
  • The ordering tables have row-level security on, no policies, and public grants revoked — shut to everything except the server.
  • Database functions are restricted to the server’s role, because the database publishes them as public endpoints by default.
  • Staff sign in with a bar passcode or a manager passcode, both stored as bcrypt hashes; sessions last 16 hours on the bar and 4 for a manager, and changing a passcode signs out every tablet using the old one.
  • Wrong passcodes lock out at 8 tries per device per 15 minutes, and 60 per venue.
  • Tables are found only by a 10-character random code; there is no way to list tables, orders or promo codes, and promo guessing is rate-limited.
  • Strict content rules, no framing by other sites, the table code never passed to another site, and staff pages never cached or indexed.

Tested before a guest saw it

Run against a local copy with 49 checks: forged and edited sessions, replayed and wrong-signature webhooks, tampered prices, guessed passcodes and double refunds. Then clicked through in a real browser as guest, bar, manager and printer.

48 passed. The one failure was a mistake in the test itself, not the code — recorded as exactly that in the handover.
Ticketing

Event ticketing with member pricing

Member prices checked at the door

SupabaseEdge FunctionsStripe CheckoutCloudflare Turnstile
Booking system

Function room booking & pricing

Date-priced bookings, confirmed by signed webhook

Supabase Edge FunctionsStripe CheckoutWebhooksNetlify
No charge

I’ll find the money before you pay me anything.

Send me your software subscriptions and I’ll come back with what’s replaceable and what it’s worth — free, and yours to keep either way. How it works →

Contact

Want the same done to your cost base?

Open to operations, automation and technical operations roles — and to talking with anyone running a multi-site business who suspects they're paying for software they could own instead.