Saltar a contenido

02 - Arquitectura Cliente-Servidor de MedTime

Identificador: TECH-CS-001 Version: 1.1.0 Fecha: 2025-12-08 Ultima Revision: Regla de 100 registros para catalogos locales - Directiva del Director Autor: SpecQueen + ArchitectureDrone Refs Funcional: MTS-OFF-001, MTS-PRI-001, INV-001, INV-008, INV-011 Estado: Aprobado



1. Principios Fundamentales

MedTime implementa una arquitectura client-heavy donde el dispositivo del usuario es el centro de procesamiento, y el servidor actua unicamente como coordinador de sincronizacion y proveedor de catalogos publicos.

1.1. Offline-First: 100% Operativo Sin Conexion

GARANTIA OFFLINE:
+------------------------------------------------------------------+
|  La aplicacion MedTime DEBE funcionar completamente sin           |
|  conexion a Internet. El 100% de las funcionalidades CORE         |
|  estan disponibles offline.                                        |
|                                                                    |
|  Funciones que requieren conexion:                                 |
|  - Crear cuenta nueva (verificacion inicial)                       |
|  - Sincronizacion de datos (Pro/Perfect)                           |
|  - OCR de recetas (Pro/Perfect)                                    |
|  - Actualizacion de catalogo de medicamentos                       |
+------------------------------------------------------------------+
Escenario Comportamiento Tier
Usuario sin Internet todo el dia 100% funcional Todos
Viaje de 1 semana sin conexion 100% funcional Todos
Zona rural sin cobertura 100% funcional Todos
Modo avion permanente 100% funcional Free permanente

1.2. Zero-Knowledge: Servidor NUNCA Ve Datos PHI en Claro

PRINCIPIO ZERO-KNOWLEDGE:
+------------------------------------------------------------------+
|  El servidor MedTime NUNCA tiene acceso al contenido              |
|  de los datos de salud (PHI) del paciente.                         |
|                                                                    |
|  - Datos se cifran ANTES de salir del dispositivo                  |
|  - Servidor almacena BLOBS opacos (indescifrable)                  |
|  - Solo el paciente tiene la clave de descifrado                   |
|  - En caso de brecha: atacante obtiene datos inutiles              |
+------------------------------------------------------------------+

Referencia: Ver INV-001 (Cifrado E2E Zero Knowledge) e INV-008 (Cifrado de Perfil).

1.3. Client-Heavy: El Dispositivo Hace el Trabajo Pesado

Procesamiento Ubicacion Porcentaje
Logica de negocio Dispositivo 95%
Calculos de adherencia Dispositivo 100%
Generacion de alertas Dispositivo 100%
Machine Learning Dispositivo 100%
Gamificacion Dispositivo 100%
Sincronizacion Compartido 50/50
Autenticacion Servidor 80%
Catalogos publicos Servidor 100%

1.4. Sync-Light: Solo Blobs Cifrados Viajan al Servidor

flowchart LR
    subgraph DEVICE["DISPOSITIVO"]
        D1["Datos en claro"]
    end

    subgraph CRYPTO["CIFRADO"]
        C1["AES-256-GCM"]
    end

    subgraph SERVER["SERVIDOR"]
        S1["Blob cifrado"]
        S2["Metadata operativa"]
        S3["Blind indexes"]
    end

    D1 -->|"Cifrar E2E"| C1
    C1 -->|"Solo blobs opacos"| S1

    style DEVICE fill:#e8f5e9,stroke:#2e7d32
    style CRYPTO fill:#fff3e0,stroke:#e65100
    style SERVER fill:#e3f2fd,stroke:#1565c0

El servidor SOLO recibe:

  • Blobs cifrados (indescifrable sin clave del usuario)
  • Metadata operativa (timestamps, tamanos, hashes)
  • Indices ciegos (blind indexes) para busqueda

2. Vision General de la Arquitectura

2.1. Division de Responsabilidades

flowchart LR
    subgraph DEVICE["DISPOSITIVO (95%)"]
        D1["Base datos local<br/>Core Data / Room<br/>Datos en CLARO"]
        D2["Cifrado E2E<br/>AES-256-GCM<br/>ANTES de enviar"]
        D3["Alertas locales<br/>100% offline<br/>AlarmManager / UNNotification"]
        D4["ML On-Device<br/>Patrones y predicciones<br/>NUNCA salen"]
        D5["Gamificacion<br/>Puntos/Rachas<br/>Sincronizados"]
        D6["Cola de Sync<br/>Operaciones pendientes"]
    end

    subgraph SERVER["SERVIDOR (5%)"]
        S1["PostgreSQL<br/>Blobs cifrados<br/>Metadata + Blind indexes"]
        S2["API de Sync<br/>Push/Pull<br/>Conflictos"]
        S3["Catalogos<br/>Medicamentos<br/>Interacciones"]
        S4["Firebase Auth<br/>Tokens + MFA"]
        S5["OCR opcional<br/>Pro/Perfect<br/>Anonimizado"]
    end

    D6 -->|"Blobs E2E"| S2

    style DEVICE fill:#e8f5e9,stroke:#2e7d32
    style SERVER fill:#e3f2fd,stroke:#1565c0

2.2. Diagrama de Arquitectura Dual

flowchart TB
    subgraph DEVICE["DISPOSITIVO (95%)"]
        direction TB
        UI["UI Layer<br/>(SwiftUI / Compose)"]
        BL["Business Logic<br/>(Domain Layer)"]

        subgraph LOCAL_STORAGE["Almacenamiento Local"]
            DB_LOCAL["Base de Datos<br/>Core Data / Room"]
            KEYCHAIN["Keychain / Keystore<br/>(Claves)"]
        end

        subgraph LOCAL_PROCESSING["Procesamiento Local"]
            ALERTS["Motor de Alertas<br/>100% Offline"]
            ML["ML Engine<br/>CoreML / TFLite"]
            CRYPTO["Motor Cifrado<br/>AES-256-GCM"]
            GAME["Gamificacion<br/>Puntos + Rachas"]
        end

        SYNC_QUEUE["Cola de Sync<br/>(Operaciones Pendientes)"]

        UI --> BL
        BL --> LOCAL_STORAGE
        BL --> LOCAL_PROCESSING
        BL --> SYNC_QUEUE
    end

    subgraph SERVER["SERVIDOR (5%)"]
        direction TB
        API_GW["API Gateway<br/>(Auth + Rate Limit)"]

        subgraph SERVICES["Servicios"]
            SYNC_SVC["Sync Service"]
            CATALOG_SVC["Catalog Service"]
            OCR_SVC["OCR Service<br/>(Pro/Perfect)"]
        end

        subgraph DATA_STORE["Almacenamiento"]
            PG["PostgreSQL<br/>(SQL Estandar)"]
            CACHE["Redis Cache"]
        end

        AUTH["Firebase Auth"]

        API_GW --> SERVICES
        SERVICES --> DATA_STORE
        API_GW --> AUTH
    end

    SYNC_QUEUE -->|"Blobs E2E<br/>Cifrados"| API_GW
    CATALOG_SVC -->|"Datos Publicos"| DB_LOCAL

3. Componentes del Sistema

3.1. Dispositivo (Cliente) - 95% del Procesamiento

3.1.1. Base de Datos Local

Plataforma Tecnologia Cifrado Capacidad
iOS Core Data + SQLite Cifrado de disco iOS Ilimitado
Android Room + SQLite Cifrado de disco Android Ilimitado

Caracteristicas:

  • Datos almacenados en CLARO dentro del sandbox de la app
  • Protegidos por cifrado de disco del sistema operativo
  • Acceso biometrico/PIN requerido para abrir app
  • Datos NUNCA exportados sin cifrar E2E
ESTRUCTURA LOCAL:
/app_sandbox/
├── databases/
│   └── medtime.db          # SQLite cifrado por OS
├── documents/
│   ├── prescriptions/       # Imagenes cifradas E2E
│   └── exports/             # Backups cifrados
└── keychain/                # Claves de cifrado
    ├── master_key           # Derivada de PIN/Biometria
    ├── sync_key             # Para sincronizacion
    └── recovery_key_hash    # Hash de Recovery Key

3.1.2. Motor de Cifrado E2E

ESPECIFICACION CRIPTOGRAFICA:
+------------------------------------------------------------------+
|  Algoritmo:     AES-256-GCM (Galois/Counter Mode)                 |
|  Key Derivation: Argon2id (64 MiB, 3 iteraciones, parallelism 4)  |
|  Nonce:         96 bits, aleatorio por operacion                  |
|  Auth Tag:      128 bits (autenticacion integrada)                |
|  Salt:          256 bits, unico por usuario                       |
+------------------------------------------------------------------+

CUMPLIMIENTO:
- NIST SP 800-132 (Key Derivation)
- FIPS 140-2 (AES)
- HIPAA Safe Harbor (cifrado apropiado)

Flujo de cifrado antes de sincronizacion:

sequenceDiagram
    participant U as Usuario
    participant A as App
    participant C as Crypto Engine
    participant K as Keychain
    participant S as Servidor

    U->>A: Modifica medicamento
    A->>A: Guarda en DB local (claro)
    A->>K: Obtiene master_key
    K->>A: master_key
    A->>C: Cifrar(datos, master_key)
    C->>C: Generar nonce aleatorio
    C->>C: AES-256-GCM encrypt
    C->>A: {blob_cifrado, nonce, tag}
    A->>S: POST /sync {encrypted_blob}
    Note over S: Servidor almacena<br/>blob opaco

3.1.3. Sistema de Alertas y Notificaciones

Referencia: OBS-066 - 100% OFFLINE (ver MTS-NTF-001)

ARQUITECTURA DE ALERTAS:
+------------------------------------------------------------------+
|  TODAS las alertas se generan y disparan LOCALMENTE               |
|  Sin dependencia de servidor, push notifications son ADICIONALES  |
+------------------------------------------------------------------+

iOS:
- UNUserNotificationCenter
- Limite: 64 notificaciones pendientes
- Persistencia: Sobrevive reinicio

Android:
- AlarmManager + WorkManager
- Sin limite practico
- Persistencia: BroadcastReceiver para boot
Funcion Implementacion Offline
Programar alerta APIs nativas OS 100%
Disparar alerta Sistema operativo 100%
Sonido/Vibracion Sistema operativo 100%
Acciones en notificacion App local 100%
Push adicional FCM/APNs Requiere conexion

3.1.4. Motor de ML On-Device

Referencia: MTS-NTF-001 - Notificaciones Inteligentes

MODELO ML LOCAL:
+------------------------------------------------------------------+
|  Framework:    CoreML (iOS) / TensorFlow Lite (Android)           |
|  Tipo:         Clasificador binario (Random Forest ligero)        |
|  Tamano:       < 500 KB                                           |
|  Entrenamiento: On-device, incremental                            |
|  Datos:        NUNCA salen del dispositivo                        |
+------------------------------------------------------------------+

FEATURES (12 total):
- dia_semana (one-hot, 7)
- hora_del_dia (normalizado, 1)
- dias_desde_ultima_omision (1)
- racha_actual (1)
- tasa_omision_historica (1)
- tiempo_respuesta_promedio (1)

OUTPUT: Probabilidad de omision [0.0 - 1.0]
Dato de ML Sale del dispositivo Razon
Patrones detectados NUNCA Privacidad maxima
Predicciones NUNCA Calculo local
Modelo entrenado NUNCA On-device training
Estadisticas de uso NUNCA LOCAL_ONLY

3.1.5. Sistema de Gamificacion

GAMIFICACION LOCAL:
+------------------------------------------------------------------+
|  Puntos:        Calculados localmente por toma/racha              |
|  Rachas:        Conteo local, sincronizado para cuidadores        |
|  Logros:        Desbloqueados localmente                          |
|  Leaderboards:  NO hay (privacidad)                               |
+------------------------------------------------------------------+
Elemento Calculo Sincronizado
Puntos por toma Local Si (Pro/Perfect)
Racha actual Local Si (Pro/Perfect)
Mejor racha Local Si (Pro/Perfect)
Logros desbloqueados Local Si (Pro/Perfect)
Nivel de adherencia Local Si (Pro/Perfect)

3.1.6. Cola de Sincronizacion

ESTRUCTURA DE COLA:
+------------------------------------------------------------------+
|  Operaciones pendientes se encolan para sync cuando hay conexion  |
+------------------------------------------------------------------+

SyncQueueItem {
    id: UUID
    operation: CREATE | UPDATE | DELETE
    entity_type: MEDICATION | DOSE | APPOINTMENT | ...
    entity_id: UUID
    encrypted_payload: Blob  // Cifrado E2E ANTES de encolar
    local_timestamp: DateTime
    attempts: Int
    status: PENDING | IN_PROGRESS | COMPLETED | FAILED
    priority: HIGH | MEDIUM | LOW
}

Prioridades de sincronizacion:

Prioridad Entidades Timeout
HIGH Dosis tomadas, alertas confirmadas 30 seg
MEDIUM Medicamentos, citas, calendario 60 seg
LOW Preferencias, estadisticas 120 seg

3.2. Servidor (Backend) - 5% Coordinacion

3.2.1. PostgreSQL (con RLS)

NOTA: La arquitectura utiliza PostgreSQL como base de datos del servidor, incluyendoRow Level Security (RLS) como mecanismo de autorizacion a nivel de base de datos. PostgreSQL es una dependencia aceptable dada su madurez, ubicuidad, y el soporte nativo de RLS que simplifica significativamente la implementacion de seguridad.

Justificacion de la dependencia PostgreSQL:

  • Madurez: PostgreSQL es una tecnologia probada con decadas de desarrollo
  • Ubicuidad: Disponible en todos los proveedores cloud principales
  • RLS nativo: Simplifica autorizacion sin codigo adicional en aplicacion
  • Compatibilidad: Si se requiere migracion futura, RLS puede replicarse en capa de aplicacion
-- Ejemplo: Tabla de datos cifrados (PostgreSQL con RLS)
-- RLS proporciona autorizacion automatica a nivel de base de datos

CREATE TABLE encrypted_user_data (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id),

    -- METADATA VISIBLE (operativa)
    entity_type VARCHAR(50) NOT NULL,  -- 'medication', 'dose', etc.
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    sync_version BIGINT NOT NULL DEFAULT 1,

    -- DATOS CIFRADOS (opacos)
    encrypted_blob BYTEA NOT NULL,      -- Blob E2E cifrado
    blob_hash VARCHAR(64) NOT NULL,     -- SHA-256 para integridad
    blob_size_bytes INT NOT NULL,
    encryption_version VARCHAR(10) NOT NULL DEFAULT '1.0',

    -- INDICES CIEGOS (para busqueda sin ver datos)
    blind_index_1 VARCHAR(64),          -- HMAC-SHA256 de campo 1
    blind_index_2 VARCHAR(64),          -- HMAC-SHA256 de campo 2

    CONSTRAINT unique_entity UNIQUE (user_id, entity_type, id)
);

-- Indices para rendimiento
CREATE INDEX idx_user_entity ON encrypted_user_data(user_id, entity_type);
CREATE INDEX idx_sync_version ON encrypted_user_data(user_id, sync_version);
CREATE INDEX idx_blind_1 ON encrypted_user_data(blind_index_1) WHERE blind_index_1 IS NOT NULL;

3.2.2. API de Sincronizacion

Referencia: MTS-OFF-001 Seccion 14 (API Endpoints de Sincronizacion)

Endpoint Metodo Descripcion Datos
/v1/sync/status GET Estado de sincronizacion Metadata
/v1/sync/push POST Enviar cambios locales Blobs E2E
/v1/sync/pull GET Obtener cambios remotos Blobs E2E
/v1/sync/resolve POST Resolver conflictos Metadata
// Ejemplo: Push Request
{
  "device_id": "uuid",
  "last_sync_version": 1234567890,
  "changes": [
    {
      "entity_type": "medication",
      "entity_id": "uuid",
      "operation": "update",
      "encrypted_blob": "base64...",  // CIFRADO E2E
      "blob_hash": "sha256:abc123...",
      "local_timestamp": "2025-12-07T10:30:00Z"
    }
  ]
}

// Ejemplo: Push Response
{
  "accepted": 5,
  "conflicts": [],
  "server_sync_version": 1234567891,
  "server_time": "2025-12-07T10:30:05Z"
}

3.2.3. API de Catalogos Publicos

Los catalogos son datos publicosque no requieren cifrado. Los clientesNO almacenan cache directade estos catalogos; en su lugar,construyen sus propios catalogos locales combinando:

  1. Datos descargados de catalogos publicos (cuando estan disponibles)
  2. Entradas manuales del usuario (medicamentos no encontrados en catalogo)

IMPORTANTE: El acceso a catalogos publicos requiere cuenta de usuario autenticada. Usuarios Free sin cuenta solo pueden agregar medicamentos manualmente.

3.2.3.1. Regla de 100 Registros - Descarga Local vs Busqueda Online
REGLA CRITICA DE CATALOGOS:
+------------------------------------------------------------------+
|  Para proteger la privacidad y optimizar el rendimiento,          |
|  MedTime aplica la REGLA DE 100 REGISTROS para determinar         |
|  si un catalogo puede descargarse al dispositivo.                 |
+------------------------------------------------------------------+

CRITERIOS:
+------------------------------------------------------------------+
| Catalogos <= 100 registros:                                       |
|   - PUEDEN embeberse en la aplicacion                             |
|   - Disponibles offline sin restricciones                          |
|   - Actualizados con cada release de la app                       |
|                                                                    |
| Catalogos > 100 registros:                                         |
|   - NO se descargan al dispositivo                                 |
|   - Requieren BUSQUEDA ONLINE                                      |
|   - Cada busqueda requiere conexion a Internet                     |
|   - Se muestra disclaimer de privacidad                            |
+------------------------------------------------------------------+

EXCEPCION - MINI-CACHE CRITICO:
+------------------------------------------------------------------+
|  Para garantizar seguridad offline, se permite un mini-cache       |
|  de <100 interacciones marcadas como CONTRAINDICADO.               |
|  Esto permite alertas de seguridad criticas sin conexion.          |
+------------------------------------------------------------------+

Justificacion de la regla:

Aspecto Razon
Privacidad Descargar catalogos grandes expone patrones de busqueda offline
Rendimiento Catalogos >100 registros impactan almacenamiento y sincronizacion
Actualizacion Catalogos pequenos se actualizan con releases; grandes via API
Seguridad Mini-cache critico garantiza alertas de interacciones peligrosas offline

Disclaimer de privacidad (busquedas online):

Al realizar busquedas en catalogos online, su consulta de busqueda se envia a los servidores de MedTime. No almacenamos historial de busquedas ni asociamos consultas con su identidad. Los resultados seleccionados se guardan SOLO en su dispositivo local.

3.2.3.2. Catalogos Principales (Enriquecibles con Datos de Usuarios)
Catalogo Endpoint Tamano Estimado Descarga Local TTL Enriquecible Especificacion
Medicamentos /v1/catalog/medications ~50,000+ NO 7d SI INV-010
Estudios/Tratamientos /v1/catalog/studies ~100 SI(limite) 7d SI INV-011
Interacciones Med-Med /v1/catalog/interactions ~1,000,000+ NO 7d SI INV-012
Interacciones Med-Estudio /v1/catalog/med-study-interactions ~5,000+ NO 7d SI INV-013
Efectos secundarios /v1/catalog/side_effects ~10,000+ NO 7d SI INV-014

ENRIQUECIMIENTO: Los catalogos marcados como "Enriquecibles" reciben datos anonimizados de usuarios siguiendo el principio de separacion de identidad (datos especificos SIN identificadores de usuario). El consentimiento es OBLIGATORIO para usuarios con cuenta. Ver INV-009.

REGLA DE 100: Solo Estudios/Tratamientos cumple el limite para descarga local. El resto requiere busqueda ONLINE con disclaimer de privacidad.

3.2.3.3. Catalogos Secundarios (Estaticos - No Enriquecibles)
Catalogo Endpoint Tamano Estimado Descarga Local TTL Enriquecible
Contraindicaciones /v1/catalog/contraindications ~5,000+ NO 7d NO
Unidades /v1/catalog/units ~30-50 SI (embebido) 30d NO
Formas farmaceuticas /v1/catalog/forms ~50-80 SI (embebido) 30d NO
Vias administracion /v1/catalog/routes ~20-30 SI (embebido) 30d NO
Frecuencias /v1/catalog/frequencies ~30-50 SI (embebido) 30d NO
Categorias terapeuticas /v1/catalog/categories ~50-100 SI (limite) 30d NO
Laboratorios (fabricantes) /v1/catalog/labs ~500+ NO 30d NO

CATALOGOS EMBEBIDOS: Los catalogos pequenos (Unidades, Formas, Vias, Frecuencias, Categorias) se incluyen directamente en el build de la aplicacion y se actualizan con cada release. Esto permite operacion 100% offline para seleccion de estos valores.

3.2.3.4. Catalogos de Codigos Estandar (Externos - No Enriquecibles)
Catalogo Fuente Tamano Estimado Descarga Local Uso en MedTime
ATC OMS ~6,000+ NO Categorizar medicamentos
LOINC Regenstrief ~90,000+ NO Codificar estudios
ICD-10-PCS OMS ~70,000+ NO Codificar tratamientos
RxNorm NIH (USA) ~100,000+ NO Normalizar nombres
COFEPRIS Gobierno MX ~15,000+ NO Validar disponibilidad MX
CSG Gobierno MX ~5,000+ NO Medicamentos autorizados MX

NOTA: Los catalogos de codigos estandar son mantenidos por organismos externos y NO se enriquecen con datos de usuarios. Todos estos catalogos exceden el limite de 100 registros, por lo que requieren consulta ONLINE exclusivamente. El usuario busca, selecciona, y solo el registro seleccionado se guarda en su catalogo local.

Flujo de construccion de catalogo local:

USUARIO BUSCA MEDICAMENTO:
+------------------------------------------------------------------+
|  1. Buscar en CATALOGO LOCAL del usuario (offline)                |
|  2. Si no existe Y tiene cuenta:                                  |
|     - Mostrar disclaimer de privacidad (primera vez o manual)     |
|     - Buscar en CATALOGO PUBLICO ONLINE                           |
|  3. Si no existe en publico:                                      |
|     - Usuario ingresa manualmente                                 |
|  4. SOLO el registro seleccionado se guarda en catalogo local     |
+------------------------------------------------------------------+

CATALOGO LOCAL = Registros seleccionados de catalogo publico
                + Entradas manuales del usuario

IMPORTANTE - PRIVACIDAD:
+------------------------------------------------------------------+
|  El servidor NO sabe que registros selecciono el usuario.          |
|  Solo ve la consulta de busqueda (texto ingresado).                |
|  El registro seleccionado se guarda SOLO en el dispositivo.        |
|  El catalogo local se sincroniza E2E (cifrado).                    |
+------------------------------------------------------------------+
// Ejemplo: Catalogo de medicamentos (datos PUBLICOS)
{
  "medications": [
    {
      "id": "rxcui-12345",
      "name": "Metformin",
      "brand_names": ["Glucophage", "Fortamet"],
      "strength": "500mg",
      "form": "tablet",
      "rxnorm_code": "12345",
      "category": "antidiabetico_oral"
    }
  ],
  "version": "2025-12-07",
  "total": 15000
}
3.2.3.5. Mini-Cache Critico de Interacciones CONTRAINDICADO

Para garantizar la seguridad del paciente incluso sin conexion a Internet, MedTime incluye un mini-cache de interacciones medicamentosas criticas embebido en la aplicacion.

MINI-CACHE CRITICO:
+------------------------------------------------------------------+
|  Proposito:     Alertas de seguridad OFFLINE para interacciones   |
|                 marcadas como CONTRAINDICADO                       |
|  Tamano:        <100 registros (cumple regla de descarga local)   |
|  Contenido:     Pares de medicamentos con severidad maxima         |
|  Actualizacion: Con cada release de la aplicacion                  |
|  Disponibilidad: TODOS los tiers (incluso Free sin cuenta)        |
+------------------------------------------------------------------+

CRITERIOS DE INCLUSION EN MINI-CACHE:
+------------------------------------------------------------------+
| - Severidad: CONTRAINDICADO (nivel maximo)                         |
| - Frecuencia: Medicamentos de uso comun                            |
| - Riesgo: Potencialmente fatal si se combinan                      |
| - Ejemplo: Warfarina + Aspirina (riesgo hemorragia)                |
| - Ejemplo: Metformina + Contraste yodado (riesgo acidosis)         |
| - Ejemplo: IMAO + ISRS (riesgo sindrome serotoninergico)           |
+------------------------------------------------------------------+

Comportamiento del mini-cache:

Escenario Comportamiento
Usuario agrega medicamento Verificar contra mini-cache local
Interaccion CONTRAINDICADO encontrada Alerta INMEDIATA, sin conexion
Interaccion no en mini-cache Verificar online si hay conexion
Sin conexion + no en mini-cache No hay alerta (limitacion conocida)

NOTA: El mini-cache NO reemplaza la verificacion completa de interacciones online. Es una red de seguridad minima para los casos mas criticos y frecuentes. Los usuarios deben consultar con su medico para informacion completa de interacciones.

3.2.3.6. Disclaimer de Privacidad para Busquedas Online

Cuando el usuario realiza busquedas en catalogos que requieren consulta online (>100 registros), se muestra un disclaimer de privacidad.

MOMENTOS DE VISUALIZACION DEL DISCLAIMER:
+------------------------------------------------------------------+
| 1. PRIMERA VEZ que habilita "Busqueda automatica en catalogo"     |
|    - Se muestra una sola vez al activar la opcion                  |
|    - Checkbox de aceptacion obligatorio                            |
|    - Se guarda preferencia localmente                              |
|                                                                    |
| 2. CADA VEZ en busqueda MANUAL (si automatica deshabilitada)      |
|    - Antes de enviar la consulta al servidor                       |
|    - Opcion para habilitar busqueda automatica                     |
|    - Toggle: "No mostrar de nuevo, activar busqueda automatica"    |
+------------------------------------------------------------------+

Texto del disclaimer:

+------------------------------------------------------------------+
|  AVISO DE PRIVACIDAD - BUSQUEDA EN CATALOGOS                      |
|                                                                    |
|  Al buscar en nuestros catalogos de medicamentos, estudios o      |
|  interacciones, su texto de busqueda sera enviado a los           |
|  servidores de MedTime.                                           |
|                                                                    |
|  LO QUE HACEMOS:                                                   |
|  [OK] Procesar su busqueda para mostrar resultados                 |
|  [OK] Eliminar la consulta inmediatamente despues                  |
|                                                                    |
|  LO QUE NO HACEMOS:                                                |
|  [X] Almacenar historial de sus busquedas                          |
|  [X] Asociar busquedas con su identidad                            |
|  [X] Compartir consultas con terceros                              |
|  [X] Usar busquedas para perfilamiento                             |
|                                                                    |
|  El resultado que seleccione se guardara UNICAMENTE en su         |
|  dispositivo, cifrado y bajo su control exclusivo.                 |
|                                                                    |
|  [ ] Entiendo y acepto continuar                                   |
|  [ ] Activar busqueda automatica (no preguntar de nuevo)           |
+------------------------------------------------------------------+

Configuracion de privacidad relacionada:

Opcion Default Descripcion
Busqueda automatica OFF Si ON, busca sin disclaimer cada vez
Mostrar disclaimer ON Si OFF (solo con auto ON), no muestra aviso

REQUISITO REGULATORIO: Este disclaimer cumple con requisitos de transparencia de LFPDPPP (Mexico), LGPD (Brasil), y HIPAA Privacy Rule (USA).

3.2.4. Firebase Auth Integration

FIREBASE AUTH:
+------------------------------------------------------------------+
|  Proposito:     Autenticacion y tokens JWT                        |
|  MFA:           Obligatorio para Pro/Perfect                      |
|  Datos en Firebase:                                               |
|  - email_hash (blind index)                                       |
|  - phone_hash (blind index para MFA)                              |
|  - tier (plain text)                                              |
|  - created_at (timestamp)                                         |
|                                                                    |
|  Datos que Firebase NO tiene:                                      |
|  - Nombre real del usuario                                         |
|  - Medicamentos                                                    |
|  - Historial medico                                                |
|  - Cualquier dato PHI                                              |
+------------------------------------------------------------------+

3.2.5. OCR Service (Opcional - Pro/Perfect)

OCR SERVICE:
+------------------------------------------------------------------+
|  Disponibilidad: Solo Pro/Perfect                                 |
|  Procesamiento:  Servidor (requiere GPU)                          |
|  Privacidad:     RESPONSABILIDAD DEL USUARIO anonimizar antes     |
+------------------------------------------------------------------+

DOCUMENTOS SOPORTADOS:
- Recetas medicas
- Resultados de laboratorio
- Informes medicos
- Prospectos de medicamentos
- Cualquier documento que el usuario desee procesar

ADVERTENCIA DE SEGURIDAD (mostrar al usuario):
+------------------------------------------------------------------+
|  ⚠️ IMPORTANTE - RESPONSABILIDAD DE ANONIMIZACION                 |
|                                                                    |
|  Antes de enviar cualquier documento para OCR, usted es           |
|  responsable de:                                                   |
|                                                                    |
|  1. Tachar/borrar nombres de personas (paciente, medico)          |
|  2. Tachar/borrar direcciones y telefonos                         |
|  3. Tachar/borrar numeros de identificacion (INE, CURP, etc.)     |
|  4. Revisar que no haya datos sensibles visibles                  |
|                                                                    |
|  MedTime procesara el documento con maxima confidencialidad,      |
|  pero la imagen sera procesada en servidor. Si contiene datos     |
|  personales no anonimizados, estos seran visibles durante el      |
|  procesamiento.                                                    |
|                                                                    |
|  [ ] He revisado y anonimizado el documento                       |
|  [ ] Acepto la responsabilidad de los datos enviados              |
+------------------------------------------------------------------+

Flujo de OCR con anonimizacion manual:

sequenceDiagram
    participant U as Usuario
    participant A as App
    participant S as Servidor OCR

    U->>A: Toma foto de documento
    A->>A: Mostrar preview + herramientas de edicion
    Note over A: Herramientas: tachar, blur, crop

    U->>A: Anonimiza manualmente (tacha nombres, etc.)
    A->>U: Mostrar advertencia de seguridad
    U->>A: Confirma "He revisado y anonimizado"

    A->>A: Guardar imagen ORIGINAL en local (cifrada E2E)
    A->>S: Enviar imagen ANONIMIZADA via TLS

    S->>S: Procesar OCR
    S->>S: Estructurar datos extraidos
    S->>S: ELIMINAR imagen inmediatamente
    S->>A: Retornar texto estructurado

    A->>A: Asociar texto con datos del usuario LOCALMENTE
    A->>A: Guardar resultado en DB local (cifrado)

    Note over S: Servidor NO retiene la imagen<br/>procesamiento temporal, sin persistencia

Garantias de privacidad:

Aspecto Implementacion
Imagen original Permanece en dispositivo, cifrada E2E, NUNCA se envia
Imagen anonimizada Se envia al servidor solo para procesamiento
Retencion en servidor CERO - imagen eliminada inmediatamente despues de OCR
Resultado OCR Texto estructurado, asociado con usuario LOCALMENTE
Responsabilidad Usuario debe anonimizar antes de enviar

Herramientas de anonimizacion en app:

  • Rectangulo de tachado (negro opaco)
  • Herramienta de blur/pixelado
  • Crop para recortar secciones
  • Preview antes de enviar
  • Checkbox de confirmacion obligatorio

4. Tabla Maestra de Clasificacion de Datos

4.1. Clasificacion por Tipo de Dato

Dato Local (Claro) Servidor Formato Servidor Clasificacion
Identificacion
email SI SI Blind Index (HMAC) SYNCED_HASH
telefono SI SI Blind Index (HMAC) SYNCED_HASH
nombre_completo SI SI Blob E2E SYNCED_E2E
fecha_nacimiento SI SI Blob E2E SYNCED_E2E
foto_perfil SI SI Blob E2E SYNCED_E2E
Datos Medicos (PHI)
medicamentos SI SI Blob E2E SYNCED_E2E
dosis_tomadas SI SI Blob E2E SYNCED_E2E
recetas SI SI Blob E2E SYNCED_E2E
citas_medicas SI SI Blob E2E SYNCED_E2E
mediciones_salud SI SI Blob E2E SYNCED_E2E
alergias SI SI Blob E2E SYNCED_E2E
condiciones_cronicas SI SI Blob E2E SYNCED_E2E
notas_medicas SI SI Blob E2E SYNCED_E2E
Machine Learning
patrones_detectados SI NO N/A LOCAL_ONLY
predicciones_omision SI NO N/A LOCAL_ONLY
modelo_ml_entrenado SI NO N/A LOCAL_ONLY
historial_respuestas SI NO N/A LOCAL_ONLY
Gamificacion
puntos_totales SI SI Blob E2E SYNCED_E2E
racha_actual SI SI Blob E2E SYNCED_E2E
logros SI SI Blob E2E SYNCED_E2E
Metadata Operativa
tier_suscripcion SI SI Plaintext SYNCED_PLAIN
fecha_registro SI SI Plaintext SYNCED_PLAIN
ultimo_acceso SI SI Plaintext SYNCED_PLAIN
sync_version SI SI Plaintext SYNCED_PLAIN
device_id SI SI Plaintext SYNCED_PLAIN
idioma SI SI Plaintext SYNCED_PLAIN
zona_horaria SI SI Plaintext SYNCED_PLAIN
Catalogos
catalogo_medicamentos Cache Source Publico SERVER_SOURCE
catalogo_interacciones Cache Source Publico SERVER_SOURCE
catalogo_unidades Cache Source Publico SERVER_SOURCE
Claves Criptograficas
master_key SI (Keychain) NO N/A LOCAL_ONLY
recovery_key SI (Usuario guarda) NO N/A LOCAL_ONLY
sync_key_encrypted SI SI Blob E2E SYNCED_E2E

4.2. Leyenda de Clasificaciones

Clasificacion Descripcion Servidor Puede Leer
LOCAL_ONLY Nunca sale del dispositivo bajo ninguna circunstancia NO
SYNCED_E2E Se sincroniza como blob cifrado E2E, servidor almacena pero no puede leer NO
SYNCED_HASH Se sincroniza como hash/blind index para busqueda, no reversible NO (solo buscar)
SYNCED_PLAIN Se sincroniza en texto claro, necesario para operacion SI
SERVER_SOURCE Datos publicos cuyo origen es el servidor, usados para construir catalogo local SI (son publicos)
ANONYMIZED_DATA Datos anonimizados para enriquecer catalogos publicos de MedTime SI (anonimizado)

4.2.1. Sobre ANONYMIZED_DATA

MedTime utiliza informacion anonimizada de los usuarios para enriquecer sus catalogos publicos, siguiendo un proceso de separacion de identidad. Ver INV-010: Anonimizacion de Medicamentos.

CONSENTIMIENTO OBLIGATORIO: Para usuarios con cuenta, el consentimiento para el tratamiento de datos anonimizados es requisito para usar la aplicacion. Este consentimiento se obtiene durante el onboarding y es explicito conforme a LFPDPPP. Ver INV-009: Consentimiento Datos de Salud.

Flujo de anonimizacion (Separacion de Identidad):

DATO ORIGINAL (en dispositivo):
+---------------------------+
| Medicamento: "Glucophage" |
| Dosis: "850mg"            |
| Usuario: Juan Perez       |
| Region: CDMX              |
| user_id: U-12345          |
+---------------------------+
          |
    ANONIMIZACION LOCAL
    (Separacion de identidad)
          |
          v
DATO ANONIMIZADO (enviado al servidor):
+-----------------------------+
| Medicamento: "Glucophage"   |  <- SI se envia medicamento especifico
| Dosis: "850mg"              |  <- SI se envia dosis
| Region: "Centro Mexico"     |  <- Generalizada
| Periodo: "2025-12"          |  <- Solo mes/año
| session_token: <efimero>    |  <- Token aleatorio no vinculado
+-----------------------------+
          |
    LO QUE SE ELIMINA:
    - user_id, email, nombre
    - device_id, IP
    - Cualquier identificador

Principios de anonimizacion (Separacion de Identidad):

  1. Los datos NUNCA pueden asociarse a un usuario especifico
  2. Se eliminan TODOS los identificadores (user_id, email, device_id, IP)
  3. SI se envian medicamentos especificos (nombre, dosis) - solo se elimina la identidad
  4. Tokens de sesion efimeros y no correlacionables entre envios
  5. Region y timestamps generalizados
  6. Combinaciones muy raras pueden suprimirse por k-anonymity

Que se envia anonimizado para enriquecer catalogos:

Dato Original Como se Anonimiza Uso
Medicamento especifico Se envia nombre SIN vinculo a usuario Enriquecer catalogo de medicamentos
Dosis Se envia dosis SIN vinculo a usuario Validar dosis estandar
Medicamento no encontrado Se envia para descubrimiento Expandir catalogo con nuevos meds
Combinaciones de meds Sin correlacion temporal Detectar interacciones

Garantia de separacion de identidad:

Lo que SI se envia Lo que NUNCA se envia
Nombre de medicamento user_id
Dosis email
Region generalizada nombre del usuario
Periodo (mes/año) device_id
Token efimero aleatorio IP
timestamps exactos

IMPORTANTE: La informacion anonimizada NUNCA afecta directamente los catalogos publicos. Los datos anonimizados se procesan por el equipo de MedTime para validacion manual antes de incorporar cualquier informacion a los catalogos oficiales.


5. Detalle por Clasificacion de Datos

5.1. LOCAL_ONLY - Nunca Sale del Dispositivo

DATOS LOCAL_ONLY:
+------------------------------------------------------------------+
|  Estos datos JAMAS abandonan el dispositivo bajo ninguna          |
|  circunstancia, incluso con orden judicial.                        |
+------------------------------------------------------------------+

LISTA COMPLETA:
- Patrones de comportamiento detectados por ML
- Predicciones de omision de tomas
- Modelo de ML personalizado entrenado
- Historial de tiempos de respuesta a alertas
- Master key de cifrado
- Recovery key (solo usuario tiene copia fisica)
- Datos biometricos (gestionados por OS)
- Cache de imagenes de recetas originales
- Estadisticas detalladas de uso de app

Justificacion tecnica y legal:

  • Datos de ML son inferencias, no datos proporcionados por usuario
  • Claves criptograficas: compromiso de seguridad si salen
  • LGPD/HIPAA: minimizacion de datos en servidor

5.2. SYNCED_E2E - Sincronizado como Blob Cifrado

PROCESO DE SINCRONIZACION E2E:
+------------------------------------------------------------------+
|                                                                    |
|  CLIENTE                          SERVIDOR                         |
|  +--------+                       +--------+                       |
|  | Datos  |  --[Cifrar E2E]-->   | Blob   |                       |
|  | Claro  |     AES-256-GCM      | Opaco  |                       |
|  +--------+                       +--------+                       |
|                                                                    |
|  Servidor almacena:                                                |
|  - blob: 0x7F8A9B2C... (indescifrable)                            |
|  - hash: sha256:abc123...                                          |
|  - size: 2048 bytes                                                |
|  - updated_at: 2025-12-07T10:30:00Z                               |
|                                                                    |
|  Servidor NO sabe:                                                 |
|  - Que medicamento es                                              |
|  - Nombre del usuario                                              |
|  - Ningun dato PHI                                                 |
|                                                                    |
+------------------------------------------------------------------+

5.3. SYNCED_HASH - Sincronizado como Hash/Blind Index

BLIND INDEX PARA BUSQUEDA:
+------------------------------------------------------------------+
|  Permite buscar sin revelar el valor original                      |
+------------------------------------------------------------------+

EJEMPLO - Email:
Original:    "paciente@ejemplo.com"
Normalizado: "paciente@ejemplo.com" (lowercase, trim)
Blind Index: HMAC-SHA256(global_salt, normalizado) = "7f8a9b2c..."

BUSQUEDA:
1. Usuario intenta login con "Paciente@Ejemplo.com"
2. Cliente normaliza y calcula blind index
3. Servidor busca por blind_index = "7f8a9b2c..."
4. Servidor retorna blob cifrado (sin ver email real)

PROTECCIONES:
- global_salt rotado anualmente
- global_salt almacenado en HSM
- Rate limiting en busquedas
- Audit log de todas las consultas

5.4. SYNCED_PLAIN - Sincronizado en Claro

DATOS EN CLARO (justificados):
+------------------------------------------------------------------+
|  Estos datos DEBEN estar en claro para operacion del sistema      |
+------------------------------------------------------------------+

| Dato              | Razon                                         |
|-------------------|-----------------------------------------------|
| tier_suscripcion  | Necesario para facturacion y limites de tier  |
| fecha_registro    | Auditoria, calculos de retencion              |
| ultimo_acceso     | Deteccion de cuentas inactivas                |
| sync_version      | Coordinacion de sincronizacion                |
| device_id         | Identificar dispositivos autorizados           |
| idioma            | Localizacion de emails transaccionales        |
| zona_horaria      | Calculos de timestamps                        |

NINGUNO de estos datos es PHI o PII sensible.

5.5. SERVER_SOURCE - Origen en Servidor, Usado para Catalogo Local

CATALOGOS PUBLICOS:
+------------------------------------------------------------------+
|  Datos publicos disponibles para usuarios autenticados            |
|  No contienen informacion personal                                 |
|  Se usan para CONSTRUIR el catalogo local del usuario              |
+------------------------------------------------------------------+

FLUJO:
1. Usuario busca medicamento en su catalogo local
2. Si no existe, busca en catalogo publico (requiere cuenta)
3. Si no existe en publico, usuario ingresa manualmente
4. Dato se guarda en catalogo LOCAL del usuario

NOTA: Los clientes NO cachean catalogos publicos directamente.
      Construyen sus propios catalogos con datos publicos + manuales.

CATALOGOS DISPONIBLES:
- Medicamentos aprobados (FDA, COFEPRIS, ANVISA)
- Tratamientos estandar
- Interacciones medicamentosas
- Contraindicaciones
- Unidades de medida
- Formas farmaceuticas
- Vias de administracion
- Frecuencias de dosificacion
- Categorias terapeuticas
- Efectos secundarios
- Laboratorios

5.6. ANONYMIZED_DATA - Datos Anonimizados para Enriquecimiento

DATOS ANONIMIZADOS (Separacion de Identidad):
+------------------------------------------------------------------+
|  Informacion de medicamentos que se envia SIN vinculo a usuario   |
|  para enriquecer los catalogos publicos de MedTime                 |
+------------------------------------------------------------------+

CONSENTIMIENTO:
- OBLIGATORIO para usuarios con cuenta
- Se obtiene durante el onboarding (explicito, conforme LFPDPPP)
- Requisito para usar la aplicacion con cuenta
- Ver INV-009: Consentimiento Datos de Salud

CARACTERISTICAS:
- Separacion de identidad: Se elimina TODO identificador
- Anonimizacion LOCAL: Se aplica ANTES de enviar
- Tokens efimeros: Cada envio tiene token diferente no correlacionable
- Region/Tiempo generalizados: Solo mes/año, solo region amplia

LO QUE SI SE ENVIA (anonimizado):
- Nombre especifico del medicamento (ej: "Glucophage")
- Dosis (ej: "850mg")
- Region generalizada (ej: "Centro Mexico")
- Periodo (ej: "2025-12")
- Token de sesion efimero aleatorio

LO QUE NUNCA SE ENVIA (eliminado):
- user_id
- email
- nombre del usuario
- device_id
- IP
- timestamps exactos
- CUALQUIER identificador directo o indirecto

PROCESO:
1. Usuario registra medicamento en su app
2. Al sincronizar, datos de medicamento se separan de identidad
3. Se genera token efimero aleatorio (no vinculado a usuario)
4. Servidor recibe: {medicamento, dosis, region_gen, periodo, token_random}
5. Servidor NO puede saber de quien proviene el dato

CRITICO: MedTime SI tiene acceso a los nombres especificos de medicamentos en forma anonimizada. La anonimizacion consiste en separar la identidad del usuario, NO en generalizar los medicamentos a categorias.

Ver detalles completos en INV-010: Anonimizacion de Medicamentos.


6. Flujo de Sincronizacion

6.1. Diagrama de Flujo de Sincronizacion

flowchart TD
    A[Usuario modifica dato] --> B[Guardar en DB local]
    B --> C[Cifrar con AES-256-GCM]
    C --> D[Agregar a cola de sync]

    D --> E{Hay conexion?}
    E -->|No| F[Mantener en cola]
    F -->|Reintentar periodicamente| E

    E -->|Si| G[Enviar batch al servidor]
    G --> H{Respuesta OK?}

    H -->|Si| I[Marcar como sincronizado]
    H -->|Conflicto| J[Resolver conflicto]
    H -->|Error| K[Reintentar con backoff]

    J --> L{Tipo de conflicto?}
    L -->|Mismo campo| M[Mostrar UI de resolucion]
    L -->|Campos diferentes| N[Auto-merge]

    M --> O[Usuario elige version]
    N --> I
    O --> I

    K --> E

    I --> P[Actualizar sync_version local]

6.2. Proceso de Cifrado Antes de Envio

FLUJO DETALLADO DE CIFRADO:
+------------------------------------------------------------------+

1. DATOS EN CLARO (local):
   {
     "medication_name": "Metformina",
     "dosage": "500mg",
     "frequency": "2x dia",
     "notes": "Tomar con alimentos"
   }

2. SERIALIZAR:
   JSON.stringify() -> "{"medication_name":"Metformina",...}"

3. OBTENER CLAVE:
   master_key = Keychain.get("master_key")

4. GENERAR NONCE:
   nonce = SecureRandom.generate(96 bits)

5. CIFRAR:
   (ciphertext, tag) = AES-256-GCM.encrypt(
     key: master_key,
     nonce: nonce,
     plaintext: serialized_data,
     aad: entity_id  // Datos adicionales autenticados
   )

6. EMPAQUETAR:
   encrypted_blob = nonce || ciphertext || tag

7. HASH PARA INTEGRIDAD:
   blob_hash = SHA-256(encrypted_blob)

8. ENVIAR AL SERVIDOR:
   {
     "entity_id": "uuid",
     "entity_type": "medication",
     "encrypted_blob": base64(encrypted_blob),
     "blob_hash": blob_hash,
     "encryption_version": "1.0"
   }

+------------------------------------------------------------------+

6.3. Estructura de Datos en Servidor

-- LO QUE EL SERVIDOR ALMACENA (ejemplo real)
SELECT
    id,
    user_id,
    entity_type,
    created_at,
    updated_at,
    sync_version,
    encrypted_blob,      -- Blob opaco, indescifrable
    blob_hash,
    blob_size_bytes,
    encryption_version
FROM encrypted_user_data
WHERE user_id = 'user-uuid-123';

-- RESULTADO:
-- id: "med-uuid-456"
-- user_id: "user-uuid-123"
-- entity_type: "medication"
-- created_at: "2025-12-07 10:30:00+00"
-- updated_at: "2025-12-07 10:30:00+00"
-- sync_version: 1234567890
-- encrypted_blob: \x7f8a9b2c4d5e6f... (binario opaco)
-- blob_hash: "sha256:abc123def456..."
-- blob_size_bytes: 256
-- encryption_version: "1.0"

-- NOTA: No hay columna "medication_name", "dosage", etc.
-- Esos datos estan DENTRO del blob cifrado.

7. Lo que NUNCA Sale del Dispositivo

7.1. Lista Exhaustiva de Datos LOCAL_ONLY

CATEGORIA: CLAVES CRIPTOGRAFICAS
+------------------------------------------------------------------+
| Dato                    | Razon                                   |
|-------------------------|----------------------------------------|
| master_key              | Compromiso total si se filtra           |
| derived_keys            | Derivadas de master_key                 |
| recovery_key (original) | Solo usuario debe tener copia fisica    |
| biometric_key           | Gestionada por Secure Enclave/TEE       |
| session_keys            | Efimeras, solo para sesion actual       |
+------------------------------------------------------------------+

CATEGORIA: MACHINE LEARNING
+------------------------------------------------------------------+
| Dato                        | Razon                               |
|-----------------------------|-------------------------------------|
| patrones_comportamiento     | Inferencias, no datos del usuario   |
| modelo_ml_personalizado     | Entrenado on-device, privado        |
| predicciones_adherencia     | Calculo local, no PHI compartido    |
| historial_tiempos_respuesta | Usado solo para ML local            |
| scores_riesgo_omision       | Calculo local                       |
+------------------------------------------------------------------+

CATEGORIA: DATOS TEMPORALES
+------------------------------------------------------------------+
| Dato                        | Razon                               |
|-----------------------------|-------------------------------------|
| imagenes_recetas_originales | Solo version anonimizada para OCR   |
| cache_busquedas             | Datos efimeros de sesion            |
| estado_ui_temporal          | Estado de la app, no persistido     |
| logs_debug_locales          | Solo para desarrollo, nunca prod    |
+------------------------------------------------------------------+

CATEGORIA: CONFIGURACION SENSIBLE
+------------------------------------------------------------------+
| Dato                        | Razon                               |
|-----------------------------|-------------------------------------|
| pin_hash_local              | Verificacion local solamente        |
| intentos_fallidos_local     | Contador de seguridad local         |
| configuracion_biometria     | Gestionada por OS                   |
+------------------------------------------------------------------+

7.2. Justificacion por Categoria

Categoria Justificacion Tecnica Justificacion Legal
Claves Si se filtran, todos los datos cifrados quedan comprometidos N/A tecnico
ML Son inferencias, no datos del usuario; no hay obligacion de compartir LGPD Art. 20: derecho a explicacion, no a modelo
Temporales Datos efimeros sin valor fuera de sesion Minimizacion de datos
Configuracion Datos de seguridad local, compartir aumenta superficie de ataque Seguridad por diseno

8. Lo que el Servidor VE vs NO VE

8.1. Tabla de Visibilidad del Servidor

+========================+=========+=========+=======================+
|        DATO            |  LOCAL  | SERVIDOR|  QUE VE EL SERVIDOR   |
+========================+=========+=========+=======================+
| Nombre: "Juan Perez"   |  Claro  |   E2E   | 0x7f8a9b2c... (blob)  |
| Email: "juan@mail.com" |  Claro  |  Hash   | "a1b2c3d4..." (HMAC)  |
| Metformina 500mg       |  Claro  |   E2E   | 0x4d5e6f... (blob)    |
| Toma 08:00 confirmada  |  Claro  |   E2E   | 0x1a2b3c... (blob)    |
| Patron: "olvida sabados"|  Claro |  NUNCA  | N/A                   |
| Tier: "Pro"            |  Claro  |  Claro  | "Pro"                 |
| Ultimo acceso          |  Claro  |  Claro  | "2025-12-07T10:30:00Z"|
+========================+=========+=========+=======================+

8.2. Ejemplo Practico: Que Ve un Admin de Base de Datos

ESCENARIO: Admin ejecuta query en produccion
+------------------------------------------------------------------+

QUERY:
SELECT * FROM users WHERE tier = 'Pro';

RESULTADO:
+----------+------------------+------+---------------------+--------+
| id       | email_blind_idx  | tier | created_at          | ...    |
+----------+------------------+------+---------------------+--------+
| uuid-123 | 7f8a9b2c4d5e6f.. | Pro  | 2025-01-15 08:00:00 | ...    |
| uuid-456 | a1b2c3d4e5f6a7.. | Pro  | 2025-03-20 14:30:00 | ...    |
+----------+------------------+------+---------------------+--------+

LO QUE EL ADMIN VE:
- IDs de usuario (UUIDs)
- Hashes de email (no reversibles)
- Tier de suscripcion
- Timestamps

LO QUE EL ADMIN NO VE:
- Emails reales
- Nombres
- Medicamentos
- Historial medico
- CUALQUIER dato PHI

QUERY PARA DATOS DE USUARIO:
SELECT encrypted_blob FROM encrypted_user_data WHERE user_id = 'uuid-123';

RESULTADO:
+------------------------------------------------------------------+
| encrypted_blob                                                    |
+------------------------------------------------------------------+
| \x7f8a9b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f |
+------------------------------------------------------------------+

El admin ve bytes aleatorios. Sin la master_key del usuario
(almacenada SOLO en el dispositivo del usuario), estos datos
son completamente indescifrables.

9. Arquitectura de Seguridad

9.1. Capas de Cifrado

MODELO DE CAPAS DE CIFRADO:
+------------------------------------------------------------------+

CAPA 4: TRANSPORTE
+----------------------------------+
| TLS 1.3 entre cliente y servidor |
| Certificate pinning              |
+----------------------------------+
           |
           v
CAPA 3: APLICACION (E2E)
+----------------------------------+
| AES-256-GCM por usuario          |
| Clave derivada de master_key     |
| Servidor NO puede descifrar      |
+----------------------------------+
           |
           v
CAPA 2: BASE DE DATOS
+----------------------------------+
| Cifrado transparente de disco    |
| Managed by cloud provider        |
+----------------------------------+
           |
           v
CAPA 1: ALMACENAMIENTO
+----------------------------------+
| Cifrado de disco fisico          |
| HSM para claves de servidor      |
+----------------------------------+

NOTA CLAVE:
- CAPA 3 (E2E) es la que importa para privacidad
- Si atacante compromete CAPAS 1-2, obtiene blobs opacos
- Solo comprometiendo dispositivo del usuario + su PIN/biometria
  se pueden descifrar los datos

9.2. Gestion de Claves

JERARQUIA DE CLAVES:
+------------------------------------------------------------------+

USER SIDE (Dispositivo):
+----------------------------------+
| Recovery Key (24 palabras BIP39) | <-- Usuario guarda offline
|        |                         |
|        v                         |
| Master Key (256 bits)            | <-- Derivada con Argon2id
|        |                         |
|        +---> Data Encryption Key | <-- Para cifrar datos PHI
|        |                         |
|        +---> Sync Key            | <-- Para sincronizacion
|        |                         |
|        +---> Share Key           | <-- Para compartir datos
+----------------------------------+

SERVER SIDE:
+----------------------------------+
| Global Salt (para blind indexes) | <-- En HSM, rotacion anual
|        |                         |
| Auth Service Keys                | <-- Firebase managed
|        |                         |
| TLS Certificates                 | <-- Auto-renovacion
+----------------------------------+

IMPORTANTE:
- Servidor NUNCA tiene acceso a:
  - Recovery Key
  - Master Key
  - Data Encryption Key
  - Share Key

- Servidor SOLO tiene:
  - Global Salt (para blind indexes)
  - Tokens de sesion (JWT, efimeros)

9.3. Flujo de Cifrado E2E

sequenceDiagram
    participant U as Usuario
    participant K as Keychain
    participant C as Crypto Engine
    participant DB as Local DB
    participant S as Servidor

    Note over U,S: ESCRITURA (Cifrar antes de sync)

    U->>DB: Crear/Modificar dato
    DB->>K: Solicitar master_key
    K->>K: Verificar biometria/PIN
    K->>DB: master_key
    DB->>C: Cifrar(data, master_key)
    C->>C: nonce = random(96 bits)
    C->>C: (ciphertext, tag) = AES-256-GCM(key, nonce, data)
    C->>DB: encrypted_blob
    DB->>S: POST /sync {encrypted_blob}
    S->>S: Almacenar blob opaco

    Note over U,S: LECTURA (Descifrar despues de pull)

    S->>DB: GET /sync -> {encrypted_blob}
    DB->>K: Solicitar master_key
    K->>K: Verificar biometria/PIN
    K->>DB: master_key
    DB->>C: Descifrar(encrypted_blob, master_key)
    C->>C: Extraer nonce, ciphertext, tag
    C->>C: data = AES-256-GCM.decrypt(key, nonce, ciphertext, tag)
    C->>DB: data (claro)
    DB->>U: Mostrar datos

10. Implicaciones para Desarrollo

10.1. Reglas para Desarrolladores de Cliente

REGLAS OBLIGATORIAS - CLIENTE:
+------------------------------------------------------------------+

1. CIFRAR ANTES DE ENVIAR
   - NUNCA enviar datos PHI en claro al servidor
   - Usar CryptoService.encrypt() ANTES de cualquier sync
   - Verificar que encrypted_blob no contiene datos legibles

2. NO LOGGING DE DATOS SENSIBLES
   - NUNCA console.log() con datos PHI
   - Usar sanitizeForLogging() en todos los logs
   - En debug builds: mostrar "[REDACTED]" para PHI

3. ALMACENAMIENTO LOCAL
   - Datos sensibles SOLO en DB cifrada por OS
   - Claves SOLO en Keychain/Keystore
   - NUNCA UserDefaults/SharedPreferences para PHI

4. ML ON-DEVICE
   - Modelos NUNCA se envian al servidor
   - Predicciones son LOCAL_ONLY
   - Features son LOCAL_ONLY

5. VERIFICAR CLASIFICACION
   - Antes de enviar cualquier dato, verificar tabla de clasificacion
   - Si dato es LOCAL_ONLY: error fatal
   - Si dato es SYNCED_E2E: cifrar primero
   - Si dato es SYNCED_HASH: calcular blind index

+------------------------------------------------------------------+

10.2. Reglas para Desarrolladores de Backend

REGLAS OBLIGATORIAS - BACKEND:
+------------------------------------------------------------------+

1. BLOBS OPACOS
   - NUNCA intentar descifrar encrypted_blob
   - NUNCA parsear contenido de blobs
   - Tratar blobs como BYTEA sin estructura

2. PostgreSQL con RLS
   - USAR Row Level Security para autorizacion a nivel de DB
   - RLS es dependencia aceptable de PostgreSQL
   - Complementar con validacion en capa de aplicacion

3. NO LOGGING DE BLOBS
   - NUNCA loggear contenido de encrypted_blob
   - Solo loggear: user_id, entity_type, blob_size, timestamp
   - Audit logs de metadata, NUNCA contenido

4. BLIND INDEXES
   - Solo usar para busqueda, no para mostrar datos
   - NUNCA exponer blind_index a usuarios
   - Rate limiting en endpoints de busqueda

5. VERIFICAR AUTORIZACION
   - Cada request: verificar que user_id del token == user_id de datos
   - NUNCA retornar datos de otro usuario
   - 403 Forbidden si no coincide

+------------------------------------------------------------------+

10.3. Checklist de Seguridad por Feature

CHECKLIST PARA CADA NUEVO FEATURE:
+------------------------------------------------------------------+

[ ] 1. CLASIFICACION DE DATOS
    - Identificar todos los datos del feature
    - Asignar clasificacion (LOCAL_ONLY, SYNCED_E2E, etc.)
    - Documentar en PR

[ ] 2. CIFRADO
    - Datos SYNCED_E2E: implementar cifrado en cliente
    - Verificar que servidor no puede leer datos
    - Test: enviar blob, verificar que es opaco en DB

[ ] 3. ALMACENAMIENTO LOCAL
    - Datos sensibles en DB cifrada
    - Claves en Keychain/Keystore
    - NO en archivos planos

[ ] 4. LOGGING
    - Sanitizar logs de datos PHI
    - Verificar que no hay leaks en consola
    - Test: revisar logs en escenario real

[ ] 5. SINCRONIZACION
    - Verificar clasificacion antes de sync
    - Manejar conflictos apropiadamente
    - Test offline: feature funciona sin conexion

[ ] 6. CODE REVIEW
    - Reviewer verifica clasificacion de datos
    - Reviewer verifica cifrado implementado
    - Reviewer verifica no hay leaks

+------------------------------------------------------------------+

11. Diferencias por Tier

11.1. Tier Free: Local por Defecto

TIER FREE:
+------------------------------------------------------------------+
|  CARACTERISTICAS:                                                  |
|  - 100% de datos almacenados localmente                            |
|  - Sin sincronizacion con servidor                                 |
|  - Cuenta de usuario OPCIONAL                                      |
|  - Backup manual exportando archivo cifrado                        |
+------------------------------------------------------------------+

MODOS DE OPERACION FREE:

1. SIN CUENTA (100% offline):
   - Medicamentos ingresados manualmente
   - Sin acceso a catalogos publicos
   - Sin posibilidad de ser paciente dependiente
   - Sin posibilidad de ser cuidador
   - Backup solo manual/local

2. CON CUENTA (hibrido):
   - Acceso a catalogos publicos para buscar medicamentos
   - Puede ser paciente dependiente (vinculado a cuidador Pro)
   - Puede compartir datos con cuidadores Pro
   - Sin sincronizacion de datos propios (Free no sincroniza)
   - Sin OCR

ARQUITECTURA FREE (SIN CUENTA):

+=====================+
|    DISPOSITIVO      |
+=====================+
| [x] DB Local        |
| [x] Cifrado local   |
| [x] Alertas locales |
| [x] ML local        |
| [x] Gamificacion    |
| [x] Backup manual   |
+=====================+
         |
         | SIN conexion a servidor
         v
+=====================+
|    SERVIDOR         |
+=====================+
| [ ] Catalogos (NO)  |
| [ ] Sync (NO)       |
| [ ] Auth (NO)       |
| [ ] OCR (NO)        |
+=====================+

ARQUITECTURA FREE (CON CUENTA):

+=====================+
|    DISPOSITIVO      |
+=====================+
| [x] DB Local        |
| [x] Cifrado local   |
| [x] Alertas locales |
| [x] ML local        |
| [x] Gamificacion    |
| [x] Backup manual   |
+=====================+
         |
         | Auth + Catalogos (solo lectura)
         v
+=====================+
|    SERVIDOR         |
+=====================+
| [x] Catalogos       |
| [x] Auth (Firebase) |
| [ ] Sync (NO)       |
| [ ] OCR (NO)        |
+=====================+

RESUMEN REQUISITOS DE CUENTA:

| Funcionalidad | Sin Cuenta | Con Cuenta Free |
|---------------|------------|-----------------|
| Usar app localmente | SI | SI |
| Catalogos publicos | NO | SI |
| Ser paciente dependiente | NO | SI |
| Vincular con cuidador | NO | SI |
| Sincronizar datos | NO | NO |
| OCR | NO | NO |

11.2. Tier Pro/Perfect: Hibrido

TIER PRO/PERFECT:
+------------------------------------------------------------------+
|  CARACTERISTICAS:                                                  |
|  - Todos los datos locales + sincronizacion cifrada               |
|  - Cuenta en servidor con blind indexes                            |
|  - Backup automatico cifrado E2E                                   |
|  - Compartir con cuidadores (Pro) y medicos (Perfect)              |
|  - OCR de recetas (procesamiento servidor con anonimizacion)       |
+------------------------------------------------------------------+

ARQUITECTURA PRO/PERFECT:

+=====================+          +=====================+
|    DISPOSITIVO      |          |    SERVIDOR         |
+=====================+          +=====================+
| [x] DB Local        |  <---->  | [x] Blobs E2E       |
| [x] Cifrado E2E     |  sync    | [x] Blind indexes   |
| [x] Alertas locales |          | [x] Metadata        |
| [x] ML local        |          | [x] Firebase Auth   |
| [x] Gamificacion    |          | [x] Catalogos       |
| [x] Cola de sync    |          | [x] OCR (Perfect)   |
+=====================+          +=====================+

DATOS EN SERVIDOR:
+-------------------+-------------------+-------------------+
| CLASIFICACION     | EJEMPLO           | SERVIDOR VE       |
+-------------------+-------------------+-------------------+
| SYNCED_E2E        | Medicamentos      | Blob opaco        |
| SYNCED_HASH       | Email             | Hash no reversible|
| SYNCED_PLAIN      | Tier, timestamps  | Valor real        |
| SERVER_SOURCE     | Catalogo meds     | Datos publicos    |
| LOCAL_ONLY        | ML patterns       | N/A (no sincroniza)|
+-------------------+-------------------+-------------------+

12. Diagrama de Despliegue

flowchart TB
    subgraph USERS["Usuarios"]
        direction LR
        IOS["iOS Device<br/>iPhone/iPad"]
        ANDROID["Android Device<br/>Phone/Tablet"]
        WEB["Web Browser<br/>(Portal Medicos)"]
    end

    subgraph DEVICE_LAYER["Capa de Dispositivo (95% procesamiento)"]
        direction TB
        subgraph IOS_STACK["iOS Stack"]
            IOS_APP["SwiftUI App"]
            COREDATA["Core Data"]
            KEYCHAIN["iOS Keychain"]
            COREML["CoreML"]
        end

        subgraph ANDROID_STACK["Android Stack"]
            ANDROID_APP["Compose App"]
            ROOM["Room DB"]
            KEYSTORE["Android Keystore"]
            TFLITE["TensorFlow Lite"]
        end
    end

    subgraph CLOUD["Cloud Infrastructure"]
        direction TB

        subgraph API["API Layer"]
            GW["API Gateway<br/>(Cloud Functions)"]
            AUTH["Firebase Auth"]
        end

        subgraph SERVICES["Services"]
            SYNC["Sync Service<br/>(Node.js)"]
            CATALOG["Catalog Service<br/>(Node.js)"]
            OCR["OCR Service<br/>(Python + GPU)"]
        end

        subgraph DATA["Data Layer"]
            PG["PostgreSQL<br/>(Blobs E2E)"]
            REDIS["Redis<br/>(Cache)"]
        end

        subgraph EXTERNAL["External"]
            FCM["FCM/APNs<br/>(Push)"]
            DRUGBANK["DrugBank API"]
        end
    end

    IOS --> IOS_STACK
    ANDROID --> ANDROID_STACK

    IOS_STACK -->|"Blobs E2E<br/>TLS 1.3"| GW
    ANDROID_STACK -->|"Blobs E2E<br/>TLS 1.3"| GW
    WEB -->|"Read-only<br/>TLS 1.3"| GW

    GW --> AUTH
    GW --> SYNC
    GW --> CATALOG
    GW --> OCR

    SYNC --> PG
    SYNC --> REDIS
    CATALOG --> PG
    CATALOG --> DRUGBANK
    OCR --> PG

    AUTH --> FCM

13. Referencias

13.1. Documentos Funcionales

13.2. Investigaciones

13.3. Documentos Tecnicos

13.4. Estandares Externos


Documento generado por SpecQueen + ArchitectureDrone - IT-02 "En MedTime, tus datos son TUYOS. El servidor es solo un mensajero ciego."