diff --git a/.planning/STATE.md b/.planning/STATE.md index ec19c8e..21ede20 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -5,33 +5,33 @@ See: .planning/PROJECT.md (updated 2026-02-15) **Core value:** Logging a workout should be fast, clear, and flexible — the app never fights the user during a session -**Current focus:** Phase 1 — Input UX +**Current focus:** Phase 2 — Flexible Sets (complete) ## Current Position -Phase: 2 of 3 (Flexible Sets) -Plan: 1 of 2 in current phase (02-01 complete) -Status: Phase 2 in progress — plan 02-01 done, 02-02 pending -Last activity: 2026-02-21 — Completed 02-01 (ExerciseCard dynamic setList, add-set modal, delete-set) +Phase: 2 of 3 (Flexible Sets) — COMPLETE +Plan: 2 of 2 in current phase (02-01 and 02-02 complete) +Status: Phase 2 complete — ready for Phase 3 planning +Last activity: 2026-02-21 — Completed 02-02 (DELETE /api/logs endpoint + deleteLog wiring) -Progress: [█████░░░░░] 50% +Progress: [███████░░░] 67% ## Performance Metrics **Velocity:** -- Total plans completed: 3 -- Average duration: ~1.3 min -- Total execution time: ~0.07 hours +- Total plans completed: 5 +- Average duration: ~2.8 min +- Total execution time: ~0.23 hours **By Phase:** | Phase | Plans | Total | Avg/Plan | |-------|-------|-------|----------| | 01-input-ux | 3/3 | ~4 min | ~1.3 min | -| 02-flexible-sets | 1/2 | ~8 min | ~8 min | +| 02-flexible-sets | 2/2 | ~10 min | ~5 min | **Recent Trend:** -- Last 5 plans: 01-01 (1 min), 01-03 (2 min), 01-02 (1 min), 02-01 (8 min) +- Last 5 plans: 01-01 (1 min), 01-03 (2 min), 01-02 (1 min), 02-01 (8 min), 02-02 (2 min) - Trend: fast *Updated after each plan completion* @@ -54,7 +54,9 @@ Progress: [█████░░░░░] 50% - Dropset weight drops: 80% then 60% of base weight, each rounded to nearest 2.5kg per app progression convention - Last-set guard: handleDeleteSet returns early if setList.length <= 1, delete button also disabled in DOM - progress-badge and all-done class reference setList.length instead of exercise.sets — badge reflects actual set count -- onDeleteSet prop is optional stub in ExerciseCard — backend wiring deferred to plan 02-02 +- No authMiddleware on DELETE /api/logs — consistent with POST /api/logs which also passes user_id in body +- deleteLog silently ignores 404 from backend — unlogged sets deleted mid-session cause no harm +- Composite key (user_id, program_exercise_id, date, set_number) uniquely identifies a workout set log row for deletion ### Pending Todos @@ -67,5 +69,5 @@ None yet. ## Session Continuity Last session: 2026-02-21 -Stopped at: Completed 02-01-PLAN.md (ExerciseCard dynamic setList, add-set modal, delete-set button) +Stopped at: Completed 02-02-PLAN.md (DELETE /api/logs endpoint + deleteLog wiring through App.jsx and WorkoutPage) Resume file: None diff --git a/.planning/phases/02-flexible-sets/02-02-SUMMARY.md b/.planning/phases/02-flexible-sets/02-02-SUMMARY.md new file mode 100644 index 0000000..6659991 --- /dev/null +++ b/.planning/phases/02-flexible-sets/02-02-SUMMARY.md @@ -0,0 +1,116 @@ +--- +phase: 02-flexible-sets +plan: "02" +subsystem: api +tags: [express, postgres, react, fetch, delete, workout-logs] + +# Dependency graph +requires: + - phase: 02-flexible-sets + plan: "01" + provides: ExerciseCard with handleDeleteSet calling optional onDeleteSet prop (stub — wired here) +provides: + - DELETE /api/logs endpoint in backend/src/index.js + - deleteLog function in App.jsx calling DELETE /api/logs + - onDeleteSet prop wired from App.jsx -> WorkoutPage -> ExerciseCard +affects: [03-custom-workouts, backend-logging] + +# Tech tracking +tech-stack: + added: [] + patterns: [DELETE endpoint with composite key (user_id, program_exercise_id, date, set_number), optimistic local state removal mirrors DB delete] + +key-files: + created: [] + modified: + - backend/src/index.js + - frontend/src/App.jsx + - frontend/src/pages/WorkoutPage.jsx + +key-decisions: + - "No authMiddleware on DELETE /api/logs — consistent with existing POST /api/logs which also passes user_id in body" + - "deleteLog silently ignores 404 responses — backend handles non-existent row gracefully (unlogged sets deleted mid-session)" + - "Local logs state updated optimistically after DELETE regardless of 404 — ensures UI stays consistent even for never-logged sets" + +patterns-established: + - "Composite-key delete: (user_id, program_exercise_id, date, set_number) is the unique identifier for a workout set log row" + - "Prop threading: deleteLog lives in App.jsx, flows as onDeleteSet -> WorkoutPage -> ExerciseCard without intermediate handlers" + +# Metrics +duration: 2min +completed: 2026-02-21 +--- + +# Phase 2 Plan 02: Flexible Sets — Backend DELETE Endpoint and Frontend Wiring Summary + +**DELETE /api/logs endpoint deletes workout_logs rows by composite key; deleteLog in App.jsx propagates through WorkoutPage to ExerciseCard, removing orphaned set rows from DB when user deletes a set** + +## Performance + +- **Duration:** ~2 min +- **Started:** 2026-02-21T17:44:02Z +- **Completed:** 2026-02-21T17:45:45Z +- **Tasks:** 2 +- **Files modified:** 3 + +## Accomplishments + +- Backend DELETE /api/logs endpoint: deletes matching workout_logs row by composite key (user_id, program_exercise_id, date, set_number), returns 200+id on success, 404 if not found +- deleteLog async function added to App.jsx alongside logSet: sends DELETE fetch, removes entry from local logs state on success +- Full prop chain wired: App.jsx onDeleteSet={deleteLog} -> WorkoutPage signature updated to accept onDeleteSet -> ExerciseCard receives onDeleteSet prop (was already calling it if provided from plan 01) +- Frontend build passes cleanly after changes + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Add DELETE /api/logs endpoint to backend** - `f9eb6cc` (feat) +2. **Task 2: Wire deleteLog through App.jsx and WorkoutPage to ExerciseCard** - `175434f` (feat) + +**Plan metadata:** committed with docs commit (docs) + +## Files Created/Modified + +- `backend/src/index.js` - Added DELETE /api/logs route (21 lines) after POST /api/logs, same composite key pattern +- `frontend/src/App.jsx` - Added deleteLog function (20 lines), added onDeleteSet={deleteLog} prop to WorkoutPage render +- `frontend/src/pages/WorkoutPage.jsx` - Updated function signature to accept onDeleteSet, passed onDeleteSet to each ExerciseCard + +## Decisions Made + +- **No auth on DELETE /api/logs:** POST /api/logs has no authMiddleware — DELETE matches that pattern for consistency; user_id from body provides identity +- **Silent 404 handling:** If a set was never logged (user added then immediately deleted without completing), the DELETE returns 404. deleteLog catches silently — the row never existed, no cleanup needed +- **Optimistic state update:** Local logs state is always updated (filter out the set_number) regardless of whether the DELETE returned 200 or 404, since in both cases the set should not appear in the UI + +## Deviations from Plan + +None — plan executed exactly as written. + +## Issues Encountered + +None — build passed cleanly after both tasks. Backend syntax verified with `node --check`. + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness + +- Phase 2 (Flexible Sets) is now complete: ExerciseCard supports dynamic set lists (plan 01), and deleting a logged set removes it from the database (plan 02) +- Ghost sets can no longer reappear after page reload — deleted sets are removed from both frontend state and backend DB +- Phase 3 (Custom Workouts) requires new DB tables (custom_workouts, custom_workout_exercises) and a source_type column on workout_logs — schema migration needed before Phase 3 planning + +## Self-Check: PASSED + +- backend/src/index.js: FOUND +- frontend/src/App.jsx: FOUND +- frontend/src/pages/WorkoutPage.jsx: FOUND +- 02-02-SUMMARY.md: FOUND +- Commit f9eb6cc (Task 1): FOUND +- Commit 175434f (Task 2): FOUND +- DELETE /api/logs in backend: FOUND +- deleteLog in App.jsx: FOUND +- onDeleteSet prop wired through WorkoutPage: FOUND + +--- +*Phase: 02-flexible-sets* +*Completed: 2026-02-21*