This commit finalizes Phase 4 of the Event & Session Overhaul: 1. Implements session pause logic across PostgreSQL schema, Valkey cache, and `auth_forward.ts` edge check (`is_paused`). 2. Implements non-destructive operational endpoints (`/api/events/:id/rotate-pin`, `/api/events/:id/expand`, `/api/events/:id/attendees`) with Zero-Trust Ownership verification. 3. Upgrades existing `end` and `extend` endpoints in `events.ts` to utilize robust Zero-Trust Ownership queries (created_by OR isGlobalAdmin). 4. Creates `EventAttendeesDrawer.tsx` to handle live participant inspection and individual session controls (Pause, Revoke). 5. Updates `EventCockpitDeck.tsx` and `SessionsScript.tsx` to mount and drive the new controls via vanilla JavaScript, respecting zero-framework guidelines. 6. Ensures `deno fmt`, `deno task lint`, `deno task check` and `deno test` execute successfully against the new schema and API guards. Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
124 lines
5.9 KiB
Markdown
124 lines
5.9 KiB
Markdown
# TASK METADATA
|
|
|
|
- **Target Files:** `server/db.ts`, `server/routes/events.ts`,
|
|
`server/routes/sessions.ts`, `server/auth-session.ts`, `server/middleware.ts`
|
|
(if needed for `auth_forward.ts`),
|
|
`ui/components/sessions/EventCockpitDeck.tsx`,
|
|
`ui/components/sessions/EventAttendeesDrawer.tsx`,
|
|
`ui/components/sessions/SessionsScript.tsx`
|
|
- **Core Objective:** Implement Phase 4 of the Event & Session Overhaul by
|
|
adding live attendee management controls, an expandable EventAttendeesDrawer,
|
|
individual session pausing, and operational card controls (Rotate PIN, +5
|
|
Seats).
|
|
- **Dependencies:** None.
|
|
- **Additional Important Notes:** Client scripts in `SessionsScript.tsx` must
|
|
use pure vanilla JavaScript for DOM manipulation. `is_paused` logic must apply
|
|
both to Postgres and the Valkey caching layer for immediate `403 Forbidden`
|
|
evaluation on active sessions.
|
|
|
|
---
|
|
|
|
## 2. Architectural Considerations & Risks
|
|
|
|
- **Risks:**
|
|
- **Caching Desync:** When pausing a session, updating PostgreSQL is
|
|
insufficient; the corresponding Valkey session object must immediately have
|
|
`is_paused: true` merged into its JSON string payload to enforce real-time
|
|
blocks.
|
|
- **Zero-Migration Query Fragility:** The attendee lookup relies on the
|
|
deterministic username format `guest_<slug>_<seatNumber>`. If the slug
|
|
format changes in the future, this lookup may fail. This is accepted as a
|
|
feature to avoid schema migrations for ephemeral associations.
|
|
- **Schema Evolution:** We are adding an `is_paused BOOLEAN DEFAULT FALSE`
|
|
column to both the `sessions` and `event_passes` tables. The migration logic
|
|
in `server/db.ts` needs soft-ignores via `try-catch` to avoid crashing if
|
|
run repeatedly.
|
|
- **DOM Complexity:** We are introducing an `EventAttendeesDrawer` which
|
|
slides out over the interface. Existing strict DOM bindings must not be
|
|
broken. Use accessible semantic markup and clear IDs.
|
|
|
|
- **Alternatives:**
|
|
- _Adding `event_id` to `sessions`:_ While more relational, it introduces a
|
|
schema migration and foreign key complexity for an ephemeral guest.
|
|
Leveraging the existing deterministic `username` prefix for attendee
|
|
querying keeps the schema decoupled and is highly efficient via standard SQL
|
|
`LIKE`.
|
|
|
|
---
|
|
|
|
## 3. Proposed Implementation
|
|
|
|
### Phase 1: Database & Backend Endpoints
|
|
|
|
1. **Schema Updates (`server/db.ts`):**
|
|
- Inject
|
|
`ALTER TABLE sessions ADD COLUMN IF NOT EXISTS is_paused BOOLEAN DEFAULT FALSE`.
|
|
- Inject
|
|
`ALTER TABLE event_passes ADD COLUMN IF NOT EXISTS is_paused BOOLEAN DEFAULT FALSE`.
|
|
2. **Session Pausing Logic (`server/routes/sessions.ts` & Auth/Middleware
|
|
Layer):**
|
|
- Add `POST /api/sessions/:id/pause` to toggle `is_paused`.
|
|
- Update the PostgreSQL `sessions` record.
|
|
- Fetch the session from Valkey, merge `is_paused: true|false`, and
|
|
re-serialize to Valkey.
|
|
- Ensure the edge auth check (`server/auth-session.ts` or forward-auth
|
|
middleware) immediately returns `403 Forbidden: Session Paused by Host` if
|
|
`is_paused === true`.
|
|
3. **Event Operational Controls (`server/routes/events.ts`):**
|
|
- Add `POST /api/events/:id/rotate-pin`: Generate a new 6-digit PIN, update
|
|
`event_passes.pin_code`, and return the new PIN. Existing sessions remain
|
|
untouched.
|
|
- Add `POST /api/events/:id/expand`: Accept `{ addSeats }`, execute
|
|
`UPDATE event_passes SET max_seats = max_seats + $1 WHERE id = $2`, and
|
|
return the updated capacity.
|
|
4. **Attendee List Endpoint (`server/routes/events.ts`):**
|
|
- Add `GET /api/events/:id/attendees`.
|
|
- Perform a deterministic SQL JOIN:
|
|
`SELECT s.*, u.username, u.display_name FROM sessions s JOIN users u ON s.user_id = u.id WHERE u.username LIKE ${'guest_' + event.slug + '_%'} AND s.expires_at > NOW() ORDER BY s.created_at DESC`.
|
|
|
|
### Phase 2: Event Deck Polish (`ui/components/sessions/EventCockpitDeck.tsx`)
|
|
|
|
1. **Countdown & UI Cleanup:**
|
|
- Add dynamic `⏳ Xh Ym left` logic or badge for active passes.
|
|
- Introduce an accessible `<details>` expander for the CLI 1-liner handoff
|
|
string to clean up the card's visual footprint.
|
|
2. **New Controls:**
|
|
- Add a `[ 🔄 Rotate PIN ]` button.
|
|
- Add a `[ 👥 Manage Attendees (N) ]` button to trigger the new slide-out
|
|
drawer, replacing static numbers with actionable links.
|
|
- Add a `[ +5 Seats ]` capacity expansion button.
|
|
- Ensure `[ End Event ]` retains clear visual destructive styling and
|
|
`aria-label`.
|
|
|
|
### Phase 3: Slide-Out Attendee Drawer (`ui/components/sessions/EventAttendeesDrawer.tsx`)
|
|
|
|
1. **Drawer Component:**
|
|
- Create a new reusable drawer
|
|
`<div id="attendeesDrawer" class="drawer-overlay">` following existing
|
|
drawer patterns (e.g., `WorkshopDrawer.tsx`).
|
|
- The drawer content container (`#attendeesDrawerContent`) will display the
|
|
fetched real-time list of attendees for a targeted event.
|
|
- Each row will show `username`, `seat_number`, `time active`, and individual
|
|
controls for `[ Pause ]` and `[ Revoke ]`.
|
|
|
|
### Phase 4: Client Logic Updates (`ui/components/sessions/SessionsScript.tsx`)
|
|
|
|
1. **Action Handlers:**
|
|
- Implement `rotatePin(eventId)` utilizing the new backend endpoint and
|
|
updating the DOM instantly.
|
|
- Implement `expandSeats(eventId, count)` to hit the endpoint and update the
|
|
progress bar/capacity max.
|
|
- Implement `openAttendeesDrawer(eventId, slug)` to trigger the fetch of
|
|
attendees, render the HTML string into `#attendeesDrawerContent`, and slide
|
|
the drawer into view.
|
|
- Implement `toggleSessionPause(sessionId)` to trigger the pause endpoint and
|
|
visually update the attendee row (e.g., strikethrough or badge update).
|
|
|
|
### Phase 5: Quality Gates
|
|
|
|
1. Run `deno fmt` and `deno task lint` across all changed files.
|
|
2. Verify all API behaviors via isolated unit tests if applicable, ensuring
|
|
`deno test -A --unstable-ffi` passes.
|
|
3. Validate client-side UI script syntax using the hermetic validation present
|
|
in `ui/ui_scripts.test.ts`.
|