API contracts: operators, templates, and users
At a glance
- Three DTO groups: operators (small), templates (large — the actual persisted mapping), users (tiny).
- Every DTO is a Zod schema with an inferred type, not a hand-written
interface— same pattern as schema serialization. TemplateSave.pluginsis exactly the shapeplugins'serialize()produces.
Alongside the tree/schema data model covered in Tree nodes and schemas, packages/types also defines three Zod-validated DTO groups: operators-api, templates-api, and users-api. These describe records that get persisted and sent over the wire, as opposed to the in-memory tree model a template is built from.
Operators
Operator (validated by operatorSchema) is the smallest of the three: an id, operatorid, a list of domains, an optional language, and an optional schemes — a nested record (domain -> type -> variant -> schema name) for overriding which schema variant applies for that operator in a given domain/type combination. The file's own example is the clearest description of the shape:
{
"operatorid": "100",
"domains": ["retail"],
"schemes": {
"retail": {
"standard": {
"table": "customRetailTableSchema"
}
}
}
}Templates
This is the largest of the three groups, built around TemplateRef — a template's own metadata: id, operatorId, name, path/deployPath, domain, priority, inputsource (a SchemaSource), enabled/deleted flags, and optional EDI fields (ediType, ediVariables — see Reserved names for how EDI variables relate to the runtime scope) and a recentFiles list.
Layered on top of TemplateRef:
TemplateSave— the actual saved content of a template:entriesandgraphs(both loosely typed asRecord<string, any>at this layer — the concrete shapes come fromschema-serialization'sSerializedSchematypes, not from here), aconfigblock (preconfiguration, an optionalconfigSnapshot,updateDiscardIds,lastTextContentHash), and apluginsblock that separately tracks global plugin state (plugins,versions,bootstrapped) and per-node registered plugin instances (version+sliceper key). See Built-in plugins for what a plugin'ssliceholds.TemplateResource—TemplateRefmerged with{ save: TemplateSave }, minuspath. This is the full template as the API would return it.CreateTemplateResourceDto/UpdateTemplateResourceDto— request bodies for creating/updating a template. Both replacesavewith astring— i.e. the client sends the save data serialized, not as a live object.Update...additionally makes every field optional (a Zod.partial()) and dropsid.TemplateDeploy/RawTemplateDeploy— the shapes used when deploying a template's compiled output (RawTemplateDeployis just{ deployPath, content }).TemplateCategory— a separate, much smaller record for grouping templates by category within a domain.
Users
User (via userSchema) is the smallest of all three groups: just userId and operatorId. There's no users-api equivalent of the template/operator richness — it exists to tag records with who/which operator they belong to, not to model a user profile.
Why these are Zod schemas, not plain types
Every DTO here is defined as a z.object(...) with a z.infer<...> type derived from it, rather than a hand-written interface. That gives callers both the compile-time type and a runtime validator from the same definition — relevant at API boundaries, where the data hasn't been type-checked by TypeScript yet. See Schema serialization for how this same runtime-validator-as-source-of-truth approach extends to the tree model itself.