Skip to content

Latest commit

 

History

History
331 lines (238 loc) · 11.9 KB

File metadata and controls

331 lines (238 loc) · 11.9 KB

Guía de Configuración

Pasos para correr DucodeApp desde cero en local y, opcionalmente, distribuir a TestFlight.

Requisitos

Requisito Versión / detalle
macOS Sonoma 14+ recomendado
Xcode 26.0 o superior
iOS deployment target 26.0
Swift 5.9
iPhone físico iPhone 15 Pro / Pro Max o iPhone 16+ (Apple Intelligence)
Cuenta Whoop developer Gratis en developer.whoop.com
Apple Developer Program De pago (~99 USD/año) para distribuir a TestFlight
Herramientas CLI brew install xcodegen y, opcionalmente, gem install fastlane

Nota: el simulador puede correr la app pero (a) el OAuth de Whoop funciona mejor en dispositivo físico, y (b) Apple Intelligence solo funciona si tu Mac la soporta y la tienes activa. Para probar la experiencia real, usa un iPhone físico compatible.


Paso 1: Whoop Developer

1.1 Crear cuenta y app

  1. Ve a developer.whoop.com y entra con tu cuenta de Whoop.
  2. Acepta los términos de desarrollador.
  3. Click "Create App" en el dashboard.
  4. Llena los campos:
    • App Name: DucodeApp
    • Description: Personal nutrition app
    • App Website: cualquier URL válida

1.2 OAuth y scopes

  1. En la sección "Redirect URLs", agrega: ducode://oauth/callback
  2. En "Scopes", habilita:
    • read:recovery
    • read:cycles
    • read:workout
    • read:sleep
    • read:profile
    • read:body_measurement

El scope offline se solicita en runtime (es necesario para obtener refresh_token); no se configura en el dashboard.

1.3 Copiar credenciales

Guarda en un lugar seguro:

  • Client ID (UUID-style)
  • Client Secret (string largo)

Paso 2: Apple Intelligence

La app usa Foundation Models (on-device). No requiere API key, no tiene costo y los datos no salen del dispositivo.

2.1 Activar en el iPhone

  1. Ve a Ajustes → Apple Intelligence y Siri.
  2. Activa Apple Intelligence.
  3. Espera a que el modelo se descargue (puede tardar varios minutos la primera vez; hazlo conectado a Wi-Fi y con carga).

2.2 Verificar disponibilidad

La app detecta automáticamente el estado y muestra un mensaje si no está disponible (dispositivo no compatible, Apple Intelligence apagada, modelo descargándose). Ver ./INTEGRATIONS.md.

Dispositivos compatibles: iPhone 15 Pro, 15 Pro Max, iPhone 16, 16 Plus, 16 Pro, 16 Pro Max o superior.


Paso 3: Secrets.xcconfig

Solo se requiere Whoop. Claude API ya no se usa.

cd /ruta/a/ducode_app
cp Secrets.xcconfig.template Secrets.xcconfig

Edita Secrets.xcconfig:

WHOOP_CLIENT_ID = tu-client-id-aqui
WHOOP_CLIENT_SECRET = tu-client-secret-aqui

Secrets.xcconfig está en .gitignore. Nunca lo commitees.


Paso 4: Apple Developer Portal (HealthKit)

Si vas a correr la app firmada (en dispositivo físico o TestFlight) necesitas habilitar HealthKit en el App ID.

  1. Entra a developer.apple.com → Account → Certificates, IDs & Profiles → Identifiers.
  2. Busca o crea el App ID com.ducode.app.
  3. En la lista de Capabilities, marca HealthKit.
  4. Save.

Si firmas con "Automatic Signing" en Xcode, el provisioning profile se regenerará al siguiente build.


Paso 5: App Store Connect (solo si vas a TestFlight)

  1. Ve a appstoreconnect.apple.com → My Apps → "+" → New App.
  2. Configura:
    • Platform: iOS
    • Name: Ducode (o el nombre que prefieras)
    • Primary Language: Spanish (Spain) o el que apliques
    • Bundle ID: com.ducode.app (debe coincidir con project.yml)
    • SKU: cualquier identificador único, p.ej. ducode-app-001
  3. Save.

No necesitas llenar metadatos de App Store si solo vas a usar TestFlight Internal Testing.


Paso 6: Generar el proyecto Xcode

cd /ruta/a/ducode_app
xcodegen generate
open DucodeApp.xcodeproj

project.yml define todo: bundle ID, deployment target (26.0), entitlements, URL scheme, background modes, Info.plist properties (incluyendo las descripciones de HealthKit).


Paso 7: Build local

Desde Xcode

  1. Conecta tu iPhone físico (recomendado para OAuth y Apple Intelligence).
  2. Selecciona el dispositivo en el dropdown de schemes.
  3. La primera vez Xcode pedirá configurar el iPhone para desarrollo. Acepta.
  4. Cmd+R para compilar y correr.
  5. En el iPhone: Settings → General → VPN & Device Management → confía en tu certificado de desarrollador.

Desde CLI (alternativa)

./scripts/archive.sh

Genera build_output/DucodeApp.xcarchive y exporta un .ipa listo para subir vía Transporter o xcrun altool.


Paso 8: Distribución a TestFlight con Fastlane (opcional)

Ver ./DISTRIBUTION.md para el detalle completo. Resumen:

8.1 Generar API key de App Store Connect

  1. Entra a App Store Connect → Users and Access → Integrations → App Store Connect API.
  2. Click "+" para generar una nueva key.
    • Name: Ducode CI
    • Access: App Manager
  3. Descarga el archivo .p8 (solo se descarga una vez).
  4. Guárdalo en envs/AuthKey_<KEY_ID>.p8. El nombre debe respetar el formato AuthKey_<KEY_ID>.p8 porque Fastlane y App Store Connect lo derivan del nombre.
  5. El archivo envs/ está en .gitignore.

8.2 Configurar fastlane/.env

Crea el archivo fastlane/.env (no se commitea):

ASC_KEY_ID=AG95PDMY96
ASC_ISSUER_ID=<tu issuer id>

El Issuer ID aparece arriba de la lista de keys en App Store Connect.

8.3 Ejecutar el lane

fastlane beta

Esto:

  1. Regenera el proyecto con xcodegen.
  2. Lee el último build number en TestFlight y bump al siguiente.
  3. Build con gym (wrapper de xcodebuild).
  4. Sube a TestFlight con pilot.
  5. No envía a Beta App Review (skip_submission: true).

8.4 Internal Testing

  1. En App Store Connect → tu app → TestFlight → Internal Testing.
  2. Crea un grupo (p.ej. "Friends").
  3. Agrega como Users (en Users and Access) a las cuentas Apple ID que quieras incluir, con el rol App Manager o Developer.
  4. Asigna esos Users al grupo.
  5. Cuando el build termine de procesarse, asígnalo al grupo.
  6. Los testers reciben un email para instalar TestFlight y la app.

Internal Testing permite hasta 100 usuarios sin Beta App Review. Si necesitas más, usa External Testing (sí requiere review).


Troubleshooting

"No such module 'FoundationModels'" o "'SwiftData'"

  • Verifica que el deployment target sea iOS 26.0 (project.yml).
  • Product → Clean Build Folder (Cmd+Shift+K) y vuelve a compilar.

OAuth callback no funciona

  • Verifica que el URL scheme en Info.plist sea ducode (lo define project.yml).
  • Verifica que el redirect URL en el dashboard de Whoop sea exactamente ducode://oauth/callback.
  • Revisa los logs en Xcode buscando [OAuth] y [Whoop].

"Apple Intelligence no disponible"

  • Confirma que el dispositivo soporta Apple Intelligence (iPhone 15 Pro+ o iPhone 16+).
  • Activa Apple Intelligence en Ajustes → Apple Intelligence y Siri.
  • Si dice "modelo descargándose", espera a que termine. Pulsa "Reintentar" en la app.

"401 Unauthorized" en Whoop

  • El refresh token puede haber expirado. Haz logout (botón superior izquierdo en el Dashboard) y vuelve a conectar.
  • Verifica que las credenciales de Secrets.xcconfig correspondan a la app correcta en developer.whoop.com.

HealthKit entitlement error

  • Habilita HealthKit en el App ID en Apple Developer Portal (paso 4).
  • Si firmas con "Automatic Signing", borra el DerivedData y rebuild para refrescar el provisioning profile.
  • Verifica que DucodeApp/DucodeApp.entitlements exista y esté referenciado en project.yml como CODE_SIGN_ENTITLEMENTS.

Provisioning profile inválido en TestFlight

  • Asegúrate de tener una membresía activa de Apple Developer Program.
  • En Xcode: Settings → Accounts → tu Apple ID → Manage Certificates → confirma que hay un Distribution Certificate vigente.
  • Re-lanza fastlane beta (gym refresca los profiles automáticamente con signingStyle: "automatic").

Conflicto de build numbers en TestFlight

  • El lane beta lee el último build via latest_testflight_build_number y suma 1. Si dos personas suben en paralelo, puede haber colisión. Espera a que el build anterior termine de procesar y reintenta.

El ícono no aparece en TestFlight

  • Asegúrate que AppIcon.appiconset no tenga canal alpha en ningún tamaño (Apple lo rechaza). Verifica en DucodeApp/Assets.xcassets/AppIcon.appiconset.

Estructura del proyecto

ducode_app/
├─ DucodeApp/
│  ├─ App/
│  │  └─ DucodeApp.swift           Entry point + ModelContainer + onOpenURL
│  ├─ Models/
│  │  ├─ Alimento.swift
│  │  ├─ Objetivo.swift
│  │  ├─ DiaRegistro.swift
│  │  ├─ WhoopHistory.swift        WhoopDailySnapshot + WhoopWeeklyAnalytics
│  │  ├─ UserPreferences.swift     + enums Cuisine y DietaryRestriction
│  │  └─ ChatMessage.swift
│  ├─ Services/
│  │  ├─ WhoopService.swift
│  │  ├─ WhoopSyncService.swift
│  │  ├─ NutritionAIService.swift  Foundation Models para planes
│  │  ├─ CoachChatService.swift    Foundation Models para chat
│  │  └─ HealthKitService.swift
│  ├─ Views/
│  │  ├─ ContentView.swift         TabView + intro + onboarding
│  │  ├─ DashboardView.swift
│  │  ├─ Health360Card.swift
│  │  ├─ PreferenciasComidaView.swift
│  │  ├─ ObjetivoView.swift
│  │  ├─ WhoopHistoryView.swift
│  │  ├─ Coach/                    CoachView, ChatBubbleView, MarkdownText
│  │  └─ Onboarding/               IntroView + OnboardingCoordinator + steps
│  ├─ Utilities/
│  │  └─ Config.swift              AppConfig (lee Info.plist)
│  ├─ Info.plist
│  └─ DucodeApp.entitlements       HealthKit
├─ DucodeApp.xcodeproj/            Generado por XcodeGen (gitignored)
├─ docs/                           Esta documentación
├─ envs/
│  └─ AuthKey_<KEY_ID>.p8          App Store Connect API key (gitignored)
├─ fastlane/
│  ├─ Fastfile                     beta / build / latest lanes
│  ├─ Appfile
│  └─ .env                         ASC_KEY_ID, ASC_ISSUER_ID (gitignored)
├─ scripts/
│  ├─ archive.sh                   Build CLI puro (xcodebuild)
│  └─ upload.sh                    Subida CLI / Transporter
├─ Secrets.xcconfig                Whoop credentials (gitignored)
├─ Secrets.xcconfig.template
├─ project.yml                     Configuración XcodeGen
└─ .gitignore

Cómo funciona la configuración de secrets

Secrets.xcconfig          # WHOOP_CLIENT_ID y WHOOP_CLIENT_SECRET
        │
        ▼
project.yml               # Las inyecta a build settings
        │
        ▼
Info.plist                # Las expone como $(VARIABLE)
        │
        ▼
AppConfig (Config.swift)  # Las lee desde Bundle.main.infoDictionary
        │
        ▼
WhoopService              # Las usa para OAuth y API calls

Esta arquitectura evita hardcodear credenciales y permite cambiar valores sin tocar código.


Documentos relacionados