From 1ef1125b4ae87593f354e1c43a1c27cab6f68718 Mon Sep 17 00:00:00 2001 From: Tyler Gillispie Date: Wed, 26 Aug 2026 15:06:57 -0700 Subject: [PATCH] docs(tasks): add and format phase 1, 2, and 3 task specifications from jules --- ...ory.events.join-reentry-and-limits-2156.md | 46 ---------- ....events.phase-1-guest-ingress-1400.ph1.md} | 0 ...events.join-reentry-and-limits-2156.ph2.md | 84 +++++++++++++++++++ ...essions-layout-drawer-machine-2156.ph3.md} | 0 4 files changed, 84 insertions(+), 46 deletions(-) delete mode 100644 tasks/new/2026-0826.01.jul.story.events.join-reentry-and-limits-2156.md rename tasks/new/{2026-0826.01.jul.story.events.phase-1-guest-ingress-1400.md => 2026-0826.01.jul.story.events.phase-1-guest-ingress-1400.ph1.md} (100%) create mode 100644 tasks/new/2026-0826.02.jul.story.events.join-reentry-and-limits-2156.ph2.md rename tasks/new/{2026-0826.01.jul.feat.ui.sessions-layout-drawer-machine-2156.md => 2026-0826.03.jul.feat.ui.sessions-layout-drawer-machine-2156.ph3.md} (100%) diff --git a/tasks/new/2026-0826.01.jul.story.events.join-reentry-and-limits-2156.md b/tasks/new/2026-0826.01.jul.story.events.join-reentry-and-limits-2156.md deleted file mode 100644 index 3f8e005..0000000 --- a/tasks/new/2026-0826.01.jul.story.events.join-reentry-and-limits-2156.md +++ /dev/null @@ -1,46 +0,0 @@ -### 1. TASK METADATA - -- **Target Files:** `server/routes/events.ts`, `ui/components/LoginPage.tsx`, `ui/components/RegisterPage.tsx`, `ui/components/EventJoinPage.tsx` -- **Core Objective:** Implement Phase 2 Event Overhaul: Add PIN discovery links, normalize input, apply tiered Valkey rate limiting, and implement NAT-safe idempotent re-entry on join. -- **Dependencies:** `server/middleware.ts` (for getClientIp), `server/ratelimit.ts` (for rate limiting logic). -- **Additional Important Notes:** Frontend changes should mirror backend normalization. Re-entry must seamlessly return an existing active guest session linked to the correct event without incrementing `seats_claimed`. - ---- - -### 2. Architectural Considerations & Risks - -- **Risks:** - - If idempotent re-entry is flawed, returning a mismatched event session could allow access to an event a user didn't register for, or incorrectly redirect them. We must strictly verify the existing session is a guest session belonging to the target event. - - Rate limiting logic might accidentally block legitimate NAT'ed traffic if thresholds are set too low; 5 fail / 3 success per minute per IP should be monitored. - - Normalization on the backend must be implemented securely using robust string replacements to prevent SQL injection or unexpected matching behaviors, especially with PostgreSQL parameterized queries (`sqlWrapper.sql`). - -- **Alternatives:** - - For normalization, instead of just runtime stripping, we could normalize upon creation and store both normalized and display values. However, stripping at runtime with `REPLACE(pin_code, '-', '')` and `LOWER(slug)` is an acceptable and low-friction approach for our scale. - - Rate limiting could use sliding window algorithms, but Valkey-backed fixed windows via the existing `rateLimitWrapper` are more efficient and standard for our stack. - -### 3. Proposed Implementation - -#### Phase 1: Login & Registration Discovery Links -- **File:** `ui/components/LoginPage.tsx` - - Add a "Join with PIN" link next to the existing "Register with Invite" in the footer links section to ensure unauthenticated users can easily discover the join portal. -- **File:** `ui/components/RegisterPage.tsx` - - Add a similar "Join with PIN" link to the footer for consistency across entry points. - -#### Phase 2: Input Normalization (Frontend & Backend) -- **File:** `ui/components/EventJoinPage.tsx` - - Enhance the UI script to tolerate input formatting, naturally handling hyphens, spaces, and case differences during submission, providing immediate visual feedback without rejecting valid raw input (e.g. `241881` vs `241-881`). -- **File:** `server/routes/events.ts` (`POST /api/join` & `GET /join/:slug`) - - Strip whitespace, hyphens, and force lowercase on the incoming code on the backend (`code.trim().replace(/[-\s]/g, '').toLowerCase()`). - - Update the `sqlWrapper` query to match normalized inputs: `WHERE (LOWER(slug) = ${code} OR REPLACE(pin_code, '-', '') = ${code})`. - -#### Phase 3: Anti-DoS Rate Limiting -- **File:** `server/routes/events.ts` (`POST /api/join`) - - Use `getClientIp(c)` from our middleware to determine the client IP address. - - Mount tiered Valkey rate limits using the keys `ratelimit:join:fail:` (limit: 5 per 60s) and `ratelimit:join:success:` (limit: 3 per 60s). - - Apply the rate limiting logic prior to executing any database queries to prevent database DoS on brute-force PIN attempts. - -#### Phase 4: NAT-Safe Idempotent Re-entry -- **File:** `server/routes/events.ts` (`POST /api/join`) - - Before claiming a seat and generating a new session, check for an existing valid user session using `getAuthenticatedUser(c)`. - - If a valid session exists, query the database to determine if the `user_id` is linked to a guest account for the target event (e.g., username matches `guest__%`). - - If the user is already a guest of this event, bypass the `seats_claimed + 1` update and early-return `{ success: true, sessionId, redirectUrl }`, keeping the existing session intact. \ No newline at end of file diff --git a/tasks/new/2026-0826.01.jul.story.events.phase-1-guest-ingress-1400.md b/tasks/new/2026-0826.01.jul.story.events.phase-1-guest-ingress-1400.ph1.md similarity index 100% rename from tasks/new/2026-0826.01.jul.story.events.phase-1-guest-ingress-1400.md rename to tasks/new/2026-0826.01.jul.story.events.phase-1-guest-ingress-1400.ph1.md diff --git a/tasks/new/2026-0826.02.jul.story.events.join-reentry-and-limits-2156.ph2.md b/tasks/new/2026-0826.02.jul.story.events.join-reentry-and-limits-2156.ph2.md new file mode 100644 index 0000000..d1ead95 --- /dev/null +++ b/tasks/new/2026-0826.02.jul.story.events.join-reentry-and-limits-2156.ph2.md @@ -0,0 +1,84 @@ +### 1. TASK METADATA + +- **Target Files:** `server/routes/events.ts`, `ui/components/LoginPage.tsx`, + `ui/components/RegisterPage.tsx`, `ui/components/EventJoinPage.tsx` +- **Core Objective:** Implement Phase 2 Event Overhaul: Add PIN discovery links, + normalize input, apply tiered Valkey rate limiting, and implement NAT-safe + idempotent re-entry on join. +- **Dependencies:** `server/middleware.ts` (for getClientIp), + `server/ratelimit.ts` (for rate limiting logic). +- **Additional Important Notes:** Frontend changes should mirror backend + normalization. Re-entry must seamlessly return an existing active guest + session linked to the correct event without incrementing `seats_claimed`. + +--- + +### 2. Architectural Considerations & Risks + +- **Risks:** + - If idempotent re-entry is flawed, returning a mismatched event session could + allow access to an event a user didn't register for, or incorrectly redirect + them. We must strictly verify the existing session is a guest session + belonging to the target event. + - Rate limiting logic might accidentally block legitimate NAT'ed traffic if + thresholds are set too low; 5 fail / 3 success per minute per IP should be + monitored. + - Normalization on the backend must be implemented securely using robust + string replacements to prevent SQL injection or unexpected matching + behaviors, especially with PostgreSQL parameterized queries + (`sqlWrapper.sql`). + +- **Alternatives:** + - For normalization, instead of just runtime stripping, we could normalize + upon creation and store both normalized and display values. However, + stripping at runtime with `REPLACE(pin_code, '-', '')` and `LOWER(slug)` is + an acceptable and low-friction approach for our scale. + - Rate limiting could use sliding window algorithms, but Valkey-backed fixed + windows via the existing `rateLimitWrapper` are more efficient and standard + for our stack. + +### 3. Proposed Implementation + +#### Phase 1: Login & Registration Discovery Links + +- **File:** `ui/components/LoginPage.tsx` + - Add a "Join with PIN" link next to the existing "Register with Invite" in + the footer links section to ensure unauthenticated users can easily discover + the join portal. +- **File:** `ui/components/RegisterPage.tsx` + - Add a similar "Join with PIN" link to the footer for consistency across + entry points. + +#### Phase 2: Input Normalization (Frontend & Backend) + +- **File:** `ui/components/EventJoinPage.tsx` + - Enhance the UI script to tolerate input formatting, naturally handling + hyphens, spaces, and case differences during submission, providing immediate + visual feedback without rejecting valid raw input (e.g. `241881` vs + `241-881`). +- **File:** `server/routes/events.ts` (`POST /api/join` & `GET /join/:slug`) + - Strip whitespace, hyphens, and force lowercase on the incoming code on the + backend (`code.trim().replace(/[-\s]/g, '').toLowerCase()`). + - Update the `sqlWrapper` query to match normalized inputs: + `WHERE (LOWER(slug) = ${code} OR REPLACE(pin_code, '-', '') = ${code})`. + +#### Phase 3: Anti-DoS Rate Limiting + +- **File:** `server/routes/events.ts` (`POST /api/join`) + - Use `getClientIp(c)` from our middleware to determine the client IP address. + - Mount tiered Valkey rate limits using the keys `ratelimit:join:fail:` + (limit: 5 per 60s) and `ratelimit:join:success:` (limit: 3 per 60s). + - Apply the rate limiting logic prior to executing any database queries to + prevent database DoS on brute-force PIN attempts. + +#### Phase 4: NAT-Safe Idempotent Re-entry + +- **File:** `server/routes/events.ts` (`POST /api/join`) + - Before claiming a seat and generating a new session, check for an existing + valid user session using `getAuthenticatedUser(c)`. + - If a valid session exists, query the database to determine if the `user_id` + is linked to a guest account for the target event (e.g., username matches + `guest__%`). + - If the user is already a guest of this event, bypass the `seats_claimed + 1` + update and early-return `{ success: true, sessionId, redirectUrl }`, keeping + the existing session intact. diff --git a/tasks/new/2026-0826.01.jul.feat.ui.sessions-layout-drawer-machine-2156.md b/tasks/new/2026-0826.03.jul.feat.ui.sessions-layout-drawer-machine-2156.ph3.md similarity index 100% rename from tasks/new/2026-0826.01.jul.feat.ui.sessions-layout-drawer-machine-2156.md rename to tasks/new/2026-0826.03.jul.feat.ui.sessions-layout-drawer-machine-2156.ph3.md