Gateway architecture for EDI staff
You will rarely need to dive into the internals — the operator-facing UIs cover almost every workflow. But knowing how the pieces fit together makes "the platform did X for me" debuggable rather than mysterious.
The pieces
Components in plain English:
| Component | What it does |
|---|---|
| rcm-core / rcm-app | The billing / clinical platform. When a claim, eligibility check, or auth needs to go out, they publish an event; they do not call the gateway directly. |
| Service Bus | Azure Service Bus. Carries claim.submission_queued, eligibility.sweep_queued, auth.request_queued, and the inbound dispatch counterparts. |
| Consumers | Small services inside edi-gateway that subscribe to specific event topics. One consumer per event class. |
| edi-gateway | The HTTP service that hosts the consumers, the admin API, and the transport workers. |
| packages/x12 | Pure functions for generate / parse of every transaction set. No I/O. Easy to test in isolation. |
| Companion guide applicator | Loads guides bound to the partner + transaction; applies rules at generate-time and validates inbound shapes. |
| Control number manager | Allocates ISA13, GS06, ST02 per partner per direction. Strictly monotonic; survives restarts. |
| Transport workers | One per partner: SFTP poll loop, AS2 push/pull, real-time HTTP client. |
| Response processor | Picks up inbound files, parses, dispatches to the right rcm-core endpoint or auth/claim status updater. |
| edi-app UI | The web app you're using. Calls edi-gateway's admin API. |
A claim's outbound journey
Key facts:
- Event-driven, not request-response. rcm-core publishes; the gateway consumes. There is no synchronous call from rcm-core to the gateway.
- Fail-and-retry. A failed transport, parser, or generator step
raises a
_failedevent. The originating claim / auth stays in the pre-submit state until a retry succeeds. This means partial runs are safe — you can re-queue without producing duplicates. - Control numbers come from the gateway. rcm-core never picks an ISA13. The gateway's manager guarantees monotonic-per-partner.
An ack's inbound journey
Key facts:
- Correlation is critical. Every inbound must map back to an outbound. Failed correlation puts the inbound in quarantine for manual handling.
- Multiple acks per outbound. A single 837 produces a TA1, a 999, and a 277CA. Each runs through the same response-processor cycle independently; each updates the source claim's status with its outcome.
Where transactions are stored
Two tables matter:
| Table | Holds |
|---|---|
billing.edi_transaction | One row per transaction (inbound or outbound). Includes the raw envelope, parsed structure, status, control numbers, correlation ID. |
billing.edi_batch | One row per batch (typically one per cron tick per partner). Each batch references many transactions. |
The transaction record is immutable once written — replays produce new records. This means audit history is complete by construction.
Where companion guides are stored
| Table | Holds |
|---|---|
edi.companion_guide | One row per guide version. The active set is resolved by (partner_id, transaction_set_id, effective_from). |
edi.companion_guide_rule | Per-rule data — type, location, value, condition. |
The applicator loads the active set at generate time; rules are not compiled into the generator code.
What you cannot reach from edi-app
The operator UI gives you almost everything. Things that are deliberately hidden:
| Capability | Where it lives |
|---|---|
| Service Bus topic / subscription management | Azure portal — platform admin's job. |
| Control number reset | DB-only operation, requires platform admin. Reserved for partner-side migrations. |
| Adding a new transaction set (e.g. 820) | Code change in packages/x12; not configurable. |
Database queries on billing.edi_transaction | Tenant-isolated; reachable via the rcm-core API only. |