Skip to content

monashcoding/verification

Repository files navigation

mac-membership-verify

A verification gate MAC puts in front of Humanitix ticket links. It checks whether a visitor is a current MAC member (via mac-auth login + the MSA membership roster) and either sends them to Humanitix with a personal discount code pre-applied, or to the normal ticket link.

See SPEC_mac_membership_verify.md for the source of truth and CLAUDE.md for the rules that are easy to get wrong. This is not a Humanitix replacement and not a payments system.

Stack

React + Vite frontend, Express API, Postgres via Drizzle ORM, single container (Dokploy on the Oracle VM). Matches the rest of the MAC Suite.

Build status (per §12 build order)

  • 1. Roster import — schema, admin upload route, safety gate, xlsx parsing.
  • 2. mac-auth integration — real Better Auth flow: session-cookie sign-in → JWT → Bearer, EdDSA JWKS verification against monashcoding/mac-auth (macUserId/roles/team claims, mac-suite audience).
  • 3. Auto-apply link discovery — confirmed ?discountcode={code} (§8), composeAutoApplyUrl.
  • 4. Linking flow — email auto-match, student-ID entry, DB rate limiting, skip, full §7 state machine.
  • 5. Code provisioning cron — deterministic codes, CSV export, Discord ping, Triggers A & B.
  • 6. Event-specific verify page/e/:slug with interstitial + manual continue.
  • 7. Generic verify page/ with active-events list.
  • 8. Events admin CRUD — create/activate fires Trigger A.
  • 9. Manual review queue — attempt-exhausted list + officer manual link.

Getting started

npm install
cp .env.example .env          # point DATABASE_URL at your Postgres
npm run db:generate           # generate SQL migrations from the Drizzle schema
npm run db:migrate            # apply them
npm run dev                   # start the API on :3000
npm run dev:web               # start the Vite SPA on :5173 (proxies /api → :3000)
npm test                      # unit tests: parser, safety gate, rate limit, codes (no DB)
npm run build                 # compile server + build SPA into dist/ (single container)
npm run cron:daily-diff       # Trigger B (§9) — wire to a scheduled job

The frontend lives in web/ (React + Vite) and is served by Express from dist/web/ in production — one container serving SPA + API (§3).

mac-auth

Integration follows monashcoding/mac-auth: the SPA POSTs /api/auth/sign-in/social → provider → callback sets a .monashcoding.com session cookie → SPA GETs /api/auth/token for a JWT and sends it as Authorization: Bearer. The backend (src/server/auth/mac-auth.ts) verifies it locally against the EdDSA JWKS, mirroring the service's own examples/verify.ts (issuer AUTH_URL, audience mac-suite, canonical id macUserId).

Account chooser (§5): mac-auth now sets prompt=select_account on its Google and Microsoft providers (suite-wide), so the provider account chooser is forced at login — no silent auto-pick of the wrong account. It only applies during an actual OAuth login; an existing MAC session is reused untouched. The app additionally shows the signed-in account with a "Not you? Switch account" control (AccountBar) for switching after the fact.

Deployment

Single container (SPA + API) + Postgres via Dokploy — see docs/deploy-dokploy.md. Migrations apply automatically on container start; auto-deploy triggers on push to main.

Roster import (step 1)

Admin-only, gated by a mac-auth exec/admin role claim.

# Upload the MSA Clubs & Societies export (Members_*.xlsx):
curl -X POST http://localhost:3000/api/admin/roster/import \
  -H "Authorization: Bearer <mac-auth JWT>" \
  -F file=@Members_2026.xlsx

# Current roster visibility:
curl http://localhost:3000/api/admin/roster/summary \
  -H "Authorization: Bearer <mac-auth JWT>"

Safety gate (§6): an import whose ENROLLED count is zero, or less than half the current ENROLLED count, is refused with HTTP 409 unless you re-submit with -F override=true. This stops a wrong-sheet or half-downloaded file from silently gutting the membership base.

Each import replaces the roster snapshot wholesale under a new import_batch_id; prior batches are kept queryable, never hard-deleted.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors