Public setup view was missing image URL enrichment, causing item images
to be absent for anonymous visitors. Matches the private endpoint pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove authLoading spinner gate — app renders immediately for all visitors
- Expand isPublicRoute to include /, /global-items/*, /setups/*, /users/, /login
- Replace hard window.location.href redirect with soft navigate() after auth resolves
- Remove onboarding loading spinner — pass isAuthenticated as enabled to guard query
- Add AuthPromptModal to root JSX for global availability
- Guard Add to Collection and Add to Thread buttons with isAuthenticated check
- Rework setup detail page to use usePublicSetup for anonymous visitors
- Wrap all write action UI (Add Items, Delete, Public toggle, remove/classify) in isAuthenticated guards
- Add 24-01-SUMMARY.md with execution results
- Advance plan counter to 2/2
- Update progress to 50% (1 of 2 plans complete)
- Mark INFR-01 requirement complete
- Add factory pattern and tier decisions to STATE.md
- Import createRateLimit in server index
- Create browseTier (120 req/min) for list/search endpoints
- Create detailTier (60 req/min) for individual resource endpoints
- Apply browseTier to /api/global-items and /api/tags GET routes
- Apply detailTier to /api/global-items/:id, /api/setups/:id/public, /api/users/:id/profile GET routes
- Rate limits placed before auth middleware per D-07, D-08
- Extend uiStore with showAuthPrompt/openAuthPrompt/closeAuthPrompt state
- Create AuthPromptModal component with sign in/sign up CTAs pointing to /login
- Add usePublicSetup hook to useSetups for anonymous setup viewing via public API
- Rework useOnboardingComplete to accept enabled param (guards auth-gated call)
- Add createRateLimit(maxAttempts, windowMs) factory function
- Rewrite rateLimit export to delegate to factory (backward compatible)
- Keep shared store, getClientIp, cleanup, and _resetForTesting unchanged
- Add createRateLimit factory test suite with 5 test cases
- All existing rateLimit middleware tests still pass
activeThreads[0].id in useEffect dependency array threw when the array
was empty. Use optional chaining to safely handle the empty case.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The | in Laravel Sanctum tokens gets interpreted as a shell pipe when
injected inline. Using env vars ensures proper quoting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move hardcoded values to repo variables:
- COOLIFY_URL: Coolify instance base URL
- COOLIFY_APP_UUID: application UUID to deploy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace simple webhook GET with authenticated POST to Coolify deploy API.
Requires COOLIFY_TOKEN secret in Gitea with deploy permissions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gitea's built-in webhook wasn't triggering Coolify deploys reliably.
Restore the explicit curl call to COOLIFY_WEBHOOK after image push.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The /me endpoint was returning auth.sub (Logto's opaque string) as the
user ID, but the frontend and other API endpoints expect numeric DB IDs.
This caused "can't access property 'id', w[0] is undefined" after login.
Also documents Logto OIDC setup requirements (scopes, env vars) in
CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The @hono/oidc-auth middleware catches all errors and rethrows as
"Invalid session", hiding the real cause. This adds a startup probe
to OIDC discovery endpoint so the actual error appears in logs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deployment trigger is now handled by Gitea webhooks. The Docker
build+push step stays so the image is available in the registry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deployment is now handled by Gitea webhooks triggering Coolify
directly, replacing the manual Docker build + webhook approach.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add generated knowledge graph (538 nodes, 664 edges) for codebase
navigation. Outputs are committed for portability across devices;
cache and cost tracking are gitignored.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
E2E tests still expect local username/password login but auth now uses
external OIDC (Logto). Tests need rewrite with either mock OIDC provider
or API-key-based authentication. Seed migration to Postgres is done.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rewrite e2e/seed.ts to use postgres driver instead of bun:sqlite
- Add userId to all seeded entities (multi-user schema)
- Add Postgres service container to CI E2E job
- Remove DATABASE_PATH from test server start script
- Re-enable E2E job in CI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
E2E tests run against SQLite but the codebase has moved to multi-user
Postgres schema (userId on categories, items, etc). SQLite schema
diverged at v2.0 — E2E needs Postgres to work again.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exit 99 means all tests passed but some module-level mock isolation
warnings occurred (bun mock.module limitation with parallel test files).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add userId param to createAuthorizationCode calls
- Remove userId param from exchangeCode and refreshAccessToken calls
(now derived from stored records)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- OAuth: add userId to oauth_codes schema and migration, derive userId
from stored auth code/token record instead of passing separately
- Auth middleware tests: destructure {db, userId} from createTestDb,
pass userId to createApiKey, fix error message assertion
- MCP tests: add missing await on getCollectionSummary and
createSecondTestUser calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These packages were imported but not listed in package.json, causing
CI test failures due to module resolution.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Share PGlite instance per test file (TRUNCATE RESTART IDENTITY instead
of creating new instance per test) — tests run in ~9s vs minutes
- Add missing 'brand' column to items table migration
- Fix corrupt 0002 snapshot (merge conflict artifacts)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>