# TASK METADATA - **Target Files:** `server/routes/sessions.ts`, `server/routes/events.ts`, `ui/components/SessionsPage.tsx`, `ui/components/sessions/EventCockpitDeck.tsx`, `ui/components/sessions/EventAttendeesDrawer.tsx` (refactored/renamed to `EventGuestsDrawer.tsx`), `ui/components/sessions/SessionDeck.tsx`, `ui/components/sessions/SessionTable.tsx`, `ui/components/sessions/SessionsScript.tsx`, `server/tests/events.test.ts`, `server/tests/scopes.test.ts`, `ui/ui_scripts.test.ts` - **Core Objective:** Implement Phase 5 Overhaul: Fix backend attendee session revocation permission checks, build a true fixed slide-over Guest Drawer, standardize dynamic countdown pills, add multi-event compact density toggle, and clean up page/session visual hierarchy. - **Dependencies:** None. - **Additional Important Notes:** Must remain 100% pure React-free Hono SSR JSX. All client interactions in `SessionsScript.tsx` must use native vanilla JavaScript DOM APIs. --- ## 2. Architectural Considerations & Risks - **Risks:** - **Zero-Trust Revocation Leakage:** When allowing event creators to delete/revoke attendee sessions via `DELETE /api/sessions/:id`, ensure the query strictly verifies that the session belongs to a guest user claimed under an event pass created by `auth.userId` (or that caller is global admin). Never allow arbitrary session deletions across different event creators. - **DOM Stacking & Focus Trapping:** A fixed slide-over drawer must properly layer (`z-index: 1050`) over the background page and support backdrop dismissal and `Escape` key capture without disrupting background table states. - **Mobile Density Regressions:** Ensure the mobile slide-up bottom sheet does not block necessary viewport scrolling or clip action buttons on small mobile viewports (320px–375px). - **Alternatives:** - _In-Page Expandable Row vs. Fixed Slide-Over Panel:_ In-page expandable cards cause massive vertical jumping and layout disruption when 5–10 events are active. A dedicated fixed slide-over drawer (right panel on desktop, bottom sheet on mobile) provides isolated context, independent scrolling, and a pinned summary header without disturbing the background dashboard. --- ## 3. Proposed Implementation ### Phase 1: Backend Revocation Permission Fix (`server/routes/sessions.ts`) 1. **Authorize Event Creators in `DELETE /api/sessions/:id`:** - Update `DELETE /api/sessions/:id` to check whether the target session is owned by `auth.userId`, or if caller is `isGlobalAdmin`, OR if the session belongs to a guest user of an event pass created by `auth.userId`: ```sql SELECT s.id FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.id = ${targetSessionId} AND ( s.user_id = ${auth.userId} OR ${isAdmin} OR EXISTS ( SELECT 1 FROM event_passes ep WHERE ep.created_by = ${auth.userId} AND u.username LIKE 'guest_' || ep.slug || '_%' ) ) ``` - If found, delete the session from Valkey cache (`valkey.del`) and PostgreSQL (`DELETE FROM sessions WHERE id = ${targetSessionId}`), logging the audit event. - Return `{ success: true }`. ### Phase 2: Page Hierarchy & Section Titles (`ui/components/SessionsPage.tsx`) 1. **Page Title:** - Update top `

` in `SessionsPage.tsx` from `Active Sessions & Passes` to **`Sessions & Passes`**. 2. **Missing Section Headings:** - Section 1: `

Event Passes

` (with compact density toggle). - Section 2: Add a prominent `

Sessions

` heading directly above `SessionTable` and `SessionDeck` with subtitle _"Direct device logins, passkey authentications, and delegated agent tokens."_ ### Phase 3: True Fixed Slide-Over Panel (`EventGuestsDrawer.tsx` & `SessionsScript.tsx`) 1. **Drawer Component Overhaul (`ui/components/sessions/EventAttendeesDrawer.tsx` -> `EventGuestsDrawer.tsx`):** - Refactor the component from an in-line `
` into a fixed slide-over overlay: - **Desktop:** `position: fixed; top: 0; right: 0; width: 420px; height: 100vh; background: var(--surface-card); box-shadow: var(--shadow-lg); z-index: 1050; display: flex; flex-direction: column;` - **Mobile:** Full-width slide-up bottom sheet (`width: 100vw; height: 80vh; bottom: 0; right: 0; border-radius: 16px 16px 0 0;`). - **Backdrop:** Dimmed backdrop overlay (`position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1040;`) closing on click. 2. **Pinned Contextual Header:** - **Title:** `

[Event Name] Guests

` - **Subheader Context Bar:** `
Event Pass · [N] / [Max] Claimed Seats · ⏳ [Xh Ym left] · (Expires [Time])
` - **Close Button:** Accessible close button in top right. 3. **Streamlined Roster Rows (`SessionsScript.tsx`):** - Discard repeated static expiration timestamps from individual rows. - Render clean, distinct cards for each guest seat: - **Left:** `Seat #[N]` (`guest__`) + relative join timestamp (`Joined 5m ago`). - **Status Badge:** `🟢 Active` / `⏸️ Paused`. - **Right Actions:** Compact `[ ⏸️ Pause ]` / `[ ▶️ Resume ]` toggle and `[ 🗑️ Revoke ]` trigger. 4. **Standardize Terminology:** - Use **`Event Guests`** and **`Claimed Seats`** across all drawer titles, buttons (`[ 👥 Manage Guests (N) ]`), and notices. ### Phase 4: Dynamic Countdown Standardization & Density Polish (`EventCockpitDeck.tsx`, `SessionDeck.tsx`, `SessionTable.tsx`) 1. **Standardized Countdown Pill:** - Create a reusable countdown formatter rendering: `⏳ 2h 45m left · (Expires 10:39 PM)` (or `⏳ 29d left · (Expires Sep 25)`). - Dynamic status coloring: **Green** (healthy) -> **Amber** (<1h remaining) -> **Red** (expired). - Apply consistently across Event Pass Cards and the Sessions Table/Deck. 2. **Multi-Event Compact Density Toggle (`EventCockpitDeck.tsx`):** - Add a `[ 🗂️ Grid ]` / `[ 📋 Compact ]` density toggle at the top of the `Event Passes` section. - In **Compact Mode**, collapse each event card into a sleek 1-row summary strip (`Title · 🟢 Active · ⏳ 2h 45m left · 12/50 Seats · PIN: 749-123 · [ 👥 Guests (12) ] · [ ▸ Details ]`), fitting 10+ active events in a single screen. 3. **Mobile Session Card Optimization (`SessionDeck.tsx`):** - Remove the dedicated full-width bottom row on remote session cards. - Move `[ 🗑️ Revoke ]` inline into the top card header row next to the status badge as a compact button (`btn-outline-danger`), reducing card height by 50% and fitting 4–5 more sessions per screen. ### Phase 5: Quality Gates & Testing 1. **Unit Tests (`server/tests/events.test.ts` & `scopes.test.ts`):** - Test event host revoking a guest attendee session via `DELETE /api/sessions/:id` succeeds (200 OK). - Test non-owner unauthorized user attempting to revoke an attendee session is rejected (404/403). - Test guest list API returns active claimed seats. 2. **Hermetic UI Validation (`ui/ui_scripts.test.ts`):** - Verify all vanilla JavaScript drawer controllers, density toggles, and countdown scripts in `SessionsScript.tsx` parse and evaluate cleanly with zero syntax errors. 3. **Formatting & Linting:** - Ensure `deno fmt`, `deno task lint`, `deno task check`, and `deno test --allow-all` execute with 100% green status.