auth-yes/tasks/new/2026-0827.04.gem.feat.ui.expired-events-archive-and-guest-telemetry-1042.md

4.8 KiB

TASK METADATA

  • Target Files:
    • server/routes/events.ts
    • ui/components/sessions/EventCockpitDeck.tsx
    • ui/components/sessions/EventGuestsDrawer.tsx
    • ui/components/sessions/SessionsScript.tsx
    • ui/components/SessionsPage.tsx
    • server/tests/events.test.ts
    • ui/ui_scripts.test.ts
  • Core Objective: Clean up the Sessions & Events dashboard by archiving expired passes into a collapsible <details> accordion with a 1-click [ 🔄 Reopen (+1h) ] action, and enrich the Guest Drawer with real-time attendee telemetry and activity logs.
  • Dependencies: None.
  • Additional Important Notes:
    • Must remain 100% pure React-free Hono SSR JSX.
    • Distinguish between naturally expired events (expires_at < NOW(), is_active = TRUE, reopenable) vs manually terminated events (is_active = FALSE, permanent archive).

2. Architectural Considerations & Risks

Risks

  1. Dashboard Clutter & Information Overload: As organizers host dozens of workshops over weeks, active and dead events pile up on the main screen, pushing active management tools below the fold.
    • Mitigation: Partition the SQL query and SSR view into two decks: activePasses (top priority grid/compact cards) and expiredPasses (collapsed under a clean <details> drawer showing count [ 📁 Expired Passes (N) ]).
  2. Re-opening State Ambiguity: If an organizer re-opens an event that expired 3 days ago, adding 1 hour via expires_at + interval '1h' leaves it in the past.
    • Mitigation: Use SET expires_at = GREATEST(expires_at, NOW()) + interval '1 hour' in PostgreSQL to guarantee the event opens immediately for 60 minutes from the moment clicked.
  3. Telemetry Performance in Large Guest Drawers: Querying full session activity logs for 100+ attendees could slow down GET /api/events/:id/attendees.
    • Mitigation: Select only last_activity_action, last_activity_at, and is_agent joined directly on sessions indexed by user_id.

Alternatives

  • Permanent Deletion of Expired Events: We considered automatically dropping expired events from the database. However, organizers frequently need to audit past workshop attendees or re-open events that ran over schedule. Keeping expired passes in an archived state maintains audit integrity.

3. Proposed Implementation

Phase 1: Split Active vs. Expired Events Query (ui/components/SessionsPage.tsx)

  1. Update event_passes query in SessionsPage.tsx:
    • Split passes into activeEvents = eventPasses.filter(e => e.is_active && (!e.expires_at || new Date(e.expires_at) > new Date())).
    • expiredEvents = eventPasses.filter(e => !e.is_active || (e.expires_at && new Date(e.expires_at) <= new Date())).
  2. Pass both arrays into EventCockpitDeck.tsx.

Phase 2: Collapsible Expired Deck & 1-Click Reopen (ui/components/sessions/EventCockpitDeck.tsx)

  1. Active Deck:
    • Render active events in standard Grid or 2-Row Compact view.
  2. Archived Deck ([ 📁 Expired Passes (N) ]):
    • Render a native <details> element below the active deck.
    • For each expired pass with is_active = TRUE, display an amber/gray card with an instant [ 🔄 Reopen (+1h) ] button.
    • For manually ended events (is_active = FALSE), show a muted [ Terminated ] badge without a reopen button.
  3. Client Script Handler (SessionsScript.tsx):
    • Add reopenEvent(eventId) calling POST /api/events/:id/extend with { extendHours: 1 }.
    • Dynamically transition the card or reload to place it back into the active deck.

Phase 3: Rich Attendee Telemetry in Guest Drawer (ui/components/sessions/EventGuestsDrawer.tsx)

  1. Backend Payload Enrichment (server/routes/events.ts):
    • In GET /api/events/:id/attendees, select:
      • s.last_activity_at
      • s.last_activity_action (e.g. ForwardAuth Ingress (ed-droid), API Token Read)
      • s.is_agent
  2. UI Card Formatting:
    • On each attendee card in the drawer, render:
      • Header: Seat #[N] + 🟢 Active / ⏸️ Paused badge + inline [ 🗑️ Revoke ].
      • Line 1 (Inverted Join Time): Joined Today · 2:15 PM · [ Active 1h 45m ].
      • Line 2 (Action Telemetry): Last Action: ForwardAuth (ed-droid) · 2m ago · 💻 Web (with device icon or agent robot emoji if is_agent = true).

Phase 4: Quality Gates & Verification

  1. Unit tests in server/tests/events.test.ts:
    • Test reopening naturally expired events with GREATEST(expires_at, NOW()) + 1h.
    • Test telemetry fields in /attendees endpoint.
  2. UI syntax tests in ui/ui_scripts.test.ts.
  3. Run deno fmt, deno task lint, deno task check, and deno test -A --no-check.