fediversity panel Constitution
Core Principles
I. Opaque Configuration
The panel MUST treat the configuration of a deployment as an opaque value. It
gets the JSON Schema of the configuration from api, renders the form with
nix-module-form, stores the value that the form gives, and passes the value
to api without change. The panel MUST NOT read, write or depend on option
names or on the structure of the configuration (for example where the
applications are, which option enables an application, or the shape of a
deployment method). A fact that the panel shows about a configuration (for
example the domain, the instances, or which parts changed) MUST come from
api as a typed field, or from the schema through nix-module-form.
panel/forms-island-adapter/ is the panel side of nix-module-form. It
connects the widget to the page, to api and to the stored value, and has
the same limits.
Rationale: core owns the configuration model and changes it. A front-end
that reads option names breaks at each change, and a second front-end must
not have to copy that knowledge.
II. Only the Public Contract of api
The panel MUST talk to api only through the public contract of api: the
HTTP interface that OpenAPI 3.1 describes, the events that AsyncAPI 3.0
describes, and api/specification.md. The panel MAY use a client that is
generated from the published OpenAPI document. The panel MUST NOT import the
code of api, read or write the state of api (its database or its state
directories), share a state directory or a secret file with api, or copy
the internal logic of api. When the panel needs a fact that the contract
does not give, api adds it to the contract first.
Rationale: api serves any API client. The panel is one client, and a
second front-end must be able to do what the panel does with the same
contract.
III. No Knowledge of core
The panel MUST NOT know the internals of core: its files, its option names,
its resources, its deployment programs or its application catalog. The
Python, TypeScript, templates and static files of the panel MUST NOT refer to
core. The Nix code of the panel (packaging, the NixOS module and the
checks) MAY use only the public surface of core, as the constitution of
core defines it, and only where the panel cannot get the fact through
api.
The panel is the top layer. Its Nix code MAY use the public outputs of core
and api (their NixOS modules, library functions and testers), and MAY give
the deploy outputs of the hosting provider (apps, nixosConfigurations),
so that core and api need no knowledge of the panel.
Rationale: api wraps core for its clients. A second path from the panel
to core makes two contracts that can disagree.
IV. The Front-End Owns Identity and Tenancy
The panel owns the business logic of the front-end: the authentication of
end users, the accounts, the sessions, the ownership of deployments
(multi-tenancy), and the authorization decision for each call to api. The
panel is the one identity authority. It MUST answer the authorization
callback of api for each call, and MUST allow a call only for a subject
that owns the scope of the call. It MUST NOT depend on api to know users.
The panel chooses the form of the deployment identifier that it gives to
api (str(pk) of the deployment), and MUST NOT expect api to parse it.
Rationale: api is agnostic to front-end business logic, so this logic must
have exactly one place. Different front-ends can have different rules for
tenancy.
V. Intent Here, Runtime Facts in api
The panel stores the intent of an operator: the draft configuration, the
human name, the owner and an optional module source pin. api owns the
runtime facts: the submitted and deployed configurations, the builds, the
state of a deployment and its instances. The panel MUST NOT keep a second
copy of a runtime fact. It reads each runtime fact from api when it shows
it, and shows a clear "unknown" or "unreachable" state when api does not
answer. An operation that changes both stores (the delete of a deployment)
MUST end in a state that the operator can see and repeat.
Rationale: two copies of one fact disagree after a failure. Orphaned live infrastructure without a record in the panel is a leak that nobody sees.
VI. Agnostic to the Hosting-Provider Business Case
The panel is a generic front-end. It MUST NOT contain the business case of
one hosting provider: its group of machines, its identity, secrets, PKI or
IPAM systems, its domain names or its brand. The identity provider, the
address of api, the event service and the secrets MUST be generic
configuration. The wiring of the panel into the deployment of a provider is
configuration of that provider.
The Fediversity hosting providers MAY also use the panel as a demo front-end. These parts MAY know that provider, and a different provider replaces them:
nix/component/, the component of thehosting-providergroup, with its PKI, SPIRE, OIDC and domain names;- the parts of the NixOS module that the component needs (
core/apex.nix, the order afteropenbao-agent-default.service); - the brand "Fediversity Panel", the
fediversity:*DOM events, and the links to git.fediversity.eu in the documentation.
The Python, TypeScript, templates and the other options of the NixOS module MUST stay generic.
Rationale: other providers must be able to run the panel, or a white-labelled copy, with their own infrastructure.
VII. A Safe Browser Surface
The browser calls api directly with a short-lived bearer token that the
panel mints. Tokens MUST be signed, short-lived and bound to one purpose.
Text that comes from api or from a schema (errors, messages, paths, log
lines) MUST be shown as text, not as HTML. An endpoint that the session does
not protect (the authorization callback, the reconcile callback, the event
proxy callbacks) MUST check its own credential or be reachable only by the
services that call it. Production settings MUST NOT depend on development
defaults.
Rationale: the panel is the only place that holds the accounts. A flaw in its browser surface gives access to all deployments of a user.
Constraints
- All inputs are pinned with npins. The pinned nixpkgs is upstream nixpkgs, not a fork.
panel/default.nixis the single source of truth for all outputs.panel/flake.nixis a thin wrapper that adds the${system}layer and does not add, remove or change outputs.- The service is Python with Django. The form is nix-module-form, bundled with the adapter in
panel/forms-island-adapter/. - The database is SQLite, or PostgreSQL when a database URL is given.
Development Workflow
- Changes go through pull requests on git.fediversity.eu, with the title prefix
panel:. Thetreefmtcheck and the checks that CI routes for the change MUST pass. - A pull request that changes behavior updates the matching specification under
panel/specs/in the same pull request. - A change in the contract of
apithat the panel needs lands inapifirst, or in the same pull request. - Prose in comments, commit messages and pull requests uses ASD-STE100, US English and ASCII punctuation, with backticks around code.
- Documentation describes the current state of the code.
Governance
This constitution has priority over other practices in panel/. An
amendment is a pull request that changes this file, updates the version and
the Sync Impact Report, and updates any specification that the amendment
affects. Versions follow semantic versioning: MAJOR for a removed or
redefined principle, MINOR for a new principle or section, PATCH for
clarifications.
Version: 1.0.1 | Ratified: 2026-09-30 | Last Amended: 2026-10-15