UserWorkoutPlan module — personal plans with cloning from system templates, soft-delete, and one-active-plan enforcement.MyPlansScreen, CreatePlanScreen, and PlanEditScreen with day-tabbed exercise editing.| Day | Task | Start Date | Completion Date | Reference Material |
|---|---|---|---|---|
| 2 | - Build UserWorkoutPlan entity + Fields: user (@ManyToOne), name (≤150), description, goalTypeId (UUID), isActive (default true), isDeleted (default false) + Soft-delete via @SQLRestriction("is_deleted = false") — deleted plans invisible to all Hibernate queries + Write Flyway V1 migration: user_workout_plan, user_workout_plan_exercises tables |
02/03/2026 | 02/03/2026 | |
| 2 | - Write Flyway V2 migration: add is_deleted BOOLEAN DEFAULT FALSE to user_workout_plans |
02/03/2026 | 02/03/2026 | |
| 3 | - Build UserWorkoutPlanExercise entity + Same scheduling fields as system: dayOfWeek, sets, reps, restSeconds, dayIndex, weekIndex, orderIndex + References Exercise (system entity), UserWorkoutPlan |
02/04/2026 | 02/04/2026 | |
| 3 | - Implement UserWorkoutPlanService key business logic + userId always extracted from Jwt.getSubject() → never from request body (IDOR prevention) + Clone: deep-copy all WorkoutPlanExercise entries into UserWorkoutPlanExercise — no FK to source plan retained + Activate: set isActive=true on target plan, set isActive=false on all other user plans (one-active rule) |
02/04/2026 | 02/04/2026 | |
| 4 | - Build UserWorkoutPlanController (/api/user-workout-plans) + POST /me — create new plan + POST /me/clone/{systemPlanId} — clone system template + GET /me (summary list), GET /me/active, GET /{id} + PUT /{id} (update metadata), PUT /{id}/activate, DELETE /{id} (soft) + POST /{planId}/exercises, GET /{planId}/exercises, PUT /{planId}/exercises/{id}, DELETE /{planId}/exercises/{id} |
02/05/2026 | 02/05/2026 | |
| 5 | - Build MyPlansScreen (Frontend) + Lists all user plans with active indicator badge + Activate/deactivate toggle; soft-delete with ConfirmModal + Navigate to CreatePlanScreen or PlanEditScreen |
02/06/2026 | 02/06/2026 | |
| 5 | - Build CreatePlanScreen (Frontend) + Form: plan name, description, goal type dropdown (fetched from GET /api/goal-types) + On submit: createMyPlan then navigate to PlanEditScreen |
02/06/2026 | 02/06/2026 | |
| 6 | - Build PlanEditScreen (Frontend) + Day-of-week tab bar (Mon-Sun) to switch exercise view per day + List exercises for selected day with reorder (up/down arrows), delete button + Navigate to PlanExercisePicker to add exercises for a given day + All changes call addExerciseToPlan, updatePlanExercise, removePlanExercise APIs |
02/07/2026 | 02/07/2026 |
ddl-auto=create-drop.@SQLRestriction works — deleted plans never appear in queries.userId always taken from the validated JWT sub claim — zero risk of IDOR attacks.MyPlansScreen correctly shows active/inactive state; delete prompts confirmation modal.CreatePlanScreen form validates name/description before submitting.PlanEditScreen day-tab architecture allows intuitive per-day exercise management.uiSlice (planEditorDay, plansReloadKey) keeps plan editor state in sync across navigator.Follow-up Review — CloudFront Distribution Flow (Deep Dive from Lab 130)
During this week I documented and consolidated the CloudFront knowledge gained from Lab 130 (Week 4) into a reusable mental model:
https://d2b5rcxzmgnvyl.cloudfront.net/), CloudFront looks for the Default Root Object (index.html), fetches it from the S3 origin, and serves it to the user.GET /api → matches the /api/* cache behavior → routes to EC2 origin → calls origin-server/api.GET /images/logo.png → matches /images/* → routes to S3 origin.GET /about.html → no specific behavior matches → uses default behavior → S3 origin.app.v2.js) to force cache bypass without invalidation.UserWorkoutSession and WorkoutLog modules for tracking live workout activity.PlanDetailScreen (active plan dashboard with day selector) and WorkoutSessionScreen (live workout screen with Redux session state).