Browse and search all Bay Area events from Luma in one place. No more scrolling the map — Luma hides events behind a mobile-only map view; this app reverse engineers their API and surfaces everything in a searchable, filterable list.
- Full-text search across event names and descriptions
- Filter by day and location
- Live event indicator (pulsing dot) for events happening right now
- Paginated list, server-rendered for fast loads
- Daily background refresh from Luma's geo + place feeds
- Next.js 16 — App Router, server components
- Postgres — shared event cache
- Tailwind CSS + shadcn/ui — UI
- Bun — runtime and package manager
| Param | Description |
|---|---|
q |
Search query |
day |
Filter by date (YYYY-MM-DD or unscheduled) |
location |
Filter by city/neighborhood |
page |
Pagination (default: 1) |
- The UI reads exclusively from Postgres — no direct Luma API calls at request time.
- A daily cron job fetches all pages from two Luma feeds:
- Geo feed — events near
LUMA_LATITUDE/LUMA_LONGITUDE - Place feed — events under
LUMA_DISCOVER_PLACE_ID
- Geo feed — events near
- Results are deduped by
event.api_idand upserted into the cache. - Newly discovered events trigger a follow-up detail fetch (
/event/get?event_api_id=...) with paced requests and backoff on403/429.
- Install deps:
bun install- Configure env:
cp .env.example .env.localEdit .env.local — at minimum set DATABASE_URL and CRON_SECRET. Set NEXT_PUBLIC_APP_URL to your production URL for correct OG metadata.
- Start Postgres (Docker):
docker compose up -d- Run DB migrations:
bun run db:migrate- Start dev server:
bun run devOpen http://localhost:3000.
To do an initial pull from Luma:
bun run bootstrap:refreshThis calls the cron route locally to populate the database for the first time.
GET /api/cron/refresh-events
Authorization: Bearer <CRON_SECRET>
Optional query param: reason=bootstrap (defaults to cron).
vercel.json schedules this daily at 0 0 * * *.
bun run lint
bun run build