Cut Supabase egress ~99%: shared cached pubs pull, column trims, kill happy-hour browser poll#188
Merged
Merged
Conversation
- New src/lib/slackNotify.ts: posts to a Slack incoming webhook (SLACK_WEBHOOK_URL env var), best-effort and never throws - /api/price-report POST now pings Slack the moment a report lands (price report, happy hour report, or stale-price flag) - Daily price-check cron now also checks the review queue and sends a reminder listing pending price reports (with oldest age) and pub submissions; silent when the queue is empty - Piggybacks on the existing cron because Vercel Hobby caps cron jobs at two and both slots are taken https://claude.ai/code/session_01HRdu5eYTJoUZ5sPJqVUzkk
- Happy hour row no longer reads 'TBC · 7 days 4pm - 5pm': the schedule is the value when the price is unknown, and '7 days' renders as 'daily'; when the price IS known it shows red with the schedule on a right-aligned sub-line, so the dotted leader never gets crushed - Checked row flags stale prices: aging/stale dates render amber with '· Nd ago' appended (recency tier now passed into the receipt) - 'from an aggregator lead' provenance jargon is now 'spotted online', moved to its own SOURCE row - Standard-pint row only renders when it differs from the hero price (it duplicated the big number on every non-happy-hour pub) - Micro-type floor raised from 8px to ~10px (banner sub-line, price label, amenity chips, CTA); CTA flex-wraps instead of squeezing https://claude.ai/code/session_01HRdu5eYTJoUZ5sPJqVUzkk
…r browser poll
Supabase free-tier egress warnings traced to three compounding causes:
1. ~20 server routes each pulled the full pubs table (~2.0MB) per
revalidation via getPubs()'s select('*'), and suburb pages pulled it
up to 8x per render (getSuburbBySlug + getSuburbPubs + getNearbySuburbs
+ getSiteStats, in both generateMetadata and the page body). One
production build cost 167MB of egress across 1,108 requests (measured
through a byte-counting proxy).
2. HappyHourClient re-fetched the entire table from every visitor's
browser every 60 seconds (~122MB/hour per open tab) even though the
live 'on now' state is derived client-side from schedules + a clock.
3. select('*') shipped columns nothing reads (context, created_at,
phone, place_id, updated_at) plus google_opening_hours (~735KB, 35%
of a pull) to pages that never render it.
Fixes:
- src/lib/cachedPubs.ts: unstable_cache-shared pulls, 1h TTL, tag
'pubs'. Raw rows cached (not Pub objects) so toPub() computes live
happy-hour status fresh per render. List pull excludes
google_opening_hours to stay under Vercel's 2MB data-cache entry
limit; happy-hour pages get full columns for just happy-hour pubs.
- supabase.ts: explicit column lists everywhere; aggregate helpers
accept a pre-fetched pubs array.
- All server callers switched to the cached variants; weekly-snapshot
cron deliberately keeps a fresh pull.
- HappyHourClient poll removed.
- /api/admin/review calls revalidateTag('pubs') on approvals so price
changes don't wait out the TTL.
Measured: build egress 167.2MB -> 1.7MB (-99%); tsc clean; 309 tests
pass. Runtime + independent agent verification in progress before PR.
https://claude.ai/code/session_01HRdu5eYTJoUZ5sPJqVUzkk
…dead Pub.source, fix stale copy Independent verification (agent-run, against the built app through a byte-counting proxy) found no correctness bugs; these are its three minor flags: - TransportHubPage (4 pubs-near-* routes) was still on uncached getPubs() - Pub.source was dead — no pubs.source column exists in any migration and nothing rendered it; removed from toPub and the Pub type - /happy-hour blurb said 'auto-refreshes every 60s' — data no longer refetches; the live status updates from the clock https://claude.ai/code/session_01HRdu5eYTJoUZ5sPJqVUzkk
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…red pubs cache The happy-hour declutter on main supersedes the refresh-copy tweak from this branch; both PROJECT-STATUS timelines kept. https://claude.ai/code/session_01HRdu5eYTJoUZ5sPJqVUzkk
iamjohnnymac
pushed a commit
that referenced
this pull request
Jun 12, 2026
iamjohnnymac
added a commit
that referenced
this pull request
Jun 12, 2026
…#176) In-repo BYOK article drafting pipeline (scripts/draft-article.mjs): Supabase-grounded brief -> Claude draft -> humanizer -> Pexels photos. Dev-only /draft preview (404s in production, noindex); article body extracted to ArticleView with the live route rewired to it. Conflict resolution on merge: /articles/[slug] keeps the shared cached pubs pull from #188. Verified post-merge: tsc clean, 321 tests pass. https://claude.ai/code/session_01HRdu5eYTJoUZ5sPJqVUzkk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Supabase free-tier egress warnings. Measured the actual causes by routing all Supabase traffic through a local byte-counting proxy:
select('*'), and suburb pages pulled it up to 8x per render (getSuburbBySlug + getSuburbPubs + getNearbySuburbs + getSiteStats, in both generateMetadata and the body). We deploy ~10x on a busy dev day — builds alone were ~1.7GB/day./happy-hourre-fetched the entire table from every visitor's browser every 60 seconds (~122MB/hour per open tab) — even though the live "on now" state is derived client-side from schedules + a ticking clock.What
src/lib/cachedPubs.ts—unstable_cache-shared pulls (1h TTL, tagpubs). Raw rows are cached,toPub()maps fresh per render so live happy-hour status is never stale. The list pull excludesgoogle_opening_hours(~735KB, 35% of a pull; only pub detail + happy-hour pages render it) which also keeps the entry under Vercel's 2MB data-cache limit. Happy-hour pages get a second small full-column pull filtered to happy-hour pubs.select('*')eliminated from all pubs-table queries insrc/lib/supabase.ts— explicit column lists, dropping columns nothing reads (context,created_at,phone,place_id,updated_at)./api/admin/reviewcallsrevalidateTag('pubs')on approvals, so price changes appear promptly despite the 1h TTL.Evidence (byte-counting proxy, before vs after)
/happy-houropen in a browser tabSteady state: ~6MB/day of hourly refreshes vs multiple GB/day.
Independent verification
A separate agent verified the work against the built app: tsc clean, 309 tests pass, diff review found no correctness bugs, 12 routes content-checked (prices, photos, opening hours, JSON-LD all present), and exact venue parity with production —
/happy-hour168 = 168 with identical link sets,/fremantle63 = 63 — proving the happy-hour pre-filter drops nothing. Its three minor flags (TransportHubPage still uncached, deadPub.sourcefield, stale "auto-refreshes every 60s" copy) are fixed in the follow-up commit.Also in this branch (already reviewed in this session)
The branch continues from merged PR #179's history — only the egress commits (
2f77fef,47a69d3, docs) are new here.https://claude.ai/code/session_01HRdu5eYTJoUZ5sPJqVUzkk
Generated by Claude Code