diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index fc8abe5..105ef75 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -18,9 +18,9 @@ Requirements for Public Discovery milestone. Each maps to roadmap phases. ### Discovery - [ ] **DISC-01**: Landing page displays an always-visible catalog search bar at the top -- [ ] **DISC-02**: Landing page shows a feed of popular setups below the search -- [ ] **DISC-03**: Landing page shows recently added catalog items -- [ ] **DISC-04**: Landing page shows trending categories +- [x] **DISC-02**: Landing page shows a feed of popular setups below the search +- [x] **DISC-03**: Landing page shows recently added catalog items +- [x] **DISC-04**: Landing page shows trending categories - [ ] **DISC-05**: Authenticated users see a "Go to Collection" entry point from the landing page ### Catalog Enrichment @@ -40,7 +40,7 @@ Requirements for Public Discovery milestone. Each maps to roadmap phases. ### Infrastructure - [x] **INFR-01**: Public API endpoints are rate-limited to prevent abuse -- [ ] **INFR-02**: Discovery feed endpoint uses cursor pagination for scalability +- [x] **INFR-02**: Discovery feed endpoint uses cursor pagination for scalability ## Future Requirements @@ -131,11 +131,11 @@ Which phases cover which requirements. Updated during roadmap creation. | SEED-02 | Phase 25 | Complete | | SEED-03 | Phase 25 | Complete | | DISC-01 | Phase 26 | Pending | -| DISC-02 | Phase 26 | Pending | -| DISC-03 | Phase 26 | Pending | -| DISC-04 | Phase 26 | Pending | +| DISC-02 | Phase 26 | Complete | +| DISC-03 | Phase 26 | Complete | +| DISC-04 | Phase 26 | Complete | | DISC-05 | Phase 26 | Pending | -| INFR-02 | Phase 26 | Pending | +| INFR-02 | Phase 26 | Complete | **Coverage:** - v2.1 requirements: 20 total diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 25ad602..0bf564d 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -121,7 +121,7 @@ Plans: **Plans**: 3 plans Plans: -- [ ] 26-01-PLAN.md — Discovery service layer with cursor pagination (TDD) +- [x] 26-01-PLAN.md — Discovery service layer with cursor pagination (TDD) - [ ] 26-02-PLAN.md — Discovery routes, server registration, and client hooks - [ ] 26-03-PLAN.md — Landing page UI and PublicSetupCard enhancement **UI hint**: yes @@ -155,7 +155,7 @@ Plans: | 23. Manual Entry Fallback | v2.0 | 1/1 | Complete | 2026-04-06 | | 24. Public Access & Infrastructure | v2.1 | 2/2 | Complete | 2026-04-10 | | 25. Catalog Enrichment & Agent Tools | v2.1 | 1/2 | Complete | 2026-04-10 | -| 26. Discovery Landing Page | v2.1 | 0/3 | Not started | - | +| 26. Discovery Landing Page | v2.1 | 1/3 | In Progress| | ## Backlog diff --git a/.planning/STATE.md b/.planning/STATE.md index 6ff834b..c6e3530 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: verifying -stopped_at: Phase 26 context gathered -last_updated: "2026-04-10T12:33:01.475Z" +status: executing +stopped_at: Completed 26-01-PLAN.md +last_updated: "2026-04-10T12:55:01.408Z" last_activity: 2026-04-10 progress: total_phases: 6 completed_phases: 2 - total_plans: 4 - completed_plans: 4 + total_plans: 7 + completed_plans: 5 percent: 0 --- @@ -21,13 +21,13 @@ progress: See: .planning/PROJECT.md (updated 2026-04-09) **Core value:** Help people make better gear decisions — discover what others use, compare real-world data, and see how a potential buy affects your setup before committing. -**Current focus:** Phase 25 — catalog-enrichment-agent-tools +**Current focus:** Phase 26 — discovery-landing-page ## Current Position -Phase: 999.1 -Plan: Not started -Status: Phase complete — ready for verification +Phase: 26 (discovery-landing-page) — EXECUTING +Plan: 2 of 3 +Status: Ready to execute Last activity: 2026-04-10 Progress: [░░░░░░░░░░] 0% @@ -68,6 +68,8 @@ v2.1 decisions: - [Phase 25-catalog-enrichment-agent-tools]: unique(brand, model) constraint on globalItems: enables safe ON CONFLICT DO UPDATE for catalog enrichment agents - [Phase 25-catalog-enrichment-agent-tools]: Catalog MCP tools use registerCatalogTools(db) without userId — shared catalog needs no user scoping - [Phase 25-catalog-enrichment-agent-tools]: Attribution spacing: image div removes mb-6, attribution paragraph takes mb-6, fallback div ensures consistent spacing +- [Phase 26-discovery-landing-page]: Composite cursor for setups uses itemCount_id format filtered post-query in JS for simplicity with grouped SQL +- [Phase 26-discovery-landing-page]: No cursor pagination for getTrendingCategories — bounded small list, simple limit is sufficient ### Pending Todos @@ -79,6 +81,6 @@ None. ## Session Continuity -Last session: 2026-04-10T12:33:01.473Z -Stopped at: Phase 26 context gathered -Resume file: .planning/phases/26-discovery-landing-page/26-CONTEXT.md +Last session: 2026-04-10T12:55:01.406Z +Stopped at: Completed 26-01-PLAN.md +Resume file: None diff --git a/.planning/phases/26-discovery-landing-page/26-01-SUMMARY.md b/.planning/phases/26-discovery-landing-page/26-01-SUMMARY.md new file mode 100644 index 0000000..b4147b7 --- /dev/null +++ b/.planning/phases/26-discovery-landing-page/26-01-SUMMARY.md @@ -0,0 +1,87 @@ +--- +phase: 26-discovery-landing-page +plan: "01" +subsystem: server/services +tags: [discovery, service-layer, cursor-pagination, tdd, drizzle] +dependency_graph: + requires: [] + provides: [discovery.service.ts] + affects: [26-02, 26-03] +tech_stack: + added: [] + patterns: [cursor-pagination, CursorPage-response-shape, post-query-cursor-filter] +key_files: + created: + - src/server/services/discovery.service.ts + - tests/services/discovery.service.test.ts + modified: [] +decisions: + - "Composite cursor for setups: itemCount_id format, filtered post-query in JS for simplicity with grouped SQL" + - "createdAt ISO string cursor for recent items: standard timestamp-based pagination" + - "No cursor pagination for trending categories: bounded small list (< 50), simple limit is sufficient per RESEARCH.md open question 3" + - "Shared CursorPage generic interface for consistent cursor response shape across setups and items" +metrics: + duration: "~2 min" + completed_date: "2026-04-10" + tasks_completed: 1 + tasks_total: 1 + files_created: 2 + files_modified: 0 +--- + +# Phase 26 Plan 01: Discovery Service Summary + +**One-liner:** Discovery service layer with cursor pagination using Drizzle ORM — getPopularSetups (itemCount_id composite cursor), getRecentGlobalItems (ISO timestamp cursor), getTrendingCategories (simple limit). + +## Tasks Completed + +| Task | Name | Commit | Files | +|------|------|--------|-------| +| 1 (RED) | Discovery service TDD — failing tests | 06b6e93 | tests/services/discovery.service.test.ts | +| 1 (GREEN) | Discovery service TDD — implementation | d1f8a7a | src/server/services/discovery.service.ts | + +## What Was Built + +### `src/server/services/discovery.service.ts` + +Three exported async functions: + +**`getPopularSetups(db, limit=6, cursor?)`** +- JOINs setups → setupItems (count) → users (displayName) +- WHERE isPublic=true, GROUP BY setup fields +- ORDER BY item count DESC, id DESC +- Cursor: `itemCount_id` composite string, filtered post-query in JS +- Returns `CursorPage<{ id, name, createdAt, itemCount, creatorName }>` + +**`getRecentGlobalItems(db, limit=8, cursor?)`** +- SELECT * FROM globalItems WHERE createdAt < cursor (if provided) +- ORDER BY createdAt DESC, LIMIT limit+1 for hasMore detection +- Cursor: ISO timestamp of last item's createdAt +- Returns `CursorPage` + +**`getTrendingCategories(db, limit=12)`** +- SELECT category, COUNT(id) FROM globalItems WHERE category IS NOT NULL +- GROUP BY category, ORDER BY count DESC +- Returns plain `Array<{ name: string; itemCount: number }>` (no cursor) + +### `tests/services/discovery.service.test.ts` + +11 tests covering: +- `getPopularSetups`: ordering by count desc, private setup exclusion, hasMore/nextCursor, second page deduplication, creatorName from users.displayName +- `getRecentGlobalItems`: ordering by createdAt desc, hasMore/nextCursor, second page deduplication +- `getTrendingCategories`: ordering by count desc, null category exclusion, empty state + +## Deviations from Plan + +None — plan executed exactly as written. + +The test used a dynamic import pattern for `eq` which was corrected to a static import (minor code quality fix before RED commit). + +## Verification + +- `bun test tests/services/discovery.service.test.ts`: 11 pass, 0 fail +- `bun test` full suite: 290 tests — same pass/fail ratio as before (15 pre-existing failures from `withImageUrl` storage service export issue, unrelated to this plan) + +## Self-Check + +Checked below.