A multi-tenant platform for an agribusiness consultancy. It projects a farm’s revenue, costs, EBITDA, break-even, cash flow and debt, rates credit risk, and generates the reports that go to the client. Two developers worked on it; I wrote about 85% of the commits, including the whole CI pipeline.
The problem
These numbers feed credit decisions, and nothing in the system could show they were right. There were unit tests, but no test started from a farm whose answer was known in advance.
A case calculated by hand, before trusting the engine
I wrote a synthetic farm with numbers simple enough to check on paper: 1,000 ha, 60 bags/ha, R$ 120 per bag, two cost categories. Expected revenue is R$ 7.2M. The harvest year is 2099, so the fixture can never collide with real data.
Running it against the API found two things.
Two endpoints contradicted each other. Projection, income statement and cash flow reported R$ 7.2M in revenue for the organization. Production summary and financial indicators reported zero for every KPI. The second pair picked the “current harvest” from the calendar year, so any organization whose data sat outside the current season would see an empty dashboard next to full reports. I recorded it as a known divergence inside the test, so whoever fixes the behavior has to update the test on purpose.
Money was stored as floating point. I measured it instead of assuming: 142 of 192 plausible combinations differed from exact decimal arithmetic, by about 5.6 × 10⁻⁹ reais. Rounded to cents the results were correct. The real risk was exact-equality comparisons, so this went in as a planned change, not an emergency rewrite.
Tests that cannot hit the wrong database
- The e2e setup refuses to run unless
TEST_DATABASE_URLpoints to a database whose name ends in_testor_audit. - API e2e tests (Jest + Supertest) run one business scenario per suite on a disposable PostgreSQL 16 in CI: 13 suites, 130 test cases.
- Tenant isolation is tested directly: another client calling the same route gets a 403.
The pipeline as the quality gate
I wrote all 12 jobs in the GitHub Actions workflow:
- backend and frontend quality (types, unit tests, build)
- authentication e2e
- golden finance: verifies the fixtures’ checksums, then runs the financial golden and shadow contracts
- report contract: rebuilds the exported workbook and reconciles it after native recalculation
- migrations plus backup and restore
- Playwright dashboard suite (setup project, then desktop, tablet and mobile) with traces and screenshots as artifacts
- Python report service tests
- lint ratchet: legacy lint debt is allowed to shrink, never to grow
- load test: five sessions for fifteen minutes against isolated services
- one aggregate required check
The golden case closes in CI: production 60,000 bags, revenue R$ 7.2M, cost R$ 4.5M, EBITDA R$ 2.7M, break-even 37,500 bags, and a cash-to-balance-sheet delta of R$ 0.00.
Replacing the financial engine without a big bang
The new projection engine goes live in three modes behind FINANCIAL_ENGINE_MODE: legacy, shadow, canonical. In shadow mode the response still comes from the old engine, and every delta is logged as structured data, correlated by X-Request-ID, with no personal data in it.
Promotion to canonical requires checksummed fixtures, a shadow comparison on representative staging data, every delta classified as an expected fix, a tolerated difference or a regression, and explicit sign-off from finance and the product owner. The old API version can only be removed after 30 consecutive days without a single legacy call. Any call restarts the clock.
What I would do next
- Move monetary fields to
Decimal. - Turn the aggregate check into a required status check under branch protection, which is not configured yet.