Refactor from weekly-based food plans to a continuous date-based model. Replace the FoodPlan entity (weekly plans) with a FoodPlanSettings entity (global configuration), change FoodPlanEntry.DayOfWeek to FoodPlanEntry.Date, add per-entry shopping list tracking, and remove auto-renewal. Requires two deployments to safely handle DB constraint changes with zero data loss.
Goal: Add new columns, migrate data, keep old columns for rollback safety.
New entity in Anything.Core/Entities/FoodPlanSettings.cs:
public class FoodPlanSettings
{
public int Id { get; set; }
public int ActiveDays { get; set; } = 31; // bitmask, Mon-Fri default
public DateTime CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
}- Single row, no soft delete (configuration entity)
- Add EF config in
Anything.Database/Configurations/FoodPlanSettingsConfiguration.cs
- Add
Date(DateTime, nullable initially for migration) - Add
AddedToShoppingListOn(DateTime?, nullable — null means not yet added) - Make
FoodPlanIdnullable (currently required FK)
Create migration that:
- Creates
FoodPlanSettingstable - Adds
Datecolumn (nullable) toFoodPlanEntries - Adds
AddedToShoppingListOncolumn (nullable) toFoodPlanEntries - Makes
FoodPlanIdnullable onFoodPlanEntries - Data migration SQL:
-- Populate Date from FoodPlan.WeekStart + DayOfWeek UPDATE "FoodPlanEntries" e SET "Date" = ( SELECT fp."WeekStart" + make_interval(days => e."DayOfWeek") FROM "FoodPlans" fp WHERE fp."Id" = e."FoodPlanId" ); -- Seed FoodPlanSettings from the most recent non-deleted FoodPlan's ActiveDays INSERT INTO "FoodPlanSettings" ("ActiveDays", "CreatedOn") SELECT COALESCE( (SELECT "ActiveDays" FROM "FoodPlans" WHERE "DeletedOn" IS NULL ORDER BY "WeekStart" DESC LIMIT 1), 31 ), NOW();
- Make
Datenon-nullable (after data is populated) - Set
FoodPlanIdto null on all entries (data is now inDate)
FoodPlanEntry.cs changes:
- Add
Date(DateTime, required) - Add
AddedToShoppingListOn(DateTime?, nullable) - Make
FoodPlanIdnullable (int?) - Keep
DayOfWeekfor now (removed in Deployment 2)
FoodPlan.cs: Keep as-is for rollback safety
Update handlers to work with the new Date field while still supporting old queries:
AddFoodPlanEntry: AcceptDateinstead ofDayOfWeek. ComputeDayOfWeekfromDatefor backward compat.UpdateFoodPlanEntry: AcceptDate, computeDayOfWeek.GetFoodPlanEntries: Query by date range instead of FoodPlanId. New query:GetFoodPlanEntriesByDateRange.AddFoodPlanToShoppingList: Update to setAddedToShoppingListOnon entries. Change to accept date range instead of FoodPlanId.- Remove
FoodPlanAutoRenewService: No longer needed.
New handlers:
GetFoodPlanSettings/UpdateFoodPlanSettings: CRUD for the settings entity.
AddFoodPlanEntryRequest: ReplaceDayOfWeekwithDate(DateTime)UpdateFoodPlanEntryRequest: ReplaceDayOfWeekwithDateAddFoodPlanToShoppingListRequest: Replace FoodPlan ID route with date range params (StartDate,EndDate)- New:
UpdateFoodPlanSettingsRequest:ActiveDays(int, 1-127) - New:
FoodPlanSettingsResponse:ActiveDays
FoodPlanEndpoints.cs restructure:
- Remove:
POST /api/food-plans(create plan),PUT /api/food-plans/{id}(update plan),DELETE /api/food-plans/{id}(delete plan),GET /api/food-plans(list plans),GET /api/food-plans/{id}(get plan) - Keep/modify: Entry endpoints move to
/api/food-plan/entries(singular "food-plan") - Add:
GET /api/food-plan/settings,PUT /api/food-plan/settings - Modify:
GET /api/food-plan/entries?startDate=...&endDate=... - Modify:
POST /api/food-plan/entries(no longer nested under plan ID) - Modify:
POST /api/food-plan/add-to-shopping-list(accepts date range in body)
Hooks (useFoodPlans.ts):
- Remove plan-level hooks (
useFoodPlans,useFoodPlan,useCreateFoodPlan,useUpdateFoodPlan,useDeleteFoodPlan) - Update entry hooks to use date-range queries
- Add
useFoodPlanSettings,useUpdateFoodPlanSettings - Update
useAddFoodPlanToShoppingListfor date-range
Components:
- Remove/refactor
FoodPlanForm.tsx(no more plan creation with WeekStart) - Update
AddToFoodPlanDialog.tsx— no plan selection needed, just pick a date - Update food plan pages to show continuous calendar view
Utils (foodPlanUtils.ts):
- Keep bitmask utilities (still used for ActiveDays)
- Remove
toDateInputValueif no longer needed
Add migration-specific integration tests:
- Data integrity test: Seed FoodPlans + FoodPlanEntries with known data, run migration, verify
Date = WeekStart + DayOfWeekfor every entry - Settings seeded test: Verify FoodPlanSettings row exists with correct ActiveDays
- Soft-deleted entries: Verify soft-deleted entries also get their Date populated correctly
- No data loss: Count entries before and after migration — must match
Update existing FoodPlanEndpointTests:
- Update to use new endpoints (date-based)
- Test AddedToShoppingListOn tracking
- Test FoodPlanSettings CRUD
- Update
useFoodPlans.test.tsxfor new hook signatures - Add tests for settings hooks
- Update component tests
Goal: Remove deprecated columns and the FoodPlans table.
- Drop
DayOfWeekcolumn fromFoodPlanEntries - Drop
FoodPlanIdcolumn fromFoodPlanEntries(FK already nullable/unused) - Drop
FoodPlanstable entirely
- Remove
DayOfWeekandFoodPlanIdfromFoodPlanEntry.cs - Delete
FoodPlan.csentity - Delete
FoodPlanConfiguration.cs - Update
FoodPlanEntryConfiguration.cs(remove FoodPlan relationship)
- Delete
CreateFoodPlan,UpdateFoodPlan,DeleteFoodPlan,GetFoodPlans,GetFoodPlanByIdhandlers - Delete
CreateFoodPlanRequest,UpdateFoodPlanRequestcontracts - Clean up any remaining references
| File | Purpose |
|---|---|
src/Anything.Core/Entities/FoodPlanSettings.cs |
Settings entity |
src/Anything.Database/Configurations/FoodPlanSettingsConfiguration.cs |
EF config |
src/Anything.Application/Features/FoodPlans/Queries/GetFoodPlanSettings.cs |
Get settings |
src/Anything.Application/Features/FoodPlans/Commands/UpdateFoodPlanSettings.cs |
Update settings |
src/Anything.Application/Features/FoodPlans/Queries/GetFoodPlanEntriesByDateRange.cs |
Date-range query |
src/Anything.Contracts/FoodPlans/UpdateFoodPlanSettingsRequest.cs |
Settings DTO |
| 2 EF migrations | Schema changes |
| File | Changes |
|---|---|
src/Anything.Core/Entities/FoodPlanEntry.cs |
Add Date, AddedToShoppingListOn, make FoodPlanId nullable |
src/Anything.Database/Configurations/FoodPlanEntryConfiguration.cs |
Update for new columns |
src/Anything.Application/Features/FoodPlans/Commands/AddFoodPlanEntry.cs |
Use Date instead of DayOfWeek |
src/Anything.Application/Features/FoodPlans/Commands/UpdateFoodPlanEntry.cs |
Use Date |
src/Anything.Application/Features/FoodPlans/Commands/AddFoodPlanToShoppingList.cs |
Date range + track entries |
src/Anything.Application/Features/FoodPlans/Commands/DeleteFoodPlanEntry.cs |
Remove FoodPlan dependency |
src/Anything.API/Endpoints/FoodPlanEndpoints.cs |
New endpoint structure |
src/Anything.Contracts/FoodPlans/AddFoodPlanEntryRequest.cs |
Date instead of DayOfWeek |
src/Anything.Contracts/FoodPlans/UpdateFoodPlanEntryRequest.cs |
Date instead of DayOfWeek |
src/Anything.Contracts/FoodPlans/AddFoodPlanToShoppingListRequest.cs |
Date range params |
anything-frontend/src/hooks/useFoodPlans.ts |
New hook structure |
anything-frontend/src/hooks/useFoodPlans.test.tsx |
Updated tests |
anything-frontend/src/app/food-plans/* |
Updated pages/components |
anything-frontend/src/components/AddToFoodPlanDialog.tsx |
Simplified flow |
anything-frontend/src/lib/foodPlanUtils.ts |
Updated utils |
| Integration tests | Updated for new endpoints |
| File | Reason |
|---|---|
src/Anything.Core/Entities/FoodPlan.cs |
Replaced by FoodPlanSettings |
src/Anything.Database/Configurations/FoodPlanConfiguration.cs |
Entity removed |
src/Anything.Application/Features/FoodPlans/Commands/CreateFoodPlan.cs |
No more plan creation |
src/Anything.Application/Features/FoodPlans/Commands/UpdateFoodPlan.cs |
No more plan updates |
src/Anything.Application/Features/FoodPlans/Commands/DeleteFoodPlan.cs |
No more plan deletion |
src/Anything.Application/Features/FoodPlans/Queries/GetFoodPlans.cs |
No more plan listing |
src/Anything.Application/Features/FoodPlans/Queries/GetFoodPlanById.cs |
No more single plan query |
src/Anything.Application/Features/FoodPlans/Services/FoodPlanAutoRenewService.cs |
No auto-renewal |
src/Anything.Contracts/FoodPlans/CreateFoodPlanRequest.cs |
No more plan creation |
src/Anything.Contracts/FoodPlans/UpdateFoodPlanRequest.cs |
No more plan updates |
- Pre-migration seed data → run migration → verify every entry has correct
Date - Soft-deleted entries preserved with correct dates
- FoodPlanSettings seeded from most recent plan's ActiveDays
- Entry count identical before and after migration
- Entries with NULL RecipeId handled correctly
- CRUD on entries with date-based API
- Date range queries return correct entries
- FoodPlanSettings CRUD
- AddToShoppingList with date range + verify
AddedToShoppingListOnset - AddToShoppingList skips entries already added (or re-adds — TBD)
- Hook tests for new API structure
- Component tests for date-based UI
- Create branch, commit pre-existing package-lock.json change
- Backend entities + EF config + migration (with data migration SQL)
- Backend handlers + commands/queries
- Backend endpoints + contracts
- Run backend build + integration tests
- Frontend hooks + utils
- Frontend components + pages
- Run frontend build + lint + tests
- Commit and push