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