183 lines
5.7 KiB
Markdown
183 lines
5.7 KiB
Markdown
# FP&A Budgeting Engine
|
|
|
|
A production-grade REST API for corporate budgeting, variance analysis, and department-level financial reporting. Built to automate the workflows FP&A teams typically run manually in Excel.
|
|
|
|
---
|
|
|
|
## The Business Problem
|
|
|
|
Every month, FP&A analysts pull actuals from ERP systems, paste them into spreadsheets, and manually calculate budget vs. actual variances by department and cost center. This is slow, error-prone, and doesn't scale.
|
|
|
|
This engine replaces that workflow with a reliable API: budget data is structured in a normalized schema, actuals are ingested on a schedule, and variance reports are available on demand — for any department, any period, any GL account.
|
|
|
|
---
|
|
|
|
## What It Does
|
|
|
|
- **Budget management** — Create and version annual budgets by department and GL account
|
|
- **Actuals ingestion** — Load actuals from CSV or JSON (ERP export format)
|
|
- **Variance analysis** — Budget vs. actual, favourable/unfavourable, percentage and absolute
|
|
- **Rollups** — P&L rollup by department, cost center, and fiscal period
|
|
- **Alerts** — Flag accounts exceeding budget by a configurable threshold
|
|
- **Audit trail** — Every budget change is timestamped and attributed
|
|
|
|
---
|
|
|
|
## Tech Stack
|
|
|
|
| Layer | Technology |
|
|
|---|---|
|
|
| API server | Go (net/http + chi router) |
|
|
| Database | PostgreSQL |
|
|
| Schema migrations | golang-migrate |
|
|
| Config | Environment variables (.env) |
|
|
| Docs | OpenAPI 3.0 (docs/openapi.yaml) |
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
fpa-budgeting-engine/
|
|
├── cmd/
|
|
│ └── server/
|
|
│ └── main.go # Entry point
|
|
├── internal/
|
|
│ ├── handler/ # HTTP handlers
|
|
│ │ ├── budget.go
|
|
│ │ ├── actuals.go
|
|
│ │ └── variance.go
|
|
│ ├── model/ # Domain types
|
|
│ │ ├── budget.go
|
|
│ │ ├── actuals.go
|
|
│ │ └── variance.go
|
|
│ ├── repository/ # DB layer
|
|
│ │ ├── budget_repo.go
|
|
│ │ └── actuals_repo.go
|
|
│ └── service/ # Business logic
|
|
│ ├── budget_service.go
|
|
│ └── variance_service.go
|
|
├── migrations/
|
|
│ ├── 001_create_departments.up.sql
|
|
│ ├── 002_create_gl_accounts.up.sql
|
|
│ ├── 003_create_budgets.up.sql
|
|
│ ├── 004_create_actuals.up.sql
|
|
│ └── 005_create_audit_log.up.sql
|
|
├── docs/
|
|
│ └── openapi.yaml
|
|
├── scripts/
|
|
│ └── seed_demo.sql # Sample data for demo/testing
|
|
├── .env.example
|
|
├── docker-compose.yml
|
|
├── Makefile
|
|
└── README.md
|
|
```
|
|
|
|
---
|
|
|
|
## Key API Endpoints
|
|
|
|
```
|
|
POST /api/v1/budgets Create a new budget entry
|
|
GET /api/v1/budgets?dept=&period= List budgets with filters
|
|
PUT /api/v1/budgets/{id} Update a budget line
|
|
POST /api/v1/actuals/ingest Ingest actuals (JSON or CSV)
|
|
GET /api/v1/variance?dept=&period= Variance report
|
|
GET /api/v1/variance/summary Full P&L summary
|
|
GET /api/v1/variance/alerts Accounts over threshold
|
|
GET /api/v1/rollup?by=department Rollup by dimension
|
|
```
|
|
|
|
---
|
|
|
|
## Finance Concepts Implemented
|
|
|
|
**Chart of Accounts** — GL accounts are typed (revenue, COGS, opex, capex) and roll up into P&L line items correctly.
|
|
|
|
**Variance conventions** — Revenue variances are favourable when actuals exceed budget. Cost variances are favourable when actuals are below budget. The engine handles both correctly.
|
|
|
|
**Fiscal periods** — Supports fiscal year offsets (e.g. FY starting April). Periods are stored as fiscal quarters and months, not calendar months.
|
|
|
|
**Budget versioning** — Original budget, Forecast 1, Forecast 2 are tracked separately, enabling Budget vs. Forecast vs. Actual three-way comparison.
|
|
|
|
---
|
|
|
|
## Getting Started
|
|
|
|
```bash
|
|
# Clone and configure
|
|
git clone https://gitea.yoursite.com/yourname/fpa-budgeting-engine
|
|
cp .env.example .env
|
|
|
|
# Start Postgres
|
|
docker-compose up -d db
|
|
|
|
# Run migrations
|
|
make migrate-up
|
|
|
|
# Seed demo data
|
|
psql $DATABASE_URL < scripts/seed_demo.sql
|
|
|
|
# Start the server
|
|
make run
|
|
# → API available at http://localhost:8080
|
|
```
|
|
|
|
---
|
|
|
|
## Example: Variance Report Response
|
|
|
|
```json
|
|
GET /api/v1/variance?dept=engineering&period=2024-Q3
|
|
|
|
{
|
|
"department": "Engineering",
|
|
"period": "2024-Q3",
|
|
"currency": "DKK",
|
|
"lines": [
|
|
{
|
|
"gl_account": "6100",
|
|
"description": "Salaries & Wages",
|
|
"budget": 4200000,
|
|
"actual": 4380000,
|
|
"variance": -180000,
|
|
"variance_pct": -4.3,
|
|
"status": "unfavourable"
|
|
},
|
|
{
|
|
"gl_account": "6300",
|
|
"description": "Software Subscriptions",
|
|
"budget": 320000,
|
|
"actual": 289000,
|
|
"variance": 31000,
|
|
"variance_pct": 9.7,
|
|
"status": "favourable"
|
|
}
|
|
],
|
|
"total_budget": 5180000,
|
|
"total_actual": 5290000,
|
|
"total_variance": -110000,
|
|
"total_variance_pct": -2.1
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Why Go for a Finance API?
|
|
|
|
Go's compile-time type safety, zero-cost abstractions, and simple concurrency model make it well-suited for financial data services:
|
|
|
|
- **No null pointer surprises** — strict typing prevents the class of bugs that corrupt financial calculations
|
|
- **Fast and predictable** — consistent sub-10ms response times under load
|
|
- **Easy to deploy** — single binary, no runtime dependencies, runs anywhere
|
|
- **Explicit error handling** — every failure path is handled, not swallowed
|
|
|
|
---
|
|
|
|
## Roadmap
|
|
|
|
- [ ] Multi-currency support with FX rate table
|
|
- [ ] Excel export of variance reports (finance teams need this)
|
|
- [ ] Webhook notifications when accounts breach threshold
|
|
- [ ] Integration adapter for SAP/NetSuite actuals export format
|
|
- [ ] Role-based access (department managers see only their cost centers) |