diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 121fbd8..562b3e3 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -49,11 +49,11 @@ Requirements for this milestone. Each maps to roadmap phases. ### User Profiles & Sharing -- [ ] **PROF-01**: User has a profile with display name, avatar, and bio -- [ ] **PROF-02**: User can view their own public profile page -- [ ] **PROF-03**: User can set a setup as public or private -- [ ] **PROF-04**: Public setups are viewable by anyone without authentication -- [ ] **PROF-05**: Public profile page lists the user's public setups +- [x] **PROF-01**: User has a profile with display name, avatar, and bio +- [x] **PROF-02**: User can view their own public profile page +- [x] **PROF-03**: User can set a setup as public or private +- [x] **PROF-04**: Public setups are viewable by anyone without authentication +- [x] **PROF-05**: Public profile page lists the user's public setups ## Future Requirements @@ -141,11 +141,11 @@ Which phases cover which requirements. Updated during roadmap creation. | GLOB-03 | Phase 18 | Pending | | GLOB-04 | Phase 18 | Pending | | GLOB-05 | Phase 18 | Pending | -| PROF-01 | Phase 18 | Pending | -| PROF-02 | Phase 18 | Pending | -| PROF-03 | Phase 18 | Pending | -| PROF-04 | Phase 18 | Pending | -| PROF-05 | Phase 18 | Pending | +| PROF-01 | Phase 18 | Complete | +| PROF-02 | Phase 18 | Complete | +| PROF-03 | Phase 18 | Complete | +| PROF-04 | Phase 18 | Complete | +| PROF-05 | Phase 18 | Complete | **Coverage:** - v2.0 requirements: 30 total diff --git a/.planning/STATE.md b/.planning/STATE.md index d9a43f1..8d53da9 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,16 +1,16 @@ --- gsd_state_version: 1.0 -milestone: v2.0 -milestone_name: Platform Foundation +milestone: v1.3 +milestone_name: Research & Decision Tools status: planning -stopped_at: null -last_updated: "2026-04-03" +stopped_at: Completed 18-03-PLAN.md +last_updated: "2026-04-05T11:12:57.693Z" last_activity: 2026-04-03 — v2.0 roadmap created (Phases 14-18) progress: - total_phases: 5 - completed_phases: 0 - total_plans: 0 - completed_plans: 0 + total_phases: 8 + completed_phases: 6 + total_plans: 12 + completed_plans: 11 percent: 0 --- @@ -35,6 +35,7 @@ Progress: [----------] 0% (v2.0 milestone) ## Performance Metrics **Velocity:** + - Total plans completed: 0 (v2.0 milestone) - Average duration: -- - Total execution time: -- @@ -46,12 +47,14 @@ Progress: [----------] 0% (v2.0 milestone) ### Decisions Key decisions made during v2.0 planning: + - Platform pivot: single-user to multi-user with discovery-first approach - External auth provider (self-hosted, open-source) — Logto vs Authentik OPEN decision - SQLite to Postgres migration — required by auth provider and multi-user concurrency - Structured UGC only — ratings and predefined fields, no freeform text until moderation - Separate globalItems table — not a flag on user items table - Single-user SQLite mode diverges at v2.0 boundary +- [Phase 18]: Public endpoints bypass auth via regex path matching in index.ts middleware ### Pending Todos @@ -64,6 +67,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-05T11:12:57.691Z +Stopped at: Completed 18-03-PLAN.md Resume file: None diff --git a/.planning/phases/18-global-items-public-profiles/18-03-SUMMARY.md b/.planning/phases/18-global-items-public-profiles/18-03-SUMMARY.md new file mode 100644 index 0000000..b1a05ad --- /dev/null +++ b/.planning/phases/18-global-items-public-profiles/18-03-SUMMARY.md @@ -0,0 +1,133 @@ +--- +phase: 18-global-items-public-profiles +plan: 03 +subsystem: server +tags: [profiles, public-setups, hono, drizzle, services, routes] + +requires: + - phase: 18-global-items-public-profiles + plan: 01 + provides: "User profile columns, setup isPublic column, Zod schemas" +provides: + - "Profile service (updateProfile, getPublicProfile, getPublicSetupWithItems)" + - "Public profile endpoint GET /api/users/:id/profile" + - "Profile update endpoint PUT /api/auth/profile" + - "Public setup endpoint GET /api/setups/:id/public" + - "Setup service isPublic support in create/update/list/detail" +affects: [18-04, 18-05] + +tech-stack: + added: [] + patterns: ["Public endpoints bypass auth middleware via regex in index.ts"] + +key-files: + created: + - "src/server/services/profile.service.ts" + - "src/server/routes/profiles.ts" + - "tests/services/profile.service.test.ts" + - "tests/routes/profiles.test.ts" + modified: + - "src/server/services/setup.service.ts" + - "src/server/services/category.service.ts" + - "src/server/routes/auth.ts" + - "src/server/routes/setups.ts" + - "src/server/index.ts" + +key-decisions: + - "Public endpoints skip auth via regex path matching in index.ts middleware" + - "Profile update placed on auth routes (PUT /api/auth/profile) since it requires auth" + - "Public setup route placed in setups.ts as GET /:id/public before GET /:id" + +patterns-established: + - "Public endpoint pattern: regex skip in auth middleware + no userId dependency in handler" + +requirements-completed: [PROF-01, PROF-02, PROF-03, PROF-04, PROF-05] + +duration: 7min +completed: 2026-04-05 +--- + +# Phase 18 Plan 03: User Profiles & Public Sharing Backend Summary + +**Profile service with CRUD and public profile data, public setup viewing, setup visibility toggle, and auth middleware bypass for public endpoints** + +## Performance + +- **Duration:** 7 min +- **Started:** 2026-04-05T11:03:46Z +- **Completed:** 2026-04-05T11:11:44Z +- **Tasks:** 2 +- **Files modified:** 9 + +## Accomplishments + +- Created profile service with updateProfile, getPublicProfile, and getPublicSetupWithItems +- Added public profile endpoint returning user info and only public setups +- Added profile update endpoint behind auth on PUT /api/auth/profile +- Added public setup view endpoint at GET /api/setups/:id/public (returns 404 for private) +- Updated setup service to handle isPublic in create, update, list, and detail +- Updated auth middleware to skip auth for public profile and setup GET requests +- 25 tests passing (15 service + 10 route tests) + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Profile service + setup isPublic + tests (TDD)** - `2d5d4f9` (test RED), `854811d` (feat GREEN) +2. **Task 2: Routes + auth middleware + route tests** - `eb8f4b7` (feat) + +## Files Created/Modified + +- `src/server/services/profile.service.ts` - updateProfile, getPublicProfile, getPublicSetupWithItems +- `src/server/routes/profiles.ts` - GET /:id/profile public endpoint +- `src/server/routes/auth.ts` - Added PUT /profile with requireAuth and updateProfileSchema validation +- `src/server/routes/setups.ts` - Added GET /:id/public endpoint using getPublicSetupWithItems +- `src/server/index.ts` - Registered profileRoutes at /api/users, added regex auth skips +- `src/server/services/setup.service.ts` - isPublic in createSetup, updateSetup, getAllSetups +- `src/server/services/category.service.ts` - Added getOrCreateUncategorized (Rule 3 fix) +- `tests/services/profile.service.test.ts` - 15 tests for profile and setup isPublic +- `tests/routes/profiles.test.ts` - 10 tests for public profile, auth profile update, public setup + +## Decisions Made + +- Public endpoints bypass auth via regex path matching in the centralized auth middleware, not per-route +- Profile update lives under /api/auth/profile since it requires authentication context +- Public setup route registered before /:id in setups.ts to prevent route conflict + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Added getOrCreateUncategorized to category service** +- **Found during:** Task 2 +- **Issue:** Auth middleware imports getOrCreateUncategorized from category.service.ts but the function didn't exist (was expected from Phase 16 multi-user conversion) +- **Fix:** Added async getOrCreateUncategorized function that finds or creates the "Uncategorized" category for a user +- **Files modified:** src/server/services/category.service.ts +- **Commit:** eb8f4b7 + +**2. [Rule 1 - Bug] Handle empty update in updateProfile** +- **Found during:** Task 1 GREEN phase +- **Issue:** Drizzle throws "No values to set" when .set() receives an empty object +- **Fix:** Added check for empty updates, returning existing user without running update query +- **Files modified:** src/server/services/profile.service.ts +- **Commit:** 854811d + +## Issues Encountered + +None beyond the auto-fixed deviations above. + +## Known Stubs + +None - all endpoints are fully wired to service functions with real database operations. + +## Next Phase Readiness + +- Profile backend complete for Plan 18-04 (client-side profile pages) +- Public setup view ready for Plan 18-05 (discovery feed) +- All service functions exported and tested for downstream consumption + +## Self-Check: PASSED + +--- +*Phase: 18-global-items-public-profiles* +*Completed: 2026-04-05*