- Import eq from drizzle-orm and users from schema
- Export requireAdmin(c, next) that returns 401 if userId not in context, 403 if user.isAdmin is falsy
- storage.service.ts: use dynamic import() inside each function so the
current @aws-sdk mock is always picked up regardless of module load order
- images.test.ts + image.service.test.ts: replace module-level storage.service
mock with @aws-sdk/client-s3 mock to avoid contaminating storage.service.test.ts
- routes/auth.test.ts: remove unnecessary oauth.service mock (no test uses
verifyAccessToken) which was contaminating oauth.service.test.ts
- middleware/auth.test.ts: complete oauth.service mock shape with all exports
All 464 tests now pass in a single bun test run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CatalogSearchOverlay: replace handleAddStub with real openAddToCollection/openAddToThread routing based on catalogSearchMode
- ConfirmDialog + __root.tsx: swap t() for Trans component on deleteItemMessage, deleteCandidateMessage, pickWinnerMessage — fixes <bold> rendering as literal text
- Biome format pass: fix 23 lint/format errors across scripts, services, tests
- Planning: mark all UAT and verification gaps resolved for phases 07, 11, 16, 20, 21, 22, 24, 32, 34; close debug sessions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Items in shared/public setups are now viewable without auth. Clicking
an item in a shared setup navigates to /items/:id?setup=:setupId&share=token
which fetches the item via a public endpoint authorized by the setup's
visibility or share token. Read-only mode hides all owner controls.
- Added getSetupItemById service function
- Added GET /api/shared/:token/items/:itemId endpoint
- Added GET /api/setups/:setupId/items/:itemId/public endpoint
- Added usePublicSetupItem and useSharedSetupItem hooks
- Item detail page detects setup context and switches to public fetch
- Back link returns to setup instead of collection in setup context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The /s/:token route was registered outside the /api/* db middleware
scope, causing db to be undefined and a 500 error on share link access.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
updateSetupSchema required name as mandatory, causing ZodError when
ShareModal sent visibility-only updates. Made name optional in update
schema and guarded against setting undefined name in service layer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Auto-fixed formatting issues and removed unused imports introduced
by background execution agents across currency, i18n, and sharing code.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create community-price.service.ts with ownership validation, upsert, median aggregation
- Create community-prices route (GET stats public, POST requires auth + ownership)
- Register community-prices route with public GET access
- Add priceCurrency to both getSetupWithItems and getSetupWithItemsById
- Aggregation uses PERCENTILE_CONT(0.5) with 3-report minimum threshold
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create market-price.service.ts with getMarketPrices, upsertMarketPrice
- Create exchange-rates route (GET /api/exchange-rates, public)
- Create market-prices route (GET/POST /api/market-prices/global-items/:id/prices)
- Register new routes in server index with public GET access
- Add priceCurrency to item service getAllItems/getItemById/createItem
- Add foundPriceCents/Currency/Date to thread candidate select and create/update
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create share.service.ts with token generation (128-bit base64url),
CRUD operations, validation, and visibility transition side effects.
Add share endpoints under /api/setups/:id/shares, shared access at
/api/shared/:token, and /s/:token short URL redirect.
Plan: 32-02 (Setup Sharing System - Share Link Backend)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace isPublic boolean with visibility enum (private/link/public) across
the full stack. Add shares table to schema for future share link support.
Update all services, routes, schemas, hooks, components, and tests.
Plan: 32-01 (Setup Sharing System - Schema Migration)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The OIDC session token retains the old email after a Logto email
change. Now the server returns the new email in the response and
the frontend optimistically updates the auth cache.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logs the URL, resource, app ID prefix, and response body when the
token request fails — helps diagnose 400 errors from Logto.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Avatar images were rendered via /uploads/ which doesn't exist since
the S3 migration. Now the server enriches profile responses with
avatarImageUrl (presigned S3 URL) and the frontend uses it directly.
Also fixed the public profile page at /users/:id.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
getAllItems and getItemById were not selecting dominantColor, cropZoom,
cropX, cropY from the database. GearImage was ignoring the dominantColor
prop. Now the fields flow end-to-end from DB to UI background fill.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The updateItem function's TypeScript type was missing dominantColor,
cropZoom, cropX, and cropY fields, causing crop settings to silently
fail to save despite the Zod schema and DB schema supporting them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Behind a reverse proxy, c.req.url resolves to internal URL which
doesn't match the registered post_logout_redirect_uri in Logto.
Use GEARBOX_URL env var (already required for OAuth) as the
redirect target.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logto needs client_id to validate the post_logout_redirect_uri and
auto-redirect back to the app. Without it, user gets stuck on
Logto's end-session success page.
Note: post_logout_redirect_uri must be registered in Logto Console
under the app's "Post sign-out redirect URIs".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After revoking the local session, redirect to Logto's /session/end
so the OIDC session is cleared too. Previously redirected to /login
which immediately re-authenticated via the still-valid Logto session.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both POST /api/images and POST /api/images/from-url now return
dominantColor in their response body.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
extractDominantColor() resizes image to 1x1 pixel for weighted average
color. Integrated into fetchImageFromUrl to return dominantColor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds Profile link to UserMenu dropdown (above Settings), extends /me
endpoint to return user's createdAt for member-since display, and
updates AuthState interface with optional createdAt field.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Creates /api/account routes with password change (verifies current first),
email update, has-password check, and account deletion with public setup
anonymization. Adds Zod validation schemas and registers routes in index.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements LogtoManagementClient with token caching, password verification,
password update, email update, user deletion, and has-password check.
All methods proxy to Logto Management API via M2M credentials.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove unused functions and imports from route tests, fix array index key
warnings in skeleton components, apply biome formatting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create src/server/routes/discovery.ts with GET /setups, /items, /categories handlers
- Register discoveryRoutes in src/server/index.ts with browseTier rate limiting
- Add auth skip for /api/discovery/* GET requests in auth middleware
- Create tests/routes/discovery.test.ts with 10 tests covering all endpoints and pagination
- New catalog.ts with catalogToolDefinitions and registerCatalogTools
- upsert_catalog_item: single item upsert with full attribution fields (SEED-03)
- bulk_upsert_catalog: batch upsert up to 100 items with created/updated counts
- Registered in createMcpServer after image tools
- 6 new MCP catalog tool tests passing
- POST /api/global-items upserts single item via upsertGlobalItem service
- POST /api/global-items/bulk upserts up to 100 items via bulkUpsertGlobalItems service
- Zod validation via @hono/zod-validator with upsertGlobalItemSchema and bulkUpsertGlobalItemsSchema
- Add upsertGlobalItemSchema and bulkUpsertGlobalItemsSchema to schemas.ts
- Add UpsertGlobalItemInput and BulkUpsertGlobalItemsInput types to types.ts
- Implement upsertGlobalItem with onConflictDoUpdate and tag sync
- Implement bulkUpsertGlobalItems processing array in single transaction
- Fix migration 0003 to only add new columns + unique constraint
- All 21 tests pass including 8 new upsert operation tests
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>
- 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