auth-yes/tasks/new/2026-0826.01.jul.story.arch.event-delegation-and-session-ux-overhaul-1440.ph1.md

3.1 KiB

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:<appName> 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:<appName> 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:<appName>, 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.