Feature Specification: Deployment of the api Service

Created: 2026-09-23

Status: Implemented

Input: Reconstructed from the code of api/ at 0bf4ecd36, api/README.md, pull requests #1184, #1249, #1901 and #1903, and the design notes of the maintainers.

User Scenarios & Testing (mandatory)

User Story 1 - Run api on a NixOS host (Priority: P1)

A provider runs api with its NixOS module. The module makes each service that api depends on a setting: the state store, the job runner, the events service, the allowed origins, the authorization callback and the service token. Optionally, the module also runs the events server and its virtual host. Secrets come from files at run time.

Why this priority: this is how a provider runs api.

Independent Test: a NixOS VM test starts the service and calls its procedures.

Acceptance Scenarios:

  1. Given the module with a database, When the host starts, Then api keeps its state in PostgreSQL.
  2. Given a service token file, When the host starts, Then api reads the token at run time, and the token is not in the Nix store.

User Story 2 - Develop api locally (Priority: P1)

A developer runs api from the development shell of api/. The shell has the tools, a local state backend, a job runner and an events server for the full setup.

Independent Test: a developer starts the local stack from the development shell.

Acceptance Scenarios:

  1. Given the development shell, When the developer starts the simple setup, Then api runs builds as local subprocesses, without a job runner.

User Story 3 - Publish the wire contract (Priority: P2)

api publishes its OpenAPI 3.1 and AsyncAPI 3.0 documents and their documentation sites, made from the models in the code.

Independent Test: validation checks of the two documents.

Acceptance Scenarios:

  1. Given a change of a model, When the documents are built, Then they show the change, and the validation passes.
  2. Given a node that runs the events server on a public name, When the node serves its AsyncAPI documentation site, Then the site names that events server. The documents that api/ builds without a deployment keep a placeholder for the name.

User Story 4 - Deploy api with a group of machines (Priority: P3)

api/ adds its component to a group of core, and gives deploy attributes that provision the machines with api. When the front-end gives an events domain, the component also runs the events server on that domain, with a generated key and a certificate from the SSL resource.

Independent Test: a VM test of a full deployment.

Edge Cases

  • A flake build of api/ cannot pin the whole repository: api then takes the default source from the self-pin.

Requirements (mandatory)

Functional Requirements

  • FR-001: The plain Nix entry point of api/ MUST be the single source of all outputs. The flake MUST only add the system layer.
  • FR-002: The NixOS module MUST make each dependency on a service of the provider (database, job runner, events, callback, service token) a setting.
  • FR-003: The module MUST read secrets from files at run time.
  • FR-004: api MUST publish OpenAPI and AsyncAPI documents that validate.
  • FR-005: The development shell MUST contain the tools to run api locally.

Key Entities

  • NixOS module: the service definition of api for a NixOS host.
  • Component: the registration of api in a group of core.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: The format check, the NixOS VM test and the validation of the two documents pass.
  • SC-002: A provider can run api with the NixOS module and its own services, without the component of the fediversity provider.

Assumptions

  • The component under api/ is the wiring for the fediversity hosting provider. It moves to the tree of the provider at the repository root, so that api/ gives only the service and its NixOS module.

Known Deviations

  • The component of api adds it to the hosting-provider group of core, with spire, NetBox IPAM, the Openprovider registrar, openbao and its own postgresql resource, and uses the deploy credentials, the operator curation and the contract modules of the provider. This is the business case of one provider inside api (principle IV). The service itself only reads a generic database URL, so it is agnostic (#1940).