docs(tasks): add and format phase 1, 2, and 3 task specifications from jules
This commit is contained in:
parent
cc38815867
commit
1ef1125b4a
@ -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:<ip>` (limit: 5 per 60s) and `ratelimit:join:success:<ip>` (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_<event.slug>_%`).
|
|
||||||
- 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.
|
|
||||||
@ -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:<ip>`
|
||||||
|
(limit: 5 per 60s) and `ratelimit:join:success:<ip>` (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_<event.slug>_%`).
|
||||||
|
- 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.
|
||||||
Loading…
x
Reference in New Issue
Block a user