Workers compensation payments. Byte4Bit. Architecture, build and deploy of the ACH processor.

Audit1ACH

I designed, built and deployed the ACH payment processor that collects workers compensation premiums by generating and reconciling NACHA files.

Role
Architecture, build, deploy
Domain
ACH, NACHA
Style
Hexagonal, DDD
IaC
Terraform
GitHub profile Index

The problem

Collecting insurance premiums by ACH means producing NACHA files a bank will accept, and then living with everything that comes back days later: returns, rejects, status changes and the reconciliation nobody sees until it is wrong. A file that is malformed is not a validation error, it is money that did not move.

I owned the architecture, the implementation and the deployment of the processor. The domain layer knows nothing about HTTP, Mongo or the message bus: NACHA generation, returns handling and reconciliation are pure logic behind ports, with adapters for everything that changes.

Node.jsTypeScriptHonoMongoDBMSSQLRedisPub/SubTerraform

The file format is domain logic, not glue

NACHA generation and parsing live in the domain, testable without a database or a bank. The adapters that move the files can be swapped without touching the rules that make them valid.

Returns are part of the design, not an afterthought

Returns, transaction status and cutover each got their own service, because the interesting part of ACH is not the send, it is the days that follow it.

Deployed as code

The processor ships with its own Terraform and container build, so an environment is a reviewable artifact rather than a runbook someone remembers.

Decisions and the price I paid for them

Hexagonal architecture with the domain at the centre

The core processes payments, so the structure should say that. Dependencies point inward, and infrastructure depends on the business logic rather than the other way around.

Trade-off accepted

More indirection than a straight service layer, and a team has to understand ports and adapters before it can move quickly in the codebase.

Validate before anything reaches the bank

A rejected NACHA file costs a settlement cycle, so schema validation sits in front of every write and every generated file rather than at the edge only.

Trade-off accepted

Stricter rejection at the boundary, and more work to let a legitimate but unusual case through.

Asynchronous by message, not by polling

Ingestion, processing, returns and reconciliation are separate concerns that fail separately, so they talk over a message bus with retries instead of one long synchronous chain.

Trade-off accepted

Eventual consistency the product has to express, and idempotency that every consumer has to earn.