Commit Graph

15 Commits

Author SHA1 Message Date
alexandrev-tibco d88cc59627 Goals por categoría: ámbito de categoría en objetivos (build 88) #46
Un Goal ya podía acotarse por cuenta; ahora también por categoría de
fuente, de modo que se puede fijar "100.000 € en Cash" y que el progreso
cuente solo las fuentes de esa categoría.

- CoreData: relación Goal.category ↔ Category.goals (opcional, Nullify)
- Goal.includes(_:)/relevantSources(from:)/scopeKey centralizan el filtro
  de ámbito (cuenta Y categoría) que antes estaba duplicado en
  GoalsViewModel, AddSourceView y NotificationService
- GoalEditorView: sección "Ámbito" con selector de categoría
- Chip de categoría en la lista de Goals y en la tarjeta del Dashboard
- ETA del Dashboard para goals con ámbito: usa la proyección del propio
  goal en vez de la evolución global de la cartera (que daría "objetivo
  alcanzado" en cuanto la cartera total superara el importe)
- GoalRepository e ImportService deduplican por (nombre, cuenta, categoría)
- Export/Import de goals incluye "category"
- Nuevas claves localizadas en los 7 idiomas

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YcDn5ccuRFV83q7xWWokBT
2026-09-12 09:32:02 +02:00
alexandrev-tibco fd1094b4fc 1.6.0 #3: limpieza CloudKit-safe de duplicados de defaults (merge + Nullify)
Reglas de borrado Account.sources/goals y Category.sources: Cascade -> Nullify.
Así un borrado de padre (local o propagado por CloudKit al importar) NUNCA arrasa
hijos — elimina de raíz el mecanismo del desastre del build 68. Además es mejor UX
(borrar una categoría ya no borra todas sus sources+snapshots).

CoreDataStack.mergeDefaultDuplicates(): fusiona los Account 'Default' duplicados y
las categorías duplicadas por nombre en un ganador DETERMINISTA (el registro con el
UUID estable si existe, si no earliest createdAt / menor UUID → todos los dispositivos
convergen). Reasigna sources/goals al ganador y borra los perdedores (seguro por Nullify).
Llamado en la carga inicial y tras cada import remoto.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2p3gUZRNWW388rWFRjiU7
2026-07-25 12:18:42 +02:00
alexandrev-tibco 1a3fce0df4 1.6.0 foundation: dedup prevención completa + atributo isEstimated
Dedup prevención: UUIDs estables (StableID v5) asignados al default Account y a las
categorías por defecto en createDefaultAccountIfNeeded, ensureDefaultCategoriesExist,
createDefaultCategories y el reset de SettingsViewModel → CloudKit fusiona nativamente,
no más acumulación de duplicados.

isEstimated: nuevo atributo Bool opcional (default NO, syncable) en Snapshot para marcar
snapshots interpolados del auto-relleno. Requiere deploy de schema CloudKit antes del
release. Compila verde (verificado antes de que el agente de widgets empezara a editar).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2p3gUZRNWW388rWFRjiU7
2026-07-25 12:09:59 +02:00
alexandrev-tibco eee0910680 Rama 1.6.0: dedup CloudKit-safe (WIP: StableID + UUIDs estables en defaults)
Funde 1.5.1 en 1.6.0. Parte 1 dedup (prevención): StableID (UUIDv5 namespace+nombre),
Account.defaultAccountStableID, Category.stableID(for:) + asignación en
createDefaultCategories. Pendiente: asignar en repos + limpieza de duplicados existentes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2p3gUZRNWW388rWFRjiU7
2026-07-25 12:04:04 +02:00
alexandrev-tibco 7eb7cb81d4 Fix sync iCloud del Goal: accessor nil-tolerante en createdAt (Goal/Account/InvestmentSource)
El modelo declara createdAt optional=YES pero las clases lo tenían @NSManaged var createdAt: Date
(no-opcional). Al materializar un registro importado por CloudKit con createdAt transitoriamente
nil, el acceso revienta el merge → contribuye al CKErrorPartialFailure y a que el Goal no sincronice.
Mismo patrón safeValue/setManagedValue ya aplicado a Snapshot (hotfix b76b8f8) que no cubrió estas 3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LZFmGhbWzibhApev3C4554
2026-07-21 15:22:42 +02:00
alexandrev-tibco b76b8f81f0 Hotfix: accessors nil-tolerantes en Core Data — crashes de bridging con iCloud sync (build 56)
Dos crashes de producción con la misma causa raíz: atributos declarados
no-opcionales en Swift (@NSManaged id: UUID, date: Date) que llegan nil en
runtime — NSPersistentCloudKitContainer materializa registros de otros
dispositivos por fases y los objetos borrados pueden seguir referenciados por
vistas vivas. El force-bridge de nil revienta:

1. UUID._unconditionallyBridgeFromObjectiveC en ForEach (keypath Identifiable.id)
2. Date._unconditionallyBridgeFromObjectiveC en ChartsViewModel.monthlyTotals

Fix sistémico (no por call-site): NSManagedObject.safeValue(forKey:fallback:healing:)
lee el primitive y cae a un valor seguro; id se auto-cura (UUID nuevo escrito al
primitive sin ensuciar el objeto). Aplicado a:
- Snapshot: id (heal), date, createdAt (fallback distantPast)
- InvestmentSource / Goal / Account: id (heal), name (fallback "")
- Category: id (heal), name, colorHex, icon (fallbacks neutros)

Los accessors son @objc → NSSortDescriptor(keyPath:) y KVC siguen funcionando.
awakeFromInsert/awakeFromFetch se mantienen. Smoke test UITest en verde.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoScpmHdVj1aUf4rAp6hbe
2026-07-10 13:28:59 +02:00
alexandrev-tibco 9927d21b86 Sync monthly contributions y allocation targets vía iCloud (CoreData)
Ambos vivían en UserDefaults (device-local, no sincroniza). Migrados a atributos
CoreData en entidades ya syncable=YES, así que ahora sincronizan por CloudKit:

- InvestmentSource.monthlyContribution (Decimal, opcional)
- Category.allocationTarget (Double, opcional)

Los stores mantienen su API por UUID (0 cambios en call sites) pero ahora leen/escriben
del atributo CoreData vía fetch por id. migrateIfNeeded(context:) mueve una sola vez los
valores del diccionario UserDefaults legacy al modelo y borra la clave; enganchado en
CoreDataStack.loadPersistentStores junto a MonthlyCheckInStore.

DashboardLayoutStore se mantiene en UserDefaults a propósito (preferencia de UI por
dispositivo: el columnSpan solo aplica en iPad).

NOTA: requiere desplegar el schema CloudKit a producción (CD_monthlyContribution,
CD_allocationTarget) antes de que sincronice en TestFlight/App Store.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015qUZrBusG82T37R7PeokqJ
2026-07-01 09:28:37 +02:00
alexandrev-tibco 270edeb536 Migrate journal entries to CoreData for iCloud sync (build 33)
- Add JournalEntry CoreData entity (syncable=YES): id, monthKey, note, moodRaw, rating, completionTime, createdAt
- Rewrite MonthlyCheckInStore: CoreData as primary storage, same public API
- One-time migration from UserDefaults triggered after store loads
- MonthlyCheckInCard: @FetchRequest on JournalEntry — reactive to iCloud sync
- MonthlyCheckInView: onReceive NSManagedObjectContextObjectsDidChange to refresh @State vars on sync
- Stats cards: observe NSManagedObjectContextObjectsDidChange instead of UserDefaults
- ChartsViewModel.completedMonthKeys: remove MonthlyCheckInStore dependency (data-driven)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 15:05:53 +02:00
alexandrev-tibco b48a47ce10 Release 1.4.0 (build 31): retención, quick update, streak, what's new
- 1A: Notificación mensual de resumen de portfolio (día 5 de cada mes)
- 1B: Badge de racha mensual en Dashboard (streak counter)
- 1C: Empty states mejorados en Goals y Journal con CTAs claros
- 2A: Quick Update sheet — actualiza todas las fuentes desde una pantalla
- 2B: Notificación batch update redirige al Quick Update sheet
- 2C: Widget deep link portfoliojournal://quickupdate abre Quick Update
- 3A: App Store version check banner en Settings
- 3C: What's New sheet en primer launch de versión nueva
- Localización completa en 7 idiomas para todas las nuevas strings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 23:09:36 +02:00
alexandrev-tibco 773da6800b Release 1.3.1 (build 20): iCloud sync fix + sources search/filter
iCloud sync:
- Fix: deploy CloudKit schema to production so exports work
- Fix: PredictionCache marked syncable=NO (binary attr caused partial failures)
- Fix: forceExportToiCloud uses createdAt+1ms for guaranteed persistent history
- Fix: auto-deduplication on CloudKit import (processRemoteChanges)
- Add: NSPersistentHistoryTrackingKey always enabled regardless of CloudKit state
- Add: cloudKitForceReload notification so repositories re-fetch on remote changes

Sources UI:
- Add: horizontal category filter chips in SourceListView
- Add: search toggle button with animated TextField

Other:
- Add: ITSAppUsesNonExemptEncryption=NO in Info.plist (skip manual compliance)
- Add: fastlane submit lane with run_precheck_before_submit=false
- Update: release notes all locales for 1.3.1
- Update: fastlane API key via pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 22:19:33 +02:00
alexandrev-tibco 7cb5f92cf4 Remove Add Transaction feature and clean all related code
Deleted files:
- AddTransactionView.swift
- TransactionRepository.swift
- Transaction+CoreDataClass.swift

Cleaned files:
- SourceDetailViewModel: removed transactions published property,
  showingAddTransaction flag, transactionRepository dependency,
  addTransaction() and deleteTransaction() methods
- SourceDetailView: removed transactionsSection, TransactionRow struct,
  Add Transaction button from quickActions, sheet presentation
- InvestmentSource+CoreDataClass: removed transactions NSManaged property,
  transactionsArray, totalInvested, totalDividends, totalFees computed
  properties, and all transaction Core Data accessors
- SettingsViewModel: removed "Transaction" from resetAllData entity list
- SampleDataService: removed transactionRepository and sample transaction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 23:04:03 +01:00
alexandrev-tibco 4761e2e5c8 1.1.0 feature work: Monthly Check-in, Charts, Goals, Share, Reviews
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:37:11 +01:00
alexandrev-tibco e328767c4a Base fixes and test harness 2026-02-01 11:12:57 +01:00
alexandrev b03d35194f Primera build enviada 2026-01-19 14:40:43 +01:00
alexandrev-tibco 7988257399 initial version 2026-01-15 09:24:06 +01:00