diff --git a/Development-Guide.md b/Development-Guide.md new file mode 100644 index 0000000..9a93c22 --- /dev/null +++ b/Development-Guide.md @@ -0,0 +1,97 @@ +# Development Guide + +--- + +## Setting Up a Dev Environment + +```bash +git clone https://git.samantha42.xyz/samantha/FPandA-Engine +cd FPandA-Engine +go mod tidy +go run ./main.go +``` + +No database setup is needed. The SQLite file is created automatically on first run. + +--- + +## Running Tests + +```bash +go test ./... +``` + +Tests use Go's built-in testing package. The test suite was migrated from Python to Go's native test runner — see commit `771eb9d`. Use `DB_PATH=:memory:` in test setup to avoid leaving `.db` files on disk. + +To run a specific package: + +```bash +go test ./Engine/internal/service/... +``` + +To run with verbose output: + +```bash +go test -v ./... +``` + +--- + +## Project Conventions + +**Layer responsibilities:** + +- `handler/` — HTTP concerns only. Decode the request body, call a service method, encode the response. No business logic here. +- `service/` — All business logic. Favourability calculation, variance rollup, budget rules. No SQL here. +- `database/` — All SQL. Repository structs implement interfaces used by the service layer. +- `model/` — Plain Go structs shared across layers. No methods with business logic. + +**Error handling:** + +Go makes every error path explicit. Handlers check service errors and return appropriate HTTP status codes. The server never panics on request errors. + +**Logging:** + +Use the `slog` logger passed into components via dependency injection (or the package-level logger if needed). Log at ERROR for unexpected failures, INFO for lifecycle events. Do not log every request unless debugging. + +--- + +## Adding a New Endpoint + +1. Add the domain type to `model/` if needed +2. Add the repository method to the relevant file in `database/` +3. Add the service method in `service/` +4. Add the handler method in `handler/` +5. Register the route in `main.go` on the `mux` + +Follow the existing patterns — each handler function decodes JSON, calls one service method, and encodes the response. + +--- + +## Adding a New Budget Version + +Budget versions are stored as a string field. Currently supported: `original`, `forecast1`, `forecast2`, `forecast3`. To add a new version (e.g. `forecast4`), update the validation in the budget service and add the new value to the Finance Concepts documentation. + +--- + +## Database Migrations + +Schema changes are applied via `database.Migrate()` on startup using `CREATE TABLE IF NOT EXISTS` and `ALTER TABLE IF NOT EXISTS` (for additive column changes). This is intentionally simple — there is no migration versioning system. + +For destructive changes (dropping columns, renaming tables), apply them manually to existing databases and update the migration function. Document any required manual steps here. + +--- + +## Building a Release Binary + +```bash +go build -o fpa-engine ./main.go +``` + +For a lean, statically linked binary suitable for containers: + +```bash +CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o fpa-engine ./main.go +``` + +Note: `modernc.org/sqlite` is a pure-Go SQLite implementation — CGO is not required, and the binary has no system library dependencies. \ No newline at end of file