68 lines
2.9 KiB
Markdown
68 lines
2.9 KiB
Markdown
# Phase 7: Attendee Relational Decoupling & Immutable Identity
|
|
|
|
## 1. Context & Rationale
|
|
|
|
Currently, guest attendee sessions are bound to their originating event via
|
|
brittle string matching on `users.username` (e.g.,
|
|
`WHERE username LIKE 'guest_' || ep.slug || '_%'`). This creates two major
|
|
architectural flaws:
|
|
|
|
1. **Rotation Breakage:** If an event host rotates the event's ingress PIN/slug
|
|
(e.g., `deno-lab-1a2b` to `deno-lab-9x8z`), the backend loses track of
|
|
previously joined guests because their usernames retain the old slug suffix.
|
|
2. **Unwieldy Data:** Guest usernames inherit the full event slug, leading to
|
|
massive, unreadable usernames in logs and the database (e.g.,
|
|
`guest_annual-cyber-security-training-workshop-4f8x_12`).
|
|
|
|
## 2. Objective
|
|
|
|
Implement a robust **"A+B Architecture"** to permanently decouple guest session
|
|
lifecycle from transient URL slugs:
|
|
|
|
- **Option A (Relational Integrity):** Link guests directly to the Event UUID
|
|
via a strict Foreign Key (`event_pass_id`).
|
|
- **Option B (Immutable Identity):** Mint short, deterministic, and immutable
|
|
usernames using the Event UUID prefix.
|
|
|
|
## 3. Scope & Acceptance Criteria
|
|
|
|
### 3.1 Database Migration (`server/db.ts`)
|
|
|
|
- [ ] Add column:
|
|
`ALTER TABLE users ADD COLUMN IF NOT EXISTS event_pass_id UUID REFERENCES event_passes(id) ON DELETE CASCADE;`
|
|
- [ ] Ensure backward compatibility with existing standalone users (column
|
|
should be nullable, as admins/owners won't have an `event_pass_id`).
|
|
|
|
### 3.2 Immutable Username Minting (`server/routes/events.ts`)
|
|
|
|
- [ ] In `POST /api/join`: Change guest username generation from
|
|
`guest_${event.slug}_${seat}` to
|
|
`guest_${event.id.split('-')[0]}_${seat}`.
|
|
- [ ] In `POST /api/join`: Insert `event.id` into the new `event_pass_id` column
|
|
for the newly minted user.
|
|
|
|
### 3.3 Query Refactoring (Zero String Parsing)
|
|
|
|
- [ ] **`GET /api/events/:id/attendees`**: Refactor the query to use
|
|
`WHERE u.event_pass_id = ${eventId}`.
|
|
- [ ] **`POST /api/events/:id/extend`**: Refactor the query to target sessions
|
|
belonging to `u.event_pass_id = ${eventId}`.
|
|
- [ ] **`POST /api/events/:id/end`**: Refactor the revocation query to target
|
|
`u.event_pass_id = ${eventId}`.
|
|
- [ ] **`DELETE /api/sessions/:id`**: Refactor the ownership check to verify
|
|
`u.event_pass_id = ${eventId}` instead of string parsing.
|
|
|
|
### 3.4 Quality Gates
|
|
|
|
- [ ] Run `deno fmt`, `deno task lint`, `deno task check`.
|
|
- [ ] All 67+ backend tests must pass. (Update `server/tests/events.test.ts` to
|
|
mock/handle the new `event_pass_id` column and short username generation).
|
|
|
|
## 4. Anti-Patterns to Avoid
|
|
|
|
- **No `LIKE 'guest_%'` queries** anywhere in the backend logic.
|
|
- **No updating usernames on slug rotation.** The
|
|
`POST /api/events/:id/rotate-pin` endpoint should ONLY touch
|
|
`event_passes.slug` and `event_passes.pin_code`, leaving attendees completely
|
|
unaffected.
|