Development Tooling¶
MkDocs Material + Mermaid¶
What: This documentation site, Markdown in docs/, built by MkDocs with the Material theme and Mermaid for diagrams, validated with mkdocs build --strict.
Why: We want a living, versioned set of docs; docs-as-code in the same repo gives that for free (Git history is the changelog, broken links fail the build). Mermaid keeps many context maps and sequence diagrams as reviewable text. Some component-and- connector and pattern diagrams use Drawio sources with rendered PNGs; those assets require an explicit render-and-diff check to prevent source/image drift. After editing a Drawio source, run:
make docs-diagrams
git diff -- docs/development/architecture/images
From a clean tree, make docs-diagrams-check re-renders the assets and fails if the committed PNGs do not match. The script uses drawio from PATH, the macOS application path, or DRAWIO_BIN.
AWS EC2, Caddy, and Cloudflare Pages¶
What: The application runs on one AWS EC2 instance. Terraform provisions the box, cloud-init installs Docker, Docker Compose runs the service containers, and Caddy is the only public entry point for HTTPS and the static Svelte build. The documentation is a separate MkDocs static site deployed to Cloudflare Pages by .github/workflows/deploy-docs-cloudflare.yml.
Why: The app needs containers, Postgres, Redpanda, and Keycloak, so a single EC2 box is the lowest-cost accepted shape that still runs the complete application stack. The docs do not need that runtime, so Cloudflare Pages keeps documentation hosting free and independent from the application host.
Make¶
What: A root Makefile exposing the repo's task vocabulary: make web, make docs, make up / make down (compose), make check, make journey and make contracts-gen.
Why: With two language toolchains, a docs pipeline and a compose stack in one repository, a single self-documenting entry point (make help) is worth more than remembering four tools' invocations. CI calls the same Make targets used locally, so a check should not behave differently after it is pushed.
GitHub Actions CI¶
What: Workflows under .github/workflows/, grouped here by validation, release, or deployment responsibility. The table was verified on the page's last_reviewed date; the directory is the current inventory.
| Workflow | When it runs | What it checks |
|---|---|---|
| Source CI | Pull requests and pushes to main, only when application or source-tooling files change | Linting, unit tests, type checks and both web builds |
| Docs and Contracts | Pull requests and pushes to main, only when relevant docs, contracts or deployment files change | JSON Schemas, generated contract types, strict MkDocs build, Compose validation and Kubernetes rendering |
| Secret Scan | Every pull request and push to main | Complete Git history with the license-free Gitleaks CLI |
| Docs Guard | Every pull request | A PR introducing a feature (feat: title or commit) must change documentation, docs/, a root '.md', or a service openapi.yaml; a maintainer may apply docs-exempt when documentation is unaffected (scripts/docs-guard.sh*) |
| Container Journey Test | Every Monday at 06:00 UTC or manually | Builds the full Compose stack, waits for every container to become healthy and checks the gateway |
| Dependency Vulnerability Scan | Every Monday at 06:00 UTC or manually | make vuln-check: govulncheck on every Go module and npm audit on every npm package |
| Semantic Release | Every push to main or manually | Reads conventional commits, updates CHANGELOG.md, creates a version tag and publishes a GitHub release |
| Deploy Images | Release/manual events | Builds and publishes service, simulator and frontend images |
| Deploy Docs | Documentation changes on configured branches | Builds and uploads the MkDocs site to Cloudflare Pages |
Why: Fast checks should protect normal development without rebuilding the entire platform after every documentation or frontend edit. Path filters avoid unrelated workflows, while concurrency cancellation stops an older run when a newer commit is pushed to the same branch.
The workflows reuse Go, npm, Python and installed-dependency caches. Cache keys include the relevant lockfiles, so a dependency change creates a fresh cache instead of using stale packages. The expensive container journey test intentionally runs rarely; it can still be started from the GitHub Actions Run workflow button or locally with make journey.
Semantic-release resumes from the latest reachable 'v' tag. A fix: commit produces a patch release, feat:* produces a minor release, and a breaking change produces a major release. Other commit types are inspected but do not create a release. This repository is not published to npm; the release artifact is the GitHub release, its tag and the generated changelog.
Action pinning¶
Policy: Third-party actions are referenced by a full commit SHA instead of a version tag, with the reviewed release tag kept as a trailing comment:
- uses: owner/action@<full-commit-sha> # reviewed release tag
Why: A version tag is a mutable pointer, whereas a full commit SHA fixes the code executed by the workflow. This matters especially for workflows with write permissions or access to secrets. Dependabot uses the trailing tag comment when proposing updates; each update still requires review. deploy-images.yml still uses mutable major-version tags for four actions. It is a current policy gap and must not be cited as evidence that action pinning is complete.
golangci-lint and architecture guardrails¶
What: make lint goes beyond formatting: golangci-lint (pinned in the Makefile, configured in .golangci.yml) runs staticcheck, gosec, errorlint and misspell over every Go module. Its depguard rules enforce core purity and adapter isolation for the applicable Go services; the gateway and Measurement have their documented exceptions. make check-boundaries fails if any Go service imports another service's packages, and ESLint no-restricted-imports rules enforce the same layer and service boundaries for the TypeScript services.
Why: The inward dependency rule and service-isolation policy require automated enforcement. The summarized rules live in the repository-root AGENTS.md, so coding agents read the constraints before touching the code, and CI rejects what slips through anyway.
Semantic-release¶
What: Automated versioning configured in .releaserc.json and executed by .github/workflows/release.yml.
Why: Conventional commits already describe the impact of a change, so version selection and release notes should not be repeated manually. On main, semantic-release analyzes commits since the latest remote 'v' tag, updates CHANGELOG.md, creates the next tag and publishes a GitHub release. The generated changelog commit includes [skip ci]* to avoid starting another CI cycle.
Triggering a major release¶
A major release normally communicates an incompatible change. The release policy additionally allows a maintainer-approved project-phase major release even when contracts remain compatible. That exception still uses a feat!: commit and a BREAKING CHANGE: footer that names the approved phase boundary. Do not create such a release without that decision. For an actual incompatible change, mark the commit as breaking using either conventional-commit form:
feat!: replace the public scan response
or add a breaking-change footer to a normal commit:
feat: replace the public scan response
BREAKING CHANGE: clients must now read product data from the passport field.
After that commit reaches main, semantic-release increments the major version, for example from v1.4.2 to v2.0.0. An incompatible change also requires an ADR and migration path; a phase major follows the release policy and explicit maintainer approval.
Git conventions¶
What: Conventional-commit messages (feat:, fix:, docs:, chore:) on a trunk-ish flow with short-lived branches.
Why: Commit types make the history scannable and machine-releasable, which keeps the Git log itself a reliable, living record of the project.