# 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*
