diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 121fbd8..c3efe8e 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -41,11 +41,11 @@ Requirements for this milestone. Each maps to roadmap phases. ### Global Item Database -- [ ] **GLOB-01**: A global item catalog exists with brand, model, category, manufacturer specs, and image -- [ ] **GLOB-02**: Global catalog is seeded with initial items from manufacturer data -- [ ] **GLOB-03**: User can search the global catalog by name or brand -- [ ] **GLOB-04**: User can link a personal collection item to a global catalog entry -- [ ] **GLOB-05**: Global item pages show basic info and owner count +- [x] **GLOB-01**: A global item catalog exists with brand, model, category, manufacturer specs, and image +- [x] **GLOB-02**: Global catalog is seeded with initial items from manufacturer data +- [x] **GLOB-03**: User can search the global catalog by name or brand +- [x] **GLOB-04**: User can link a personal collection item to a global catalog entry +- [x] **GLOB-05**: Global item pages show basic info and owner count ### User Profiles & Sharing @@ -136,11 +136,11 @@ Which phases cover which requirements. Updated during roadmap creation. | IMG-02 | Phase 17 | Pending | | IMG-03 | Phase 17 | Pending | | IMG-04 | Phase 17 | Pending | -| GLOB-01 | Phase 18 | Pending | -| GLOB-02 | Phase 18 | Pending | -| GLOB-03 | Phase 18 | Pending | -| GLOB-04 | Phase 18 | Pending | -| GLOB-05 | Phase 18 | Pending | +| GLOB-01 | Phase 18 | Complete (18-02) | +| GLOB-02 | Phase 18 | Complete (18-02) | +| GLOB-03 | Phase 18 | Complete (18-02) | +| GLOB-04 | Phase 18 | Complete (18-02) | +| GLOB-05 | Phase 18 | Complete (18-02) | | PROF-01 | Phase 18 | Pending | | PROF-02 | Phase 18 | Pending | | PROF-03 | Phase 18 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 2be42f5..16eae8c 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -192,4 +192,4 @@ Plans: | 15. External Authentication | v2.0 | 0/? | Not started | - | | 16. Multi-User Data Model | v2.0 | 0/? | Not started | - | | 17. Object Storage | v2.0 | 0/? | Not started | - | -| 18. Global Items & Public Profiles | v2.0 | 0/? | Not started | - | +| 18. Global Items & Public Profiles | v2.0 | 2/5 | In progress | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index d9a43f1..f1a258b 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -25,12 +25,12 @@ See: .planning/PROJECT.md (updated 2026-04-03) ## Current Position -Phase: 14 of 18 (PostgreSQL Migration) -Plan: 0 of ? in current phase -Status: Ready to plan -Last activity: 2026-04-03 — v2.0 roadmap created (Phases 14-18) +Phase: 18 of 18 (Global Items & Public Profiles) +Plan: 2 of 5 in current phase +Status: Executing +Last activity: 2026-04-05 — Completed 18-02 global items service and routes -Progress: [----------] 0% (v2.0 milestone) +Progress: [##--------] 20% (v2.0 milestone) ## Performance Metrics @@ -64,6 +64,6 @@ None active. ## Session Continuity -Last session: 2026-04-03 -Stopped at: v2.0 roadmap created with 5 phases (14-18) covering 30 requirements +Last session: 2026-04-05 +Stopped at: Completed 18-02-PLAN.md (global items service and routes) Resume file: None diff --git a/.planning/phases/18-global-items-public-profiles/18-02-SUMMARY.md b/.planning/phases/18-global-items-public-profiles/18-02-SUMMARY.md new file mode 100644 index 0000000..20eb71e --- /dev/null +++ b/.planning/phases/18-global-items-public-profiles/18-02-SUMMARY.md @@ -0,0 +1,136 @@ +--- +phase: 18-global-items-public-profiles +plan: 02 +subsystem: server +tags: [global-items, service, routes, seed, search, linking] + +requires: + - phase: 18-01 + provides: "globalItems/itemGlobalLinks tables, Zod schemas, seed JSON" +provides: + - "Global item search service with case-insensitive LIKE and wildcard escaping" + - "Global item detail with owner count aggregation" + - "Item-to-global link/unlink service functions" + - "GET /api/global-items and GET /api/global-items/:id public routes" + - "POST /api/items/:id/link and DELETE /api/items/:id/link auth-protected routes" + - "Idempotent seed script integrated into startup" +affects: [18-03, 18-04, 18-05] + +tech-stack: + added: [] + patterns: ["LIKE search with wildcard escaping for SQLite", "Owner count via junction table aggregation"] + +key-files: + created: + - "src/server/services/global-item.service.ts" + - "src/server/routes/global-items.ts" + - "src/db/seed-global-items.ts" + - "tests/services/global-item.service.test.ts" + - "tests/routes/global-items.test.ts" + modified: + - "src/server/routes/items.ts" + - "src/server/index.ts" + - "src/db/seed.ts" + - "src/db/schema.ts" + - "src/shared/schemas.ts" + - "src/shared/types.ts" + - "src/db/global-items-seed.json" + +key-decisions: + - "Used SQLite LIKE (case-insensitive for ASCII) instead of Postgres ILIKE since codebase is still SQLite" + - "Auth middleware already skips GET requests globally, no additional skip needed for /api/global-items" + - "Link/unlink endpoints placed on items routes (/api/items/:id/link) since they act on user items" + +patterns-established: + - "Junction table count aggregation for owner counts" + - "Wildcard character escaping in search queries" + +requirements-completed: [GLOB-01, GLOB-02, GLOB-03, GLOB-04, GLOB-05] + +duration: 4min +completed: 2026-04-05 +--- + +# Phase 18 Plan 02: Global Items Service and Routes Summary + +**Global item catalog backend with LIKE search, owner count aggregation, item linking, idempotent seeding, and full test coverage** + +## Performance + +- **Duration:** 4 min +- **Started:** 2026-04-05T11:03:16Z +- **Completed:** 2026-04-05T11:07:46Z +- **Tasks:** 2 +- **Files created:** 5 +- **Files modified:** 6 + +## Accomplishments + +- Built global-item.service.ts with 4 service functions following existing DI pattern +- Implemented case-insensitive search with wildcard escaping (%, _) for safe user input +- Added owner count aggregation via junction table count query +- Created public GET routes for global item catalog (search + detail) +- Added authenticated POST/DELETE link/unlink endpoints on item routes +- Wrote idempotent seed script that imports 18-item bikepacking catalog on startup +- Full TDD: 12 service tests + 10 route tests, all passing +- Full suite: 278 tests, 0 failures + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Global item service + seed script + tests (TDD)** + - RED: `3a6876f` - Failing tests for service and seed + - GREEN: `60dd9f4` - Implementation passing all tests +2. **Task 2: Global item routes + link/unlink + route tests** - `d97d5d9` + +## Files Created/Modified + +- `src/server/services/global-item.service.ts` - searchGlobalItems, getGlobalItemWithOwnerCount, linkItemToGlobal, unlinkItemFromGlobal +- `src/server/routes/global-items.ts` - GET / (search), GET /:id (detail with ownerCount) +- `src/db/seed-global-items.ts` - Idempotent seed function importing from JSON +- `src/db/seed.ts` - Added seedGlobalItems call to seedDefaults +- `src/server/routes/items.ts` - Added POST /:id/link and DELETE /:id/link +- `src/server/index.ts` - Registered /api/global-items route +- `src/db/schema.ts` - Added globalItems and itemGlobalLinks SQLite tables +- `src/shared/schemas.ts` - Added searchGlobalItemsSchema and linkItemSchema +- `src/shared/types.ts` - Added GlobalItem, ItemGlobalLink, SearchGlobalItems, LinkItem types +- `src/db/global-items-seed.json` - 18 bikepacking gear items across 7 categories +- `tests/services/global-item.service.test.ts` - 12 service tests +- `tests/routes/global-items.test.ts` - 10 route tests + +## Decisions Made + +- Used SQLite LIKE instead of Postgres ILIKE since the codebase is still on SQLite; SQLite LIKE is already case-insensitive for ASCII characters +- Auth middleware already has a global GET skip rule, so no additional middleware change was needed for public global item access +- Link/unlink endpoints placed on /api/items/:id/link (item-centric) rather than on global-items routes + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Applied 18-01 schema prerequisites to SQLite codebase** +- **Found during:** Pre-task setup +- **Issue:** Plan 18-01 was executed by a parallel agent on a Postgres-migrated schema, but this worktree is still on SQLite +- **Fix:** Added globalItems/itemGlobalLinks as sqliteTable definitions, Zod schemas, types, seed JSON, and migration directly in this branch +- **Files modified:** src/db/schema.ts, src/shared/schemas.ts, src/shared/types.ts, src/db/global-items-seed.json, drizzle migration + +**2. [Rule 1 - Bug] Used LIKE instead of ILIKE for SQLite compatibility** +- **Found during:** Task 1 +- **Issue:** Plan specified ilike (Postgres-only), but codebase uses SQLite where LIKE is already case-insensitive for ASCII +- **Fix:** Used drizzle-orm `like` operator which maps to SQLite LIKE +- **Files modified:** src/server/services/global-item.service.ts + +## Known Stubs + +None - all endpoints return real data from the database. + +## Next Phase Readiness + +- Global item catalog fully queryable via API +- Link/unlink API ready for client integration in Plan 18-03 +- Seed data available for development and testing + +--- +*Phase: 18-global-items-public-profiles* +*Completed: 2026-04-05*