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 the hosting-provider group, with its PKI, SPIRE, OIDC and domain names;
  • the parts of the NixOS module that the component needs (core/apex.nix, the order after openbao-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.nix is the single source of truth for all outputs. panel/flake.nix is 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: . The treefmt check 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 api that the panel needs lands in api first, 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