Feature Specification: Configuration Form
Created: 2026-09-23
Status: Implemented
Input: Reconstructed from the code at 0bf4ecd36 (panel/forms-island-adapter/panel-adapter.ts, panel/src/panel/deployment_value.py, views.py, urls.py, templates/deployment_form.html, templates/deployment_section_form.html, static/deployment_submit.js, panel/nix/package.nix), panel/README.md (section "Section form"), panel/docs/index.md, api/specification.md (section "Schema and migration sources"), the specifications of nix-module-form (pull request nix-module-form#27), pull requests #1017, #1022, #1056, #1073, #1102, #1115, #1117, #1188, #1200, #1219, #1329, #1343, #1791 and #1795, and the design notes of the maintainers.
User Scenarios & Testing (mandatory)
User Story 1 - Edit a configuration in a form made from the schema (Priority: P1)
The panel gets the JSON Schema of the configuration from api, and shows a
form that nix-module-form makes from it. The operator edits the form. The
panel stores the value that the form gives. The panel does not know the
options.
Why this priority: the options change with each version of core. The
form must follow without a change in the panel.
Independent Test: in apps-panel, the operator edits a deployment in the
form and saves it. test_schema.py proves that the panel server does not
serve or read the schema.
Acceptance Scenarios:
- Given a deployment without a pin, When the form opens, Then the browser gets the schema from
GET /schemaofapi. - Given a deployment with a module source pin, When the form opens, Then the browser gets the schema from
POST /schema/get_forwith a bearer token, and polls whileapianswers202. - Given a deployment that has no value, When the form opens, Then the form starts from the defaults of the schema, with the seed document of the panel configuration (
NEW_DEPLOYMENT_SEED) laid over them. - Given an error of
api, When the form cannot open, Then the page shows the message ofapias text, disables Deploy and Validate, and keeps Save.
User Story 2 - See what changed since the last deploy (Priority: P1)
The form marks the fields that differ from the configuration that is deployed now. Deploy is disabled when nothing changed.
Why this priority: the operator must know what a deploy will change.
Independent Test: run panel-python-tests (test_deployment_form.py).
The baseline is the deployed configuration from api, not the submitted one.
Acceptance Scenarios:
- Given a deployed configuration, When the operator changes a field, Then the form marks the field, and Deploy is enabled.
- Given a submitted configuration that failed, When the form opens, Then the baseline is the last deployed configuration, and the operator can deploy again.
- Given a deployment that was never deployed, or that
apidoes not know, When the form opens, Then the form has no baseline.
User Story 3 - Keep old values after a schema change (Priority: P2)
When the options change, the form moves old values to their new names with the
rename table of api, and shows the schema changes against the deployed
version. Values that cannot move stay under their old names, and the page
says so.
Independent Test: in apps-panel, a value with an old name opens under
the new name.
Acceptance Scenarios:
- Given a value with a renamed option, When the form opens, Then the value shows under the new name.
- Given a value that cannot move, When the form opens, Then a banner lists the old and new names.
User Story 4 - Edit one section (Priority: P3)
From the list of instances, the operator opens the section that configures
one instance. api gives the sections of the configuration and their places
(POST /configuration/sections), and the schema and the renames of one section
(?section=<id>). The page shows the schema of that section only, and saves
the value of the section back into the whole value. The panel reads no place
of a section and moves no path through the renames itself.
Independent Test: run panel-python-tests
(test_deployment_section_form.py).
Acceptance Scenarios:
- Given a saved deployment, When the operator opens
/deployments/<pk>/section/<id>/, Then the page shows the form of that section, with the label thatapigives. - Given a configuration that has no place for the value of the section, When the operator opens the page, Then the page says to save the deployment first.
- Given a section that
apidoes not declare, When the operator opens the page, Then the page shows the400message ofapi. - Given a deployed configuration, When the operator opens the page, Then the diff compares with the value at the deployed path of the section that
apigives. - Given the address
/deployments/<pk>/<id>/, When the operator opens it, Then the panel redirects to/deployments/<pk>/section/<id>/.
Edge Cases
- The schema build of a pin takes longer than 90 seconds: the form stops and shows an error.
- Validation finds errors: Validate lists them. Save still stores the draft.
- The operator changes the branch of a union: the form keeps the values that both branches share.
Requirements (mandatory)
Functional Requirements
- FR-001: The panel MUST get the schema, the rename table and the facts about a configuration from
api. - FR-002: The panel MUST render the configuration with nix-module-form from the schema, and MUST NOT have a form that names options.
- FR-003: The panel MUST store and submit the value without change, except the renames that the rename table of
apigives. - FR-004: The diff baseline MUST be the configuration that
apireports as deployed. - FR-005: The panel MUST keep Save available when the schema or the form fails.
- FR-006: The panel MUST show messages of
apiand of the schema as text. - FR-007: The panel MUST start a value that was never saved from the root
defaultof the schema, with the seed document of its configuration (NEW_DEPLOYMENT_SEED) laid over it, and MUST NOT read the option names in the seed.
Key Entities
- Schema: the JSON Schema that
apiserves for a module source, optionally for one section. - Rename table: the renames of options that
apiserves for a module source, optionally for one section. - Section: a part of the configuration that a form edits on its own, as
apigives it: an id, a label, its path in the configuration, its path in the deployed configuration, and whether it changed. - Baseline: the deployed configuration and module source, from
api. - Adapter:
panel/forms-island-adapter/panel-adapter.ts, the panel side of nix-module-form.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: A change of the options in
coreneeds no change in the panel. - SC-002: The Python, TypeScript and templates of the panel contain no option names of the configuration.
Assumptions
apiserves the sections of a configuration, and the schema and the renames of one section, re-rooted at the options of that section.
Known Deviations
- The VM checks and the screenshot scripts hard-code option names of
core(deployment-method,applications,mastodon,pixelfed,peertube,enable,domain,subdomain):checks/apps-panel/(interact-with-panel.py,extra-test-script.py,nixosTest.nix),nix/tests.nix,nix/test-script.py,nix/seed-screenshots.pyandnix/take-screenshots.py(#2127). A change of the configuration model breaks these tests.