Building from source
SpeculaPro ships as one file: the speculapro binary. The web app, the database migrations and the API documentation are all compiled into it, so a server needs nothing else from the repository to run it.
How to build
Section titled “How to build”From the repository root:
make buildThis does two things:
- Builds the web app (
make web): runsnpm ciandnpm run buildinfrontend/, writing the compiled app tobackend/internal/web/dist/. - Builds the Go binary with the web app embedded, writing it to
bin/speculapro.
Check the result:
./bin/speculapro versionv0.1.0-3-g1a2b3c4 1a2b3c4The first value is the version, the second the commit it was built from.
make help lists every target in the Makefile, grouped: local services, database and topics, running, building, checks, and one target for each command-line tool (make sp ARGS="…" runs any speculapro command from the repository root).
Version stamping
Section titled “Version stamping”The version and commit are taken from git at build time:
| Value | Taken from | When git is unavailable |
|---|---|---|
| Version | git describe --tags --always |
dev |
| Commit | git rev-parse --short HEAD |
none |
Override them when building in CI:
make build VERSION=1.2.0 COMMIT=$(git rev-parse --short HEAD)Static binary
Section titled “Static binary”The binary is built with CGO_ENABLED=0, so it has no dependency on system libraries. The same file runs on any Linux distribution of the matching CPU architecture, including minimal container images such as distroless or scratch.
To build for another platform, set Go’s standard variables:
cd backendGOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags "-s -w" -o ../bin/speculapro-linux-arm64 ./cmd/speculaproRemember to run make web first so the web app is included.
How to build the container image
Section titled “How to build the container image”The repository has a Dockerfile that builds the same binary inside containers, so the build machine
needs only Docker (or another OCI image builder), not Go or Node.js. From the repository root:
docker build \ --build-arg VERSION=$(git describe --tags --always) \ --build-arg COMMIT=$(git rev-parse --short HEAD) \ -t speculapro .What the image contains, how to run commands in it and the full list of commands are on The image and its commands.
Checks on every change
Section titled “Checks on every change”Every change to the code is checked automatically before it is merged. You can run the same checks
yourself with make check:
| Check | What it catches |
|---|---|
gofmt |
Go code not in the standard format |
sqlc diff, sqlc vet |
Database access code out of date with its SQL, or SQL that breaks lint rules. In CI, every query is also prepared against a freshly migrated database, so a query that doesn’t match the schema fails |
go vet |
Suspicious Go code |
| Tests with the race detector | Behaviour, including the schema tests (tenant isolation, four-eyes rules, the append-only timeline) against PostgreSQL 18 |
govulncheck |
Known vulnerabilities in Go dependencies that the code actually reaches |
| Frontend type check, tests and build | Errors in the web app |
| Container image build | A Dockerfile that no longer builds |
Helm chart validation (make helm-check, which runs deploy/helm/validate.sh; make check doesn’t include it) |
A chart that doesn’t lint or render, produces invalid Kubernetes objects, or stops refusing unsafe settings |
The tools these checks use are pinned to exact versions (govulncheck v1.8.0), and the automation
that runs them is pinned to exact commits, so a compromised upstream release can’t change what
runs. Dependabot proposes updates to the Go modules, the web app’s packages, the base images, the
images in the production Compose file and that automation, each reviewed like any other change.