auth-yes/tasks/new/2026-0826.05.gem.feat.sessions-ui.sessions-and-guest-drawer-overhaul-2023.ph5.md

97 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 (320px375px).
- **Alternatives:**
- *In-Page Expandable Row vs. Fixed Slide-Over Panel:* In-page expandable cards cause massive vertical jumping and layout disruption when 510 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 `<h1>` in `SessionsPage.tsx` from `Active Sessions & Passes` to **`Sessions & Passes`**.
2. **Missing Section Headings:**
- Section 1: `<h2>Event Passes</h2>` (with compact density toggle).
- Section 2: Add a prominent `<h2>Sessions</h2>` 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 `<div class="card">` 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:** `<h2 id="guestDrawerTitle" style="margin: 0; font-size: 1.25rem;">[Event Name] Guests</h2>`
- **Subheader Context Bar:** `<div id="guestDrawerContext" style="font-size: 0.8rem; color: var(--text-secondary); margin-top: 0.25rem;">Event Pass · [N] / [Max] Claimed Seats · ⏳ [Xh Ym left] · (Expires [Time])</div>`
- **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_<slug>_<N>`) + 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 45 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.