Contribute
Working on backd itself: workflow, repository layout, tests, architecture and the API contract.
This section is for the contributor: whoever changes backd itself. To run the repository’s development stack and the example apps, start at Local development. Using backd to build an application is Build; running it for others is Operate.
Workflow
- Work happens in small steps. Every step ends with exactly one commit with a concise message.
- Every step updates this documentation site (
docs/) in the same commit, so the docs always match the code.
Repository layout
| Path | Contents |
|---|---|
cmd/backd/ | The backd CLI: only main, which runs internal/cli. deps_test.go fails, naming the import chain, if the CLI reaches a server package or the MongoDB driver |
cmd/backd-server/ | The backd-server binary: only main, which runs internal/servercli |
internal/cli/ | The CLI’s command tree (cli.go) and grouped help, run in-process by cli.Run so tests drive it like the binary; it never links the server. The commands are in project/ (local, on CONFIG_DIR), account/ (your sign-in) and admin/ (the admin API; opener.go is the seam export, import and the field keys share with backd-server), on clicore/ (the target server, credentials, export packages) |
internal/servercli/ | backd-server’s command tree: the roles, and the tools that work on MongoDB or run Deno directly |
internal/dbnames/ | The names of backd’s own databases and collections, for the CLI |
internal/server/ | The server roles: settings and config loading, the startup checks, serve, worker, provision, the executor and egress bootstrap, and the dev-mode reloader |
internal/e2e/ | End-to-end tests: a server started in the test, on MongoDB and Deno, driven through the CLI and the clients |
internal/buildinfo/ | The version the binaries were built as |
internal/cmdtest/ | Test helpers the CLI, server and end-to-end tests share |
internal/cmdutil/ | Helpers the command trees share: flag definitions and reads, the command wrapper, exit codes, terminal input and JSON output |
internal/settings/ | Runtime settings from environment variables; limits/ reads the instance limits backd config check also applies |
internal/registry/ | Loads and validates the CONFIG_DIR tree into the registry |
internal/jsonnum/ | JSON number normalization (int64 / float64) |
internal/httpapi/ | HTTP layer: router, middleware, error envelope, document, /_auth and /_admin handlers, CORS |
internal/auth/ | Users, sessions, API keys, invitations, roles, password hashing and login throttling (storage-neutral); authtest/ has an in-memory store for tests |
internal/authcore/ | The parts of authentication that need no store, shared with the CLI: API key scopes, the secrets cipher, field key encoding, the portable form of authentication data |
internal/apiheaders/ | Names of the HTTP headers both the server and the CLI read |
internal/rules/ | Checks, compiles and evaluates the rules: of collection.yaml; turns read rules into storage filters |
internal/templates/ | Starter files for backd template |
internal/query/ | Parses and checks where / order_by / count against the schema |
internal/storage/ | Backend-neutral repository interface and query conditions |
internal/mongodb/ | MongoDB specifics: connection, $jsonSchema validator translation, provisioner (including realm system databases), repository, auth store |
internal/appconfig/ | A realm’s app configuration: values over declared defaults, with history and rollback |
internal/changefeed/ | A database’s change history, driver-neutral: the base of triggers and realtime |
internal/triggers/ | The dispatcher that runs a collection’s triggers: one lease per deployment, a durable position |
internal/realtime/ | Realtime subscriptions as server-sent events: limits, buffers, resume tokens |
internal/functions/ | backd-server functions build: bundles each function with Deno and records the manifest startup checks |
internal/executor/ | The supervisor behind backd-server executor: one Deno process per call, with its permissions and limits |
internal/egress/ | backd-server egress: the only way a function reaches the network |
internal/cron/ | Five-field cron expressions and their schedule, in UTC or a time zone |
internal/email/ | Email kinds, templates (from _realm/email) and rendering |
internal/push/, internal/pushsend/ | Push messages and templates; the FCM, APNs and Web Push senders |
internal/oauth/ | Google, Microsoft and Apple sign-in: authorize URLs, code exchange, ID token checks |
internal/fieldcrypt/ | Field encryption: encrypting before the database, decrypting for readers |
internal/imaging/ | Image versions: resizing safely, in pure Go, with the pixel count checked first |
internal/exportpkg/, internal/exportreadme/ | The format of an export package, and the README of a personal data export |
internal/typegen/, internal/openapigen/ | backd types (TypeScript and Dart) and backd openapi for a realm |
internal/rulestest/ | The fixtures of backd rules test |
internal/metrics/ | Prometheus instrumentation |
api/openapi.yaml | The HTTP API contract (OpenAPI 3.1) and its lint settings |
clients/js/ | The JavaScript client (backd-js) |
clients/dart/, clients/dart-examples/ | The Dart client (package:backd) and the Flutter Shelf demo |
clients/functions-testing/ | The fake ctx for testing functions, vendored into the template project |
design/ | The design of each feature (design/<feature>.md): the reasoning behind the behavior the docs describe |
ui/admin/ | The admin UI: TypeScript, Vue 3, Vite, Vue Router, Pinia and Tailwind. npm run build writes into internal/adminui/dist, which internal/adminui embeds (a Go build without it still works) |
docs/ | This documentation site (Hugo + hugodoks) |
examples/config/ | Sample CONFIG_DIR used by docker-compose.yml and by make dev-examples. workshop/ is the functions cookbook: its code is what the Functions pages quote (through the example-file shortcode, which reads it from examples/config/workshop), and it is tested for real (Deno unit tests with make functions-testing-test, and TestWorkshopExample, which runs every function on MongoDB with a real executor and worker) |
docker-compose.yml | The stack for working on backd (make example), on https://localhost:8443: images built from your checkout, nginx in front of backd + MongoDB, the docs site and the example app |
docker-compose.dev.yml | The stack for working with backd (make dev), on the same address: released images, your own ./config, the API and the worker apart, Prometheus and Grafana; see the two stacks |
docker/ | Images and config for the local stacks: the docs server (Hugo), nginx (default.conf.template for make example, dev.conf.template and the dev/ landing page for make dev), Prometheus, and the certificate templates (docker/cfd/) |
docker/certs/ | Generated, gitignored: the local CA and nginx’s certificate |
scripts/example.sh | Runs the local stack for make example |
scripts/dev.sh, scripts/example-seed.sh | Run the development stack for make dev, dev-examples, dev-down, dev-reset, dev-logs and dev-backd; seed the example realms (shared with scripts/example.sh) |
scripts/check-dashboards.py | Checks the Grafana dashboards: valid, only documented metrics, a panel for every alert (and, with --prometheus, every query) |
scripts/example-ci.sh | Starts its own local stack and runs every attack script against it, as CI does |
scripts/local-certs.sh | Creates or renews the local CA and certificate with certsfor |
deploy/production/ | The production reference deployment and its end-to-end test |
Dockerfile | Multi-stage build into a distroless image |
docker-compose.test.yml | Dockerized test environment (project backd-test) |
.github/workflows/ci.yml | CI: vet, OpenAPI lint, dockerized tests, release configuration check, the production reference test, the tutorial replayed against a stack built from the checkout (make shelf-tour-ci), docs build |
.github/workflows/js.yml | The JavaScript client: type-check, unit tests on Node 22 and 26, the package check and integration tests against backd and MongoDB in Docker (docker-compose.js.yml) |
.github/workflows/ui.yml | The admin UI: type-check, lint, unit tests, build, npm audit of what ships in the bundle, and its Playwright tests against the example stack |
.github/workflows/pages.yml | On version tags, builds this documentation site, checks its links and callouts, and publishes it to GitHub Pages (see Releasing) |
.github/workflows/publish-js.yml | On js-v* tags, publishes the JavaScript client to npm (see Releasing the JavaScript client) |
.github/workflows/release.yml, .goreleaser.yaml | Releases on version tags: binaries, GitHub release, container image (see Releasing) |
.github/dependabot.yml | Weekly dependency updates (see Supply chain) |
docker-compose.js.yml | Stack for the JavaScript client’s integration tests (project backd-js-test) |
The two local stacks
make example | make dev / make dev-examples | |
|---|---|---|
| For | Working on backd: you change the Go code, the admin UI, the docs or the client | Building with backd: you write realms, rules and functions |
| Images | Built from your checkout every time it needs to | Released ghcr.io/fernandezvara/backd-executor (BACKD_VERSION, latest by default); BACKD_VERSION=local builds them from your checkout with make dev-build |
| Config | examples/config | ./config (CONFIG_DIR), or the examples with make dev-examples; mounted read-write, followed live |
| Worker | Folded into the API (serve --with-worker) | Its own service (WORKERS=3 make dev) that follows the config like the API |
| Docs | Served from docs/ with live reload | The online site |
| Observability | Prometheus and Grafana | Prometheus and Grafana |
| Address | https://localhost:8443 | https://localhost:8443: the same, so run one at a time; both use the CA in docker/certs/ |
The development stack runs the API, the worker, the executor and egress from the executor image, which is the backd binary plus the pinned Deno: dev mode needs Deno to bundle functions when they change, and the deployment image (backd, distroless) has none. That image carries the admin UI for this reason. The stack is not the production image: functions still run in the executor in both, so the difference is the bundling only. The full walkthrough — commands, addresses, the HTTPS CA, the example realms — is in Local development.
Testing
All automated tests run in a dockerized environment, both locally and in CI:
make test # docker compose -f docker-compose.test.yml run --rm tests
make test-local # plain `go test ./...` for tests without external services
make lint-api # lint api/openapi.yaml (needs Node)
make js-test # JavaScript client: type-check and unit tests (needs Node)
make js-package # the JavaScript client packed and installed like an npm user gets it (Node and TypeScript)
make js-integration # JavaScript client against backd + MongoDB in Docker
make ui # build the admin UI into internal/adminui/dist, where the Go build embeds it (needs Node)
make ui-test # admin UI: type-check, lint (v-html is an error), Vitest
make ui-e2e # admin UI: Playwright against a stack of its own (CSP violations and requests to other origins fail it; axe checks the views)
make example # the stack for working on backd, on https://localhost:8443: built from your checkout, with the docs (live reload) and example apps behind nginx
make dev-build && make dev # the stack for working with backd: released images and your ./config (see the next section)
make hack-expenses # attack the expenses example on the running local stack
make hack-expenses-functions # attack the expenses-with-functions example on the running local stack
make workshop-tour # walk the workshop tour without a browser on the running local stack, checking each step
make example-attacks # start a stack of its own and run every attack script against it (CI does this); stop `make example` first
Two differential tests guard against data leaks and failed writes, and run against the real MongoDB in make test and CI:
internal/mongodb/rules_diff_test.gochecks that read rules pushed down to MongoDB never leak or hide documents. For each read rule, it compares the documents the rule allows when evaluated in memory with what lists return and what single reads (GET /{id}, and the lookups ofPUT,PATCHandDELETE) return. It does this for every caller: anonymous, users with and without roles, owners and members.- It runs on hundreds of generated documents, some ownerless, some with missing or null fields.
- The rules exercise
&&,||and!short-circuiting,nilguards,inon arrays,hasRole, andnowagainst_metatimestamps. - It runs the same comparison for the read rule of every sample collection’s
rules:in the repository (examples/config, the template sample and the JavaScript client’s test configs), on documents generated from its schema. - It pins how missing and null fields behave where the rule language can’t decide (
nil > 3). - A self-test breaks the filters on purpose (a lost negation,
&&and||swapped,!=as==, and so on) and fails unless the comparison notices each break.
internal/mongodb/validator_diff_test.gochecks that every document the API’s JSON Schema validation accepts is also accepted by the MongoDB validator. It covers tricky number spellings and_metawith and without ownership fields. It runs on a synthetic schema and on every sampleschema.json, with documents generated from each schema, valid and invalid, including extra properties foradditionalProperties: false.
New sample collections under those directories are picked up automatically.
make test builds the test container from docker/test/Dockerfile (Go plus the Deno version functions are bundled with, so the function build tests run), and starts a single-node MongoDB replica set (mongo:8.2) next to it, plus a standalone MongoDB used only to check that backd refuses one. Integration tests read MONGO_TEST_URI (and MONGO_STANDALONE_TEST_URI) and are skipped when it isn’t set. Each test uses its own uniquely named realm and drops its databases afterwards.
To run the integration tests outside the compose setup:
docker run -d --name backd-test-mongo -p 27018:27017 docker.io/library/mongo:8.2 --replSet rs0
docker exec backd-test-mongo mongosh --quiet --eval \
"rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'localhost:27018'}]})"
MONGO_TEST_URI='mongodb://localhost:27018/?replicaSet=rs0' go test ./...
Performance tests
Changes to the change feed, the trigger dispatcher or the realtime hub can make them slower or hungrier without breaking a test. Their scenarios are tests that print results, run at a reduced scale in CI (where they check correctness under load: nothing lost, nothing doubled, every drop accounted for) and at full scale on demand:
export MONGO_TEST_URI='mongodb://localhost:27018/?replicaSet=rs0' # see Testing above
make perf # both suites at scale 10, 30 s soaks, results in perf-results/*.txt (a few minutes)
or one at a time, with -v to see the RESULT scenario=… key=value lines:
| Suite | Command | Measures |
|---|---|---|
| Trigger dispatcher (needs MongoDB) | go test ./internal/triggers -run TestLoad -v | an import of many documents, a hot collection with several triggers and a costly when, a chained storm and the depth cap, the backlog ceiling, a lease failover under traffic, an outage followed by rescan, a soak |
| Realtime hub (scripted history, no database) | go test ./internal/realtime -run TestLoad -v | fan-out with and without grouping keys (checks per change), large documents, a mass stall against the memory budget, an organization-wide access change, idle replicas and several instances, a soak with stream churn |
| Pre-change images and the change stream (needs MongoDB) | BACKD_MEASURE=1 go test ./internal/mongodb -run MeasurementGate -v | write cost with and without pre-images, storage per update, stream throughput and several consumers |
| Aggregations and search (needs MongoDB) | BACKD_LOAD_TEST=1 go test ./internal/mongodb -run TestAggregateAndSearchLoad -v | aggregate and search times on 300,000 documents |
The knobs: BACKD_LOAD_SCALE multiplies documents, streams and events (1 is the CI size, 10 is what the documented numbers used), BACKD_SOAK is the seconds of a soak, BACKD_LOAD_REPORT=<file> appends the result lines to a file. Add -race to look for concurrency bugs, not for numbers.
The baseline is in the operations guide (the dispatcher and the hub), measured on a development machine, so compare ratios and orders of magnitude, not absolute numbers: run make perf on the commit before your change and on yours, on the same idle machine, twice each (the first run warms caches), and look at:
- Dispatcher: jobs per second of the import and the hot collection, the time to drain after a failover, the heap of the soak (it must stay flat), and that
queued + gapsstill equals the number of changes in the backlog scenario. - Hub: checks per change with and without keys (the gap between them is the point of the index), microseconds per change, peak buffered memory against the budget, and the heap after the soak.
- A regression is a drop of a third or more in a throughput, a heap that grows with the length of a soak, or a correctness line that fails; the latter fail the test, not just the report.
When a change moves the baseline on purpose, update the tables in the operations guide with the new numbers in the same commit.
Translating the admin UI
Every string of the admin UI is in ui/admin/src/i18n/en.json; es.json is its Spanish translation, with the same keys and the same {placeholders}. A new string goes into en.json first and into every other file in the same change: a Vitest check (npm test in ui/admin, make ui-test) fails when a key is missing from one file, when a message uses different placeholders than its English original, or when a translation was left identical to English without being listed as a name or technical word. To add a language, add its file, its code and its own name to ui/admin/src/i18n/locale.ts and i18n/index.ts, and translate the keys; the language switch and the browser detection pick it up from there.
Continuous integration
GitHub Actions runs on every push and pull request:
go vet, a check of the compose files, the OpenAPI lint, the dockerized test suite, and a check of the release configuration;- supply chain:
govulncheck, and a Trivy scan of the image; - the JavaScript client (
.github/workflows/js.yml): type-check, unit tests and integration tests againstbackdand MongoDB; - the admin UI (
.github/workflows/ui.yml): type-check, lint, unit tests, build andnpm auditof what ships in the bundle, and its Playwright tests against the example stack (the Go jobs build the UI first, so the binary embeds it); - the production reference test (
deploy/production/test.sh); - a build of this documentation site.
Releasing
Releases are published by .github/workflows/release.yml when a version tag is pushed:
- Make sure
mainis what you want to release: the release notes are generated by GitHub from the commits since the previous tag, so commit subjects should say what changed, and a breaking change should say so in the subject or body. - Bump the version where it is pinned:
grep -rn "0.X.0" .finds the template files (internal/templates/files/project),api/openapi.yaml,SECURITY.md, the examples in the docs (deploying.md,cron.md,getting-started.md), the landing page (docs/data/landing.yaml) and the tutorial’sdocs/static/tutorial/compose.yaml; add an Upgrading to section todocs/content/docs/operate/_index.md, the “current version” line ofdocs/content/docs/_index.md, and an entry toCHANGELOG.md. Bumpclients/js/package.json(and its lock file),versioninclients/dart/pubspec.yamland__version__inclients/python/src/backd/__init__.pyto the same version, and turn “Unreleased” into the version inCHANGELOG.md,clients/dart/CHANGELOG.mdandclients/python/CHANGELOG.md: the server and the clients are released together, on the same version. - Once the release preparation is merged, tag the same commit once for each thing released, each tag starting its own workflow:
git tag vX.Y.Z(the server and its images, below),git tag js-vX.Y.Z(the JavaScript client),git tag dart-vX.Y.Z(the Dart client) andgit tag py-vX.Y.Z(the Python client), then push them in two steps,git push origin vX.Y.Zandgit push origin js-vX.Y.Z dart-vX.Y.Z py-vX.Y.Z: GitHub starts no workflow for the tags of a push that carries more than three.make release-tag VERSION=vX.Y.Zdoes all of it: it fails withoutVERSION, offmain, with local changes, whenmainis behindorigin, or when any of the four tags exists, and pushes the server tag, then the three client tags together. Edit the notes on the GitHub release afterwards if they need context.
The workflow then:
- builds the binaries with GoReleaser (
.goreleaser.yaml):backd(the CLI) for Linux, macOS and Windows andbackd-serverfor Linux, on amd64 and arm64, as archives withLICENSEandREADME.md, pluschecksums.txt; - adds an SPDX SBOM for each archive, made with Syft;
- embeds the admin UI in the binaries (it is built first) and attaches the same build as
admin-ui_vX.Y.Z.tar.gzto the release; - creates the GitHub release with those files and generated notes;
- builds the image and scans it with Trivy, and stops if it finds a critical or high vulnerability that has a fix;
- builds and pushes the multi-arch container image
ghcr.io/fernandezvara/backd:vX.Y.Zwith Docker Buildx, pluslatestfor versions without a pre-release suffix (a tag such asv1.0.0-rc.1is a pre-release and doesn’t movelatest), with SBOM and provenance attestations; - signs the image with cosign, keyless: the signature is tied to this repository’s release workflow through GitHub’s OIDC identity.
A second workflow, pages.yml, runs on the same tag and publishes this documentation site to GitHub Pages, so the site always shows the latest tagged version. It needs Settings → Pages → Source: GitHub Actions set once in the repository. To publish a documentation fix between releases, run it by hand: Actions → pages → Run workflow, on main.
The version reaches both binaries through -X github.com/fernandezvara/backd/internal/buildinfo.Version, in GoReleaser and both Dockerfiles (--build-arg VERSION); local builds report dev.
make release-check validates the configuration and builds every archive into dist/ without publishing. CI runs goreleaser check on every push.
Releasing the JavaScript client
The client is published to npm as backd-js by .github/workflows/publish-js.yml, on its own js-v tags, with the same version as the server’s:
- Set
versioninclients/js/package.jsonto the server’s version (done with the server’s release preparation; semver, and while it is 0.x a breaking change bumps the minor) and merge it tomain. - Tag and push:
git tag js-vX.Y.Z && git push origin js-vX.Y.Z. The tag must match the version and point at a commit onmain; a version with a suffix,js-v0.3.0-rc.1, is published under thenextdist-tag and doesn’t movelatest.
The workflow type-checks, runs the unit tests, then runs scripts/check-js-package.sh: it packs the library, checks what the tarball holds (the library, its declarations, README.md and LICENSE; no tests or examples), installs the tarball into a fresh project and uses it from Node and from strict TypeScript. CI runs the same check on every push (make js-package). Then it publishes with a provenance attestation, so each version on npm links to the commit and workflow that built it.
One-time setup, on npmjs.com. Publishing uses trusted publishing: the workflow proves who it is to npm with GitHub’s OIDC identity, so no npm token is stored in the repository. In the package’s Settings → Trusted Publisher, choose GitHub Actions and enter the owner fernandezvara, the repository backd and the workflow filename publish-js.yml. For the package, set Publishing access to require two-factor authentication and disallow tokens.
Mistakes. A published version can’t be changed or reused. Fix it with a new version, and mark the bad one with npm deprecate backd-js@X.Y.Z "reason, use X.Y.Z+1". npm allows unpublishing only in narrow cases (within 72 hours, or for packages almost nobody uses), and a version number is never reusable, so deprecating is the way to correct a release.
Releasing the Dart client
The client is published to pub.dev as backd by .github/workflows/publish-dart.yml, on its own dart-v tags, with the same version as the server’s:
- Set
versioninclients/dart/pubspec.yamlto the server’s version (done with the server’s release preparation) and merge it tomain. - Tag and push:
git tag dart-vX.Y.Z && git push origin dart-vX.Y.Z. The tag must match the version and point at a commit onmain; a version with a suffix,dart-v0.9.3-rc.1, is a pre-release on pub.dev anddart pub add backdkeeps getting the latest stable one.
The workflow analyzes and tests the package, checks what the archive holds with scripts/check-dart-package.sh (CI runs the same check on every push), and publishes with pub.dev’s OIDC trusted publishing: no token is stored in the repository. One-time setup, on pub.dev: in the package’s Admin → Automated publishing, enable GitHub Actions with the repository fernandezvara/backd, the workflow filename publish-dart.yml and the tag pattern dart-v{{version}}.
A published version can’t be changed or reused: fix a mistake with a new version, and retract the bad one on pub.dev.
Releasing the Python client
The client is published to PyPI as backd by .github/workflows/publish-python.yml, on its own py-v tags. Versions were 0.0.x while the client was being built; from its first release they follow the server’s:
- Set
__version__inclients/python/src/backd/__init__.pyto the server’s version (done with the server’s release preparation) and merge it tomain. - Tag and push:
git tag py-vX.Y.Z && git push origin py-vX.Y.Z. The tag must match the version and point at a commit onmain; a version with a suffix,py-v0.10.0-rc.1(PyPI writes it0.10.0rc1), is a pre-release thatpip install backdskips unless asked.
The workflow checks the generated sync code is current, runs ruff, mypy --strict and the unit tests, then scripts/check-python-package.sh (make python-package): it builds the sdist and the wheel, validates their metadata with twine check, checks what the wheel holds (the library, its generated sync half, the py.typed marker and the licence; no tests or examples), installs the wheel into a fresh virtualenv and uses both clients from a script. The same build runs, without publishing, on every pull request that touches clients/python and on every push (python.yml). Publishing uses PyPI’s trusted publishing: no token is stored in the repository.
One-time setup, on pypi.org. The project does not exist yet, so add a pending publisher (Your account → Publishing): the project name backd, the owner fernandezvara, the repository backd, the workflow filename publish-python.yml and the environment pypi (create the environment in the repository’s Settings → Environments, and require a reviewer if you want a pause before each release). The first release then creates the project.
A published version can’t be changed or reused. Fix a mistake with a new version and yank the bad one on PyPI (it stays installable by exact version but is skipped by pip install backd).
Supply chain
- Vulnerabilities in the code: CI runs
govulncheckon every push. It fails only on vulnerabilities in codebackdactually calls; those in unused parts of dependencies are reported, not fatal. - Vulnerabilities in the image: CI builds the image and scans it with Trivy on every push, failing on critical or high findings that have a fix. Releases scan again before publishing.
- Updates: Dependabot (
.github/dependabot.yml) opens grouped weekly pull requests for Go modules (the server and the docs theme), the JavaScript client’s dev dependencies, GitHub Actions, and the Dockerfiles’ base images. CI checks each one. - Releases publish SBOMs and a signed image (see Releasing).
Building the docs
The documentation site is built with Hugo and the hugodoks theme, built on Pico CSS.
Requirements
- The theme is imported as a Hugo module, so
docs/has its owngo.mod. Building needs Hugo ≥ 0.154, plus Go and git. docs/is a separate Go module, so it’s excluded from the rootgo test ./....
Where things live
| Path | Contents |
|---|---|
docs/hugo.toml | Site and theme configuration |
docs/content/docs/ | Documentation pages |
docs/data/landing.yaml | Landing page sections |
docs/layouts/shortcodes/ | The live-example shortcode (shown only in the local stack) |
Front matter
Each page needs title, description (shown in navigation and section lists), icon (a Phosphor icon name, kebab-case, such as gear-six or lock; unknown names render blank), weight and toc: true. The theme’s documentation covers the shortcodes and site params the pages here use.
Commands
make docs-serve # live preview at http://localhost:1313/backd/
make docs # build into docs/public/
Packages, the query pipeline, storage mapping and conditional writes.
API contractapi/openapi.yaml, the contract tests that keep the server true to it, and the lint.
Local developmentThe repository’s development stack: make dev, live config reload, HTTPS with a local CA, the example realms, and building backd from source.