Ownership

An operations console for a healthcare integration engine

Built the API layer, PHI-access auditing features and most of the frontend for a console that operates an HL7 integration engine.

Role
Top contributor
Period
2025 to 2026
Status
Shipped, then feature work paused by the client
Outcome
I wrote 272 of the 389 commits, the largest share in the repository.

01 / Problem

Hospitals route clinical messages between systems with integration engines. The people who run one needed a web console to search messages, reprocess and export them, start and stop channels, and watch traffic trends. It is operations tooling, not clinical software. The engine already had its own server API and its own audit log, so the console had to sit in front of both without disturbing either, and it had to stay honest when one channel was slow. My part was the backend-for-frontend, most of the React frontend, the CI/CD pipeline and the staging deployment.

My role: Top contributor: backend-for-frontend, most of the frontend, CI/CD and staging

02 / System

React console 1 Backend for frontend 2 Global search 3 PHI audit 4 Engine API 5 React console 1 Backend for frontend 2 Global search 3 PHI audit 4 Engine API 5
A global search, from the browser to the engine.

Select a component to read what it does and how it fails.

  1. React console. Search, reprocess, export, channel control and dashboards, with focus trapping and keyboard navigation. It shows the gaps in a result instead of hiding them.
  2. Backend for frontend. Proxies the engine's API with CSRF handling, login rate limiting and input validation. When the engine is slow, this layer has to cope.
  3. Global search. Queries channels in batches of 10, with a 10-second timeout each. It fails per channel, and names the channels that timed out.
  4. PHI audit. Searches and message views on patient-ID channels post an audit event to the engine. Fails if the console's own polling adds false entries.
  5. Engine API. The engine's own server API, outside my control. Reprocess, export and channel control go through it. One channel can be slow while others are fine.

03 / Decisions

Batch the global search and name the gaps

Decision
I made global search query channels in batches of 10, gave each a 10-second timeout, and added a banner naming every channel that timed out.
Rejected
The old code fired one request per channel, all at once, with no timeout and no cap. A comment in it admitted the risk and moved on.
Why
One slow channel could stall the whole search. A result that hides its own gaps is worse than a slow one.
Cost
A search over many channels now runs in rounds, so the best case is slower than firing everything at once.

Keep the console out of the audit log

Decision
I moved the dashboard's polling to a coarser endpoint and filtered in the browser, then built the PHI-access auditing feature on top.
Rejected
Building auditing on a log that the console's own background polling was already filling with false entries.
Why
An audit log full of noise is no use to the person who has to read it.
Cost
The dashboard fetches more than it shows and does the filtering itself.

Replace the hidden time picker with a modal

Decision
I replaced the hidden native datetime input with a custom jump-to-time modal.
Rejected
Hiding the native input behind an icon, which was the original design.
Why
Firefox draws the time part inline inside the input, so hiding the input hid the time picker, in Firefox only.
Cost
A custom control that I have to keep accessible and consistent myself.

04 / What broke

Every trend count was too high

Symptom
Each message count on the dashboard trend chart was inflated.
Cause
Every data point summed connector-level rows on top of the channel-level aggregate that already included them.
Fix
I kept only the channel-level aggregate rows.

Formatting changed HL7 messages

Symptom
Viewing a pipe-delimited HL7 message with formatting on added stray brackets.
Cause
Every message went through the XML formatter, and HL7 is not XML.
Fix
I added XML detection, so anything else is shown untouched.

The staging image would not build

Symptom
Staging builds failed outright.
Cause
One copy step staged a single script, not the directory its dependencies lived in.
Fix
I copied the whole directory.

05 / Outcome

  • I shipped the feature build and set up the CI/CD pipeline and the Traefik staging deployment. The client then paused feature work, and my later commits are deployment and infrastructure migration only.
  • The console has ARIA labels, focus trapping and keyboard navigation.
  • I have no figures for users, channels or messages handled, so I make no usage claim.

06 / The rule I took from this

A partial result should look partial.

Rule 5 of 9

Stack

  • React 19
  • TypeScript
  • Vite
  • Node.js
  • Express-style BFF
  • Sequelize
  • Jest
  • Docker
  • Traefik
  • CSRF protection
  • Monorepo

Next