Saltar al contenido
Por qué asíCómo funciona →

Arquitectura local-first — por qué así

Cómo funciona: como-funciona/arquitectura-local-first.md · Decisiones: D1 (2026-08-28), D3 (2026-08-28), D-C1 (2026-09-08), D-S (2026-09-08) · Normativo: ROADMAP_MAESTRO.md §0, §2.2-bis, §4 · Última revisión: 2026-09-20. Citas por clave → referencias.md (pendiente de escribir).

1. Contexto y problema

En junio de 2026 la app pedía su audio a un Django que corría en el Mac de Hayo: POST /api/render/ devolvía el WAV del estímulo mMIDST. Servía para demostrar la terapia con Hayo al lado. No servía para nada más.

La meta que ordenó todo el desarrollo fue «app en TestFlight, usable por cualquiera sin que Hayo esté al lado». Eso convirtió la dependencia del Mac en el problema central: había que decidir de dónde sale el estímulo en producción (D1), y esa decisión arrastraba todo lo demás — si hay cuentas, si hay servidor que mantener, qué cruza la red, qué hay que consentir, y qué le toca mirar a un comité de ética.

2. Lo que dice la evidencia

La adherencia es la terapia, y la terapia es larga. El protocolo de mMIDST publicado es de 1 h al día, 5 días por semana, 12 semanas [Henríquez-2026]. Son unas 60 horas de escucha repartidas en tres meses. En ese régimen, una arquitectura que necesita conectividad para entregar la sesión no pierde comodidad: pierde dosis. Una sesión perdida por falta de señal es señal clínica destruida por ingeniería, y no se recupera.

El tamaño del estímulo. Un estímulo mMIDST completo pesa del orden de 51 MB. Generarlo en el teléfono cuesta prácticamente cero; servirlo por red, almacenarlo y versionarlo por paciente no escala de ninguna manera razonable.

El estímulo es personal por diseño. mMIDST incrusta cuatro tonos calculados desde la Ft del paciente dentro de la música que el paciente eligió. No hay un catálogo finito de estímulos que pre-renderizar: el espacio es Ft × pista × estrategia.

Lo regulatorio se simplifica. Si el audio y el perfil nunca salen del teléfono, lo único que cruza la red es telemetría — y eso vuelve mucho más simple el consentimiento, la conversación con el comité ético-científico y la discusión de software como dispositivo médico.

3. Alternativas consideradas

3.1 De dónde sale el estímulo (D1)

AlternativaA favorEn contraResultado
A. Backend desplegado (Django en Railway/Fly/VPS)Rápido de hacer; reusa el oráculo Python, así que cero riesgo de divergencia del estímuloCosto mensual permanente; hay que servir y almacenar WAV de ~51 MB; latencia; un servidor que mantener y que puede caerse a mitad de las 12 semanasDescartada
B. Motor en Dart on-deviceSin servidor, sin costo, sin latencia; funciona sin red; escala a cualquier número de usuarios sin costo marginal; cambiar la Ft y oír el resultado al instanteTrabajo de DSP real y riesgo de que el port se desvíe del oráculoElegida (Hayo, 2026-08-28)
C. Híbrido: pre-renderizar en el servidor un set por Ft y descargarloSimple de implementarNo personaliza la música propia, que es la esencia de mMIDSTDescartada

El riesgo de B se asumió con una mitigación obligatoria y explícita: el arnés de equivalencia (H2.0) se construye ANTES de confiar en el port, y el backend se conserva como renderizador de referencia. Un port que se desvíe entregaría a los pacientes una terapia que no es la del RCT publicado, y eso es un daño silencioso: nadie lo notaría oyendo.

3.2 Cuentas y login

AlternativaA favorEn contraResultado
Registro con correo y contraseñaRecuperar datos al cambiar de teléfono; un solo identificadorFricción en el primer minuto de una app que un paciente angustiado abre por primera vez; obliga a tener datos personales en el servidor desde el arranque, aunque el paciente nunca comparta nadaDescartada
Identidad local seudónima (UUID)Nada que recordar, nada que filtrar; el servidor no sabe quién es nadie mientras no haya vínculoPerder el teléfono es perder los datos (ver §6)Elegida
Cuenta solo al vincularse con un equipoEs lo que se hace: el código del médico crea la cuenta, y con ella C2

3.3 Dónde guardar lo local (D3)

AlternativaResultado
drift/sqlite desde el principioDescartada por sobre-diseño: la decisión fue empezar simple y migrar si el historial lo pide
JSON en shared_preferences + bitácora en JSONLEs lo que hay. drift nunca se instaló: no está en pubspec.yaml

4. Decisiones

idFechaQuiénQuéPor qué, en una línea
D12026-08-28HayoMotor de síntesis on-device (Opción B)La app tiene que ser lo más autónoma posible; la nube solo para que el médico y el desarrollador vean uso
D32026-08-28Coworkshared_preferences + JSON; drift solo si el historial lo pideNo sobre-diseñar
D-C12026-09-08HayoSin consentimiento no sale un byte; tres consentimientos separados, opt-in, rechazables sin perder funciónReemplaza el principio anterior «sin vínculo clínico no sale nada», que dejaba fuera el caso del paciente que usa la app solo y quiere ayudar
D-S2026-09-08HayoEl servidor vive en SantiagoDatos de pacientes chilenos
2026-08-28HayoSin cuentas ni login; UUID localConsecuencia obligatoria de que el dispositivo sea la fuente de verdad

5. Consecuencias

Obliga a: que ninguna pantalla se bloquee esperando red; que toda salida de datos pase por una cola local reintentable; que el motor Dart se valide contra el oráculo en cada cambio; y que el esquema del perfil lleve reglas de migración escritas, porque la única copia de los datos está en el teléfono.

Prohíbe: pedir cuenta para usar la app; hacer que una función dependa de haber consentido; mandar el audio por la red.

Toca otros temas: datos-privacidad-y-borradopendiente (pendiente) hereda de acá los tres consentimientos y el borrado; plataforma-clinica-y-panelpendiente (pendiente) es todo lo que existe por encima de esta arquitectura y solo se enciende con C2; mmidst (pendiente) es la razón de que el motor tenga que ser exacto.

6. Límites conocidos y riesgos

  1. Perder el teléfono es perder los datos. No hay restauración desde el servidor para quien nunca se vinculó ni consintió: es el precio directo de no tener cuentas. El respaldo de iOS arrastra el perfil, pero H6.12 planea marcar la bitácora como excluida del respaldo, y ese hito no está hecho. Nadie ha probado todavía qué pasa al restaurar un iPhone desde un respaldo.
  2. La divergencia del port es un riesgo permanente, no uno que se cerró. Hoy el motor coincide con el oráculo al último bit, y hay tests que lo vigilan. Ese arnés es la única cosa que separa la terapia entregada de la terapia publicada: tocarlo, saltárselo o dejarlo caer en rojo es la falla más cara que este proyecto puede cometer.
  3. La migración de esquema no tiene ensayo general. El perfil va en la versión 6 y cada salto tiene su regla escrita, pero ninguna se ha ejecutado sobre el teléfono de un paciente real.
  4. Nada de esto se ha probado fuera del simulador. Quedan quince recorridos -bis pendientes.
  5. El paciente que usa la app solo es invisible al proyecto si no da C1. Es exactamente lo que se quería, y también significa que la cohorte que se pueda estudiar será un subconjunto sesgado hacia quienes consienten.

7. Qué revisar y cuándo

8. Historia