Created a detailed Markdown task specification in `tasks/new/` for Phase 4 of the event system overhaul, outlining the database updates for session pausing, API endpoints for live controls, and UI enhancements for the attendee slide-out drawer based on provided architectural guidance. Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
5.9 KiB
5.9 KiB
TASK METADATA
- Target Files:
server/db.ts,server/routes/events.ts,server/routes/sessions.ts,server/auth-session.ts,server/middleware.ts(if needed forauth_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.tsxmust use pure vanilla JavaScript for DOM manipulation.is_pausedlogic must apply both to Postgres and the Valkey caching layer for immediate403 Forbiddenevaluation 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: truemerged 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 FALSEcolumn to both thesessionsandevent_passestables. The migration logic inserver/db.tsneeds soft-ignores viatry-catchto avoid crashing if run repeatedly. - DOM Complexity: We are introducing an
EventAttendeesDrawerwhich slides out over the interface. Existing strict DOM bindings must not be broken. Use accessible semantic markup and clear IDs.
- Caching Desync: When pausing a session, updating PostgreSQL is
insufficient; the corresponding Valkey session object must immediately have
-
Alternatives:
- Adding
event_idtosessions: While more relational, it introduces a schema migration and foreign key complexity for an ephemeral guest. Leveraging the existing deterministicusernameprefix for attendee querying keeps the schema decoupled and is highly efficient via standard SQLLIKE.
- Adding
3. Proposed Implementation
Phase 1: Database & Backend Endpoints
- 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.
- Inject
- Session Pausing Logic (
server/routes/sessions.ts& Auth/Middleware Layer):- Add
POST /api/sessions/:id/pauseto toggleis_paused. - Update the PostgreSQL
sessionsrecord. - Fetch the session from Valkey, merge
is_paused: true|false, and re-serialize to Valkey. - Ensure the edge auth check (
server/auth-session.tsor forward-auth middleware) immediately returns403 Forbidden: Session Paused by Hostifis_paused === true.
- Add
- Event Operational Controls (
server/routes/events.ts):- Add
POST /api/events/:id/rotate-pin: Generate a new 6-digit PIN, updateevent_passes.pin_code, and return the new PIN. Existing sessions remain untouched. - Add
POST /api/events/:id/expand: Accept{ addSeats }, executeUPDATE event_passes SET max_seats = max_seats + $1 WHERE id = $2, and return the updated capacity.
- Add
- 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.
- Add
Phase 2: Event Deck Polish (ui/components/sessions/EventCockpitDeck.tsx)
- Countdown & UI Cleanup:
- Add dynamic
⏳ Xh Ym leftlogic 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.
- Add dynamic
- 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 andaria-label.
- Add a
Phase 3: Slide-Out Attendee Drawer (ui/components/sessions/EventAttendeesDrawer.tsx)
- 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 ].
- Create a new reusable drawer
Phase 4: Client Logic Updates (ui/components/sessions/SessionsScript.tsx)
- 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).
- Implement
Phase 5: Quality Gates
- Run
deno fmtanddeno task lintacross all changed files. - Verify all API behaviors via isolated unit tests if applicable, ensuring
deno test -A --unstable-ffipasses. - Validate client-side UI script syntax using the hermetic validation present
in
ui/ui_scripts.test.ts.