For the CTO and the IT reviewer
How it stays honest.
The engineering behind “the software never invents a number”. None of this belongs on a desk’s screen, and all of it gets asked in the second meeting.
01 Determinism
Same inputs, same outputs, every time.
Every financial calculation lives in a pure domain layer with no I/O and no dependency on anything above it. CI enforces that boundary, so it does not rest on convention. We version the rules, so you can recompute a figure from last quarter under the rule that applied when it was first computed. A language model never calculates money. It only reads documents a human then confirms.
A property-based and golden-master suite covers the engines, running [X] automated checks across the two products.
The strongest form of that check is external. Build the same voyage in Estimator and in the licensed Windows tool a desk uses today, and the two agree on duration, bunkers, port charges, earnings per day and profit. That comparison runs on every code change, so a regression in the arithmetic never reaches a desk.
02 The event log
A decision is never edited, only superseded by a second fact.
The store is bitemporal. It records both when something was true and when the system was told about it. That turns “replay the fleet as of any past date” into a query rather than a restore from backup, and it means nobody can rewrite an approval trail after the fact. An approval is a fact on the voyage’s log, not a row in a workflow table.
Every figure carries its lineage: the event that produced it, the document behind that event, and the version of the rule that was applied.
03 The stack
Two products, two runtimes.
ESTIMATOR
Next.js · TypeScript · Zod
A deterministic estimation engine in TypeScript with schema-validated inputs at every boundary. It runs in the browser, so there is nothing to install, per seat or otherwise. Routing and distance come from a licensed enterprise feed, proxied server-side so credentials never reach the client.
VOYAGE MANAGER
Python · FastAPI · PostgreSQL · React
A modular monolith with hexagonal layering. Postgres with row-level security and immutability triggers on the event store; every external feed sits behind an anti-corruption layer, so a supplier changing their payload cannot reach the domain.
04 What feeds in
The integration surface.
- Your existing voyage system. We read it on a schedule and map it to domain events. That is how the live deployment works, so you never face a cutover and nobody retypes a voyage.
- Routing and distance. Per-leg nautical miles, with the ECA split taken from the route’s own geometry rather than typed in by a charterer.
- AIS and vessel reference data. Positions, tracks, and observed steaming against declared consumption. Where a feed cannot tell you something, the screen marks it absent rather than inventing it.
- Bank balances. These give the cash ladder its opening position. You enter and date any cash that lives outside the source system, and you void an entry rather than delete it.
- File imports. Land the file as it arrived, say what each column means, then apply it. You can undo a whole batch.
- Outbound messages. We render and queue these in the same transaction as the fact they describe, then drain the queue separately. A mail server going down cannot roll back an approval, and no message can describe a decision that never committed.
05 Hosting and access
Where it runs, and who can see what.
- Roles are per desk. Finance screens exist only for the roles that should see them; port disbursements are hidden from desks that cannot see them. Enforced at the database with row-level security, not only in the interface.
- Four eyes on approvals. The raiser of a request cannot be the one who approves it.
- Audit trail on every change, with its actor and time, kept permanently.
- Hosting and data residency. [region and provider]. Each client gets a dedicated instance rather than shared tenancy.
- Backup and recovery. [RPO / RTO].
The fastest technical review is a real fixture.
Bring one you have already settled and check the arithmetic against your own close. Everything above is easier to judge once the numbers have held.
