Compare commits

..

2 Commits

4 changed files with 287 additions and 61 deletions

View File

@ -1,27 +1,98 @@
NODE_BASE_URL=http://localhost
# Configuración del contenedor de NGINX (ajusta según tus necesidades, por ejemplo, para SSL)
# =============================================================================
# IPS Nodo Dominio — Variables de entorno
# Copiar este archivo a .env y completar los valores requeridos.
# =============================================================================
# =============================================================================
# NODO
# =============================================================================
# URL pública del nodo (usada por GDHCN para construir sus URLs)
NODO_BASE_URL=http://localhost
# URL base del nodo (usada por bus-gateway internamente)
NODO_URL_BASE=http://localhost
# Zona horaria para todos los servicios
TZ=America/Argentina/Buenos_Aires
# =============================================================================
# BUS DE SALUD — Requeridas
# =============================================================================
# URL base del Bus de salud nacional
BUS_URL=https://bus-host/fhir
# Secreto compartido para firmar tokens JWT (HS256) contra el Bus
BUS_JWT_SECRET=your-shared-secret
# Identificador del emisor JWT (ej.: URL del repositorio del nodo)
BUS_ISSUER=https://your-repositorio-url
# Scopes OAuth para el Master Patient Index
MPI_SCOPE=Patient/*.read,Patient/*.write
# Scopes OAuth para el Document Registry
DOCUMENT_REGISTRY_SCOPE=DocumentReference/*.read,DocumentReference/*.write
# =============================================================================
# BUS DE SALUD — Opcionales (por defecto usan BUS_URL)
# =============================================================================
# URL del Master Patient Index si difiere del Bus principal
# MPI_URL=https://mpi-host/fhir
# URL del Document Registry si difiere del Bus principal
# DOCUMENT_REGISTRY_URL=https://document-registry-host/fhir
# Habilita logs detallados de requests/responses salientes al Bus (true | false)
BUS_DEBUG=false
# =============================================================================
# NGINX
# =============================================================================
# Modo de operación del proxy inverso: http (default) o https
NGINX_CONF=http
# NGINX_CONF=http
# Rutas a los certificados TLS del servidor (solo necesarias en modo https)
# SSL_CERT_PATH=./certs/server.crt
# SSL_KEY_PATH=./certs/server.key
# Bus FHIR (base, usado como fallback si se definen MPI_URL o DOCUMENT_REGISTRY_URL)
BUS_URL=http://bus-host:8080
BUS_JWT_SECRET=your-shared-secret
BUS_ISSUER=https://your-repositorio-url
# =============================================================================
# CERTIFICADOS / DOCKER SECRETS
# Los archivos se inyectan como Docker secrets.
# Los valores por defecto apuntan a ./certs/ — reemplazar en producción.
# =============================================================================
# Servicios del Bus (opcionales, por defecto usan BUS_URL)
MPI_URL=http://mpi-host:8080
DOCUMENT_REGISTRY_URL=http://document-registry-host:8080
# Certificado de la red de confianza (TNG/GDHCN)
SIGNATURE_CERT_PATH=./certs/trust-network.pem
SIGNATURE_KEY_PATH=./certs/trust-network.key
# Scopes por servicio
MPI_SCOPE=Patient/*.read,Patient/*.write
DOCUMENT_REGISTRY_SCOPE=DocumentReference/*.read,DocumentReference/*.write
# Clave privada para firma de documentos (Document Signing Certificate)
SSL_DCC_KEY_PATH=./certs/signature.key
# =============================================================================
# VERIFIABLE HEALTH LINKS (VHL)
# =============================================================================
# Habilita logs de requests/responses salientes al Bus (true | false)
BUS_DEBUG=false
# Ruta a una clave EC P-256 en formato PEM para firmar CWTs.
# Si se omite, se genera una clave efímera en memoria (se pierde al reiniciar).
# VHL_PRIVATE_KEY_FILE=./certs/vhl.key
# URI del emisor VHL (iss del CWT). Por defecto usa BUS_ISSUER.
# VHL_ISSUER=https://your-repositorio-url
# URL pública del gateway para construir las URLs de manifiesto y documento.
# Requerida si se usan los endpoints /vhl/*.
# VHL_BASE_URL=https://your-nodo-url
# TTL del token VHL en segundos (default: 604800 = 7 días)
# VHL_TOKEN_TTL=604800
# =============================================================================
# HAPI FHIR (Spring Boot)
# =============================================================================
SPRING_CONFIG_LOCATION="file:///data/hapi/application.yaml"
SPRING_DATASOURCE_URL="jdbc:postgresql://hapi-db:5433/root"
@ -29,6 +100,11 @@ SPRING_DATASOURCE_USERNAME="root"
SPRING_DATASOURCE_PASSWORD="hapifhir2023"
SPRING_DATASOURCE_DRIVERCLASSNAME="org.postgresql.Driver"
SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT="ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect"
# =============================================================================
# POSTGRESQL (hapi-db)
# =============================================================================
POSTGRES_DB="root"
POSTGRES_USER="root"
POSTGRES_PASSWORD="hapifhir2023"

234
README.md
View File

@ -1,56 +1,85 @@
# IPS Dominio Backend
# IPS Nodo Dominio
Proyecto Docker Compose con los servicios necesarios para el nodo de dominio IPS (International Patient Summary).
Plataforma de interoperabilidad en salud basada en Docker Compose que implementa el **Nodo de Dominio IPS** (International Patient Summary). Actúa como gateway de integración entre servicios FHIR locales y el Bus nacional de salud (Federador MSAL).
## Arquitectura
```
Internet / Red interna
nginx:80/443
┌────┴─────────────────────────────────────────┐
│ /fhir/IPSTransaction → bus-gateway:3000 │
│ /fhir/IPSDocument → bus-gateway:3000 │
│ /fhir/DocumentReference→ bus-gateway:3000 │
│ /fhir/Patient → bus-gateway:3000 │
│ /vhl/* → bus-gateway:3000 │
│ /gdhcn/* → gdhcn-validator │
│ /fhir/* (resto) → hapi-fhir:8080 │
└──────────────────────────────────────────────┘
```
## Servicios
| Servicio | Imagen / Fuente | Descripción |
|---|---|---|
| `hapi-fhir` | `hapiproject/hapi:latest` | Servidor FHIR R4 (implementación Spring Boot) |
| `hapi-db` | `postgres:14.6` | Base de datos PostgreSQL para HAPI FHIR |
| `bus-gateway` | `./bus-gateway` | Gateway hacia el Bus de salud (MPI y Document Registry) |
| `nginx` | `nginx:alpine` | Proxy inverso — punto de entrada HTTP/HTTPS |
| Servicio | Imagen / Fuente | Puerto | Descripción |
|---|---|---|---|
| `hapi-fhir` | `hapiproject/hapi:latest` | 8080 (interno) | Servidor FHIR R4 (Spring Boot) con búsqueda Lucene |
| `hapi-db` | `postgres:14.6` | 5433 (interno) | Base de datos PostgreSQL para HAPI FHIR |
| `bus-gateway` | `./bus-gateway` (Node.js) | 3000 (interno) | Gateway al Bus de salud nacional (MPI + Document Registry) |
| `gdhcn-validator-service` | `createchile/gdhcn-validator_backend:v1.1` | 8182 | Validador de documentos de salud verificables (firmas digitales) |
| `gdhcn-db` | `postgres:16-alpine` | 5432 (interno) | Base de datos PostgreSQL para el validador GDHCN |
| `nginx` | `nginx:alpine` | 80 / 443 | Proxy inverso — punto de entrada HTTP/HTTPS |
### Routing nginx
**Red interna**: todos los servicios se comunican a través de la red Docker `hapi-network`.
| Ruta | Destino |
|---|---|
| `/bus-gateway/*` | `bus-gateway:3000` |
| todo lo demás | `hapi-fhir:8080` |
**Volúmenes persistentes**: `hapi-data` (PostgreSQL de HAPI), `gdhcn-data` (PostgreSQL de GDHCN).
## Transacciones IHE implementadas
El `bus-gateway` implementa los siguientes perfiles de interoperabilidad:
| Transacción | Método | Ruta | Descripción |
|---|---|---|---|
| **ITI-65** | POST | `/fhir/IPSTransaction` | Provide Document Bundle (transacción) |
| **ITI-65** | POST | `/fhir/IPSDocument` | Provide Document Bundle (documento IPS) |
| **ITI-67** | GET | `/fhir/DocumentReference` | Find Document References |
| **ITI-78** | GET | `/fhir/Patient` | Patient Demographics Query (búsqueda) |
| **ITI-78** | GET | `/fhir/Patient/:id` | Patient Demographics Query (por ID) |
| **ITI-104** | POST | `/fhir/Patient` | Patient Identity Feed (alta) |
| **ITI-104** | PUT | `/fhir/Patient/:id` | Patient Identity Feed (actualización) |
| **VHL** | POST | `/vhl/:patientId` | Emitir Verifiable Health Link (token QR) |
| **VHL** | GET | `/vhl/manifest/:id` | Servir manifiesto VHL |
| **VHL** | GET | `/vhl/document/:id` | Servir documento VHL cifrado |
## Requisitos
- Docker >= 20.10.8
- Docker Compose >= 1.29.2
## Configuración
## Instalación y configuración
### 1. Variables de entorno
Copia el archivo de ejemplo y completa los valores:
```bash
cp .env.example .env
```
| Variable | Descripción |
|---|---|
| `BUS_URL` | URL base del Bus de salud |
| `BUS_JWT_SECRET` | Secreto compartido para JWT con el Bus |
| `BUS_ISSUER` | Issuer del token JWT |
| `MPI_URL` | URL del servicio MPI (default: `BUS_URL`) |
| `DOCUMENT_REGISTRY_URL` | URL del Document Registry (default: `BUS_URL`) |
| `MPI_SCOPE` | Scopes OAuth para MPI |
| `DOCUMENT_REGISTRY_SCOPE` | Scopes OAuth para Document Registry |
| `BUS_DEBUG` | Habilita logs de requests al Bus (`true` / `false`) |
| `SPRING_DATASOURCE_URL` | JDBC URL de la BD — debe usar puerto `5433` (`jdbc:postgresql://hapi-db:5433/root`) |
| `SPRING_DATASOURCE_USERNAME` | Usuario de la base de datos |
| `SPRING_DATASOURCE_PASSWORD` | Contraseña de la base de datos |
| `POSTGRES_DB` | Nombre de la base de datos PostgreSQL |
| `POSTGRES_USER` | Usuario PostgreSQL |
| `POSTGRES_PASSWORD` | Contraseña PostgreSQL |
Editar `.env` completando al menos las variables marcadas como requeridas. Ver la sección [Variables de entorno](#variables-de-entorno) para la descripción completa.
### 2. Configuración de nginx (HTTP o HTTPS)
### 2. Certificados
Los certificados se inyectan como **Docker secrets**. Las rutas se configuran en el `.env` (todas tienen valores por defecto apuntando a `./certs/`):
| Archivo por defecto | Descripción |
|---|---|
| `./certs/server.crt` / `./certs/server.key` | Certificado TLS para nginx (solo modo HTTPS) |
| `./certs/trust-network.pem` / `./certs/trust-network.key` | Certificado de la red de confianza (GDHCN/TNG) |
| `./certs/signature.key` | Clave privada para firma de documentos (DSC) |
> Ver [certs/README.md](certs/README.md) para instrucciones de generación de certificados de prueba.
### 3. Configuración de nginx (HTTP o HTTPS)
La variable `NGINX_CONF` en el `.env` selecciona el modo:
@ -59,20 +88,20 @@ La variable `NGINX_CONF` en el `.env` selecciona el modo:
NGINX_CONF=http
```
**HTTPS** (requiere certificados):
**HTTPS** (requiere certificados válidos en `./certs/`):
```env
NGINX_CONF=https
SSL_CERT_PATH=./certs/server.crt
SSL_KEY_PATH=./certs/server.key
```
Los certificados se inyectan como Docker secrets y nginx los lee desde `/run/secrets/ssl_cert` y `/run/secrets/ssl_key`. En modo HTTPS el tráfico HTTP (puerto 80) se redirige automáticamente a HTTPS (443).
En modo HTTPS el tráfico HTTP (puerto 80) se redirige automáticamente a HTTPS (443). Los certificados los lee nginx desde `/run/secrets/ssl_cert` y `/run/secrets/ssl_key`.
Los archivos de configuración están en [nginx/http.conf](nginx/http.conf) y [nginx/https.conf](nginx/https.conf).
### 3. Configuración HAPI FHIR
### 4. Configuración HAPI FHIR
Los parámetros del servidor FHIR se ajustan en [hapi-config/application.yaml](hapi-config/application.yaml). El servidor usa **Lucene** como backend de búsqueda (índice local, no requiere servicio externo).
Los parámetros del servidor FHIR se ajustan en [hapi-config/application.yaml](hapi-config/application.yaml). El servidor usa **Lucene** como backend de búsqueda (índice local, no requiere servicio externo). CORS está habilitado para todos los orígenes (`*`).
## Levantar los servicios
@ -80,19 +109,22 @@ Los parámetros del servidor FHIR se ajustan en [hapi-config/application.yaml](h
docker compose up -d
```
HAPI FHIR tarda aproximadamente **30-40 segundos** en arrancar completamente.
HAPI FHIR tarda aproximadamente **3040 segundos** en inicializar. El `bus-gateway` espera activamente a que el servidor FHIR esté listo antes de aceptar conexiones (hasta ~3 minutos de reintentos).
## Verificar el despliegue
```bash
# Estado de los contenedores (hapi-db debe aparecer "healthy")
# Estado de los contenedores
docker compose ps
# CapabilityStatement FHIR a través de nginx
curl http://localhost/fhir/metadata
# Bus Gateway a través de nginx
curl http://localhost/bus-gateway/health
# Health check del Bus Gateway a través de nginx
curl http://localhost/fhir/Patient?_summary=count
# Logs de un servicio específico
docker compose logs -f bus-gateway
```
## Detener los servicios
@ -101,6 +133,124 @@ curl http://localhost/bus-gateway/health
# Solo detener
docker compose down
# Detener y eliminar volúmenes (borra datos de la BD)
# Detener y eliminar volúmenes (borra todos los datos)
docker compose down -v
```
## Variables de entorno
Todas las variables se definen en el archivo `.env` de la raíz del proyecto.
### Bus de salud (requeridas)
| Variable | Requerida | Descripción |
|---|---|---|
| `BUS_URL` | Sí | URL base del Bus de salud nacional |
| `BUS_JWT_SECRET` | Sí | Secreto compartido para firmar JWT (HS256) |
| `BUS_ISSUER` | Sí | Identificador del emisor JWT (ej.: URL del repositorio) |
| `MPI_SCOPE` | Sí | Scopes OAuth para el MPI (ej.: `Patient/*.read,Patient/*.write`) |
| `DOCUMENT_REGISTRY_SCOPE` | Sí | Scopes OAuth para el Document Registry |
### Bus de salud (opcionales)
| Variable | Default | Descripción |
|---|---|---|
| `MPI_URL` | `BUS_URL` | URL del Master Patient Index (si difiere del Bus principal) |
| `DOCUMENT_REGISTRY_URL` | `BUS_URL` | URL del Document Registry (si difiere del Bus principal) |
| `BUS_DEBUG` | `false` | Habilita logs detallados de requests/responses al Bus |
### Nodo
| Variable | Default | Descripción |
|---|---|---|
| `NODO_BASE_URL` | `http://localhost` | URL pública del nodo (usada por GDHCN para construir URLs) |
| `NODO_URL_BASE` | `http://localhost` | URL base del nodo (usada por bus-gateway) |
| `TZ` | `America/Argentina/Buenos_Aires` | Zona horaria para todos los servicios |
### FHIR local (gestionada internamente)
| Variable | Valor fijo | Descripción |
|---|---|---|
| `FHIR_URL` | `http://hapi-fhir:8080/fhir` | URL del servidor FHIR interno (fijada en docker-compose) |
### Nginx
| Variable | Default | Descripción |
|---|---|---|
| `NGINX_CONF` | `http` | Modo de operación: `http` o `https` |
| `SSL_CERT_PATH` | `./certs/server.crt` | Ruta al certificado TLS del servidor |
| `SSL_KEY_PATH` | `./certs/server.key` | Ruta a la clave privada TLS del servidor |
### Certificados / Secrets
| Variable | Default | Descripción |
|---|---|---|
| `SIGNATURE_CERT_PATH` | `./certs/trust-network.pem` | Certificado de la red de confianza (TNG/GDHCN) |
| `SIGNATURE_KEY_PATH` | `./certs/trust-network.key` | Clave privada de la red de confianza |
| `SSL_DCC_KEY_PATH` | `./certs/signature.key` | Clave privada para firma de documentos (DSC) |
### Verifiable Health Links (VHL)
| Variable | Default | Descripción |
|---|---|---|
| `VHL_PRIVATE_KEY_FILE` | *(efímera)* | Ruta a clave EC P-256 en PEM para firmar CWTs. Si se omite, se genera una clave en memoria que se pierde al reiniciar |
| `VHL_ISSUER` | `BUS_ISSUER` | URI del emisor VHL (iss del CWT) |
| `VHL_BASE_URL` | — | URL pública del gateway para construir URLs de manifiesto y documento. Requerida para usar endpoints VHL |
| `VHL_TOKEN_TTL` | `604800` | TTL del token VHL en segundos (default: 7 días) |
### HAPI FHIR / PostgreSQL
| Variable | Default | Descripción |
|---|---|---|
| `SPRING_CONFIG_LOCATION` | `file:///data/hapi/application.yaml` | Ruta al archivo de configuración de HAPI |
| `SPRING_DATASOURCE_URL` | `jdbc:postgresql://hapi-db:5433/root` | URL JDBC de la BD (debe usar puerto `5433`) |
| `SPRING_DATASOURCE_USERNAME` | `root` | Usuario de la base de datos |
| `SPRING_DATASOURCE_PASSWORD` | `hapifhir2023` | Contraseña de la base de datos |
| `SPRING_DATASOURCE_DRIVERCLASSNAME` | `org.postgresql.Driver` | Driver JDBC |
| `SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT` | `ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect` | Dialecto Hibernate |
| `POSTGRES_DB` | `root` | Nombre de la base de datos PostgreSQL |
| `POSTGRES_USER` | `root` | Usuario PostgreSQL |
| `POSTGRES_PASSWORD` | `hapifhir2023` | Contraseña PostgreSQL |
## Estructura del proyecto
```
ips-nodo-dominio/
├── docker-compose.yml # Orquestación principal (6 servicios)
├── .env.example # Plantilla de variables de entorno
├── hapi-config/
│ └── application.yaml # Configuración de HAPI FHIR (Spring Boot)
├── nginx/
│ ├── http.conf # Config nginx modo HTTP
│ └── https.conf # Config nginx modo HTTPS
├── certs/ # Certificados TLS y claves de firma
│ └── README.md # Instrucciones para generar certificados de prueba
├── bus-gateway/ # Gateway Node.js/Express
│ ├── controllers/ # Manejadores de transacciones IHE (ITI-65/67/78/104, VHL)
│ ├── routes/ # Definición de rutas Express
│ ├── services/ # Clientes de servicios externos (MPI, Document Registry, FHIR)
│ ├── utils/ # Utilidades (auth, logging, criptografía VHL)
│ ├── docs/ # Diagramas de secuencia Mermaid
│ └── tests/ # Suite de pruebas Jest
├── json/ # Fixtures y schemas JSON
└── tests/
└── fixtures/ # Fixtures para pruebas de integración
```
## Desarrollo
### Ejecutar tests del bus-gateway
```bash
cd bus-gateway
npm install
npm test
```
### Debug remoto
El `bus-gateway` arranca con `--inspect=0.0.0.0:9229`, por lo que se puede conectar un debugger Node.js al puerto `9229`.
### Diagramas de secuencia
Los flujos de cada transacción están documentados como diagramas Mermaid en [bus-gateway/docs/](bus-gateway/docs/).

View File

@ -76,7 +76,7 @@ http {
}
location /gdhcn/ {
proxy_pass http://gdhcn-validator-service:8080;
proxy_pass http://gdhcn-validator-service:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

View File

@ -92,7 +92,7 @@ http {
}
location /gdhcn/ {
proxy_pass http://gdhcn-validator-service:8080;
proxy_pass http://gdhcn-validator-service:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;