Skip to content

About

V1 GTM Dashboard

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

26 Commits

Folders and files

Repository files navigation

V1 GTM Dashboard

Netlify Status

Member and event tracking for the V1 Michigan community team. Implements v1-gtm-dashboard-architecture.md §1–10; §11 is deliberately not built.

Run it locally

cp .env.example .env        # fill in SEED_ADMIN_EMAIL at minimum
pnpm install
supabase start              # Postgres + Auth + Storage + Studio, migrations and seed applied
make dev                    # or: pnpm dev

make reset re-applies every migration and reseeds. make tunnel prints a public URL for the Slack and Tally webhook routes during development. DEV_BYPASS_AUTH=true injects a fixed admin session and runs server reads through the service-role key, bypassing RLS. It is honoured in every environment, production included — while it is on, anyone who can reach the site has full admin access without signing in. See lib/flags.ts.

See performance notes for the load-time changes, local benchmark results, and commands to verify the RLS optimization.

Layout

app/(auth)/login          email + password sign-in, and the rejected-account notice
app/(dashboard)           every admin page; middleware 404s the `member` role here
app/api                   imports, export, slack events, webhook stubs
lib/supabase              server (RLS) / browser / service-role clients
lib/matching              normalize + matchPerson, the TS mirror of the SQL ladder
lib/imports               per-kind Zod schemas, the §4.9 column mappings, parsing
lib/queries.ts            the cached read layer — every page renders from here
lib/cache.ts              tag constants + withCache/revalidate
supabase/migrations       the only way the schema changes
netlify/functions         slack-sync, daily
fixtures/csv              one sample file per import kind

Conventions

  • Reads go through lib/queries.ts. Each is wrapped in withCache(keyParts, tags, fn); writes call revalidate(...) with the tags they touched. Counts come from SQL views, never from JS.
  • Types live in lib/types.ts and are attached at the query boundary. The file mirrors supabase/migrations; regenerate with supabase gen types if it drifts.
  • Server Actions do mutations. Any write to a people or events field also writes a field_changes row — call the SQL helpers rather than duplicating that.
  • The service-role client is only legal inside app/api/webhooks/*, app/api/slack/*, and netlify/functions/*, each of which verifies its own signature.

Design system

The V1 website visual language is consolidated in app/v1-theme.css: cream backgrounds, charcoal text, gold accents, Instrument Serif display headings, and Inter interface text. app/globals.css exposes the same semantic tokens to Tailwind v4. See the design system for source references, color roles, component guidance, and accessibility adaptations.

Deviation from spec §5, recorded here as the spec asks. The spec fixes Google as the only provider with email/password disabled. This build uses email

  • password instead, at the owner's direction, with no self-serve sign-up — an admin provisions each account in /settings and hands over a one-time password. Creating an auth user needs the Admin API, so provisionUser() is the one Server Action that touches the service-role client; it is guarded by requireAdmin() and writes nothing but app_users and auth.users. The access rule is unchanged and is still enforced where it always was: the auth.users trigger in the baseline migration refuses any address that is not @umich.edu and either on app_users or attached to a person with is_v1_member = true. Switching provider does not widen who can get in. Email confirmations are off, so no SMTP is required.

One deviation from spec §2, recorded here as the spec asks. The spec names shadcn/ui. The dashboard already ships .btn, .card, .table, .tag, .input, .seg and .dialog as finished CSS, so generating shadcn's components and then re-theming each one against those same variables would be strictly more code for identical pixels. Instead components/ui/ wraps Radix primitives — the parts that carry real behaviour and accessibility (dialog, popover, combobox, radio group, checkbox) — in the shared design-system classes, and everything purely visual uses the classes directly. TanStack Table, Tailwind and the token mapping are unchanged.

About

V1 GTM Dashboard

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages