Case study 10 · seed 3898701039
Café discoveryLoyalty programSolo full-stack build2 items gate a real pilot
Brew & the City

Good coffee near me,is the wrong question.

A café discovery app that scores every room against a 7-dimension taste profile, what you’re there for, and how far you’re willing to walk in a Calgary winter, instead of a single star rating. Underneath it, a City Card loyalty program that partner cafés run themselves, from their own portal — receipts in, stamps out.

Role
Solo, full-stack
Surface
Web app, café portal, admin
Stage
Security-audited, pre-pilot
Your City Card
Brew & the City
4 of 5 · one to go
RECEIPTAPPROVED
STAMPCAFÉ-ISSUED
REWARDREDEEM IN PERSON
CAP: 3 RECEIPTS / MEMBER / DAY
01 — The taste vector

Seven axes. A café gets scored on all of them, same as a person.

A person heading in for three hours of deep work and a person meeting a first date have almost nothing in common except that both walked into a café. Every user and every café gets the same 7-dimension profile, plus a separate categorical answer for primary drink, because “sweet vs. bold” and “coffee vs. matcha” are different questions a single axis would blur together.

Drink · ×1.3
Sweet, milky
↔ strong, bold
Energy · ×1.2
Quiet room
↔ lively room
Aesthetic · ×1.0
Minimal
↔ cosy, maximal
Pace · ×1.1
In and out
↔ linger for hours
Adventure · ×0.8
The classics
↔ rotating seasonal
Price · ×1.0
Under $5
↔ won’t flinch at $9+
Food · ×0.7
Drink-only visits
↔ serious pastry case
Primary drink, kept separate:CoffeeMatchaTea / chaiOther
02 — The product

One quiz, four screens that actually use it.

Take the quiz once. It feeds a matched “Today” feed, the context picker on every café’s own page, and the café’s own portal for reviewing receipts — four screens off one taste vector, not four separate flows bolted together.

quiz.tsx
QUESTION 4 OF 7 · ENERGY
Quiet spaces
Lively, social rooms
today.tsx
92%
Fjord & Filter
0.4 km · quiet
cafes/[slug].tsx
StudyDateQuick
portal/[slug].tsx
Receipt review
#0142 · $6.75✓✕
#0141 · $4.20APPROVED

Reconstructed layouts, not literal screenshots — the app has no marketing screenshots yet.

03 — The matching engine

What a 92% match is structurally not allowed to include.

Paid or partner status can change whether a café gets promoted; it can never change its match score. The scoring function’s input type has no field for partner status or price paid, so there’s nothing for it to read — the guarantee is enforced by the type system, not by convention.

✓
The rule we don’t break

Cafés can pay to be listed, featured, or entered into the City Card. They can never pay for a better Match %. Every café gets the same honest number, partner or not — copied verbatim from the app’s own marketing copy, because I wanted the case study to hold itself to it.

Fjord & Filter
Quiet · $$ · 0.4 km
92%
no partner-status field to read
0.4 km, decayed harder — it’s winter
seven axes, never one star rating

A missing input drops out of the blend entirely, renormalized — a café with no known coordinates isn’t scored as 0m or ∞ away, proximity just isn’t part of its score yet. A test in score.test.ts pins the no-partner-field guarantee down so it can’t regress silently.

04 — City Card

Receipt in, stamp out, five before a reward.

01
Save & visit

A matched café from Today or Discover, saved and visited in person.

02
Upload a receipt

Capped at 3 uploads a day per member — a receipt, not a claim, is the unit of trust.

03
Café approves

Reviewed from the café’s own portal, not the consumer-facing admin tools.

04
Stamp, then reward

Five stamps unlock a reward, activated and redeemed in person.

★★★★☆
a star rating
92%
a match, to you
05 — Security

Two passes through my own code before a pilot user touches it.

Pass one covered auth, database, application, and infrastructure broadly. Pass two went back through the row-level security policies and the analytics write path line by line and caught three issues pass one missed, one of them critical. I’m keeping the findings table, not polishing it out.

Findings, as recorded
Stamps mintable, skipping receiptsCritical · written, not appliedCafé portal, unauth lockoutFixedForgeable partner metricsFixedPortal PIN, no rate limitFixedAnalytics endpoint, unthrottledFixedFree-tier backups, unverifiedOpen · operational
10 of 12 findings closed in code · 2 remain operational, not technical
Brew & the CityCafé discovery & loyalty — case study
Search & jumpesc