Specification — runtime
Domain registration, route mounting, entity resolution and discovery.
What a domain is, and how to add one, is docs/domains.md and
the companion's playbook for adding a domain. This document says only what must hold.
Domain registration
REQ-1001 — A domain MUST be registered under its name.
Registering a second domain with a name already held MUST be rejected.
REQ-1002 — Two domains MUST NOT share a route_prefix.
Registration of the second MUST be rejected, and the error MUST name the domain already holding the prefix.
Not the same rule as REQ-1001: the names may differ while the prefixes collide, and the failure then is silent shadowing rather than a duplicate.
REQ-1003 — Every registered domain MUST expose name, domain_type, version, route_prefix and entity_id_param.
route_prefix MUST begin with / and MUST NOT end with one.
REQ-1004 — A domain declared in config/domains.yaml MUST resolve to a module-level DTDomain instance.
A class, or an instance constructed inside a function, MUST NOT satisfy the declaration.
Path resolution
The domain that serves a request is resolved from the URL at request time, not bound when the route is mounted. These requirements are what makes that safe.
REQ-1010 — An inbound path MUST resolve to the registered domain whose route_prefix is the longest prefix of that path.
REQ-1011 — Prefix matching MUST be on segment boundaries.
A path MUST match a prefix only when it equals that prefix or continues it with /.
/aboutmust not resolve to the domain mounted at/a. A bare string-prefix test serves that request from the wrong domain, with a 200.
REQ-1012 — A trailing slash MUST NOT affect resolution.
REQ-1013 — A path matching no registered prefix MUST resolve to no domain.
Route mounting
REQ-1020 — Every registered domain MUST mount, under {route_prefix}/{{{entity_id_param}}}: /info, /summary, /values, /simulations and /ontology.
REQ-1021 — Modules under src/celine/dt/domains/{name}/routes/ exporting a module-level router MUST be discovered and mounted inside the same entity scope, at their declared __prefix__.
REQ-1022 — A domain with no routes/ package MUST mount successfully with no custom routes.
Absence MUST NOT be an error.
REQ-1023 — Every mounted operation id MUST be prefixed with the domain name, with hyphens replaced by underscores.
celine-sdkis generated from this schema. Two domains both mounting/infowould otherwise collide onget_infoand generate one method for both.
REQ-1024 — The entity path parameter MUST appear as a path parameter in the OpenAPI document for every entity-scoped route.
Without it the generated SDK method loses the argument that identifies the entity.
Entity resolution
REQ-1030 — The entity identifier MUST be taken from the path parameter named by entity_id_param and passed to the domain's resolve_entity.
REQ-1031 — When resolve_entity returns None, the request MUST answer 404.
REQ-1032 — Metadata returned by resolve_entity MUST be available to that request's query templates as entity.metadata, and to custom routes through the context.
REQ-1033 — The default resolve_entity MUST accept any entity identifier.
Rejection is a domain's own responsibility.
Stated because it is permissive and not obvious: a domain that forgets to override
resolve_entityserves the entire identifier space.
Authentication
REQ-1040 — Every built-in entity-scoped route MUST require a JWT.
A request without one MUST answer 401, and MUST NOT reach entity resolution.
Discovery
REQ-1050 — GET /health MUST answer 200 and report the number of currently registered domains.
REQ-1051 — GET /domains MUST list every registered domain with its name, domain_type, version, route_prefix, entity_id_param and the identifiers of its value fetchers.
REQ-1052 — The value identifiers reported by GET /domains MUST be the domain-local ones, matching what the values API accepts (REQ-1103).
These two endpoints read the domain registry through
app.state.infra, which is the only application statecreate_appsets. Reading it from anywhere else reports an empty service with a 200 — a health check that passes while describing nothing.
Domains this service ships
Not requirements — the current registry, recorded so the identifiers above have referents.
Regenerate rather than trust: GET /domains.
| Name | Type | Prefix | Entity parameter |
|---|---|---|---|
it-energy-community |
energy-community |
/communities/it |
community_id |
it-participant |
participant |
/participants |
participant_id |
it-grid |
grid |
/grid |
network_id |