Approvals · specification through rollout · 2025–2026
One hard-coded approver did not survive the second customer
The obvious fix was a branch per customer, which compounds forever. Instead the business configures its own ladders, spending authority and price guards, and a new customer costs no code at all.
How it was reported
“Approvals are wrong for this customer.”
What it actually was
The first customer had one approver, hard-coded. The second had a hierarchy, and the request arrived as a bug about their approvals being wrong.
Branching per customer works today and compounds forever: every fleet adds a branch, none can safely be removed, and nobody can answer "what are this customer's rules" without reading code.
The rule underneath was not about approvals at all. A customer's hierarchy, spending authority and chart of accounts are their operating procedure — they change without asking us, so they belong in configuration, not in a release.
Getting that right meant sitting with operations, purchasing and finance staff to find the real rule before specifying anything.
What shipped
- An approval engine the business configures itself: sequential and parallel ladders, per-approver spending authority, mandatory price checks, guards above a budget owner's limit, and super-approver override.
- Bypass states rendered honestly. When a ladder is short-circuited the screen says so, because a trail that hides its own exceptions is worse than no trail.
- Specification and decision records first, then implementation across shared contracts, the API, the dashboard and the app — one change landing coherently across four surfaces instead of four drifting.
Evidence
- customer organisations on their own hierarchies
- 3
- open design questions resolved
- 50+
- to rebuild it
- < 3 weeks
- escalations handled directly
- 100+
Named decision owner on the decision records. Every customer since has configured their own hierarchy without a code change.
- NestJS
- Next.js
- React Native
- MySQL
- TypeScript
- shared contracts