- MealSlot.secondaryDishId (opcional, aditivo CloudKit); se limpia al
sustituir/quitar/vaciar/marcar comer fuera y viaja en swaps, copia de
semana anterior, undo y snapshot KV de iCloud (retrocompatible)
- Picker de hueco lleno: toggle "anadir como segundo plato" + boton para
quitarlo; HomeViewModel.assignSecondaryDish/removeSecondaryDish
- Se muestra "Plato + Segundo" en calendario, widget y export; la lista
de la compra incluye los ingredientes del segundo; stats lo cuentan
- Evento analytics secondary_dish_added; strings en 6 idiomas
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013H6bXqGX1ygwib1Dm3n3UG
- Shopping list: dishes under "No ingredients yet" now open the dish editor on
tap (pencil affordance); list reconciles on dismiss. This was a dead end on
devices without Apple Intelligence (no Generate button, e.g. iPhone 14).
- Planner: dish photo as a scrimmed card background in the week calendar,
behind a new Settings toggle (settings_show_dish_photos, default on). New
optional AppSettings.showDishPhotosInPlanner (CloudKit/migration safe).
- FilledSlotView: inlines the meal-card chrome to support the photo layer.
- Toggle localized in all 6 languages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
Foundation for 2.1 family sharing (CKShare needs these models + container).
SwiftData cannot share across Apple IDs today, so 2.0 ships true multi-device
sync for the same account instead:
- Models made CloudKit-compatible: dropped @Attribute(.unique) on all 5,
inline defaults on every attribute, WeekPlan.slots stored as optional
relationship (name preserved → lightweight migration) with non-optional
slotList facade; ~73 call sites renamed.
- Container: cloudKitDatabase .automatic, falling back to the local-only
store when CloudKit is unavailable; failures recorded to Crashlytics.
- Entitlements: iCloud CloudKit service (container already existed);
remote-notification background mode for push-driven sync.
- Legacy KV snapshot sync (ICloudSyncService) stays inert when CloudKit is
active — kept only for 1.x devices.
- DeduplicationService collapses cross-device duplicates deterministically on
launch (settings singleton, default tags with tagId remapping, same-week
plans).
- Note: AppSettings.isPremium now syncs across same-Apple-ID devices; StoreKit
(PremiumSyncService + Transaction.updates) remains the source of truth and
reconciles on every launch/foreground.
All 21 unit tests pass, including ICloudSyncPremiumIsolationTests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
- ShoppingItem model (per-week lines; dish-derived or free-text) + schema.
- ShoppingListService.reconcile mirrors planned dishes' ingredients into the
list, preserving check-off state and user items; plain-text export helper.
- ShoppingListView: grouped by dish, check-off, swipe-delete, free-text adds,
clear-checked, ShareLink export, and inline on-device "Generate" for planned
dishes without ingredients (paywall after 3 free generations,
source=ingredient_generation).
- Home toolbar: cart entry point (all users) + sheet.
- Analytics: shopping_list_opened, shopping_item_added, ingredients_generated.
- Localized in all 6 languages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG