verifhir-gateway

module
v0.0.0-...-b25d0a0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 4, 2026 License: Apache-2.0

README

VeriFHIR Gateway

CI CI codecov
Package Go Version Go Reference
Meta PRs Welcome Domain Status

HL7v2 to FHIR gateway with quality scoring, pipeline-based routing, and a management UI.

Why This Project

Healthcare integrations often stop at message translation, but production systems also need measurable output quality and fine-grained control over which messages reach which systems. VeriFHIR Gateway combines:

  • Multi-source HL7v2 ingestion via MLLP TCP listeners or HTTP POST
  • HL7v2 parsing and FHIR mapping
  • Quality scoring — each message receives a confidence score
  • Pipeline-based routing — filter by source, event type, and quality score before delivery
  • Web UI — manage sources, channels, and pipelines without restarting the gateway
  • Audit trail — every routing decision is recorded

This gives teams a practical path to migrate legacy clinical interfaces while keeping full visibility into transformation quality.

Current Status

The gateway is fully operational with a complete processing pipeline:

  1. Receive raw HL7v2 via MLLP listener or HTTP ingest endpoint
  2. Parse segments and normalise fields
  3. Map to FHIR resource model
  4. Score message quality (completeness + conformity)
  5. Route to destination channels through configurable pipelines
  6. Record every decision in the audit log

Quick Start

Prerequisites: Docker Desktop or Docker Engine with Compose v2.

# 1. Clone the repository
git clone https://github.com/vagnercazarotto/verifhir-gateway.git
cd verifhir-gateway

# 2. Build images and start all services
docker compose up --build -d

Open in your browser: http://localhost:3000

Port Service
3000 Web UI (React)
8080 REST API
2575 MLLP listener (default source)

Stop and remove:

docker compose down

Option 2 — Run without Docker

Prerequisites: Go 1.22+, Node 22+.

git clone https://github.com/vagnercazarotto/verifhir-gateway.git
cd verifhir-gateway

# Terminal 1 — Go Gateway (starts on :8080, MLLP on :2575)
mkdir -p .local
go run ./cmd/gateway

# Terminal 2 — Web UI dev server (hot-reload, proxies /api to :8080)
cd web && npm install && npm run dev

Web UI available at http://localhost:5173.

Configuration

Environment variables:

Variable Default Description
GATEWAY_HTTP_PORT 8080 REST API and UI proxy port
DATABASE_URL (SQLite) PostgreSQL connection string, e.g. postgres://user:pass@host/db. Omit to use the embedded SQLite file at .local/gateway.db.
MLLP_ADDR 0.0.0.0:2575 Default MLLP listener address
AUDIT_DIR .local/audit Directory for audit log files

See configs/config.example.yaml for a full annotated example.

Sending HL7v2 Messages

Via MLLP (TCP)

Any HL7v2 sender that supports MLLP framing can connect to port 2575.

To test with the included dataset generator:

# Generate 20 synthetic ADT messages
go run ./cmd/datasetgen -count 20 -out .local/datasets/demo

# Send them to the MLLP listener
go run ./cmd/mllpsend -dir .local/datasets/demo -addr localhost:2575
Via HTTP (no MLLP client required)
curl -s -X POST http://localhost:8080/api/v1/ingest \
  -H "Content-Type: text/plain" \
  --data-raw "MSH|^~\&|SENDER|FAC|RECV|DEST|20260502120000||ADT^A01|MSG001|P|2.5
EVN|A01|20260502120000
PID|1||MRN001^^^FAC^MR||Doe^John||19800101|M"

Response:

{"id": "3a7f2c1b9e4d0f8a", "status": "accepted"}

Managing Sources, Channels, and Pipelines

Web UI

Open http://localhost:3000 and use the sidebar to navigate to:

  • Sources — register MLLP listener addresses and assign each a unique ID
  • Channels — configure delivery destinations (FHIR servers, MLLP passthrough)
  • Pipelines — wire a source to one or more channels with optional filters
REST API

All resources follow the same pattern: GET, POST, GET /{id}, PUT /{id}, DELETE /{id}.

Create a source:

curl -s -X POST http://localhost:8080/api/v1/sources \
  -H "Content-Type: application/json" \
  -d '{
    "id": "ward-adt",
    "name": "Ward ADT Listener",
    "type": "mllp",
    "addr": "0.0.0.0:2575",
    "enabled": true
  }'

Create a delivery channel:

curl -s -X POST http://localhost:8080/api/v1/channels \
  -H "Content-Type: application/json" \
  -d '{
    "id": "fhir-server-1",
    "name": "HAPI FHIR Server",
    "output_type": "fhir",
    "url": "http://hapi-fhir:8080/fhir",
    "min_quality_score": 0.6,
    "enabled": true
  }'

Create a pipeline:

curl -s -X POST http://localhost:8080/api/v1/pipelines \
  -H "Content-Type: application/json" \
  -d '{
    "id": "adt-to-fhir",
    "name": "ADT to FHIR",
    "source_id": "ward-adt",
    "filters": {
      "event_types": ["ADT^A01", "ADT^A03", "ADT^A08"],
      "min_score": 0.6
    },
    "destination_ids": ["fhir-server-1"],
    "enabled": true
  }'
Pipeline routing

Once at least one pipeline is registered the router switches to pipeline mode. Each incoming message is tested against every enabled pipeline in order:

Filter Empty / zero value Non-empty value
source_id Matches any source Matches only that source ID
filters.event_types Matches all event types Must match one of the listed types
filters.min_score No minimum Score must be ≥ this value

Messages that do not match any pipeline are not delivered (recorded as no_channels in the audit log).
To return to the default fan-out behaviour (every message to every enabled channel), delete all pipelines.

Synthetic Dataset Generator

This project includes a local-only HL7v2 dataset generator so you can develop and validate without committing synthetic data to GitHub.

# Generate with defaults (100 messages, small-hospital profile)
go run ./cmd/datasetgen

# Generate with custom parameters
go run ./cmd/datasetgen \
  -count 500 \
  -error-rate 0.25 \
  -profile large-network \
  -types A01,A03,A08 \
  -out .local/datasets/custom

Output written to .local/ (git-ignored):

File Description
*.hl7 One HL7v2 message per file
manifest.csv File-level metadata (profile, severity)
summary.json Run summary with seed, profile, and counts

Available profiles: small-hospital, large-network, emergency-dept.

See docs/DATASET-GENERATOR.md for all options and error injection details.

Project Structure

cmd/
  gateway/        Application entrypoint
  datasetgen/     Synthetic HL7v2 dataset generator CLI
internal/
  api/rest/       HTTP REST API server (sources, channels, pipelines, ingest, audit)
  channel/        Source, Channel, and Pipeline registries (thread-safe in-memory)
  config/         Runtime configuration loading
  connector/      Delivery adapters (FHIR HTTP, MLLP passthrough)
  hl7v2/          Low-level HL7v2 parser and serializer
  ingest/         MLLP ingest adapter
  mapping/        HL7v2 → FHIR mapping rules
  model/          Shared domain types (HL7Message, RoutedPayload)
  parser/         HL7v2 parsing logic used by the ingest layer
  quality/        Quality scoring engine
  router/         Pipeline-based and legacy fan-out routing
web/              React + TypeScript + Tailwind management UI
configs/          Sample configuration files
docs/             Architecture, scope, standards, and demo guides
scripts/          Local development helper scripts

For standards, terminologies, and regulations see docs/STANDARDS.md.
For architecture diagrams see docs/ARCHITECTURE.md.

Processing Pipeline

Ingest (MLLP / HTTP)
       │
       ▼
  HL7v2 Parser
       │
       ▼
  FHIR Mapper
       │
       ▼
 Quality Scorer  ──── score attached to payload
       │
       ▼
    Router
  ┌────┴────────────────────────────────────┐
  │  Pipeline mode (when pipelines exist):  │
  │    filter by source_id                  │
  │    filter by event_type                 │
  │    filter by min_score                  │
  │    deliver to destination_ids           │
  │                                         │
  │  Legacy mode (no pipelines):            │
  │    fan-out to all enabled channels      │
  └─────────────────────────────────────────┘
       │
       ▼
Delivery Channels (FHIR HTTP / MLLP passthrough)
       │
       ▼
  Audit Log

Contributing

Contributions are welcome. Open an issue describing:

  1. the use case or bug
  2. expected behaviour
  3. proposed approach

Before opening a pull request, make sure all checks pass locally:

# Go — format, vet, test
gofmt -l ./...           # should produce no output
go vet ./...
go test ./... -count=1

# Frontend — lint and build
cd web && npm run build

See CONTRIBUTING.md for the full contribution guide.

Quality Gates (CI)

Checks run on every push and pull request to main:

  • gofmt verification
  • go vet
  • go test ./... with -race and coverage profile
  • go build ./...
  • Coverage upload to Codecov

CI workflow: .github/workflows/ci.yml

PowerShell alternative:

.\scripts\quality-check.ps1

Recommended branch protection for main:

  1. Require pull request before merge
  2. Require status checks to pass
  3. Select required check: CI / quality
  4. Require branch to be up to date before merge

VS Code Tasks

This repository includes preconfigured VS Code tasks in .vscode/tasks.json.

Open the command palette and run Tasks: Run Task, then choose:

  • Quality Check (Git Bash)
  • Go Test ./...
  • Run Gateway (Git Bash)
  • Generate Dataset (Git Bash)

License

Apache 2.0

Directories

Path Synopsis
cmd
batchval command
batchval processes a directory of HL7v2 files through the full gateway pipeline (parse → map → score) and prints a JSON report to stdout.
batchval processes a directory of HL7v2 files through the full gateway pipeline (parse → map → score) and prints a JSON report to stdout.
datasetgen command
gateway command
internal
api/rest
Package rest exposes a JSON REST API over the message store.
Package rest exposes a JSON REST API over the message store.
audit
Package audit emits one structured JSON line per pipeline stage.
Package audit emits one structured JSON line per pipeline stage.
channel
Package channel defines the Channel type and an in-memory Registry that stores the set of active delivery channels.
Package channel defines the Channel type and an in-memory Registry that stores the set of active delivery channels.
connector/destination/dlq
Package dlq implements a dead-letter queue that persists failed delivery payloads to the local filesystem as JSON files.
Package dlq implements a dead-letter queue that persists failed delivery payloads to the local filesystem as JSON files.
connector/destination/http
Package http provides an HTTP destination adapter that delivers a FHIR Bundle to a remote server using a standard HTTP POST request.
Package http provides an HTTP destination adapter that delivers a FHIR Bundle to a remote server using a standard HTTP POST request.
connector/destination/mllp
Package mllp provides an MLLP destination adapter that delivers the original raw HL7v2 message to a remote system over a TCP connection using MLLP framing.
Package mllp provides an MLLP destination adapter that delivers the original raw HL7v2 message to a remote system over a TCP connection using MLLP framing.
connector/destination/retry
Package retry wraps any Sender with exponential-backoff retry logic.
Package retry wraps any Sender with exponential-backoff retry logic.
hl7v2
Package hl7v2 parses HL7 v2.x messages into a typed structure with field-level access via HL7-style dotted paths (e.g.
Package hl7v2 parses HL7 v2.x messages into a typed structure with field-level access via HL7-style dotted paths (e.g.
ingest/mllp
Package mllp implements the Minimal Lower Layer Protocol (MLLP) transport for HL7v2 messages over TCP.
Package mllp implements the Minimal Lower Layer Protocol (MLLP) transport for HL7v2 messages over TCP.
mapping/adt
Package adt implements HL7v2 ADT event mapping to FHIR R4 resources.
Package adt implements HL7v2 ADT event mapping to FHIR R4 resources.
mapping/mdm
Package mdm implements HL7v2 MDM^T02 (Medical Document Management) mapping to the FHIR R4 DocumentReference resource.
Package mdm implements HL7v2 MDM^T02 (Medical Document Management) mapping to the FHIR R4 DocumentReference resource.
mapping/orm
Package orm implements HL7v2 ORM^O01 (order message) mapping to the FHIR R4 ServiceRequest resource.
Package orm implements HL7v2 ORM^O01 (order message) mapping to the FHIR R4 ServiceRequest resource.
mapping/oru
Package oru implements HL7v2 ORU^R01 (observation result) mapping to the FHIR R4 DiagnosticReport + Observation resources.
Package oru implements HL7v2 ORU^R01 (observation result) mapping to the FHIR R4 DiagnosticReport + Observation resources.
mapping/siu
Package siu implements HL7v2 SIU (Scheduling Information Unsolicited) message mapping to the FHIR R4 Appointment resource.
Package siu implements HL7v2 SIU (Scheduling Information Unsolicited) message mapping to the FHIR R4 Appointment resource.
router
Package router dispatches a routed payload to the appropriate delivery channels.
Package router dispatches a routed payload to the appropriate delivery channels.
store
Package store defines the shared types and interface used by all storage backends (SQLite, PostgreSQL, …).
Package store defines the shared types and interface used by all storage backends (SQLite, PostgreSQL, …).
store/postgres
Package postgres persists processed HL7/FHIR payloads and their delivery outcomes in a PostgreSQL database.
Package postgres persists processed HL7/FHIR payloads and their delivery outcomes in a PostgreSQL database.
store/sqlite
Package sqlite persists processed HL7/FHIR payloads and their delivery outcomes in a local SQLite database.
Package sqlite persists processed HL7/FHIR payloads and their delivery outcomes in a local SQLite database.
scripts
mllp_send command
mllp_send sends HL7v2 files from a directory to a gateway via MLLP TCP.
mllp_send sends HL7v2 files from a directory to a gateway via MLLP TCP.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL