A REST API for corporate budget management, actuals ingestion, and variance reporting — built to replace the manual Excel workflow that smaller finance teams still run every month. Single binary, no infrastructure, deploys anywhere.
The problem it solves
At companies below a certain size — typically below 500 employees, or without the budget for enterprise planning platforms like Anaplan or Adaptive Planning — the monthly FP&A close still runs on spreadsheets. Actuals are exported from the ERP, pasted into a workbook, and variances are computed by hand across departments and GL accounts. The process is slow, error-prone, and breaks the moment someone edits the wrong cell.
Large enterprises have solved this with dedicated tooling. The gap is the mid-market: companies that have outgrown Excel but cannot justify a six-figure implementation project. This engine sits in that space — structured schema, versioned budgets, on-demand actuals ingestion, and instant variance reports with no pivot tables and no shared file conflicts.
The goal was not to build something clever.
It was to build something that solves a real problem
finance teams in the mid-market actually have.
Stack
Most finance tooling is Python notebooks or Excel macros — useful for analysis, fragile in production. Go compiles to a single binary with no runtime dependencies, makes every error path explicit, and handles concurrency safely. SQLite was chosen over Postgres deliberately: for a tool running inside a finance team's environment, zero infrastructure matters. The database is a single file. Backups are a file copy.
| Layer | Choice | Reason |
|---|---|---|
| Language | Go | Single binary, no runtime, explicit errors |
| Routing | net/http (stdlib) | No deps; method+path routing since Go 1.22 |
| Database | SQLite | Zero infrastructure, file-based, ships with binary |
| Schema | Auto-migrated | CREATE TABLE IF NOT EXISTS on startup |
API surface
Three resource groups. Budgets support full CRUD by department, GL account, fiscal period, and version. Actuals are ingested via a single upsert endpoint — idempotent by period, department, and GL code, designed to accept ERP JSON exports directly. Variance endpoints return computed reports immediately.
POST /api/v1/budgets Create a budget line
PUT /api/v1/budgets/{id} Update amount or notes
DELETE /api/v1/budgets/{id} Remove a budget line
POST /api/v1/actuals/ingest Upsert an actual (idempotent)
GET /api/v1/variance Full variance report
GET /api/v1/variance/alerts Lines exceeding threshold
GET /api/v1/health Returns 200 if DB is reachable
Variance endpoints accept year, period,
dept, version, and threshold
as query parameters.
Finance concepts implemented correctly
Favourability logic. Whether a
variance is good or bad depends on account type. Revenue accounts are
favourable when actuals exceed budget; cost accounts when actuals come in
under. The engine handles both via a favour_high flag per GL
account — a distinction generic reporting tools consistently leave to manual
configuration.
Budget versioning. Original budget and up to three forecast revisions are stored separately, enabling a full budget vs. forecast vs. actual three-way comparison without overwriting history — the standard FP&A reforecast workflow.
GL account typing. Accounts are
typed as revenue, cogs, opex,
capex, or headcount. This drives the P&L
rollup structure and the favourability logic together, reflecting how an
actual chart of accounts is structured.
Fiscal period decoupling. Periods are stored as integers 1–12, decoupled from calendar months — required for any company not on a January fiscal year.
Example output
Engineering department, FY2024 P09. Cloud infrastructure came in under budget. Consulting exceeded by 51%.
| GL | Description | Budget | Actual | Var % | Status |
|---|---|---|---|---|---|
| 6100 | Salaries & Wages | 4,200k | 4,380k | −4.29% | unfavourable |
| 6500 | Consulting & Contractors | 450k | 680k | −51.11% | unfavourable |
| 5000 | Cloud Infrastructure | 850k | 791k | +6.94% | favourable |
Running it
git clone https://git.samantha42.xyz/samantha/FPandA-Engine cd FPandA-Engine cp .env.example .env go mod tidy go run ./cmd/server # → http://localhost:8080 # → fpa.db created on first run
Two environment variables: DB_PATH (use :memory:
for tests) and PORT. Demo seed data for Engineering, Sales,
and Marketing is included in scripts/seed_demo.sql.