Skip to main content
The deliverable resource is deliberately generic: one model carries nine domain concepts, and its type field decides which one a node is. That keeps the model simple, and it means the raw endpoints will accept a tree that makes no sense. The /concepts endpoints sit on top of the same data and enforce the rules. They speak the domain language, and they check what the raw endpoints do not: valid nesting, the fields each concept requires, station linkage, and department scoping. Prefer these for writes. Reads are the same either way, so use GET /deliverable with its filters and joins when you are reading.
A department is a shop, carried as data.shopId. null means the node applies across departments.

The nesting grammar

POST /concepts/deliverables rejects anything outside this grammar with a 400, so a step under an order fails here rather than becoming a node the app cannot display. You do not have to hard-code this. GET /concepts returns the same grammar as data, which lets you validate a payload before you send it.

Concept reference

* marks a field that is required in data. Every node also carries the base deliverable columns: identifier, quantity, schedule, progress, computed, and the rest. You can set identifier yourself on any type. Leave it out and one is generated.

Stage nodes and their station

A stage node always carries data.stageId pointing at a stage, which is a reusable station scoped to one department. On create, three things can happen:
  • You send data.stageId. It is validated: the station has to exist, and its department has to match the node’s resolved department.
  • You leave it out. The layer finds or creates a station named after the node, in the node’s department, and links it. You get sensible stations without having to pre-create them.
  • You leave it out and no department can be resolved. The request is rejected. A station belongs to a department, so without one there is nothing to search or create in.
A node’s effective department is its own data.shopId, or the nearest ancestor’s if it has none. Either way it is exposed as computed.shopId.

Applying routes

Setting originTemplateId on create, or data.linkedRouteId on a container, applies that route’s structure underneath the node. Routes compose recursively and are cycle-protected, so a route that references itself through another route is rejected rather than expanding forever. Applying a department-scoped route overrides the target’s department.

Endpoints

Call /plan before /apply for anything destructive, such as rework. It returns the effect and writes nothing, which gives you something concrete to show someone before they commit.
Concept writes still respect your key’s record permissions. Creating a station needs stage:create, and the flow edges a route brings with it need deliverable_dependency:create.

Starting an order from a route

This is the common path for work that follows a standard process:
You get back the new order’s context, so you can see the tree the route produced without a second read.