Admin / Curation Portal
Replaces wp-admin. One portal, all 4 sites, permissioned per site via
admin_user_site_roles (owner / editor / curator / venue_partner).
Structure: separate app, shared monorepo
/apps
/web — the public Next.js multi-site frontend
/admin — this portal, its own Next.js app
/packages
/api-client — typed client for the /v1 API, used by both apps
/schema-types — generated types from the Postgres schema
Kept as a separate app from the public site, not a /admin route inside it:
different audience, different UX needs (dense tables, forms, bulk actions),
different deploy cadence (you'll iterate on curator workflows far more often
than on public page templates, and a bug in the admin app should never risk
the public sites). Both are still cheap to host on Vercel — this isn't a
meaningfully bigger infra footprint than one app.
Modules
- Dashboard — per site (or all-sites rollup for
owner): ingestion items pending review, upcoming featured events, recent activity - Ingestion review queue — the flagship new workflow, see below
- Venues — CRUD, region/category assignment,
calendar_url/website_url(feeds the ingestion pipeline), featured toggle. Shows a "linked on other sites" indicator whenvenue_group_idis set (e.g. a HeyAustin curator editing "Friends Bar" sees it's also listed on 6thStreet) — informational only, each site's row stays independently editable - Events — CRUD, calendar view, filter by
source(manual / ai_ingested / facebook_import / user_submitted), featured toggle, bulk actions. User-submitted events land here withstatus='draft'for review, same queue-before-publish treatment as AI-ingested events - Rentals — CRUD, same shape as venues
- Artists — CRUD (name, bio, image, social links), linked to their events; mostly light-touch since it's built up incrementally as events get tagged with performers, not maintained as its own heavy workflow
- Deals — CRUD with the recurring-schedule fields (days of week, time window, valid date range) instead of a single start/end timestamp
- Posts — rich text editor, AI-drafted SEO fields shown as editable suggestions (never auto-published without a look)
- Media library
- Reviews moderation — flagged
reviewsfrom app users - Users & roles — manage
admin_usersand their per-site roles;venue_partneraccounts get a restricted view scoped to only their venue - Site settings — per-site
brand_config(theme, logo, social links)
Ingestion review queue (flagship screen)
This is the screen that directly replaces the current manual "hunt for events on partner pages" work, so it gets the most design attention:
- List of
ingested_eventswherereview_status = 'pending', grouped by venue, newest run first - Each row: raw extracted title/date/description side-by-side with the
matched existing event (if
match_status = 'matched_existing') so a curator can see exactly what would change - One-click approve (writes/updates the real
eventsrow) or reject, plus bulk-approve for a whole run when it's clean - Per-venue source trust indicator (streak count toward auto-publish eligibility, per the ingestion pipeline's graduation model) so curators can see which venues are close to needing less oversight
- Real-time via Supabase subscriptions: new pending items appear without a manual refresh — a scheduled overnight ingestion run should show up in the queue when a curator opens the portal in the morning, not require a poll
Stack
- Next.js + shadcn/ui components + TanStack Table for the data-heavy CRUD screens — fast to build, no reason to hand-roll tables/forms
- Supabase Auth for login; JWT site/role claims drive both API authorization (server-side, already covered in the API design) and UI nav visibility (client-side, cosmetic only — never the actual security boundary)