From a194844309deb5b53e3d808450238957986b44d3 Mon Sep 17 00:00:00 2001 From: Tyler Gillispie Date: Wed, 26 Aug 2026 20:22:39 -0700 Subject: [PATCH] docs(tasks): add Phase 5 Sessions UI overhaul, slide-over guest drawer, and revoke fix task --- ...ions-and-guest-drawer-overhaul-2023.ph5.md | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 tasks/new/2026-0826.05.gem.feat.sessions-ui.sessions-and-guest-drawer-overhaul-2023.ph5.md diff --git a/tasks/new/2026-0826.05.gem.feat.sessions-ui.sessions-and-guest-drawer-overhaul-2023.ph5.md b/tasks/new/2026-0826.05.gem.feat.sessions-ui.sessions-and-guest-drawer-overhaul-2023.ph5.md new file mode 100644 index 0000000..d397ec2 --- /dev/null +++ b/tasks/new/2026-0826.05.gem.feat.sessions-ui.sessions-and-guest-drawer-overhaul-2023.ph5.md @@ -0,0 +1,96 @@ +# 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.