# TASK METADATA - **Target Files:** - `server/db.ts` - `server/routes/events.ts` - `server/routes/sessions.ts` - `server/routes/forward_auth.ts` - `ui/components/events/VouchingModal.tsx` - `ui/components/sessions/EventGuestsDrawer.tsx` - `ui/components/sessions/SessionsScript.tsx` - `server/tests/vouching.test.ts` - **Core Objective:** Implement a decentralized Peer-to-Peer (P2P) Vouching Web of Trust for high-security events, where joining guests enter a quarantined read-only state until verified by a peer or host via QR/Emoji pairing, with recursive cascade revocation. - **Dependencies:** - Existing `event_passes` schema and `users.event_pass_id` relational linking. - Valkey L1/L2 cache for real-time session state propagation. - **Additional Important Notes:** - Must remain opt-in per event via `require_vouching BOOLEAN DEFAULT FALSE`. - UI must remain 100% React-free Hono SSR JSX with vanilla JavaScript DOM state manipulation. --- ## 2. Architectural Considerations & Risks ### Risks 1. **Vouching Graph Cycles & Endless Loops:** If attendee A vouches for B, B vouches for C, and C attempts to vouch for A, cyclical graphs could corrupt hierarchy metrics or create infinite loops during cascade revocation. - _Mitigation:_ Enforce an acyclic tree constraint. A user can only be vouched for once (setting an immutable `vouched_by UUID` pointing to their verified parent). Vouchers must already be in an `active` (non-quarantined) state. 2. **Cascade Revocation Overhead & Blast Radius:** If an organizer revokes a rogue voucher at the root of a large subtree, revoking dozens of downstream guest sessions could block the event loop or leave orphaned cache records. - _Mitigation:_ Use a PostgreSQL Recursive Common Table Expression (CTE) to fetch all downstream descendant session IDs in a single atomic query (`WITH RECURSIVE subordinates AS (...)`), followed by bulk atomic cache eviction in Valkey using pipelined `UNLINK`. 3. **UX Friction in Standard Workshops:** Mandating vouching for open public demos or casual workshops adds unnecessary friction. - _Mitigation:_ Make P2P vouching an opt-in toggle (`require_vouching`) in the `[ Delegate Session ]` creation drawer. ### Alternatives - **Centralized Host-Only Approval Queue:** Instead of P2P vouching, all attendees could wait in a lobby for the host to click "Approve". While simpler, this creates an operational bottleneck for workshops with 50+ attendees. P2P vouching allows any already-admitted participant to onboard their neighbor, enabling rapid, distributed verification. - **WebRTC / Bluetooth Proximity:** We considered WebRTC or WebBluetooth for physical co-location verification. However, browser support and permission prompts make this fragile. A 3-emoji visual sequence + 1-click QR code camera scan provides instant, high-friction-to-bots physical co-presence verification with zero native permission dependencies. --- ## 3. Proposed Implementation ### Phase 1: Database Schema & Entity Relationships (`server/db.ts`) 1. Add vouching metadata columns to `event_passes`: - `require_vouching BOOLEAN DEFAULT FALSE` - `vouch_depth_limit INT DEFAULT 2` (0 = host-only, 1 = direct guests only, 2+ = transitive) 2. Add verification tracking to `users`: - `is_quarantined BOOLEAN DEFAULT FALSE` - `vouched_by UUID REFERENCES users(id) ON DELETE SET NULL` - `vouched_at TIMESTAMP WITH TIME ZONE` 3. Add ephemeral vouching challenge table `vouch_challenges`: - `id UUID PRIMARY KEY DEFAULT gen_random_uuid()` - `target_user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE` - `event_id UUID NOT NULL REFERENCES event_passes(id) ON DELETE CASCADE` - `emoji_sequence TEXT NOT NULL` (e.g. `🚀-🦊-⚡`) - `pairing_code TEXT UNIQUE NOT NULL` (6-char alphanumeric code or QR token) - `created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()` - `expires_at TIMESTAMP WITH TIME ZONE NOT NULL` ### Phase 2: Ingress Quarantine & Verification API (`server/routes/events.ts`) 1. **Quarantined Ingress:** - In `POST /api/join` and `GET /join/:slug`, if `event.require_vouching = TRUE`, set `users.is_quarantined = TRUE` and tag the session with custom scope `['guest:quarantined']`. - Issue a `vouch_challenge` returning the 3-emoji sequence, QR payload, and pairing code. 2. **ForwardAuth Guard:** - In `server/routes/forward_auth.ts`, check if the session contains `guest:quarantined`. If quarantined, block access to internal apps (return 403 or redirect to `/vouch/pending`). 3. **Vouching Endpoints:** - `POST /api/events/:id/vouch/verify`: - Authenticated voucher submits the 3-emoji sequence or scans the QR pairing token. - Verify the voucher is an active (non-quarantined) participant of the same event. - Check `vouch_depth_limit`. - Atomically update `users.is_quarantined = FALSE`, set `users.vouched_by = voucher.id`, delete the challenge, and broadcast session upgrade to Valkey. ### Phase 3: Recursive Cascade Revocation (`server/routes/sessions.ts`) 1. Refactor `DELETE /api/sessions/:id`: - If the target session belongs to a guest user who has vouched for others, execute a recursive CTE query: ```sql WITH RECURSIVE tree AS ( SELECT id, event_pass_id FROM users WHERE id = ${targetUserId} UNION ALL SELECT u.id, u.event_pass_id FROM users u INNER JOIN tree t ON u.vouched_by = t.id ) SELECT s.id as session_id, t.id as user_id FROM sessions s JOIN tree t ON s.user_id = t.id; ``` - Delete all discovered sessions in PostgreSQL and evict all matching keys from Valkey. ### Phase 4: UI & Mobile Pairing Interface 1. **Attendee Waiting Screen (`ui/components/events/QuarantineLobby.tsx`):** - Render large high-contrast 3-emoji sequence and QR code: "Show this to the workshop host or an admitted attendee to unlock full access". - Poll or listen for activation event via SSE/fetch. 2. **Voucher Action Modal (`ui/components/events/VouchingModal.tsx`):** - Admitted attendees see a `[ 🤝 Vouch for Peer ]` button in their top bar or Guest Drawer. - Opens simple camera QR scanner or 3-emoji selector grid to confirm the peer in front of them. 3. **Guest Drawer Web of Trust Tree:** - In `EventGuestsDrawer.tsx`, show vouching tree indentation / badge (`Vouched by Tyler G`). ### Phase 5: Quality Gates & Integration Testing 1. Authored unit and integration tests in `server/tests/vouching.test.ts`: - Verify unvouched attendees cannot access ForwardAuth-protected endpoints. - Verify valid emoji/QR verification lifts quarantine immediately. - Verify cascading revocation cleans up all child and grandchild sessions recursively. 2. Run `deno fmt`, `deno task lint`, `deno task check`, and `deno test -A --no-check`.