# TASK METADATA - **Target Files:** - `server/routes/auth_forward.ts` - `ui/db_queries.ts` - `ui/mod.ts` - `server/routes/events.ts` - `server/tests/forward_auth.test.ts` - `server/tests/events.test.ts` - **Core Objective:** Implement Phase 1 of the Event Delegation & Ingress Overhaul: enable Traefik ForwardAuth guest ingress for scoped event attendees, bridge session custom scopes to the Launchpad UI, and wire audit logging on seat claims. - **Dependencies:** None. - **Additional Important Notes:** - Strictly 100% pure Hono SSR JSX. - Zero-Trust Ingress Rule: `account_status: 'guest'` must ONLY be permitted if the session holds the specific `app:` custom scope for the target host. - Must pass all quality gates (`deno fmt`, `deno task lint`, `deno task check`, and `deno test --allow-all`). --- ## Architectural Considerations & Risks ### Risks 1. **Scope Leakage:** If ForwardAuth allows any guest account through without validating the specific `app:` scope, a guest for Event A could access Event B's workload. - *Mitigation:* In `server/routes/auth_forward.ts`, explicitly require that either `grantRole` exists in PostgreSQL or `auth.customScopes` includes `app:${appRecord.name}`. 2. **Launchpad Scope Resolution:** Guests do not have rows in the `grants` table. - *Mitigation:* Update `getDashboardApps` in `ui/db_queries.ts` to accept optional `customScopes?: string[]` from `auth` and query matching apps with role `'Guest (Viewer)'`. --- ## Proposed Implementation ### 1. ForwardAuth Guest Ingress (`server/routes/auth_forward.ts`) - Update the user account status validation (around line 120): - Permit `user.account_status === "active" || user.account_status === "guest"`. - Update the grant resolution check (around line 128): - Check if `auth.customScopes` contains `app:${appRecord.name}`. - If matched, set `grantRole = "viewer"` (or the role defined in scopes) and allow ingress with injected `X-Forwarded-*` headers. ### 2. Launchpad Guest Scopes (`ui/db_queries.ts` & `ui/mod.ts`) - Update `getDashboardApps(userId: string, isAdmin: boolean, customScopes?: string[])`: - If `customScopes` contains items formatted as `app:`, query the `apps` table for those app names. - Return the app records with `role: "Guest (Viewer)"`. - In `ui/mod.ts` under `/dashboard`: Pass `auth.customScopes` to `getDashboardApps`. ### 3. Join Audit Logging (`server/routes/events.ts`) - In `POST /api/join` (around line 265): - Call `auditWrapper.auditLog(guestUuid, "event_seat_claimed", event.id, { eventName: event.name, slug: event.slug, seatNumber: event.seats_claimed }, getClientIp(c))` - Ensures all guest claims are captured in the Merkle audit ledger. ### 4. Unit & Integration Tests - In `server/tests/forward_auth.test.ts`: - Add test: `Tier 1 & 2: GET /api/forward-auth - Guest session with app scope allowed`. - Add test: `Tier 1 & 2: GET /api/forward-auth - Guest session without app scope rejected (403)`. - In `server/tests/events.test.ts`: - Verify that `POST /api/join` triggers `event_seat_claimed` audit event.