Commit Graph

130 Commits

Author SHA1 Message Date
alexandrev-tibco 79423e3511 tests: target MealMoodUITests que recorre el onboarding completo
El bug de los pasos 5 y 6 era invisible a los tests unitarios: el contrato de
datos estaba bien, lo que fallaba era que la vista se desmontaba antes de pintar
el aha moment y el paywall. Hace falta recorrer la UI de verdad.

Anade el target MealMoodUITests (solo simulador, sin firma) y un test que hace
el onboarding entero en instalacion limpia y comprueba que Week Ready y el
paywall aparecen antes de la Home.

Los CTA del onboarding llevan ahora accessibilityIdentifier para que el test no
dependa de los textos, que estan en 6 idiomas.

Validado en los dos sentidos: pasa con el fix, y revirtiendo temporalmente
markFinished: false falla en la asercion de Week Ready. Suite completa: 27 tests.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Ks8uUcMA9mjypVK7F2Pkt
2026-08-05 23:06:04 +02:00
alexandrev-tibco 9f5db245a9 fastlane: lane refresh_dsyms para subir dSYMs a Crashlytics
La build phase de Xcode solo sube el dSYM de la compilacion local. No habia red
de seguridad, asi que un fallo del script deja los crashes sin simbolizar.

refresh_dsyms baja los dSYM de App Store Connect y los manda a Crashlytics. Se
ejecuta aparte de beta a proposito: beta usa skip_waiting_for_build_processing,
asi que justo tras el upload los dSYM aun no existen en ASC.

Dos detalles que salieron al ejecutarla de verdad:

- upload_symbols_to_crashlytics busca el binario en ./Pods, pero Firebase entra
  por SPM y vive en DerivedData. Se resuelve con un glob.
- ASC no tiene dSYMs para la build 64 (normal sin bitcode: Apple no recompila
  nada). Sin fallback la lane seria un no-op permanente, asi que tira de los
  dSYM del ultimo archive local (app + widget).

Verificado ejecutandola: sube los dos dSYM de la 64 correctamente.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Ks8uUcMA9mjypVK7F2Pkt
2026-08-05 20:57:50 +02:00
alexandrev-tibco 3694297d4f 2.0: mostrar los dos ultimos pasos del onboarding (aha moment + paywall)
completeOnboarding escribia settings.onboardingCompleted al terminar el paso
de platos. Ese flag es el que ContentView observa para cambiar de OnboardingView
a HomeView, asi que el save destruia el flujo antes de que nextStep() pudiera
pintar el paso 5. WeekReadyStepView (el aha moment de la 1.2.0) y PaywallStepView
no se han visto nunca. GA4 lo confirma: 3 onboarding_completed en 28 dias y cero
eventos con step 5 o 6.

Se separa persistir los datos de marcar el onboarding como terminado:
completeOnboarding(markFinished:) commitea platos y plan sin tocar el flag, y el
nuevo finishOnboarding() lo escribe al salir del paywall. HomeView ya difiere su
prompt premium a la segunda sesion, asi que no hay paywall duplicado.

De paso, los nombres de paso en AnalyticsService estaban desalineados: el indice
5 decia "5_paywall" cuando el paso 5 es WeekReady, y el 6 no tenia nombre.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Ks8uUcMA9mjypVK7F2Pkt
2026-08-05 20:53:10 +02:00
alexandrev-tibco 10a3d8bf32 2.0: bump build 63 → 64 after TestFlight upload (slider, banner, share toolbar)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-26 09:21:43 +02:00
alexandrev-tibco a4aedffd5a 2.0: banner export solo en semana completa + compartir desde toolbar
- El banner "ready to export" ya no aparece con la semana incompleta; solo
  cuando no quedan slots vacíos (y sigue siendo descartable con la X).
- Se añade un icono de compartir en la toolbar (cuando hay algo planificado)
  para no perder el acceso a exportar en semanas parciales; misma lógica de
  premium/paywall que el banner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-26 08:34:05 +02:00
alexandrev-tibco 543254337f 2.0: banner export descartable + slider calendario/platos en iPad
- El banner "Your week is ready to export" ahora tiene botón de cerrar (X)
  que lo oculta para esa semana (persistido en AppStorage).
- iPad/Mac: handle arrastrable entre calendario y platos para rebalancear
  el alto (fracción persistida, clamp 0.28–0.72); el calendario y la lista
  se recalculan al arrastrar. Sustituye la altura fija anterior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-24 16:29:22 +02:00
alexandrev-tibco b70140191a 2.0: firma manual (app+widget) para Push + bump build 62 → 63
El archive con firma automática no podía incluir la capability Push de
forma headless. Se pasan los targets MealMood y MealMoodWidget (config
Release) a firma manual con "Apple Distribution" y sus perfiles AppStore
(regenerados con Push). Build 63 sube a TestFlight con aps-environment
production para el sync CloudKit en tiempo real.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-24 15:59:42 +02:00
alexandrev-tibco d957921fe3 2.0: sync CloudKit en tiempo real vía push silencioso
NSPersistentCloudKitContainer solo sincronizaba de forma oportunista (sin
push), por lo que un plato nuevo tardaba mucho o no aparecía en el otro
dispositivo. Se activa el push de CloudKit:

- aps-environment en MealMood.entitlements vía variable APS_ENVIRONMENT
  (development en Debug, production en Release) para no romper TestFlight.
- AppDelegate con registerForRemoteNotifications() + manejo del push
  silencioso; el mirror de SwiftData importa al ser despertado.
- (Capability Push Notifications habilitada en el App ID por API.)

Pendiente: regenerar el provisioning profile AppStore con Push antes de
la build 63, y validar el sync push en iPhone+iPad vía TestFlight.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-24 15:47:46 +02:00
alexandrev-tibco 19bf3178d8 2.0: actualizar review notes (sin login, dictado, IA ingredientes, premium)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-24 15:03:14 +02:00
alexandrev-tibco 5862180426 2.0: bump build 61 → 62 after TestFlight upload (dedup platos)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-24 15:01:37 +02:00
alexandrev-tibco 9a898be7cf 2.0: release notes "What's New" en los 6 idiomas
Lista de compra, ingredientes IA on-device, dictado, fotos de platos,
desayuno/merienda, sync CloudKit, editar plato desde la lista.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-24 14:59:59 +02:00
alexandrev-tibco 4f3664cdd4 2.0: deduplicar Dishes por id en DeduplicationService (determinista)
DeduplicationService colapsaba settings, tags y week plans pero NO los
platos, dejando duplicados de CloudKit (mismo UUID) que causaban el crash
de arranque y platos repetidos en pantalla. Se añade dedupeDishes:

- Solo agrupa y colapsa copias que comparten el mismo id (nunca fusiona
  platos distintos ni toca platos únicos).
- Keeper elegido de forma DETERMINISTA (copia más rica: foto/desc/
  ingredientes/tags/prioridad; desempate por persistentModelID estable),
  así todos los dispositivos de la cuenta borran los mismos perdedores y
  el grafo converge a una copia, nunca a cero.
- CloudKit private DB por Apple ID (sin CKShare) → jamás cruza cuentas de
  Family Sharing.

Junto con el uniquingKeysWith previo, la app deja de crashear y limpia los
platos duplicados en cada arranque, sin borrar la BD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-22 20:39:07 +02:00
alexandrev-tibco 0ac81e5fe3 2.0: bump build 60 → 61 after TestFlight upload (fix crash arranque IDs duplicados)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-22 18:28:05 +02:00
alexandrev-tibco 5272f6533f 2.0: fix crash de arranque por IDs duplicados (CloudKit)
Fatal error "Duplicate values for key" al construir diccionarios con
Dictionary(uniqueKeysWithValues:) sobre dishes/tags/slots cuyos UUID se
duplican por la sincronización CloudKit de 2.0. Se sustituyen todas las
ocurrencias por Dictionary(_, uniquingKeysWith:) para tolerar duplicados
(se conserva el primero) en lugar de abortar. La app ya no crashea al
abrir con datos duplicados; la deduplicación real queda pendiente aparte.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-22 18:23:50 +02:00
alexandrev-tibco 817ae549dc 2.0: bump build 59 → 60 after TestFlight upload (dictado + calendario iPad)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-22 18:17:07 +02:00
alexandrev-tibco 8e4d0c2d89 2.0: dictado de platos/ingredientes + calendario más alto en iPad/Mac
- Dictado por voz (Speech/SFSpeechRecognizer, on-device) en el nombre de
  plato y en ingredientes, con transcripción en vivo.
- Un solo texto dictado se separa en ingredientes individuales vía Apple
  Foundation Models on-device (IngredientParser), con fallback heurístico.
- Permisos de micrófono y reconocimiento de voz en Info.plist.
- Cadenas de dictado en los 6 idiomas.
- iPad/Mac: el calendario reclama ~50% de la altura disponible en lugar
  de quedar fijo a ~240px; iPhone (compact) sin cambios.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3HaWmmtTQ1vdTERtSYU6p
2026-07-22 18:16:51 +02:00
alexandrev-tibco cbcccd66ed 2.0: bump build 58 → 59 after TestFlight upload (GA4 onboarding step fix)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Df9kZEUMXPLn4Kb9Zx1f5o
2026-07-21 09:23:09 +02:00
alexandrev-tibco 148a301d6c 2.0: analytics — log onboarding step as String + step_name for GA4 drop-off
GA4 text custom dimensions do not capture numeric params (step showed as
"(not set)"). Log step as String and add a readable step_name so the
onboarding drop-off is queryable. Registered source/environment/step_name
custom dimensions in the GA4 property to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Df9kZEUMXPLn4Kb9Zx1f5o
2026-07-21 09:19:50 +02:00
alexandrev-tibco 029e8d7e1a 2.0: bump build 57 → 58 after TestFlight upload (beta feedback round 1)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-14 22:28:03 +02:00
alexandrev-tibco 29cba08678 2.0: beta feedback — edit dish from shopping list + dish photos in planner
- 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
2026-07-14 22:06:11 +02:00
alexandrev-tibco 9118cc6e86 2.0: bump build 56 → 57 after TestFlight upload (2.0 beta)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-13 21:54:33 +02:00
alexandrev-tibco 13f0d8c04a docs: CLAUDE.md → version 2.0
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-12 18:16:00 +02:00
alexandrev-tibco 4ffa15b06a 2.0: CloudKit private-database sync replaces KV snapshot sync
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
2026-07-12 18:13:45 +02:00
alexandrev-tibco e15ff93465 2.0: breakfast and snack meal types across the app
- MealType gains breakfast/snack (chronological order drives slot/row order).
- AppSettings.activeMealTypes: single source of truth for enabled meals, backed
  by new optional enabledMealTypesRaw with legacy mealWindows fallback —
  additive migration, keeps pre-2.0 installs and iCloud snapshots working.
  Legacy field kept coherent by the setter. time(for:) resolves per-meal event
  times (breakfast 8:00 / snack 17:00 defaults on old stores).
- Replaced the 5 duplicated mealWindows→[MealType] derivations (slot sync,
  default plan creation, week calendar, export view) with activeMealTypes.
- CalendarService: per-type event names and times.
- Export styles: per-type accent colors and gradients.
- Widget: generic meals list (N rows) instead of hardcoded lunch/dinner;
  compact families fall back to main meals when >2 are active.
- Settings: 4 meal toggles (min 1) replace the 3-option picker.
- Onboarding: meal step is now multi-select over the 4 types.
- iCloud sync: enabledMealTypesRaw synced (optional, pre-2.0 compatible).
- Localized breakfast/snack in all 6 languages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-12 18:00:50 +02:00
alexandrev-tibco 98230c732d 2.0: dish editor gains photo picker and ingredients section
- PhotosPicker with downscaling (1024pt max, JPEG 0.8) before storing in
  photoData; change/remove actions.
- Ingredients: editable line list (add/edit/remove) + on-device "Generate"
  from the dish name (hidden when Foundation Models unavailable; paywall
  after the free generation quota, source=ingredient_generation).
- DishViewModel: drafts ingredients/photo, cleans empty lines on save.
- Localized in all 6 languages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-12 17:51:33 +02:00
alexandrev-tibco ce88d7b265 2.0: weekly shopping list from planned dishes
- 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
2026-07-12 17:47:41 +02:00
alexandrev-tibco a5c304e209 2.0: Dish gains optional ingredients + photo; on-device ingredient generation
- Dish: ingredients [String] (default [], never required) and photoData
  (externalStorage). Additive SwiftData migration — existing stores unaffected.
- ICloudSyncService: sync ingredients (optional in payload so pre-2.0 snapshots
  still decode); photos deliberately excluded from KV sync (1MB limit).
- IngredientGenerator: Foundation Models (iOS 26+) generates localized
  ingredient lines from the dish name, fully on-device. isAvailable gates the
  UI affordance on older OS/devices; failures record to Crashlytics and
  return [].

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-12 17:41:46 +02:00
alexandrev-tibco c6c33d8143 2.0: bump MARKETING_VERSION 1.2.1 → 2.0 (major feature release: ingredients + shopping list, photos, breakfast/snacks, CloudKit family sharing)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-12 17:37:21 +02:00
alexandrev-tibco 75cf7ebaad docs: update CLAUDE.md current version to 1.2.1 (1.2.0 shipped)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-11 11:00:15 +02:00
alexandrev-tibco 8ba8e4e933 1.2.1: bump MARKETING_VERSION 1.2.0 → 1.2.1 (1.2.0 shipped to App Store)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-11 10:59:43 +02:00
alexandrev-tibco 6ba71e6341 1.2.1: surface "Copy previous week" on the empty-week banner
The exact-copy-from-previous-week action already existed but was buried in the
magic-wand long-press context menu. Expose it as a visible secondary button on
the auto-assign banner (shown only when the previous week actually has a menu),
so users landing on a fresh week can one-tap copy last week's plan and then tweak
it. Confirms before overwriting a week that already has dishes.

- Extract requestCopyPreviousWeek() shared by the menu and the banner.
- Add week_copied_previous analytics (copied_slots + source: empty_banner|menu).
- Reuses the existing localized home_copy_previous_week string (all 6 languages).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-11 10:58:53 +02:00
alexandrev-tibco c5fd1088cd 1.2.0: bump build 55 → 56 after TestFlight upload (Crashlytics non-fatals)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-10 14:37:32 +02:00
alexandrev-tibco 56abe28a82 1.2.0: report non-fatal errors to Crashlytics across key error paths
CrashlyticsService was wired only for the is_premium custom key. Route the
swallowed errors in the main catch blocks through CrashlyticsService.record
with a context tag, so non-fatals show up in Firebase (StoreKit load/purchase/
restore, calendar access/create/update/delete, reset-all-data, onboarding save).
Debug prints kept.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-10 14:27:28 +02:00
alexandrev-tibco 619d5f921d 1.2.0: localized App Store screenshots (es/de/fr/it/pt-BR) + 1.2.0 release notes
- Caption-localized the 5 iPhone 6.7" + 5 iPad 12.9" screenshots into the 5
  non-English locales, reusing the en-US framed captures (in-frame UI stays EN).
  Tooling in fastlane/screenshot_localize/ (Pillow: repaints the pastel caption
  band, re-renders headline/subtitle in SF Pro; auto-fits + wraps per language).
- Rewrote release_notes 1.2.0 in all 6 languages: since 1.1.5 never shipped
  publicly (last public = 1.1.4), the notes consolidate 1.1.5 + 1.2.0 features.
- Fastfile: new `publish` lane — uploads metadata + screenshots for an existing
  TestFlight build (skip_binary_upload, no submit) so offer codes can be set up
  before submission.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkanrydYtrme8wipTzWssG
2026-07-09 10:42:44 +02:00
alexandrev-tibco 313403ecd5 1.2.0: bump version 1.1.5 → 1.2.0, build 54 → 55 after TestFlight upload
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtWT52pAE91D7mbDda1cAM
2026-07-03 10:19:43 +02:00
alexandrev-tibco cbe0ca1326 1.2.0: offer code redemption + share link alongside export image
- "Redeem promo code" button in PremiumView via offerCodeRedemption
  (hidden on Mac where the sheet is unavailable); entitlement re-checked
  on success — unblocks influencer/blog promo campaigns
- System share sheet now includes a localized text with the mealmood.app
  link next to the exported image (viral loop no longer QR-only)
- 2 new strings × 6 languages

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtWT52pAE91D7mbDda1cAM
2026-07-03 10:14:58 +02:00
alexandrev-tibco f5cb67adc0 1.2.0: widget deep-link, Lock Screen widgets, in-app widget promo
- Tapping the widget now deep-links via mealmood://today back to the current
  week (URL scheme registered, onOpenURL handler in Home)
- New Lock Screen widget families: accessoryRectangular (weekday + both
  meals) and accessoryInline (next relevant meal)
- One-time dismissable widget promo card on Home from the 2nd session,
  with widget_promo_shown/dismissed analytics
- 2 new strings × 6 languages

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtWT52pAE91D7mbDda1cAM
2026-07-03 10:11:40 +02:00
alexandrev-tibco 73c2039338 1.2.0: contextual notifications + in-onboarding auto-fill (aha moment)
- New "Week Ready" onboarding step: auto-fills the first week inline right
  after dish creation, then pitches the Sunday reminder with context before
  requesting OS notification permission (no more cold prompt on Home)
- Notifications section in Settings: weekly reminder toggle, deep-link to
  system settings when permission is denied
- NotificationService: remindersEnabled preference, requestPermission(),
  authorizationStatus(), cancelAllReminders()
- Post-onboarding premium prompt deferred to 2nd session (paywall was just
  shown as the final onboarding step — 2s-later alert was prompt fatigue)
- Back navigation blocked after onboarding commit to avoid duplicate dishes
- 10 new strings × 6 languages

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtWT52pAE91D7mbDda1cAM
2026-07-03 10:08:04 +02:00
alexandrev-tibco 13ece5f2e7 1.1.5: bump build 53 → 54 after TestFlight upload
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtWT52pAE91D7mbDda1cAM
2026-07-02 13:31:39 +02:00
alexandrev-tibco 9cadc1ad18 1.1.5: fix activation analytics blind spots + purchase environment tagging
- dish_added now carries a `source` param; onboarding-created dishes fire
  it with source="onboarding" (previously untracked, undercounting activation)
- onboarding_completed now reports dish_count
- premium_purchased tagged with StoreKit environment (production/sandbox/xcode)
  so test purchases can be excluded from conversion metrics
- add .gitignore to keep signing secrets (.p12/.cer/.mobileprovision) and
  build artifacts out of the repo
- document branch↔MARKETING_VERSION naming convention

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtWT52pAE91D7mbDda1cAM
2026-07-02 13:26:45 +02:00
alexandrev-tibco 95f43c7f23 1.1.5: bump build 52 → 53 after TestFlight upload
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 08:05:17 +02:00
alexandrev-tibco caf25bc33f 1.1.5: auto-fill first week after onboarding
Land new users on a ready, auto-planned week (with confetti) instead of an
empty one, to improve activation. Only fires when the user added dishes;
otherwise keeps the current empty-week + auto-assign prompt behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 08:02:15 +02:00
alexandrev-tibco 82d623aa05 1.1.5: bump build 51 → 52 after TestFlight upload
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:27:04 +02:00
alexandrev-tibco b45cb2a530 1.1.5: conversion funnel overhaul
Paywall:
- Redesigned PremiumView with yearly/monthly/lifetime side by side
- 7-day free trial badge with savings % vs monthly
- Social proof line, BEST VALUE highlight on yearly
- StoreManager: new yearlyProduct, lifetimeProduct, yearlySavingsPercent, hasTrialAvailable

Funnel:
- Paywall step added to onboarding (PaywallStepView)
- Contextual modal at dish limit (replaces silent block)
- Visible "X/15 dishes" counter in DishListView
- BottomPromoBanner rotates AdMob with internal "Remove ads" CTA (1 in 4)
- Free dish limit lowered 20 → 15
- Review prompt earlier: 2 weeks → 1 week

Analytics:
- paywall_viewed/dismissed with source + seconds_on_screen
- dish_limit_hit, week_limit_hit, free_trial_started events
- Every PremiumView call site now passes its source

StoreKit:
- MealMood.storekit: added yearly $19.99 + 7d trial, monthly trial, lifetime $39.99
- AppStoreConnect-1.1.5-setup.md with full manual setup instructions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:21:36 +02:00
alexandrev-tibco 72770801d3 1.1.5: add analytics for stats_viewed and week_rated events
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 13:49:33 +02:00
alexandrev-tibco 946c788ef6 Fastfile: enable automatic_release by default in release lane
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 17:07:09 +02:00
alexandrev-tibco 790c412329 1.1.4: release notes — remove emoji (App Store API restriction)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 14:16:47 +02:00
alexandrev-tibco bd9ecab64d 1.1.4: App Store release notes in 6 languages
Stats, smarter auto-assign, and feedback loop (implicit rejection
+ weekly 👍/👎 rating).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 13:45:23 +02:00
alexandrev-tibco f4e1aef8d5 1.1.4 (50): TestFlight upload — switch to ASC API key auth
Build 50 uploaded to TestFlight. Also migrates Fastfile from
Apple ID + app-specific-password to App Store Connect API key
(via pass) to avoid session expiry on future uploads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 19:36:49 +02:00
alexandrev-tibco 304774991d 1.1.4 (49): bump version for TestFlight
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 19:26:13 +02:00