Avēre
A map-first happy-hour club that can prove a diner actually walked in.
Happy hour is one of the last high-intent local-discovery categories that is still a mess to navigate. A restaurant's best deals — the thing that actually fills a slow Tuesday — live in a PDF on their website, a chalkboard, or an Instagram story that vanished yesterday. There is no structured, trustworthy, right-now index of “where is a good happy hour near me, and is it on at 5:15 on a Thursday?”
For the diner, the status quo is a patchwork: Google Maps has no happy-hour structure, Yelp has reviews not deals, and blog directories are flat, ad-supported lists. For the restaurant, the deeper problem is attribution — Yelp and Google can show impressions and clicks, but neither can prove a human actually walked in. A bar spending on discovery marketing has no honest answer to “did that drive a visit?”
The technical difficulty is threefold. Happy-hour time is genuinely irregular — a venue might run a 2–5pm food window, a drinks-only reverse happy hour from 9pm to close, and a Sunday all-day window at once, which a single hours string cannot model. Proving a physical visit requires location-verified action, not a self-reported tap. And a two-sided marketplace needs a security model where a venue only ever sees its own numbers and a user can never grant themselves a paid tier — enforced at the data layer, not just the UI.
Avēre is a map-first happy-hour discovery PWA and restaurant-analytics platform built on Next.js 16 and Supabase. Its defining choice is that the backend is the database: business rules, security, and the rewards economy all live in Postgres as SECURITY DEFINER functions, triggers, and row-level-security policies — there is no application server holding the logic. Two live markets (Dallas–Fort Worth and South Florida, 800 venues) run from one codebase.
Structured happy-hour windows
Each venue stores a JSONB array of windows — {days, start, end, all_day, kind} where kind is food, drinks, or both — so one venue can carry a food window and a separate drinks-only reverse happy hour simultaneously. isOpenNow() evaluates them (including cross-midnight windows) and describeWindows() renders them per kind on the card. 786 of 800 venues use structured windows.
Location-verified check-ins
The check_in(venue_id, lat, lng) Postgres RPC is SECURITY DEFINER and validates GPS proximity server-side, returning “mayor” status. Check-ins gate ratings and drive badges — and this verified visit is the platform's core attribution primitive, the thing neither Google nor Yelp can prove.
The Postgres-native backend
Business logic is not in an app server — it is 33 SECURITY DEFINER functions, 7 triggers, and 29 RLS policies across 15 tables, with row-level security on every table. The rules cannot be bypassed by a rogue client because they are the data layer, and there is no server to run or scale.
The hybrid referral rewards engine
A self-contained economy implemented entirely in Postgres triggers. When other people engage with a venue you submitted, you earn a per-check-in drip worth the others' average rating (minimum 1), plus gated milestone bonuses at 10/25/50/100 check-ins that only pay if the rating clears 4.0–4.5★. The referrer's own actions are excluded and claims are capped at 3 rewarded check-ins per person per venue per week — all with zero application-server code.
Flash deals + check-in-to-claim
Venues compose time-boxed flash deals that surface as an in-app ⚡ banner. claim_deal() verifies the deal is live, that the user's membership tier meets the deal's min_tier, and — critically — that they have a location-verified check-in at the venue within the window. A claim is therefore a proven conversion, not a tap.
Membership tiers, structurally enforced
Guest / Prime ($15) / Elite ($25) live in a dedicated memberships table users can read but never write — tier is set only by an admin RPC or a future Stripe webhook. Because profiles has an update-own RLS policy, putting tier there would let anyone upgrade themselves to Elite for free; isolating it makes free self-upgrade structurally impossible.
Funnel analytics & venue accounts
A venue_events spine logs impressions, views, intent-taps, and saves; combined with check-ins and ratings it forms a funnel. Admins get a global dashboard, per-venue drill-downs (dependency-free inline-SVG charts), and a check-in hotspot map; restaurants get a self-serve dashboard scoped by an orgs/members model, surfacing the headline stat — new guests introduced by Avēre.
The reasoning behind the build — and what each choice cost.
The backend is Postgres — RPCs, triggers, and RLS, not an app server
Making the database authoritative means the security model and rewards economy cannot be bypassed by a rogue client, there is no server to run or scale, and a solo build could move fast — 33 functions, 7 triggers, and 29 RLS policies are the backend.
Logic lives in SQL that is harder to unit-test, and the 26 migrations were applied directly to Supabase rather than checked into the repo — a real tech-debt gap, mitigated by running Supabase's security advisor after every schema change.
Membership tier in a separate, user-unwritable table
profiles has an update-own RLS policy, so a tier column there would let any user upgrade themselves to Elite for free. Isolating billing-controlled state in a select-only memberships table makes free self-upgrade structurally impossible.
An extra table and a join — correctness beat convenience.
Structured JSONB windows over a normalized windows table
JSONB let the food/drinks/both split ship with zero migration, and since a venue rarely has more than a few windows, in-memory evaluation (isOpenNow, describeWindows) is cheap. 786/800 venues carry structured windows as a result.
Validation and querying happen app-side, and there is no referential integrity on window shape.
Fixed-price flash deals as the pay-in-app on-ramp
A fixed-price deal's amount is known without reading a POS, so it is the one payment product that needs no Toast/Square/Clover integration — the cheapest path to real payments, and simultaneously the strongest attribution signal, since redemption requires a verified visit.
Only fixed-amount transactions are addressable for now; open-check settlement is deferred.
One venues table + a metro column for multi-market
At 800 rows, fetching a metro's venues and filtering client-side is trivial, one codebase serves both markets, and switching metros is instant with no refetch. Adding a market becomes “insert rows + one config entry.”
No server-side tenant isolation between markets, and payload grows with the catalog.
Stripe and push notifications deliberately stubbed
Both are the highest-risk, highest-effort integrations, and push depends on a native app that does not exist yet. Shipping the entire flash-deal and membership pipeline end-to-end minus the last mile lets the model be validated before the risky wiring.
The product is not monetized yet and has no proactive delivery — flash deals reach only users who open the app.
Client-orchestrated ingestion, not a maintained ETL
Ad-hoc Node scripts, Google Places geocoding, extraction of a competitor's WordPress REST API to seed South Florida, and temporary-RLS bulk inserts loaded 800 venues across two markets in days.
Seeding was not a durable, repeatable pipeline — made safe by dropping and verifying every temporary bulk-write policy immediately after use (0 remaining).
Avēre shipped end to end in about three days — first commit July 3, live on Vercel by July 6 across 38 commits — as roughly 8,700 lines of TypeScript/TSX (the HappyHourMap component alone is 1,569), 13 page routes, and a Supabase backend of 15 tables, 26 migrations, 33 functions, 29 RLS policies, and 7 triggers.
The dimension with real scale today is the catalog: 800 venues (474 DFW, 326 South Florida), 786 with structured multi-window happy-hour data, 170 distinct neighborhoods with zero nulls after backfill, plus a live moderation pipeline (55 submissions, 14 approved) and 550 audit rows recording every action.
The North Star is deliberately not downloads or time-in-app — it is verified visits attributed to Avēre, specifically new guests introduced (a diner's first-ever check-in at a venue). That is the number the whole architecture is built to produce, and the number a restaurant would actually pay for. Monetization (Stripe) and push are the stubbed last mile, left until the model is validated.