Sistema Médico Hospital Nacional d. Ingenieros y Programadores 3. Diseño del backend
HN Ingenieros · Sección 3 de 10
⚙️

3. Diseño del backend

Cómo construir un microservicio paso a paso. Una receta única replicable para los 25.

3.1 Stack obligatorio

3.2 Estructura de paquetes (estándar)

// Patrón Hexagonal / Ports & Adapters por servicio
com.toscana.sih.<servicio>
├── domain            // Entidades + reglas de negocio (puro Java, sin frameworks)
│   ├── model
│   ├── service
│   └── port              // Interfaces hacia afuera (in/out)
├── application       // Casos de uso · orquestación
│   └── usecase
├── infrastructure    // Adaptadores
│   ├── persistence       // Spring Data JPA / MongoTemplate
│   ├── messaging         // Productores y consumidores Kafka
│   ├── http              // Clientes REST hacia otros servicios
│   └── external          // RENAP / SICOIN / FHIR
├── interfaces        // Adaptadores entrantes
│   ├── rest              // Controladores REST
│   ├── ws                // WebSockets
│   └── event             // Listeners Kafka
└── config            // Beans Spring · Security · Observabilidad

3.3 Plantilla mínima de microservicio (paso a paso)

  1. Crear repo sih-<servicio>-svc desde la plantilla de GitHub toscana-sih/template-svc. Ya trae Maven, Dockerfile, helm chart, Makefile y workflow CI.
  2. Definir el dominio en domain/model: clases inmutables (Java records cuando posible), invariantes en el constructor, sin anotaciones de framework.
  3. Definir puertos en domain/port: RepositorioPaciente, PublicadorEventos, ClienteRenap. Son interfaces puras.
  4. Casos de uso en application/usecase: una clase por caso (RegistrarPaciente, FusionarPacientes). Reciben puertos por constructor.
  5. Adaptador de persistencia en infrastructure/persistence: implementa RepositorioPaciente con Spring Data JPA. Tabla con created_at, updated_at, deleted_at, version.
  6. Adaptador de mensajería: PublicadorEventosKafka serializa a Avro/JSON y publica a sih.<contexto>.<evento> con clave paciente_id.
  7. Controlador REST en interfaces/rest: usa @RestController, valida con @Valid, mapea a DTO, maneja errores con @RestControllerAdvice.
  8. Migraciones con Flyway en db/migration/V001__init.sql. Nunca modificar una migración aplicada — siempre crear una nueva.
  9. Pruebas: unitarias del dominio sin Spring, integración con Testcontainers (Postgres, Kafka), contrato con Pact contra consumidores.
  10. Dockerfile multi-stage: imagen base distroless · usuario no-root · puerto 8080 · healthcheck /actuator/health.
  11. Helm chart en deploy/chart: values por entorno (DEV/QA/STAGING/PROD-HNSM) con secretos vía SealedSecrets.
  12. Pipeline: build → test → escaneo (Trivy + OWASP Dep-Check) → push → ArgoCD detecta y despliega.

3.4 Convenciones de API REST

# Recurso plural en kebab-case · versión en path
GET    /api/v1/pacientes/{id}                  → 200 PacienteDto | 404
POST   /api/v1/pacientes                       → 201 + Location · Idempotency-Key obligatoria
PATCH  /api/v1/pacientes/{id}                  → 200 PacienteDto · usa JSON Merge Patch
DELETE /api/v1/pacientes/{id}                  → 204 (soft delete)
GET    /api/v1/pacientes?cui=...&limit=20      → 200 Page<PacienteDto>

# Errores: RFC 7807 (Problem Details)
{
  "type":"https://sih.hnsm/errors/validation",
  "title":"CUI inválido",
  "status":400,
  "detail":"El CUI 1234567890123 no pasa el algoritmo verificador",
  "instance":"/api/v1/pacientes",
  "trace_id":"abc-123"
}

3.5 Convenciones de eventos

# Topic: sih.<contexto>.<evento>   ej. sih.identidad.paciente.creado
# Clave: paciente_id  → asegura orden por paciente
# Esquema (JSON):
{
  "id":"01JEVENTID...",            // ULID
  "type":"paciente.creado",
  "ts":"2026-05-15T08:30:00-06:00",
  "actor":"u-Admin-HNSM-001",
  "trace_id":"abc-123",
  "data":{ "paciente_id":"...", "cui":"..." },
  "version":1
}

3.6 Cifrado de campo (paso a paso)

  1. Cada servicio recibe su clave maestra desde Vault al arrancar.
  2. Para columnas sensibles se usa AES-GCM 256 con IV aleatorio por fila.
  3. El campo se almacena como v1$base64(iv)$base64(ciphertext)$base64(tag).
  4. Búsqueda por igualdad usa columna espejo con HMAC determinista del valor; nunca se busca por el ciphertext.
  5. La rotación de clave produce v2$...; el lector entiende ambas hasta el cierre de la migración.

3.7 Listo cuando…

← Volver a d. Ingenieros y Programadores 🏥 Inicio del Sistema Médico 🏠 Inicio Toscana