diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 6dff897..60f849b 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -9,11 +9,11 @@ Requirements for Public Discovery milestone. Each maps to roadmap phases. ### Public Access -- [ ] **PUBL-01**: User can browse the global item catalog without logging in -- [ ] **PUBL-02**: User can view public setups without logging in -- [ ] **PUBL-03**: User can view user profiles without logging in -- [ ] **PUBL-04**: Anonymous visitors see the landing page without auth spinner or redirect -- [ ] **PUBL-05**: Login is only required when user attempts to create/edit/delete their own data +- [x] **PUBL-01**: User can browse the global item catalog without logging in +- [x] **PUBL-02**: User can view public setups without logging in +- [x] **PUBL-03**: User can view user profiles without logging in +- [x] **PUBL-04**: Anonymous visitors see the landing page without auth spinner or redirect +- [x] **PUBL-05**: Login is only required when user attempts to create/edit/delete their own data ### Discovery @@ -116,11 +116,11 @@ Which phases cover which requirements. Updated during roadmap creation. | Requirement | Phase | Status | |-------------|-------|--------| -| PUBL-01 | Phase 24 | Pending | -| PUBL-02 | Phase 24 | Pending | -| PUBL-03 | Phase 24 | Pending | -| PUBL-04 | Phase 24 | Pending | -| PUBL-05 | Phase 24 | Pending | +| PUBL-01 | Phase 24 | Complete | +| PUBL-02 | Phase 24 | Complete | +| PUBL-03 | Phase 24 | Complete | +| PUBL-04 | Phase 24 | Complete | +| PUBL-05 | Phase 24 | Complete | | INFR-01 | Phase 24 | Complete | | CATL-01 | Phase 25 | Pending | | CATL-02 | Phase 25 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index e06e209..d48bc6f 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -68,7 +68,7 @@ **Milestone Goal:** Transform GearBox from a login-first tool into a public-first discovery platform with always-on catalog search and a browsable feed of community content. -- [ ] **Phase 24: Public Access & Infrastructure** - Remove the login wall from read-only routes and add rate limiting to public endpoints +- [x] **Phase 24: Public Access & Infrastructure** - Remove the login wall from read-only routes and add rate limiting to public endpoints (completed 2026-04-10) - [ ] **Phase 25: Catalog Enrichment & Agent Tools** - Add attribution fields to global items, bulk import API, and MCP tools for agent-powered seeding - [ ] **Phase 26: Discovery Landing Page** - Replace the dashboard with a public-first landing page featuring catalog search and community feed @@ -88,7 +88,7 @@ Plans: - [x] 24-01-PLAN.md — Rate limit factory and tiered public endpoint protection -- [ ] 24-02-PLAN.md — Client-side public access (render-first root, auth prompt, setup/catalog guards) +- [x] 24-02-PLAN.md — Client-side public access (render-first root, auth prompt, setup/catalog guards) **UI hint**: yes @@ -144,7 +144,7 @@ Plans: | 21. Item & Catalog Detail Pages | v2.0 | 3/3 | Complete | 2026-04-06 | | 22. Add-from-Catalog & Thread Integration | v2.0 | 2/2 | Complete | 2026-04-06 | | 23. Manual Entry Fallback | v2.0 | 1/1 | Complete | 2026-04-06 | -| 24. Public Access & Infrastructure | v2.1 | 1/2 | In Progress| | +| 24. Public Access & Infrastructure | v2.1 | 2/2 | Complete | 2026-04-10 | | 25. Catalog Enrichment & Agent Tools | v2.1 | 0/TBD | Not started | - | | 26. Discovery Landing Page | v2.1 | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 5655ef5..8da6b43 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,15 +2,15 @@ gsd_state_version: 1.0 milestone: v2.1 milestone_name: Public Discovery -status: executing -stopped_at: Completed 24-01-PLAN.md -last_updated: "2026-04-10T08:08:39.065Z" +status: verifying +stopped_at: Completed 24-02-PLAN.md +last_updated: "2026-04-10T08:11:06.987Z" last_activity: 2026-04-10 progress: total_phases: 6 - completed_phases: 0 + completed_phases: 1 total_plans: 2 - completed_plans: 1 + completed_plans: 2 percent: 0 --- @@ -27,7 +27,7 @@ See: .planning/PROJECT.md (updated 2026-04-09) Phase: 24 (public-access-infrastructure) — EXECUTING Plan: 2 of 2 -Status: Ready to execute +Status: Phase complete — ready for verification Last activity: 2026-04-10 Progress: [░░░░░░░░░░] 0% @@ -62,6 +62,8 @@ v2.1 decisions: - Phase 999.3 (Public Access Auth Model backlog item) is now Phase 24 — PROMOTED - [Phase 24-public-access-infrastructure]: createRateLimit factory pattern for configurable rate limiting per endpoint tier - [Phase 24-public-access-infrastructure]: Browse tier 120/min, detail tier 60/min — same limits for auth and anon users +- [Phase 24]: Both auth prompt CTAs go to /login — Logto handles sign-in and sign-up at the same OIDC endpoint +- [Phase 24]: Soft navigate() replaces hard window.location.href for private route redirect — defers until auth resolves ### Pending Todos @@ -73,6 +75,6 @@ None. ## Session Continuity -Last session: 2026-04-10T08:08:39.063Z -Stopped at: Completed 24-01-PLAN.md +Last session: 2026-04-10T08:11:06.985Z +Stopped at: Completed 24-02-PLAN.md Resume file: None diff --git a/.planning/phases/24-public-access-infrastructure/24-02-SUMMARY.md b/.planning/phases/24-public-access-infrastructure/24-02-SUMMARY.md new file mode 100644 index 0000000..3732fee --- /dev/null +++ b/.planning/phases/24-public-access-infrastructure/24-02-SUMMARY.md @@ -0,0 +1,91 @@ +--- +phase: 24-public-access-infrastructure +plan: 02 +subsystem: client/auth +tags: [public-access, auth-prompt, anonymous-browsing, setup-sharing] +dependency_graph: + requires: [] + provides: [public-route-access, auth-prompt-modal, anonymous-setup-viewing] + affects: [__root.tsx, uiStore, useSetups, useSettings, global-items-detail, setup-detail] +tech_stack: + added: [] + patterns: [zustand-modal-state, conditional-hook-enabled, render-first-auth] +key_files: + created: + - src/client/components/AuthPromptModal.tsx + modified: + - src/client/stores/uiStore.ts + - src/client/hooks/useSetups.ts + - src/client/hooks/useSettings.ts + - src/client/routes/__root.tsx + - src/client/routes/global-items/$globalItemId.tsx + - src/client/routes/setups/$setupId.tsx +decisions: + - Both auth prompt CTA buttons point to /login — Logto handles sign-in and sign-up at the same OIDC endpoint + - usePublicSetup hits /api/setups/:id/public — separate endpoint for anonymous access without auth middleware + - useOnboardingComplete(enabled) guards the settings query — prevents 401 spam for anonymous users + - Soft navigate() replaces hard window.location.href for private route redirect +metrics: + duration_seconds: 258 + completed_date: "2026-04-10" + tasks_completed: 3 + files_changed: 6 +--- + +# Phase 24 Plan 02: Public Access Infrastructure — Client Layer Summary + +Public-first browsing implemented: anonymous visitors see content immediately, write actions show a friendly sign-in/sign-up prompt, and the setup detail page renders read-only for unauthenticated users via a dedicated public API endpoint. + +## Tasks Completed + +| # | Task | Commit | Files | +|---|------|--------|-------| +| 1 | Add auth prompt state, modal, usePublicSetup hook, guard onboarding | cd85715 | uiStore.ts, AuthPromptModal.tsx, useSetups.ts, useSettings.ts | +| 2 | Rework __root.tsx, guard write actions on catalog and setup pages | 7b0efae | __root.tsx, $globalItemId.tsx, $setupId.tsx | +| 3 | Verify public access flows (auto-approved in auto mode) | — | — | + +## What Was Built + +### uiStore.ts +Extended with `showAuthPrompt`/`openAuthPrompt`/`closeAuthPrompt` state following the existing Zustand boolean modal pattern. + +### AuthPromptModal.tsx +New component rendered globally in `__root.tsx`. Fixed overlay with centered card, backdrop click-to-close, Escape key dismiss. Two buttons ("Sign in" and "Create account") both pointing to `/login` — Logto handles both flows at the same OIDC endpoint. + +### usePublicSetup hook +Added to `useSetups.ts`. Calls `GET /api/setups/:id/public` with `enabled: setupId != null` guard and 404-aware retry logic. Returns `SetupWithItems` shape identical to the private endpoint. + +### useOnboardingComplete(enabled) +Reworked from `useSetting("onboardingComplete")` delegation to a direct `useQuery` call that accepts an `enabled` parameter. Prevents auth-gated settings query from firing for anonymous users. + +### __root.tsx +- Removed `authLoading` spinner gate — app renders immediately for all visitors +- Expanded `isPublicRoute` to include `/`, `/global-items/*`, `/setups/*`, `/users/*`, `/login` +- Replaced `window.location.href = "/login"` with `navigate({ to: "/login" })` (soft redirect, only fires after auth resolves and `!authLoading`) +- Removed `onboardingLoading` spinner gate +- Passes `isAuthenticated` to `useOnboardingComplete()` as the `enabled` param +- Added `` to JSX for global availability + +### global-items/$globalItemId.tsx +"Add to Collection" and "Add to Thread" buttons now check `isAuthenticated` before executing. Unauthenticated users see the `AuthPromptModal` instead. + +### setups/$setupId.tsx +- Conditionally uses `useSetup` (authenticated) or `usePublicSetup` (anonymous) +- All write action UI elements wrapped in `{isAuthenticated && ...}` guards: Add Items button, Public toggle, Delete Setup button and confirmation dialog, empty-state Add Items button +- ItemCard `onRemove` and `onClassificationCycle` props are `undefined` for anonymous users +- ItemPicker rendered only for authenticated users + +## Deviations from Plan + +None — plan executed exactly as written. + +## Verification + +- `bun run lint`: 0 errors in `src/` (4 pre-existing `.obsidian/` format errors) +- `bun test`: 247 pass, 15 fail — identical to pre-change baseline (failures are pre-existing `withImageUrl` module issue in storage service, unrelated to this plan) + +## Known Stubs + +None. The public setup endpoint (`/api/setups/:id/public`) must exist server-side for `usePublicSetup` to work — this is the responsibility of Plan 24-01 (server-side public access routes). If that plan has not yet run, anonymous users will see an error state instead of the setup content. + +## Self-Check: PASSED