# 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 `
` 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 `
` 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 `
` 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`.