Agregar proxy de transformaciones IPS hacia el nodo nacional (bundle-signer)

Nuevas rutas GET /fhir/Bundle/:id/$ddcc, $dvc, $icvp2 y $meow: obtienen el
Bundle del HAPI FHIR local y delegan la transformación al nodo nacional
(bundle-signer), que es quien tiene las claves de firma, devolviendo la
respuesta tal cual. Se agrega BUNDLE_SIGNER_URL como variable de entorno
requerida para configurar la URL del nodo nacional.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gomez Auad 2026-07-13 03:16:43 +00:00
parent 2919873247
commit 1fbc308d66
8 changed files with 109 additions and 0 deletions

View File

@ -52,6 +52,13 @@ DOCUMENT_REGISTRY_URL=https://bus-test.msal.gob.ar/fhir/DocumentReference
# Habilita logs detallados de requests/responses salientes al Bus (true | false)
BUS_DEBUG=false
# =============================================================================
# NODO NACIONAL
# =============================================================================
# URL del nodo nacional (bundle-signer): ejecuta las transformaciones IPS ($ddcc, $dvc, $icvp2, $meow)
BUNDLE_SIGNER_URL=https://conectaton.msal.gob.ar/nodo/fhir
# =============================================================================
# NGINX
# =============================================================================

View File

@ -16,6 +16,9 @@ DOCUMENT_REGISTRY_SCOPE=DocumentReference/*.read,DocumentReference/*.write
# HAPI FHIR Server
FHIR_URL=http://hapi-fhir-host:8080/fhir
# Nodo nacional (bundle-signer): ejecuta las transformaciones IPS ($ddcc, $dvc, $icvp2, $meow)
BUNDLE_SIGNER_URL=https://conectaton.msal.gob.ar/nodo/fhir
LOG_LEVEL=debug
# Habilita logs de requests/responses salientes al Bus (true | false)

View File

@ -20,6 +20,10 @@ El componente actúa exclusivamente como gateway: no contiene lógica de negocio
| ITI-78 | `GET` | `/fhir/Patient/:id` | Patient Demographics Query: obtención de un paciente por ID en el MPI. |
| ITI-104 | `POST` | `/fhir/Patient` | Patient Identity Feed: alta de paciente en el MPI. |
| ITI-104 | `PUT` | `/fhir/Patient/:id` | Patient Identity Feed: actualización de paciente en el MPI. |
| — | `GET` | `/fhir/Bundle/:id/$ddcc` | Obtiene el Bundle IPS del HAPI FHIR local y delega la transformación DDCC al nodo nacional (bundle-signer). |
| — | `GET` | `/fhir/Bundle/:id/$dvc` | Obtiene el Bundle IPS del HAPI FHIR local y delega la transformación DVC al nodo nacional (bundle-signer). |
| — | `GET` | `/fhir/Bundle/:id/$icvp2` | Obtiene el Bundle IPS del HAPI FHIR local y delega la transformación ICVP (HCERT) al nodo nacional (bundle-signer). |
| — | `GET` | `/fhir/Bundle/:id/$meow` | Obtiene el Bundle del HAPI FHIR local y delega la transformación MeOW (HCERT) al nodo nacional (bundle-signer). |
## Variables de entorno
@ -39,6 +43,7 @@ cp .env.example .env
| `MPI_URL` | No | URL base del servicio MPI (Master Patient Index). Si no se define, usa `BUS_URL`. |
| `DOCUMENT_REGISTRY_URL` | No | URL base del Document Registry. Si no se define, usa `BUS_URL`. |
| `FHIR_URL` | Sí | URL base del servidor HAPI FHIR local. |
| `BUNDLE_SIGNER_URL` | Sí | URL base del nodo nacional (bundle-signer) donde se ejecutan las transformaciones IPS (`$ddcc`, `$dvc`, `$icvp2`, `$meow`). |
| `PORT` | No | Puerto en que escucha el servidor. Por defecto `3000`. |
### Usar la misma URL para todos los servicios del Bus

View File

@ -8,6 +8,7 @@ var iti65Router = require('./routes/iti65');
var iti67Router = require('./routes/iti67');
var iti78Router = require('./routes/iti78');
var iti104Router = require('./routes/iti104');
var bundleSignerRouter = require('./routes/bundleSigner');
var app = express();
@ -27,6 +28,9 @@ app.use('/fhir', iti78Router);
// ITI-104: Patient Identity Feed → POST /fhir/Patient, PUT /fhir/Patient/:id
app.use('/fhir', iti104Router);
// Transformaciones IPS (nodo nacional) → GET /fhir/Bundle/:id/$ddcc, $dvc, $icvp2, $meow
app.use('/fhir', bundleSignerRouter);
// 404
app.use(function (req, res, next) {
const host = req.get('host') || 'localhost';

View File

@ -13,6 +13,9 @@ const config = {
fhir: {
url: process.env.FHIR_URL,
},
bundleSigner: {
url: process.env.BUNDLE_SIGNER_URL,
},
logging: {
enabled: true,
level: 'debug',
@ -35,6 +38,7 @@ const required = [
['MPI_SCOPE', config.bus.mpiScope],
['DOCUMENT_REGISTRY_SCOPE', config.bus.documentRegistryScope],
['FHIR_URL', config.fhir.url],
['BUNDLE_SIGNER_URL', config.bundleSigner.url],
];
const missing = required.filter(([, val]) => !val).map(([key]) => key);

View File

@ -0,0 +1,71 @@
const axios = require('axios');
const config = require('../config');
/**
* Fetches the Bundle from the local HAPI FHIR server and delegates the
* transformation to the national node (bundle-signer), which holds the
* signing keys. Returns the national node's response as-is.
*/
async function transformBundle(id, operation, query) {
const bundleUrl = `${config.fhir.url}/Bundle/${id}`;
const { data: bundle } = await axios.get(bundleUrl);
const response = await axios.post(
`${config.bundleSigner.url}/Bundle/$${operation}`,
bundle,
{ params: query },
);
return response;
}
/**
* GET /fhir/Bundle/:id/$ddcc
*/
async function getDDCC(req, res, next) {
try {
const response = await transformBundle(req.params.id, 'ddcc', req.query);
res.status(response.status).json(response.data);
} catch (err) {
next(err);
}
}
/**
* GET /fhir/Bundle/:id/$dvc
*/
async function getDVC(req, res, next) {
try {
const response = await transformBundle(req.params.id, 'dvc', req.query);
res.status(response.status).json(response.data);
} catch (err) {
next(err);
}
}
/**
* GET /fhir/Bundle/:id/$icvp2
*/
async function getICVP2(req, res, next) {
try {
const response = await transformBundle(req.params.id, 'icvp2', req.query);
res.status(response.status).json(response.data);
} catch (err) {
next(err);
}
}
/**
* GET /fhir/Bundle/:id/$meow
*/
async function getMeow(req, res, next) {
try {
const response = await transformBundle(req.params.id, 'meow', req.query);
res.status(response.status).json(response.data);
} catch (err) {
next(err);
}
}
module.exports = {
getDDCC, getDVC, getICVP2, getMeow,
};

View File

@ -0,0 +1,14 @@
const express = require('express');
const router = express.Router();
const {
getDDCC, getDVC, getICVP2, getMeow,
} = require('../controllers/bundleSigner');
// Transformaciones IPS delegadas al nodo nacional (bundle-signer):
// obtienen el Bundle del HAPI FHIR local y postean al nodo nacional.
router.get('/Bundle/:id/([\$])ddcc', getDDCC);
router.get('/Bundle/:id/([\$])dvc', getDVC);
router.get('/Bundle/:id/([\$])icvp2', getICVP2);
router.get('/Bundle/:id/([\$])meow', getMeow);
module.exports = router;

View File

@ -56,6 +56,7 @@ services:
MPI_SCOPE: ${MPI_SCOPE}
DOCUMENT_REGISTRY_SCOPE: ${DOCUMENT_REGISTRY_SCOPE}
FHIR_URL: http://hapi-fhir:8080/fhir
BUNDLE_SIGNER_URL: ${BUNDLE_SIGNER_URL}
BUS_DEBUG: ${BUS_DEBUG}
ports:
- 9229:9229