Saltar al contenido principal

Arquitectura y Seguridad

Este documento detalla la estructura técnica del ecosistema de Salud y las capas de protección implementadas para garantizar la integridad de los datos (PII/PHI) y el cumplimiento legal.


1. Stack Tecnológico Oficial

CapaTecnologíaJustificación Técnica
Backend CoreGo (Golang)Alta performance, gestión eficiente de concurrencia (Goroutines) para búsquedas masivas y binarios ligeros para microservicios.
Frontend WebNext.js (React + TS)Renderizado híbrido (SSR/SSG) para SEO médico, tipado fuerte con TypeScript y excelente manejo de rutas.
Mobile AppFlutterCódigo único para iOS y Android con performance nativa y una interfaz de usuario altamente consistente.
Base de DatosPostgreSQL + PostGISEstándar de oro para datos relacionales y consultas geográficas complejas (Validación Triple).
ComunicacióngRPC / RESTgRPC para comunicación ultra rápida entre servicios internos y REST/JSON para el Frontend.
Caché / ColasRedisAlta velocidad para sesiones y gestión de envíos de correo en background.
DocumentaciónDocusaurus + SwaggerLiving Documentation integrada al ciclo de vida.

2. Arquitectura del Sistema (C4 Model)

2.1 Nivel 1: Diagrama de Contexto

Muestra cómo el sistema interactúa con los actores externos y servicios de terceros.

2.2 Nivel 2: Diagrama de Contenedores

Detalle de la infraestructura interna y la comunicación entre servicios.

2.3 Patrón DDD + Clean Architecture (Go)

  • Capas: domain (entidades/valores), application (use cases), infrastructure (adapters: repos DB, pubsub, http clients), interfaces/http (handlers/DTOs). Dependencias solo hacia adentro; domain no importa infraestructura.
  • Reglas: handlers solo orquestan y mapean DTO ↔ use case; validaciones de negocio viven en application; repos son interfaces definidas en dominio/aplicación y sus implementaciones en infrastructure/persistence.
  • Carpetas sugeridas (por servicio Go): /cmd/<service> (wire DI), /internal/domain/<bounded_context>, /internal/application/<usecase>, /internal/infrastructure/{persistence,pubsub,clients}, /internal/interfaces/http (handlers, middleware, mappers).
  • DTOs vs entidades: los contratos HTTP (OpenAPI) modelan DTOs de interfaz; no exponen detalles de persistencia ni structs de dominio.

3. Infraestructura y Gestión de Datos

3.1 Gestión de Secretos (Security First)

Se prohíbe el almacenamiento de credenciales en el código fuente o variables de entorno del servidor sin cifrar.

  • Herramienta: Uso de [Secret Manager - ej. HashiCorp Vault / AWS Secrets] para inyección dinámica de secretos en tiempo de ejecución.
  • Zero Trust: Cada microservicio en Go tiene permisos mínimos (IAM roles) para acceder solo a sus tablas y buckets específicos.

3.2 Almacenamiento de Objetos (Storage)

  • Servicio: S3 compatible (AWS S3 / Google Cloud Storage).
  • CDN: Cloudflare para el cacheo de activos estáticos (fotos de médicos, logos).
  • Procesamiento: Uso de un Worker en Go para el redimensionamiento y compresión de imágenes a formato WebP tras la carga (REG-600/700).

4. Estrategia de Seguridad y Autenticación

Para mitigar riesgos de secuestro de sesión y ataques de fuerza bruta, se implementa el siguiente estándar:

4.1 Gestión de Tokens (Security Stack)

  1. JWT Dinámico: El Access Token emitido por el servicio en Go tendrá una validez de 15 minutos.
  2. Almacenamiento Seguro:
    • Web: El Refresh Token se almacena en una Cookie HttpOnly, Secure y SameSite=Strict.
    • Mobile: Uso de Flutter Secure Storage (Keychain en iOS y AES en Android).
  3. Refresh Token Rotation: Mecanismo automático para invalidar sesiones ante cualquier intento de reutilización de tokens antiguos.
  4. Verify/Reset Safety: Tras token/verify o reset-password, rotar refresh y invalidar accesos previos.

4.2 Protección de Endpoints

  1. Rate Limiting: Máximo 10 intentos de login por cada 5 minutos por IP. Implementado en el nivel de Go (usando golang.org/x/time/rate) para mitigar ataques DoS.
  2. CORS: Política restrictiva permitiendo únicamente dominios oficiales de la organización.
  3. OWASP Headers: Implementación de Helmet.js para prevenir XSS, Clickjacking y Sniffing.
  4. Validación de Esquema: Uso de Protocol Buffers o JSON Schema para asegurar que los datos de entrada cumplan estrictamente con el Modelo de Dominio.
  5. Captcha Adaptativo: Activar tras patrones de abuso (5 intentos fallidos en login o verify) y en flujos de registro según reglas de producto.
  6. Detonantes de Captcha (referencia rápida):
    • Login: 5 intentos fallidos por IP/correo.
    • Refresh reuse detectado → exigir captcha en siguiente login.
    • Registro: 5 fallos en /auth/register o múltiples correos desde misma IP.
    • Verify OTP: 5 códigos fallidos o más de 3 reenvíos en 15 min.
    • Forgot/Reset: 3 solicitudes fallidas en 15 min.

4.4 Protocolo de Comunicación

  • Interna (Microservicios): gRPC para baja latencia y contratos estrictos (Protobuf).
  • Externa (Client-to-Server): REST API sobre TLS 1.3.

5. Requerimientos No Funcionales (NFRs)

5.1 Rendimiento y Disponibilidad

  • Disponibilidad: Objetivo del 99.9% (High Availability).
  • Latencia: Consultas al buscador deben responder en menos de 300ms (P99) utilizando índices GIST de PostGIS y caché en Redis.
  • Escalabilidad: Contenedores Docker sobre infraestructura elástica para soportar picos de tráfico.

5.2 Estrategia de Caché

  • Nivel de Catálogo: Caché de larga duración (24h) para países y especialidades.
  • Nivel de Red (Validación Triple): Caché de corta duración (30 min) con invalidación inmediata vía Pub/Sub al modificar convenios de aseguradoras.
  • PII (Personally Identifiable Information): Los teléfonos y correos deben encriptarse en la base de datos si no se usan para búsqueda.
  • Borrado Lógico: No se eliminan registros físicos; se usa deleted_at para trazabilidad y auditoría médica.
  • Backups: Respaldos automáticos diarios con encriptación AES-256 y retención de 30 días.

5.4 Observabilidad

  • Logs: Centralizados en formato JSON para análisis rápido. Estructurados en JSON para ingestión en [ELK Stack / Datadog].
  • Tracing: Implementación de OpenTelemetry para rastrear peticiones desde Next.js hasta la base de datos a través de Go.
  • Eventos Auth/Registro: Emitir USER_LOGGED_IN, REFRESH_REUSE, OTP_VERIFIED, REGISTER_STARTED, REGISTER_COMPLETED con trace_id, user_id, ip, channel y device_fingerprint cuando aplique.

5.5 Retención y Anonimización

  • Retención PII: Anonimizar usuarios eliminados después de 24 meses manteniendo agregados estadísticos.
  • PHI mínima en tránsito: No incluir diagnósticos ni notas clínicas en notificaciones; solo referencias de cita/doctor.
  • Mascaramiento en UI/Logs: Ocultar parcialmente email/phone; prohibido loggear tokens y OTP.
  • Roles acumulativos: PATIENT es base; al otorgar DOCTOR/ENTITY_ADMIN no se elimina el rol paciente. Validar scopes en backend.
  • Auditoría de perfil: eventos USER_PROFILE_UPDATED y ROLE_GRANTED deben registrar changed_by, timestamp e IP/UA.

5.6 Resiliencia y DR

  • RPO: ≤ 5 minutos (RDS PITR + backups horarios de Redis snapshots).
  • RTO: ≤ 60 minutos para restaurar stack productivo (infra IaC + restore de DB + warm-up).
  • Zonas/AZ: Despliegue multi-AZ para RDS y ECS; ALB cross-AZ.
  • Chaos/Failover: Drill semestral de restauración y conmutación manual documentada.

5.7 Costos y Cuotas

  • Rate Limits públicos: 100 req/min por IP en endpoints de búsqueda; 20 req/min en auth.
  • Guardrails de almacenamiento: Tamaño máximo de adjuntos 5 MB; retención de logs en caliente 30 días, frío 180 días.
  • Alerts Financieras: Alarmas de gasto diario >110% del promedio semanal en SES/SMS y egress CDN.

5.8 Checklist de Observabilidad por Servicio

ServicioMétrica P95Fallos/ErroresEventos claveLog/Trace keys
auth-servicelogin_latency_p95 < 300mstasa 401/422 < 2%USER_LOGGED_IN, PASSWORD_RESET, REFRESH_REUSEtrace_id, user_id, ip, route, status
auth-service (registro)verify_p95 < 350msfallos OTP < 5%OTP_VERIFIED, REGISTER_STARTED, REGISTER_COMPLETEDtrace_id, user_id, email, channel
catalog-servicecatalog_geo_p95 < 300ms5xx < 1%CATALOG_UPDATEDtrace_id, user_id, resource, operation
search-servicesearch_p95 < 300msresultados vacíos < 10%SEARCH_PERFORMEDtrace_id, q, lat, lng, specialty_id, insurance_id
notification-servicenotif_send_p95 < 2sfallos < 2%NOTIF_SENT, NOTIF_FAILEDtrace_id, message_id, channel, template
appointments-serviceappointment_create_p95 < 400msconflictos 409 < 5%APPOINTMENT_CONFIRMED, APPOINTMENT_CANCELLED, NOSHOWtrace_id, appointment_id, doctor_id, entity_id, patient_id
availability-serviceavailability_p95 < 300ms5xx < 1%SLOT_RESERVEDtrace_id, doctor_id, entity_id, from, to
entity-serviceentity_update_p95 < 400ms4xx < 3%ENTITY_CREATED, AGREEMENT_ENABLEDtrace_id, entity_id, agreement_id
dashboard-doctordashboard_p95 < 400mswidget errors < 1%DOCTOR_DASH_LOADEDtrace_id, doctor_id, widgets
dashboard-entidaddashboard_p95 < 400mswidget errors < 1%ENTITY_DASH_LOADEDtrace_id, entity_id, widgets
profile-servicepatch_profile_p95 < 400ms4xx < 3%DOCTOR_UPDATED, PATIENT_UPDATEDtrace_id, user_id, doctor_id

Colas y DLQ: cada worker (notifs) debe exponer queue_depth, dlq_depth, processing_latency y alarmar si dlq_depth > 0 por >5 min.

5.9 Dashboards y consultas operativas (accionables)

Dashboards mínimos por servicio

DashboardPanels obligatoriosFrecuencia de revisión
auth-service-overviewrequests por código, login p95, refresh reuse rate, errores OAuthDiario
search-service-overviewp95 búsqueda, vacíos por filtro, cache hit rate, errores DBDiario
appointments-service-overviewcreate p95, conflictos 409, cancelaciones, no-show rateDiario
notification-service-overviewenvíos por canal, latencia, fail rate, dlq_depthCada 4h
catalog-service-overviewlecturas p95, mutaciones admin, cache invalidationsSemanal

Consultas de referencia (CloudWatch Logs Insights)

Errores por ruta (últimos 15 min):

fields @timestamp, route, status, trace_id
| filter status >= 500
| stats count() as errors by route, status
| sort errors desc

Latencia p95 por servicio (si se registra duration_ms):

fields service, duration_ms
| filter ispresent(duration_ms)
| stats pct(duration_ms, 95) as p95_ms by service
| sort p95_ms desc

Intentos fallidos de autenticación por IP:

fields @timestamp, ip, route, status
| filter route = "/api/v1/auth/login" and status in [401, 429]
| stats count() as failed_attempts by ip
| sort failed_attempts desc
| limit 50

Eventos críticos de seguridad:

fields @timestamp, event, user_id, trace_id, ip
| filter event in ["REFRESH_REUSE", "ROLE_GRANTED", "PROFILE_VERIFIED"]
| sort @timestamp desc
| limit 100

Consultas de referencia (PromQL, si aplica)

histogram_quantile(0.95, sum(rate(http_request_duration_ms_bucket{service="auth-service"}[5m])) by (le))
sum(rate(http_requests_total{service="appointments-service",status=~"5.."}[5m])) / sum(rate(http_requests_total{service="appointments-service"}[5m]))
max(queue_depth{service="notification-service"}) by (queue)

5.10 Routing de alertas por severidad

SeveridadCriterio típicoCanal de alertaTiempo objetivo de respuestaEscalamiento
SEV1Caída total, corrupción de datos, auth indisponible generalPager + Slack #incidents-sev1 + llamada5 minIncident Commander + Tech Lead + DevOps
SEV2Degradación severa p95 o error rate sostenidoPager + Slack #incidents-sev215 minOwner de servicio + QA Lead
SEV3Falla parcial con workaround disponibleSlack #alerts-platform60 minOwner de servicio
SEV4Ruido operativo o riesgo bajoTicket automático backlog24 hOwner de módulo

Reglas:

  • Toda alerta debe incluir: service, severity, trace_id (si existe), métrica disparadora y enlace de dashboard.
  • SEV1 y SEV2 requieren postmortem (template-postmortem.md).
  • Alertas repetidas sin acción en 2 semanas se revisan en hygiene review para tuning de umbrales.

5.11 Inventario inicial de dashboards y alarmas (nomenclatura oficial)

Prefijo estándar por entorno: salud-{env}- donde {env} es dev, stg o prod.

Dashboards CloudWatch

DashboardNombre oficial
Auth overviewsalud-{env}-cw-dashboard-auth-overview
Search overviewsalud-{env}-cw-dashboard-search-overview
Appointments overviewsalud-{env}-cw-dashboard-appointments-overview
Notifications overviewsalud-{env}-cw-dashboard-notifications-overview
Catalogs overviewsalud-{env}-cw-dashboard-catalogs-overview
Platform SLOsalud-{env}-cw-dashboard-platform-slo

Alarmas CloudWatch (mínimo operativo)

AlarmaNombre oficialUmbral inicialSeveridad
Auth 5xx ratesalud-{env}-alarm-auth-5xx-rate> 2% por 5 minSEV2
Auth login p95salud-{env}-alarm-auth-login-p95> 350 ms por 5 minSEV3
Search p95salud-{env}-alarm-search-p95> 400 ms por 5 minSEV2
Appointments conflictssalud-{env}-alarm-appointments-409-rate> 8% por 10 minSEV3
Notification DLQ depthsalud-{env}-alarm-notifications-dlq-depth> 0 por 5 minSEV2
Catalog mutation failuressalud-{env}-alarm-catalogs-mutation-5xx> 1% por 10 minSEV3
RDS CPU highsalud-{env}-alarm-rds-cpu-high> 80% por 10 minSEV2
ECS task restart stormsalud-{env}-alarm-ecs-task-restarts> 3 restarts por 10 minSEV2

Canales de notificación (SNS/ChatOps)

DestinoNombre oficialUso
SNS SEV1salud-{env}-sns-incidents-sev1Pager + llamada + bridge
SNS SEV2salud-{env}-sns-incidents-sev2Pager + Slack
SNS Platformsalud-{env}-sns-alerts-platformAlertas no críticas
Slack canal SEV1#incidents-sev1Coordinación incidente crítico
Slack canal SEV2#incidents-sev2Coordinación degradación severa
Slack canal Platform#alerts-platformRuido operativo y seguimiento

Reglas de mantenimiento:

  • No crear dashboards o alarmas fuera de esta nomenclatura.
  • Cualquier cambio de umbral debe quedar en changelog de release (14-release-changelog.md).
  • Revisar umbrales al menos cada 30 días con datos reales.

5.12 Tabla de provisioning (Terraform)

Esta tabla define los campos mínimos para declarar dashboards/alarmas vía IaC.

Tiponamemetric_namespacemetric_namecomparison_operatorthresholdperiod_secondsevaluation_periodsseveritytarget
alarmsalud-{env}-alarm-auth-5xx-rateSalud/APIauth_5xx_rategt23001SEV2salud-{env}-sns-incidents-sev2
alarmsalud-{env}-alarm-auth-login-p95Salud/APIauth_login_p95_msgt3503001SEV3salud-{env}-sns-alerts-platform
alarmsalud-{env}-alarm-search-p95Salud/APIsearch_p95_msgt4003001SEV2salud-{env}-sns-incidents-sev2
alarmsalud-{env}-alarm-appointments-409-rateSalud/APIappointments_409_rategt86001SEV3salud-{env}-sns-alerts-platform
alarmsalud-{env}-alarm-notifications-dlq-depthSalud/Workersnotification_dlq_depthgt03001SEV2salud-{env}-sns-incidents-sev2
alarmsalud-{env}-alarm-catalogs-mutation-5xxSalud/APIcatalog_mutation_5xx_rategt16001SEV3salud-{env}-sns-alerts-platform
alarmsalud-{env}-alarm-rds-cpu-highAWS/RDSCPUUtilizationgt806001SEV2salud-{env}-sns-incidents-sev2
alarmsalud-{env}-alarm-ecs-task-restartsECS/ContainerInsightstask_restartsgt36001SEV2salud-{env}-sns-incidents-sev2
dashboardsalud-{env}-cw-dashboard-auth-overviewN/AN/AN/A000N/AN/A
dashboardsalud-{env}-cw-dashboard-platform-sloN/AN/AN/A000N/AN/A

Ejemplo de estructura (terraform.tfvars.json) para alarmas:

{
"cw_alarms": [
{
"name": "salud-prod-alarm-auth-5xx-rate",
"namespace": "Salud/API",
"metric_name": "auth_5xx_rate",
"statistic": "Average",
"comparison_operator": "GreaterThanThreshold",
"threshold": 2,
"period": 300,
"evaluation_periods": 1,
"datapoints_to_alarm": 1,
"treat_missing_data": "notBreaching",
"severity": "SEV2",
"sns_topic_arn": "arn:aws:sns:us-east-1:123456789012:salud-prod-sns-incidents-sev2",
"runbook_url": "https://docs.example.com/runbooks/auth"
}
]
}

6. Matriz de Trazabilidad Técnica

Entidad de DominioEndpoint APITabla Base de DatosPaquete Go (Backend)
Doctor/api/v1/doctorsdoctor_profilesinternal/doctor
Clínica/Sede/api/v1/entitieshealth_entitiesinternal/entity
Seguro/api/v1/insurancesinsurancesinternal/insurance
Reseña/api/v1/reviewsreviewsinternal/doctor/reviews

7. Convenciones Transversales de API

7.1 Formato de errores (estándar)

  • Respuesta base: { "message": "texto", "trace_id": "..." }.
  • Códigos usados: 400 datos inválidos; 401 no autorizado; 403 prohibido; 404 no encontrado; 409 conflicto/duplicado; 422 datos semánticamente inválidos; 429 rate limit.

7.2 Versionado y deprecación

  • Versión actual: /api/v1. Para cambios breaking, publicar /api/v2 y mantener v1 deprecado con fecha de retiro.
  • Anunciar deprecaciones en release notes y header Deprecation cuando aplique.

7.3 Autenticación/Autorización

  • JWT bearer para la mayoría de endpoints; refresh en cookie HttpOnly.
  • Roles: PATIENT, DOCTOR, ENTITY_ADMIN, CATALOG_ADMIN y SUPERADMIN; scopes reflejados en rutas y trazabilidad.
  • Endpoints públicos: /api/v1/search/entities, /api/v1/search/doctors, /api/v1/verify.

7.4 Paginación y filtros

  • Parámetros estándar: page (default 1, min 1), page_size (default 20, máx 100).
  • Sort opcional en buscador: sort=distance|rating|relevance.

7.5 Caché y ETags

  • Catálogos (geo/taxonomía): caché 24h; invalidar tras cambios admin.
  • Búsqueda/disponibilidad: caché corto (minutos) en Redis; evitar cache cliente cuando hay JWT.
  • Usar Cache-Control/ETag en recursos de solo lectura donde aplique.

7.6 Internacionalización y zonas horarias

  • API entrega fechas en UTC ISO-8601; front convierte a zona del usuario.
  • Errores/mensajes en español; otros idiomas vía i18n en front.

7.7 Seguridad y privacidad

  • No loggear PII/PHI (emails, teléfonos, tokens, OTP). Mascarar cuando sea imprescindible.
  • Retención: logs en caliente 30d, frío 180d; anonimizaciones según política.

7.8 Integraciones externas

  • Email (SES/SendGrid), SMS (Twilio/Vonage), Push (FCM/APNS). Timeouts 5s, 3 reintentos exponenciales, DLQ si falla.

7.9 Feature flags y toggles

  • Flags en VITE_* (front) y env vars backend; documentar impacto (no-show, aprobación manual, cache bust).

7.10 Datos de prueba / fixtures

  • Usar ejemplos en OpenAPI (login, availability, appointments, preferences) y seeds mínimas para QA manual.

7.11 Procesos de entrega

  • Diseño-first: static/openapi.yaml es la fuente; actualizar y commitear en cada cambio de contrato.
  • Checklist PR: OpenAPI actualizado, docs alineadas, linters/tests, build Docusaurus.

7.12 Observabilidad y runbooks

  • Cada servicio debe enlazar a su dashboard/alertas. Ver eventos en 5.8.
  • Runbook mínimo: qué hacer ante 5xx sostenidos, DLQ>0, caída de proveedor de notifs.

7.13 Exposición de IDs y datos sensibles

  • Exponer solo UUID/ULID públicos; evitar IDs autoincrementales o internos.
  • Si hay PK interna numérica, usar public_id (UUID) en DTOs y mapear internamente.
  • Validar ownership/rol en servidor aunque llegue un UUID (no confiar en el ID del cliente).
  • No incluir campos innecesarios en responses (ej. emails completos, IP, refresh tokens); usar DTO mínimos por pantalla.
  • Links a archivos/evidencias deben ser URLs firmadas y con expiración.
  • Mascarar PII en logs y payloads cuando no sean estrictamente requeridos.