Files
GearBox/.planning/phases/24-public-access-infrastructure/24-02-SUMMARY.md
Jean-Luc Makiola 9177296223 docs(24-02): complete public access client layer plan
- SUMMARY.md created for 24-02 (auth prompt modal, render-first root, public setup viewing)
- STATE.md updated: plan advanced, progress 100%, decisions recorded
- ROADMAP.md updated: phase 24 complete (2/2 plans with SUMMARYs)
- REQUIREMENTS.md: PUBL-01 through PUBL-05 marked complete
2026-04-10 10:11:17 +02:00

4.6 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
24-public-access-infrastructure 02 client/auth
public-access
auth-prompt
anonymous-browsing
setup-sharing
requires provides affects
public-route-access
auth-prompt-modal
anonymous-setup-viewing
__root.tsx
uiStore
useSetups
useSettings
global-items-detail
setup-detail
added patterns
zustand-modal-state
conditional-hook-enabled
render-first-auth
created modified
src/client/components/AuthPromptModal.tsx
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
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
duration_seconds completed_date tasks_completed files_changed
258 2026-04-10 3 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 <AuthPromptModal /> 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