Feature Specification: Package, Demo and Documentation

Created: 2026-09-22 Status: Implemented Input: Reconstructed from the code at d225ebe (default.nix, flake.nix, shell.nix, package.nix, vite.config.ts, patches/, test.nix, dom-test.nix, nix/demo.nix, nix/docs.nix, nix/screenshots.nix, nix/take-screenshots.py, demo/, docs/, .forgejo/workflows/), the pull requests of fediversity/nix-module-form about the documentation, the demo, the screenshots and the flake, the history of the extraction from the fediversity monorepo, and the Claude Code logs of the maintainers.

User Scenarios & Testing (mandatory)

User Story 1 - Build the bundle for a host page (Priority: P1)

An embedder builds the widget with Nix and serves the JavaScript and CSS files on its page. When the embedder needs glue code for its page (for example to read the value from a hidden input), it gives one TypeScript file as entry. The build puts that file next to the library source and bundles it as the entry point.

Why this priority: the widget is useful only when an embedder can build it and add its own glue without a fork.

Independent Test: build packages.default, and build the demo, which uses its own entry.

Acceptance Scenarios:

  1. Given no entry, When the package builds, Then the output contains nix-module-form.js and nix-module-form.css built from src/index.ts.
  2. Given an entry file that imports ./index, When the package builds with it, Then the bundle starts from that file and contains the library.
  3. Given the pinned npm lock file, When the package builds twice, Then the outputs are the same.

User Story 2 - Try the widget without a host (Priority: P1)

A developer runs nix run .#demo and opens the printed address. Two pages show the widget with the demo module: one with a value and a baseline, one with two versions of the module and a rename.

Why this priority: a developer must see the widget before they decide to embed it, and the maintainers need a page to test changes.

Independent Test: run nix run .#demo and open both pages.

Acceptance Scenarios:

  1. Given the demo is built, When a developer runs nix run .#demo, Then an HTTP server serves the pages, because ES modules do not load from file://.
  2. Given demo/module.nix, When the demo builds, Then its schemas come from module-schema at build time, not from a stored copy.

User Story 3 - Read the documentation (Priority: P2)

A developer reads the documentation site: an overview, the usage with the API reference and the supported schema shapes, the demo with images, and a comparison with similar tools.

Why this priority: embedders need the API and the schema contract, and they need to know when a different tool fits better.

Independent Test: build packages.docs and open the result.

Acceptance Scenarios:

  1. Given the sources under docs/, When nix build .#docs runs, Then the result is the complete site, with the images from the demo.
  2. Given a change to the demo, When the screenshots package builds, Then a headless browser captures new images in the light and the dark theme, after the page is settled and with transitions off.
  3. Given a merge to main, When the publish workflow runs, Then the site is published.

User Story 4 - Develop and test (Priority: P2)

A contributor enters the development shell, changes the source and runs the checks.

Why this priority: fast, reproducible checks keep changes safe.

Independent Test: run nix develop (or nix-shell) and nix flake check.

Acceptance Scenarios:

  1. Given the development shell, When a contributor enters it, Then the Node toolchain of the package, oxfmt, npins and spec-kit are available.
  2. Given a change, When CI runs, Then the formatter check, the unit tests, the DOM tests, the demo build, the documentation build and the image capture run as separate checks.

Edge Cases

  • A flake user and a user of import ./. { } get the same packages. The flake adds only the system layer.
  • A bug or a performance defect in an upstream package needs a fix before upstream has one: the build applies a patch to the vendored package after the npm dependencies are installed. The package and the DOM tests apply the same patches (patches/vue-vuetify-additional-properties-ajv.nix and patches/jsonforms-vue-stable-control.nix).
  • The browser for the images is heavy: only the screenshots check needs it. Other tests run in Node with a headless DOM.

Requirements (mandatory)

Functional Requirements

  • FR-001: default.nix MUST be the single entrypoint and MUST return packages, apps, devShells, formatter, checks and args, for one system. flake.nix MUST only add the system layer, and shell.nix MUST read the development shell from default.nix.
  • FR-002: All inputs MUST be pinned with npins.
  • FR-003: The package MUST build with buildNpmPackage from the npm lock file and MUST output one JavaScript file and one CSS file.
  • FR-004: The package MUST take an optional entry file for the glue code of an embedder. The public interface for this is packages.default.override { entry = ...; } of default.nix. The file package.nix is internal.
  • FR-005: The demo MUST make its schemas from demo/module.nix with module-schema at build time, and apps.demo MUST serve the pages over HTTP.
  • FR-006: The docs package MUST build the documentation site with nix-docs-lib, including the images that the screenshots package captures from the demo.
  • FR-007: checks MUST contain the formatter check, the unit tests, the DOM tests, the demo build, the documentation build and the image capture.
  • FR-008: The development shell MUST contain the Node toolchain of the package, oxfmt, npins and spec-kit.

Key Entities

  • Bundle: the JavaScript file and the CSS file that a host page loads.
  • Entry: an optional TypeScript file of an embedder that imports the library and adds glue for its page.
  • Demo: two static pages built from demo/module.nix and its own entry.
  • Documentation site: the pages under docs/, built with nix-docs-lib.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: nix flake check passes on main.
  • SC-002: The published site shows images of the current demo.
  • SC-003: An embedder adds its glue without a change to this repository.

Assumptions

  • The documentation is published to the pages of git.fediversity.eu.
  • The CI runners of fediversity run the checks. The checks do not depend on the runners.

Known Deviations

None.