Saltar al contenido
Cómo funcionaPor qué así →

Local-first: qué corre en el teléfono y qué en la nube

Por qué así: por-que-asi/arquitectura-local-first.md · Normativo: ROADMAP_MAESTRO.md §0, §2.1, §2.2 y §2.2-bis · Código: lib/core/, lib/data/, lib/features/audio/, backend/ Verificado contra f15a912 el 2026-09-20 · Probado en iPhone: no

Qué es, en tres frases

Todo lo que importa clínicamente ocurre dentro del teléfono: la síntesis del sonido de las cuatro terapias, el perfil, el historial y los cuestionarios. La app se instala, se configura y entrega doce semanas de terapia sin red y sin haber aceptado nada. El servidor es un accesorio asíncrono: recibe telemetría si el paciente consintió, sirve el catálogo de música y sostiene el panel del terapeuta — pero si está caído, nadie se entera.

El reparto

En el teléfonoEn la nube (Django)
Síntesis del estímulo de las cuatro terapiasTelemetría de uso y adherencia
Perfil de tinnitus completoPanel clínico: qué usó cada paciente, cuánto, series
Historial de sesiones y bitácora de usoCatálogo de música curada (descarga única, cacheada)
Cuestionarios (THI, GÜF, Goldberg, EVA)Configuración remota de parámetros / versión de spec
Reproducción y dosificaciónDatos para investigación, agregados y sin UUID

Ninguna pantalla queda bloqueada esperando red. Todo request es opcional y reintentable, y la cola de telemetría se drena cuando hay conexión.

Sin cuentas ni login

No hay registro, no hay correo, no hay contraseña. La identidad es un UUID seudónimo generado en el primer arranque y guardado en el teléfono (PerfilTinnitus.idLocal). Solo al vincularse con un equipo clínico —canjeando un código que entrega el médico— se crea una cuenta del lado del servidor.

Qué sale del teléfono, y con qué permiso

Sin consentimiento no sale un byte. Los tres consentimientos son opt-in, están apagados por defecto y se pueden rechazar sin perder ninguna función:

Qué permiteCuándo se pide
C1Telemetría seudónima al centro del proyecto, ligada al UUID, sin correo ni bóveda de identidadPrimer arranque
C2El equipo clínico ve los datos del paciente; crea la cuentaAl canjear el código del centro
C3Uso en investigación, agregado y sin UUID, solo en estudios con comité ético-científicoPrimer arranque; requiere C1 o C2

La cola de telemetría no drena nada sin C1 o C2 vigente, y el servidor lo vuelve a comprobar del otro lado. La única petición que sale sin consentimiento vigente es el borrado.

Dónde se guardan las cosas

Cómo está partido el código

lib/
  core/       theme · router · config · api_client · storage
  domain/     modelos puros y reglas: PerfilTinnitus, Terapia, Sesion, Tinnitumetria
  data/       repositorios: local (fuente de verdad) + remoto, con cola de subida
  features/   una carpeta por pestaña, más audio/ y laboratorio/

Regla dura: features/audio/ no importa nada de UI ni de red. El motor se puede probar solo, y se prueba: existe un arnés que compara muestra a muestra el estímulo generado en Dart contra el del oráculo Python de referencia (tools/oracle/mmidst_reference.py, v3.3). Coinciden al último bit (diferencia de 1,110e-16, un ulp).

El backend no se botó: además de panel y catálogo, es el renderizador de referencia contra el que se valida el motor Dart.

Lo que NO hace, a propósito

Las pantallas de laboratorio

Las dos pantallas de los primeros hitos siguen en el repo tras un flag de depuración (kLaboratorioHabilitado), porque son parte del arnés de validación. Son el único código que todavía le pide audio al servidor (POST /api/render/), y no aparecen en una build de release. Desde H6.2 esa API no responde a anónimos: para usarla en el Mac hay que levantar el servidor con MINDTUNE_API_ABIERTA_EN_DESARROLLO=true, que solo funciona con DEBUG=True y que check bloquea en producción.