03 - Estrategia de Datos¶
Versión: 1.1 Última Actualización: 2025-12-08 Estado: Aprobado
1. Clasificación de Datos¶
MedTime clasifica datos en 6 categorías según su ubicación, sincronización y tratamiento de seguridad:
| Clasificación | Ubicación | Sincronización | Cifrado | Ejemplo |
|---|---|---|---|---|
| LOCAL_ONLY | Cliente | No | Aplicable | Caché de UI, logs locales, preferencias de usuario, patrones ML |
| SYNCED_E2E | Cliente + Servidor | Sí, E2E | Siempre | Recetas OCR, diagnósticos, registros médicos, medicamentos |
| SYNCED_HASH | Cliente + Servidor | Sí, hash verificable | Condicionalmente | Email, teléfono (Blind Index) |
| SYNCED_PLAIN | Cliente + Servidor | Sí, plano | No | Tiempos de sincronización, versiones de datos, tier |
| SERVER_SOURCE | Servidor | Búsqueda Online | Requerido | Catálogos públicos >100 registros (medicamentos, interacciones) |
| ANONYMIZED_DATA | Cliente → Servidor | Sí, anonimizado | No (ya anonimizado) | Datos para enriquecer catálogos públicos |
1.1. Sobre SERVER_SOURCE¶
REGLA DE 100 REGISTROS (Directiva del Director):
Los catálogos públicos siguen estas reglas estrictas:
| Tamaño del Catálogo | Estrategia | Se Descarga al Cliente | Notas |
|---|---|---|---|
| >100 registros | Búsqueda ONLINE only | ❌ NO | Búsqueda por API en tiempo real |
| ≤100 registros | Embebido en app | ✅ SÍ | Puede incluirse en el bundle de la app |
| Registros seleccionados | Local + Sync E2E | ✅ SÍ | Solo los que el usuario elige/usa |
Excepción: Mini-cache de <100 interaccionesCONTRAINDICADO críticas puede almacenarse localmente para validación offline de seguridad.
Ver: 02-arquitectura-cliente-servidor.md sección 3.2.3.1 para detalles completos.
1.1.1. Construcción de Catálogos Locales del Usuario¶
Los clientes NO cachean catálogos públicos completos. En su lugar, construyen catálogos personales combinando:
- Búsquedas online en catálogos >100 registros (resultados no se cachean)
- Registros seleccionados por el usuario (guardados como SYNCED_E2E)
- Entradas manuales del usuario (guardadas como SYNCED_E2E)
El catálogo personal del usuario (medicamentos elegidos, análisis usados, etc.) se sincroniza como SYNCED_E2E.
1.2. Sobre ANONYMIZED_DATA¶
Datos que se envían sin vínculo a la identidad del usuario para enriquecer los catálogos públicos de MedTime.
1.2.1. Consentimiento¶
- OBLIGATORIO para usuarios con cuenta (no es opt-in)
- Se obtiene durante el onboarding (explícito, conforme LFPDPPP)
- Requisito para usar la aplicación con cuenta
- Ver INV-009: Consentimiento Datos de Salud
1.2.2. Catálogos Enriquecibles¶
| Catálogo | Datos de Usuario | Especificación |
|---|---|---|
| Medicamentos | Medicamentos ingresados manualmente | INV-010 |
| Estudios/Tratamientos | Resultados de laboratorio, tratamientos | INV-011 |
| Interacciones Med-Med | Combinaciones usadas, efectos observados | INV-012 |
| Interacciones Med-Estudio | Medicamentos que afectan estudios | INV-013 |
| Efectos Secundarios | Efectos adversos reportados | INV-014 |
1.3. Aplicación de la Regla de 100 Registros por Catálogo¶
Tabla de catálogos públicos con su clasificación según tamaño:
| Catálogo | Tamaño Estimado | Estrategia | Descarga al Cliente | Justificación |
|---|---|---|---|---|
| Medicamentos México | ~15,000 registros | ❌ Búsqueda Online | NO | Demasiado grande, búsqueda por API |
| Interacciones Med-Med | ~500,000 pares | ❌ Búsqueda Online | NO | Consulta por API con pares específicos |
| Interacciones Med-Estudio | ~50,000 pares | ❌ Búsqueda Online | NO | Consulta por API bajo demanda |
| Estudios Clínicos Comunes | ~200 registros | ❌ Búsqueda Online | NO | Excede umbral de 100 |
| Efectos Secundarios | ~10,000 registros | ❌ Búsqueda Online | NO | Base de datos farmacológica |
| Contraindicaciones Críticas | <100 pares | ✅ Mini-cache Local | SÍ (excepción) | Seguridad offline, validación crítica |
| Unidades de Medida | ~30 registros | ✅ Embebido | SÍ | Pequeño, estático |
| Vías de Administración | ~15 registros | ✅ Embebido | SÍ | Pequeño, estático |
| Frecuencias de Dosis | ~20 registros | ✅ Embebido | SÍ | Pequeño, estático |
Notas Importantes:
- Medicamentos del Usuario: Los medicamentos que el usuario ha seleccionado o agregado manualmente se guardan localmente como SYNCED_E2E, no como parte del catálogo público.
- Cache de Búsquedas: NO se implementa cache de resultados de búsquedas de catálogos >100 registros.
- Contraindicaciones Críticas: Única excepción, debe contener <100 interacciones de alto riesgo (ej: warfarina + aspirina, IMAO + SSRIs) para validación offline.
1.3.1. Principio de Anonimización: Separación de Identidad¶
NO es generalización a categorías. MedTime envía datos específicos pero elimina todos los identificadores:
Lo que SÍ se envía (anonimizado):
- Nombres específicos (medicamento, estudio, tratamiento)
- Resultados en rangos (bucketing): "Glucosa 140-150" no "147"
- Región generalizada: "Centro Mexico" no "CDMX"
- Período: "2025-Q4" no "2025-12-07"
Lo que NUNCA se envía (eliminado):
- user_id, email, nombre del usuario
- device_id, IP
- Timestamps exactos
- Valores exactos de resultados
- Cualquier identificador directo o indirecto
1.3.2. Umbrales de Seguridad¶
| Tipo de Dato | k-anonymity Mínimo | Tratamiento Especial |
|---|---|---|
| Medicamentos comunes | >= 1000 | Reportar |
| Estudios comunes | >= 1000 | Reportar con bucketing |
| Efectos secundarios leves | >= 1000 | Generalizar a categoría (GI, Neuro) |
| Efectos secundarios severos | NUNCA | Suprimir completamente |
| Medicamentos sensibles (VIH, cáncer) | NUNCA | Suprimir completamente |
2. Esquemas Conceptuales¶
2.1. Entidades Principales - Cliente (LocalStorage)¶
| Entidad | Clasificación | Retención | Sincronización |
|---|---|---|---|
| User | SYNCED_HASH | Indefinida | Hash públicamente verificable |
| MedicationSchedule | SYNCED_E2E | Indefinida | Cifrado E2E |
| MedicationLog | SYNCED_E2E | 2 años | Cifrado E2E |
| Appointment | SYNCED_HASH | 1 año | Hash verificable |
| DiagnosisRecord | SYNCED_E2E | Indefinida | Cifrado E2E |
| RecipeOCR | SYNCED_E2E | Indefinida | Cifrado E2E |
| AnomalyLog | SYNCED_E2E | 1 año | Cifrado E2E |
| UserPreferences | LOCAL_ONLY | Indefinida | No sincroniza |
| UICache | LOCAL_ONLY | 24 horas | No sincroniza |
2.2. Entidades Principales - Servidor (Database)¶
| Entidad | Clasificación | Indexación | Auditable | Retención |
|---|---|---|---|---|
| User | SERVER_SOURCE | PK: user_id | Sí | Indefinida |
| Device | SERVER_SOURCE | FK: user_id | Sí | Indefinida |
| MedicationSchedule | SYNCED_E2E | FK: user_id | Sí | Indefinida |
| MedicationLog | SYNCED_E2E | FK: user_id, FK: schedule_id | Sí | 2 años |
| Appointment | SYNCED_HASH | FK: user_id | Sí | 1 año |
| DiagnosisRecord | SYNCED_E2E | FK: user_id | Sí | Indefinida |
| RecipeOCR | SYNCED_E2E | FK: user_id | Sí | Indefinida |
| AnomalyLog | SYNCED_E2E | FK: user_id, FK: medication_id | Sí | 1 año |
| AccessLog | SERVER_SOURCE | FK: user_id, FK: device_id | Sí | 90 días |
| AuditTrail | SERVER_SOURCE | FK: resource_id | Sí | 7 años |
2.3. Mapeo Cliente-Servidor¶
CLIENTE (LocalDB) SERVIDOR (PostgreSQL)
┌─────────────────────┐ ┌─────────────────────┐
│ User (SYNCED_HASH) │ ◄────► │ User (SERVER_SOURCE)│
│ MedicSchedule (E2E) │ ◄────► │ MedicSchedule (E2E) │
│ MedicLog (E2E) │ ◄────► │ MedicLog (E2E) │
│ Appointment (HASH) │ ◄────► │ Appointment (HASH) │
│ DiagRecord (E2E) │ ◄────► │ DiagRecord (E2E) │
│ RecipeOCR (E2E) │ ◄────► │ RecipeOCR (E2E) │
│ AnomalyLog (E2E) │ ◄────► │ AnomalyLog (E2E) │
│ UserPrefs (ONLY) │ │ AccessLog (SRC) │
│ UICache (ONLY) │ │ AuditTrail (SRC) │
└─────────────────────┘ └─────────────────────┘
3. Sincronización¶
3.1. Cola de Operaciones (Operation Queue)¶
Cada cliente mantiene una cola de operaciones pendientes:
| Campo | Tipo | Descripción |
|---|---|---|
| queue_id | UUID | Identificador único de operación |
| entity_type | String | Tipo de entidad (MedicSchedule, MedicLog, etc.) |
| entity_id | UUID | ID de la entidad |
| operation | Enum | CREATE, UPDATE, DELETE |
| payload | JSON | Datos serializado (cifrados si E2E) |
| timestamp | DateTime | Timestamp local de creación |
| status | Enum | PENDING, SYNCED, FAILED |
| retry_count | Int | Número de reintentos (máx 5) |
Flujo:
- Operación local se agrega a queue con status = PENDING
- Sincronización intenta enviar al servidor
- Si success: status = SYNCED
- Si error: retry_count++, reintenta en 30s, 1m, 5m, 15m, 60m
- Si falla después de 5 intentos: status = FAILED, notifica usuario
3.2. Resolución de Conflictos¶
| Clasificación | Conflicto | Estrategia |
|---|---|---|
| SYNCED_E2E | Actualizaciones en paralelo | Merge manual: usuario elige versión |
| SYNCED_E2E | Eliminación vs. Actualización | Merge manual: usuario decide si mantener o eliminar |
| SYNCED_HASH | Conflicto de metadata | Server timestamp wins (servidor es fuente de verdad) |
| SYNCED_HASH | Hash mismatch | Cliente recibe versión servidor, recalcula hash |
| SERVER_SOURCE | Cualquier conflicto | No aplica, cliente siempre recibe estado servidor |
Resolución Manual E2E:
- Usuario ve versión local y versión servidor en paralelo
- Puede elegir: mantener local, aceptar servidor, o merge manual
- Ambas versiones permanecen en auditoria
4. Retención y Backup¶
4.1. Políticas de Retención por Clasificación¶
| Clasificación | Cliente | Servidor | GDPR Right to Erasure |
|---|---|---|---|
| LOCAL_ONLY | 24 horas (configurable) | No aplica | N/A |
| SYNCED_E2E | Indefinida (encriptada) | Indefinida | Sí, full deletion |
| SYNCED_HASH | 1 año (configurable) | 1 año (configurable) | Sí, hash removal |
| SYNCED_PLAIN | 90 días | 90 días | Sí, full deletion |
| SERVER_SOURCE | No aplica | 7 años (logs/audits) | Sí, con redacción |
4.2. Backup Strategy¶
Cliente (Mobile):
- Daily incremental backup to encrypted local cache
- User can export full backup as encrypted file (.medtime_backup)
- Backup stored in Documents/MedTime/ (user-controlled location)
- Expiration: None unless user deletes
Servidor:
- Continuous WAL (Write-Ahead Logging) backup
- Daily full backup + hourly incremental
- Replication a standby PostgreSQL
- Retention: 30 días de backups (PITR capable)
- Encryption at rest: AES-256
4.3. Recuperación de Desastres¶
RTO (Recovery Time Objective): 4 horas RPO (Recovery Point Objective): 1 hora
- Standby disponible para failover automático
- Client syncroniza desde último checkpoint conocido
- Auditoria de recuperación registrada en AuditTrail
5. Integridad y Verificación¶
5.1. Checksums y Hashes¶
- SYNCED_E2E: SHA-256 de contenido cifrado (verificable sin decriptar)
- SYNCED_HASH: SHA-256 de contenido plano (verificable por cliente y servidor)
- SYNCED_PLAIN: CRC32 para detección de corrupción en tránsito
- SERVER_SOURCE: Verificación de integridad en base de datos nativa
5.2. Auditable Operations¶
Todas las operaciones en SYNCED_E2E y SERVER_SOURCE generan entrada de AuditTrail:
- Quién: user_id + device_id
- Qué: operation + entity_type + entity_id
- Cuándo: timestamp server + timezone
- Dónde: IP + user_agent
- Por qué: reason (si aplica)
- Hash: SHA-256 de toda la entrada
6. Estrategia de Particionado para Tablas de Alto Volumen (DV2-P3)¶
6.1. Contexto: DB-BAJO-004¶
Problema: A medida que MedTime escale, ciertas tablas del servidor pueden crecer rapidamente (millones de registros), impactando performance de queries, indices y mantenimiento. El particionado es una estrategia para dividir tablas grandes en segmentos manejables.
6.2. Tablas Candidatas para Particionado¶
6.2.1. Analisis de Volumetria (Proyeccion 1 ano)¶
| Tabla | Registros/Usuario/Ano | Usuarios Objetivo | Total Estimado | Crecimiento | Candidata |
|---|---|---|---|---|---|
cli_dose_logs |
~1,095 (3/dia) | 100K | ~110M | Alto | ✅ SI |
srv_ocr_requests |
~50 (Perfect only) | 10K | ~500K | Medio | ✅ SI |
srv_prescription_sync |
~100 | 50K | ~5M | Bajo | ⚠️ Considerar |
srv_audit_trail |
~1,000 | 100K | ~100M | Alto | ✅ SI |
srv_access_log |
~3,650 (10/dia) | 100K | ~365M | Muy Alto | ✅ SI |
cli_medications |
~5 | 100K | ~500K | Bajo | ❌ NO |
srv_drug_catalog |
N/A (catalogo) | N/A | ~50K | Muy Bajo | ❌ NO |
Conclusiones:
- ALTO volumen:
cli_dose_logs,srv_audit_trail,srv_access_log - MEDIO volumen:
srv_ocr_requests - BAJO volumen: Resto (no requieren particionado en v1.0)
6.3. Estrategia de Particionado por Tabla¶
6.3.1. cli_dose_logs (Cliente - SYNCED_E2E)¶
NO aplica particionado en cliente:
- SQLite/Realm NO soportan particionado nativo
- Cada cliente tiene volumen moderado (~1K registros/ano)
- Cleanup automatico de logs > 2 anos mitiga crecimiento
Alternativa: Archivado de logs antiguos a tabla separada cli_dose_logs_archive.
6.3.2. srv_audit_trail (Servidor - Logs de Auditoria)¶
Estrategia: Particionado porrango de tiempo (RANGE) mensual.
-- Tabla padre
CREATE TABLE srv_audit_trail (
audit_id UUID NOT NULL,
user_id UUID NOT NULL,
action VARCHAR(50) NOT NULL,
entity_type VARCHAR(50) NOT NULL,
entity_id UUID NOT NULL,
details JSONB,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (audit_id, created_at)
) PARTITION BY RANGE (created_at);
-- Particiones mensuales (ejemplo para 2025-Q1)
CREATE TABLE srv_audit_trail_2025_01 PARTITION OF srv_audit_trail
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
CREATE TABLE srv_audit_trail_2025_02 PARTITION OF srv_audit_trail
FOR VALUES FROM ('2025-02-01') TO ('2025-03-01');
CREATE TABLE srv_audit_trail_2025_03 PARTITION OF srv_audit_trail
FOR VALUES FROM ('2025-03-01') TO ('2025-04-01');
-- Indices en cada particion (automaticos si se crean en tabla padre)
CREATE INDEX idx_audit_trail_user_created ON srv_audit_trail(user_id, created_at);
CREATE INDEX idx_audit_trail_entity ON srv_audit_trail(entity_type, entity_id);
Ventajas:
- Queries filtrados por fecha usan solo particiones relevantes (pruning)
- Eliminacion de particiones antiguas es instantanea (DROP TABLE)
- Mantenimiento de indices mas rapido (indices por particion)
Mantenimiento:
-- Job mensual para crear nueva particion (2 meses adelante)
CREATE OR REPLACE FUNCTION create_next_audit_partition()
RETURNS VOID AS $$
DECLARE
partition_date DATE;
partition_name TEXT;
start_date TEXT;
end_date TEXT;
BEGIN
partition_date := DATE_TRUNC('month', NOW() + INTERVAL '2 months')::DATE;
partition_name := 'srv_audit_trail_' || TO_CHAR(partition_date, 'YYYY_MM');
start_date := TO_CHAR(partition_date, 'YYYY-MM-DD');
end_date := TO_CHAR(partition_date + INTERVAL '1 month', 'YYYY-MM-DD');
EXECUTE format(
'CREATE TABLE IF NOT EXISTS %I PARTITION OF srv_audit_trail FOR VALUES FROM (%L) TO (%L)',
partition_name, start_date, end_date
);
END;
$$ LANGUAGE plpgsql;
-- Job mensual para eliminar particiones > 7 anos (compliance)
CREATE OR REPLACE FUNCTION drop_old_audit_partitions()
RETURNS VOID AS $$
DECLARE
partition_record RECORD;
partition_date DATE;
BEGIN
FOR partition_record IN
SELECT tablename FROM pg_tables
WHERE tablename LIKE 'srv_audit_trail_%'
ORDER BY tablename
LOOP
-- Extraer fecha de nombre de particion
partition_date := TO_DATE(SUBSTRING(partition_record.tablename FROM 17), 'YYYY_MM');
IF partition_date < NOW() - INTERVAL '7 years' THEN
EXECUTE format('DROP TABLE IF EXISTS %I', partition_record.tablename);
RAISE NOTICE 'Dropped partition: %', partition_record.tablename;
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
6.3.3. srv_access_log (Servidor - Logs de Acceso)¶
Estrategia: Particionado porrango de tiempo (RANGE) semanal.
-- Tabla padre
CREATE TABLE srv_access_log (
log_id UUID NOT NULL,
user_id UUID NOT NULL,
device_id UUID NOT NULL,
endpoint VARCHAR(200) NOT NULL,
method VARCHAR(10) NOT NULL,
status_code INT NOT NULL,
response_time_ms INT,
ip_address INET,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (log_id, created_at)
) PARTITION BY RANGE (created_at);
-- Particiones semanales (mas granular por alto volumen)
CREATE TABLE srv_access_log_2025_w01 PARTITION OF srv_access_log
FOR VALUES FROM ('2025-01-01') TO ('2025-01-08');
-- Indices
CREATE INDEX idx_access_log_user_created ON srv_access_log(user_id, created_at);
CREATE INDEX idx_access_log_endpoint ON srv_access_log(endpoint);
CREATE INDEX idx_access_log_status ON srv_access_log(status_code) WHERE status_code >= 400;
Retention: 90 dias (mas corto que audit_trail). Particiones semanales permiten eliminacion precisa.
6.3.4. srv_ocr_requests (Servidor - Solicitudes OCR)¶
Estrategia: Particionado porhash de user_id (HASH).
-- Tabla padre
CREATE TABLE srv_ocr_requests (
id UUID NOT NULL,
user_id UUID NOT NULL,
prescription_id UUID NOT NULL,
anonymized_image BYTEA,
status VARCHAR(20) NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (id, user_id)
) PARTITION BY HASH (user_id);
-- 4 particiones (por hash de user_id)
CREATE TABLE srv_ocr_requests_p0 PARTITION OF srv_ocr_requests
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE srv_ocr_requests_p1 PARTITION OF srv_ocr_requests
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE srv_ocr_requests_p2 PARTITION OF srv_ocr_requests
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE srv_ocr_requests_p3 PARTITION OF srv_ocr_requests
FOR VALUES WITH (MODULUS 4, REMAINDER 3);
Por que HASH:
- Distribucion uniforme de carga (no hay "hot partitions")
- Queries siempre incluyen
user_id(partition pruning) - Crecimiento balanceado entre particiones
Ventajas:
- Cleanup job mas rapido (corre en paralelo por particion)
- Indices mas pequenos por particion
6.4. Metricas de Monitoreo¶
6.4.1. Queries para Monitorear Particionado¶
-- Tamano de particiones
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
WHERE tablename LIKE 'srv_audit_trail_%'
OR tablename LIKE 'srv_access_log_%'
OR tablename LIKE 'srv_ocr_requests_%'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
-- Conteo de registros por particion
SELECT
schemaname,
tablename,
n_tup_ins AS rows_inserted,
n_tup_upd AS rows_updated,
n_tup_del AS rows_deleted
FROM pg_stat_user_tables
WHERE tablename LIKE 'srv_audit_trail_%'
OR tablename LIKE 'srv_access_log_%'
ORDER BY tablename;
-- Verificar partition pruning (queries usando particiones)
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM srv_audit_trail
WHERE created_at >= '2025-01-01' AND created_at < '2025-02-01';
-- Debe mostrar solo "srv_audit_trail_2025_01" en el plan
6.4.2. Alertas¶
| Metrica | Umbral | Accion |
|---|---|---|
| Particion > 10 GB | Alerta | Considerar particionado mas granular |
| Particiones faltantes (futuro) | 2 meses | Crear particiones automaticamente |
| Particiones antiguas sin eliminar | > 7 anos (audit) / > 90 dias (access) | Ejecutar cleanup job |
| Query sin partition pruning | N/A | Optimizar query para incluir filtro de fecha/user_id |
6.5. Consideraciones de Implementacion¶
6.5.1. Fase de Implementacion¶
| Fase | Tabla | Timeline | Complejidad |
|---|---|---|---|
| v1.0 | Ninguna | N/A | Volumetria aun baja |
| v1.1 | srv_audit_trail |
6 meses post-lanzamiento | Baja (solo inserts) |
| v1.2 | srv_access_log |
9 meses post-lanzamiento | Baja (solo inserts) |
| v2.0 | srv_ocr_requests |
12 meses post-lanzamiento | Media (tiene updates) |
6.5.2. Migracion de Tabla Existente a Particionada¶
-- Ejemplo: Migrar srv_audit_trail existente a particionada
-- 1. Renombrar tabla original
ALTER TABLE srv_audit_trail RENAME TO srv_audit_trail_old;
-- 2. Crear tabla particionada
CREATE TABLE srv_audit_trail (
-- Schema igual a original
) PARTITION BY RANGE (created_at);
-- 3. Crear particiones para datos historicos
-- (por cada mes en tabla original)
-- 4. Copiar datos de tabla original a particionada
INSERT INTO srv_audit_trail
SELECT * FROM srv_audit_trail_old;
-- 5. Verificar conteo
SELECT COUNT(*) FROM srv_audit_trail;
SELECT COUNT(*) FROM srv_audit_trail_old;
-- 6. Eliminar tabla original (tras verificacion)
DROP TABLE srv_audit_trail_old;
Ventana de mantenimiento: 2-4 horas para 10M registros.
6.6. Decision Matrix: Cuando Particionar¶
| Criterio | Umbral | Accion |
|---|---|---|
| Tamano de tabla | > 100 GB | Considerar particionado |
| Registros | > 50M | Considerar particionado |
| Crecimiento | > 10M registros/mes | Considerar particionado |
| Query pattern | Siempre filtra por fecha/user_id | Ideal para RANGE/HASH |
| Retention policy | Elimina datos antiguos periodicamente | Ideal para RANGE (drop partition) |
NO particionar si:
- Tabla < 10 GB
- Queries escanean tabla completa (sin filtros)
- Updates frecuentes en registros antiguos
7. Referencias Cruzadas¶
- Arquitectura Cliente-Servidor:
/02-arquitectura-cliente-servidor.md(ver sección 3.2.3.1 para Regla de 100 Registros) - Seguridad Cliente:
/04-seguridad-cliente.md - Modelos de Base de Datos:
/database/ - APIs de Sincronización:
/apis/sync/ - APIs de Búsqueda de Catálogos: Ver
/apis/catalogs/para endpoints de búsqueda online - Políticas de Retención GDPR:
/functional-spec/02-requisitos-regulatorios.md(Sección LGPD/GDPR)
Documento Generado: SpecQueen - 2025-12-07 Actualizado: ArchitectureDrone (Regla de 100 Registros) - 2025-12-08