docs(24): capture phase context
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# Phase 24: Public Access & Infrastructure - Context
|
||||
|
||||
**Gathered:** 2026-04-09
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## Phase Boundary
|
||||
|
||||
Remove the login wall from read-only routes so anyone can browse the global item catalog, public setups, and user profiles without logging in. Add rate limiting to all public endpoints. Auth only required for write operations and personal data access.
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## Implementation Decisions
|
||||
|
||||
### Auth Boundary Redesign
|
||||
- **D-01:** Keep `requireAuth` as default middleware on `/api/*`. Expand the existing allowlist of public GET routes that skip auth (current pattern: regex checks in `src/server/index.ts`).
|
||||
- **D-02:** Categories stay auth-gated — they are user-scoped organizational data. Public browsing uses tags (already public via GET `/api/tags`).
|
||||
- **D-03:** Public setup views include the owner's category names as read-only display context (data already returned by GET `/api/setups/:id/public`).
|
||||
|
||||
### Client-Side Routing for Anonymous Users
|
||||
- **D-04:** Expand the `isPublicRoute` check in `__root.tsx` to include catalog routes (`/global-items/*`), public setup views, and the root `/`. Keep login redirect only for truly private routes (`/collection`, `/settings`, `/threads`).
|
||||
- **D-05:** No changes needed for TotalsBar — it's already only shown in collection views, not in the global header.
|
||||
- **D-06:** When an anonymous user attempts a write action (add to collection, create thread, etc.), show an inline popup/modal saying "To manage your own collection, sign in or sign up" with links to both. Do NOT hard-redirect to `/login` — this is hostile to new users who haven't signed up yet.
|
||||
|
||||
### Rate Limiting Strategy
|
||||
- **D-07:** Apply rate limiting to all public GET endpoints. Current rate limiter (`src/server/middleware/rateLimit.ts`) needs new tiers — the existing 5 req/15 min is only appropriate for OAuth.
|
||||
- **D-08:** Same rate limits for authenticated and anonymous users — no exemptions. Tune limits based on real usage data over time.
|
||||
|
||||
### Claude's Discretion
|
||||
- Rate limit numbers: Claude picks appropriate limits per endpoint type (browse, search, detail). Start with reasonable defaults, expect tuning later.
|
||||
|
||||
### Loading Experience for Visitors
|
||||
- **D-09:** Fire-and-forget auth check — render the page immediately, check `/api/auth/me` in the background. Anonymous users see content right away with no spinner or redirect. When auth resolves, UI updates silently (FAB appears, write actions enable).
|
||||
- **D-10:** Show a "Sign in" button in the top-right corner on all public pages for anonymous visitors. When authenticated, replace with the existing user menu.
|
||||
|
||||
</decisions>
|
||||
|
||||
<canonical_refs>
|
||||
## Canonical References
|
||||
|
||||
**Downstream agents MUST read these before planning or implementing.**
|
||||
|
||||
### Auth & Middleware
|
||||
- `src/server/middleware/auth.ts` — Current `requireAuth` implementation (API key, OAuth bearer, OIDC session)
|
||||
- `src/server/middleware/rateLimit.ts` — Current rate limiter (in-memory Map, needs new tiers for public endpoints)
|
||||
- `src/server/index.ts` — Route registration and auth middleware skip logic (lines 121-140)
|
||||
|
||||
### Client Routing & Layout
|
||||
- `src/client/routes/__root.tsx` — Root layout with `isPublicRoute` check, auth loading spinner, login redirect logic
|
||||
- `src/client/hooks/useAuth.ts` — Auth state hook (`useAuth`) used throughout client
|
||||
|
||||
### Requirements
|
||||
- `.planning/REQUIREMENTS.md` — PUBL-01 through PUBL-05, INFR-01
|
||||
|
||||
</canonical_refs>
|
||||
|
||||
<code_context>
|
||||
## Existing Code Insights
|
||||
|
||||
### Reusable Assets
|
||||
- `requireAuth` middleware — well-structured, supports API key + OAuth + OIDC. No changes to its internals needed — just control when it's applied.
|
||||
- `rateLimit` middleware — functional but needs configurable tiers (currently hardcoded 5/15min). Structure is reusable.
|
||||
- `useAuth` hook — returns `{ user, authenticated }`. Already used throughout client for conditional rendering.
|
||||
- `UserMenu` component — exists for authenticated users. Anonymous "Sign in" button will be its counterpart.
|
||||
|
||||
### Established Patterns
|
||||
- Auth skip in `index.ts` uses regex path matching — extend this list for new public routes.
|
||||
- Client `isPublicRoute` is a simple pathname check — extend with additional prefixes.
|
||||
- Public data endpoints already exist: GET `/api/global-items`, GET `/api/tags`, GET `/api/users/:id/profile`, GET `/api/setups/:id/public`.
|
||||
|
||||
### Integration Points
|
||||
- `__root.tsx` line 121-145: Auth loading/redirect logic — needs rework to render immediately instead of spinner-then-redirect.
|
||||
- `FabMenu` visibility already gated on `isAuthenticated` — will naturally hide for anonymous visitors.
|
||||
- Write action buttons across components need to check auth state and show the signup/signin popup instead of the normal action.
|
||||
|
||||
</code_context>
|
||||
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
- The auth-required popup should be welcoming to new users — "sign in **or sign up**" language, not just "log in". The user emphasized that new user experience matters more than returning user convenience, since returning users will be re-authenticated quickly anyway.
|
||||
- Tags are the public taxonomy, categories are the private taxonomy. This distinction should be clear in any public-facing UI.
|
||||
|
||||
</specifics>
|
||||
|
||||
<deferred>
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within phase scope
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 24-public-access-infrastructure*
|
||||
*Context gathered: 2026-04-09*
|
||||
@@ -0,0 +1,122 @@
|
||||
# Phase 24: Public Access & Infrastructure - Discussion Log
|
||||
|
||||
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||
|
||||
**Date:** 2026-04-09
|
||||
**Phase:** 24-public-access-infrastructure
|
||||
**Areas discussed:** Auth boundary redesign, Client-side routing for anonymous users, Rate limiting strategy, Loading experience for visitors
|
||||
|
||||
---
|
||||
|
||||
## Auth Boundary Redesign
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Allowlist public routes | Keep requireAuth as default on /api/*, maintain explicit list of public GET routes that skip auth. Extends current pattern. | ✓ |
|
||||
| Separate route registration | Register public routes BEFORE auth middleware, private routes AFTER. Route order determines auth. | |
|
||||
| Per-route middleware | Remove blanket /api/* auth. Each route file applies requireAuth on its own write endpoints. | |
|
||||
|
||||
**User's choice:** Allowlist public routes (recommended)
|
||||
**Notes:** None
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Yes, make categories public | Categories are structural data — needed for catalog browsing context. | |
|
||||
| No, keep categories auth-gated | Only expose what's strictly required. | |
|
||||
|
||||
**User's choice:** Other — Categories are user-scoped. Unauthenticated users access global items which use tags, not categories. Categories stay private.
|
||||
**Notes:** "the thing is currently all item categories are what the user defines them to be, so if the user isn't authenticated the items they are accessing shouldn't have a category in the first place, instead they have tags, for sorting searching etc"
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Show category names in public view | Include owner's category name as read-only display context in public setup view. | ✓ |
|
||||
| Items without category context | Public setup view shows items with weight/price but no category labels. | |
|
||||
|
||||
**User's choice:** Show category names in public view (recommended)
|
||||
**Notes:** None
|
||||
|
||||
---
|
||||
|
||||
## Client-Side Routing for Anonymous Users
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Expand public route list | Extend isPublicRoute check to include /global-items/*, /setups/*/public, /catalog, and /. Keep login redirect for private routes. | ✓ |
|
||||
| Invert to private route list | List private routes instead; everything else accessible without auth. | |
|
||||
| You decide | Claude picks cleanest approach. | |
|
||||
|
||||
**User's choice:** Expand public route list (recommended)
|
||||
**Notes:** None
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Hide TotalsBar for anonymous | No TotalsBar when not authenticated. Public pages show their own header. | |
|
||||
| Show a simplified public header | Replace TotalsBar with minimal header for anonymous visitors. | |
|
||||
| Keep TotalsBar with login CTA | Replace stats with sign-in message. | |
|
||||
|
||||
**User's choice:** Other — TotalsBar is already only in collection views, not in the header. No changes needed.
|
||||
**Notes:** "there should only be a totals bar in the collection views etc, we should have removed the one from the header already, so no need there"
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Redirect to /login with return URL | Standard redirect-based pattern. | |
|
||||
| Show inline login prompt | Show modal/toast instead of navigating away. Keeps context visible. | ✓ |
|
||||
| You decide | Claude picks best UX pattern. | |
|
||||
|
||||
**User's choice:** Show inline login prompt — but specifically with "sign in or sign up" messaging, not just login.
|
||||
**Notes:** "we should show a popup saying to manage your own collection you need to sign in or sign up, because while a direct sending to signin might be a better flow for already signed up users it is terrible for new users, which i think matters more"
|
||||
|
||||
---
|
||||
|
||||
## Rate Limiting Strategy
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| 100 req/min per IP | Generous for normal browsing, blocks scraping. Standard for public APIs. | |
|
||||
| 60 req/min per IP | More conservative. | |
|
||||
| You decide | Claude picks appropriate limits per endpoint type. | ✓ |
|
||||
|
||||
**User's choice:** You decide
|
||||
**Notes:** None
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Exempt authenticated users | Authenticated users trusted, rate limiting for anonymous abuse. | |
|
||||
| Higher limits for authenticated | Still rate-limit but at 5-10x anonymous limit. | |
|
||||
| Same limits for everyone | Simplest, no distinction. | ✓ |
|
||||
|
||||
**User's choice:** Same limits for everyone
|
||||
**Notes:** "i feel like there is no diff, authenticated users could still spam the api, we should find a good sweet spot for the amount of calls that are being made, i think this is something that will change with experience"
|
||||
|
||||
---
|
||||
|
||||
## Loading Experience for Visitors
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Fire-and-forget auth check | Render page immediately, check auth in background. Anonymous users see content right away. | ✓ |
|
||||
| Fast auth with skeleton | Check auth first but show content skeleton instead of spinner. | |
|
||||
| You decide | Claude picks best approach. | |
|
||||
|
||||
**User's choice:** Fire-and-forget auth check (recommended)
|
||||
**Notes:** None
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Login button in top-right corner | Simple 'Sign in' link on all public pages. Disappears when authenticated. | ✓ |
|
||||
| No persistent login link | Users find login through write-action popup only. | |
|
||||
| You decide | Claude picks based on navigation patterns. | |
|
||||
|
||||
**User's choice:** Login button in top-right corner (recommended)
|
||||
**Notes:** None
|
||||
|
||||
---
|
||||
|
||||
## Claude's Discretion
|
||||
|
||||
- Rate limit numbers per endpoint type (browse, search, detail)
|
||||
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within phase scope
|
||||
Reference in New Issue
Block a user