Skip to content

TAPPaaS configuration schemas

This directory holds the JSON-Schema (draft 2020-12) field definitions for every typed configuration object in TAPPaaS. Each type has:

  • a schema here in schemas/ (the field definitions + validation rules),
  • a live location under ~/config/ on the tappaas-cicd mothership (the deployed instances), and
  • an owning manager that performs all create/read/update/delete through verbs.

Admins drive verbs, not JSON (ADR-007). You never hand-edit these files — the owning manager writes validated config and a reconcile pushes it to the live system. Hand-editing remains possible but is only valid when followed by the manager's reconcile. Every write is schema- + reference-validated first.

configuration.json (the old monolith) is retired — it was split into site.json + per-environment files + per-module config (this is why there is no configuration.md anymore).

The configuration objects

Object Schema (schemas/) Live location (~/config/) Owning manager — CRUD verbs
Site (singleton) site-fields.json site.json site-managersite show/modify; node list/add/delete; repository list/add/delete/reconcile; validate; reconcile [--deep]
Environment environment-fields.json environments/<env>.json environment-manageradd/modify/delete/list/show/validate; reconcile [--deep] (env + its zone via network; --deep → consuming modules). --dns-mode per-service\|wildcard
Organization organization-fields.json people/organizations/<name>.json people-managerorg add/modify/delete/list/show
Group group-fields.json people/groups/<name>.json people-managergroup add/modify/delete/list/show
Role role-fields.json people/roles/<name>.json people-managerrole add/modify/delete/list/show
User user-fields.json people/users/<name>.json people-manageruser add/modify/delete/list/show. People-wide: reconcile (push → Authentik; alias sync), validate
Module (deployed) module-fields.json <module>.json module-managermodule add/modify/delete/list/show/validate/reconcile/test/snapshot-vm. add=deploy, modify=redeploy, reconcile=re-apply current config (leaf)
Module catalog module-catalog-fields.json src/module-catalog.json (in each repo) site-managerrepository add/delete/list/reconcile (registers/clones the repo that ships the catalog)
Zones zones-fields.json zones.json network-manageradd/delete/list/show/exists (the zone keyword is an optional legacy prefix); validate (alias zones-check); init/merge/distribute (aliases zones-init/zones-merge/zones-distribute); reconcile [--apply] [--only <plane>]. (No free-form modify — state + access-to are governed by the lifecycle + init/merge.)

Service field manifests (service-fields.json)

service-fields.json is the odd one out: it does not describe a ~/config/ object at all. It is the schema for services/<service>/fields.json — the per-provider manifest ADR-020 introduces, which lives in a module's SOURCE tree next to the scripts that perform the change.

The two module schemas answer different questions and neither duplicates the other:

Question Answered by
What fields exist, what do they mean, what is the default, and which service uses each one (usedBy)? module-fields.json
For that (field, service) pair — what does changing it cost after install, and how is the change applied? services/<service>/fields.json

The change class is keyed by the pair, not the field, which is why the manifest sits with the service rather than in the field schema. module-manager validate lints it: a service that ships a fields.json must classify every field module-fields.json says it owns, using the classes the schema defines. A service with no fields.json has not been migrated to the contract yet and is skipped.

The operator-facing surface it unlocks is documented in the module-manager README: modify <module> --set field=value, which refuses an immutable or recreate field before it writes anything and rejects a mixed --set whole; and the two — only two — ways to authorize a change that needs downtime, modify --force (an operator, now) and the per-module rebootOk (a standing permission honoured only in the scheduled sweep). update-tappaas --force is neither: it means "run the sweep now" and is never forwarded as permission to reboot.

Objects without a schema in this directory

Object Live location Owner / how it's written
Switch / AP topology switch-configuration-{actual,desired}.json schema is network/switch-configuration-schema.json; switch-controller / ap-controller (add-controller/add-switch/add-port/interrogate/reconcile), driven by network-manager reconcile --only switch\|ap.
TLS cert refids cert-refids.json runtime state (no schema) — written by acme-setup.sh, keyed by environment name. An environment's domains.dnsMode (environment-manager --dns-mode) selects whether a wildcard cert refid is stored here.
Backup policy not a file — the .backup block on site.json / environments/<env>.json / <module>.json (cascade: module > env > site) backup-managermodify <module> writes the module .backup layer; site/env layers via site/environment modify. list/show/validate/reconcile (resolve cascade → PBS via backup-controller); restore.

Conventions

  • validate — every config manager exposes a validate verb (the schema + reference-integrity gate). Writes are validated before they land.
  • reconcile — pushes config → live. Shallow by default; --deep cascades into dependents (site → people + network + environments → modules); --apply commits (default is preview). Reconcile is idempotent.
  • Managers vs controllersmanagers own configuration (these objects) and the verb front door; controllers (opnsense / proxmox / switch / ap / backup / identity) execute against live infrastructure and are driven by their manager.

See docs/design/ADR-007-verb-alignment.md for the full verb/CRUD model and the reconcile cascade.

Attribution: contributor, author, maintainer

Three roles, one home each — nothing duplicated (see ADR-015 — Community Governance and Contribution Files for the repo/org-level contribution model):

Role Definition Recorded in
Contributor Anyone with an accepted change (the broadest set) git history — never listed in files
Author The copyright-bearing subset optional per-module AUTHORS.md — additive lines of <year> @<handle> — <role> (template: src/apps/00-Template/AUTHORS.md)
Maintainer The current responsible party (moves on handover) maintainer in <module>.json — the one machine-readable governance field, kept there so issues can be reported/routed automatically

Authorship does not go into <module>.json — it is not needed to run the module. AUTHORS.md is optional. Per-file headers (.nix # Author: lines) are not authoritative and may be dropped when touched; the module-level AUTHORS.md covers every artifact in the module (DRY).

AI assistance: an AI tool is at most a contributor — AI-generated output carries no copyright, so an AI is never an author (it never appears in AUTHORS.md) and never holds maintainer. Per ADR-015 and Codeberg etiquette, a contribution is attributed to the human contributor: do not add an AI Co-Authored-By: trailer to commits or pull requests.