Skip to main content
Version: v5.6.1

Node (project, environment, asset)

Included from Basic tierassets

JSON:API types: project, environment, asset — the resource type is the node's kind. This page covers the whole node family.

The v2 OpenAPI document declares this resource's schema; the resource-field coverage gate holds this page to it.

Nodes form the target tree every other resource hangs off. A node is addressed by its path — alternating collection/code pairs: /api/projects/<code>[/environments/<code>][/assets/<code>]. The authorisation path is the same string with /api stripped (e.g. /projects/demo/environments/dev), and it is what RBAC rules and the node filters elsewhere address. Codes are stored stripped and lowercased (^[a-z0-9_]+$, max 50).

Endpoints​

VerbPathBehaviour
GET/api/projectsProject index (read-filtered per node).
POST/api/projectsCreate a project — update on /projects and on the new node's own path, 404-on-deny.
GET/api/projects/{project_code}Project show.
PATCH/PUT/api/projects/{project_code}Update the bare project — same permit list and authorisation as the node-path update below.
DELETE/api/projects/{project_code}Soft delete (the node-path catch-all cannot address a bare project).
GET/api/projects/{project_code}/{node_path...}The node-path dispatch: an even pair count shows one node, an odd count indexes a child collection (filter[archived_eq] supported); a recognised trailing resource segment (changes, workflows, triggers, maintenance, bookmarks, …) dispatches to that resource instead. Shows apply the default include list project, bookmarks, template, template_version, children, children.template, children.template_version.
POST…/environments | …/assetsCreate a child node under the resolved parent.
PATCH/PUT<node path>Update (name, description, archived, template_version — the last ignored on non-assets). Authorised as update on the node's own path.
DELETE<node path>Soft delete the subtree.
POST<node path>/restoreUndo a soft delete; answers the restored node.
GET/POST<node path>/destroyGET previews the per-type destroy manifest; POST is the irreversible cascade, valid only on a soft-deleted node.
GET<node path>/export[?with_history=true]Streams the credential-free zip archive of the subtree.

Attributes​

Common to every kind:

AttributeTypeMeaning
codestringThe path segment. Immutable (not in the update permit list).
namestringDisplay name.
descriptionstring, nullableNull when never set.
archivedbooleanArchive flag (update verb).
created_bystringUsername of the creating user.
maintenanceobject, omitted when absentThe maintenance badge, present while an active window covers the node (its own, or an ancestor's — the innermost wins) or a scheduled one covering it starts within the server's badge horizon (api.maintenance_badge_horizon_minutes, default 60): {reason, until (nullable), window_path, scheduled, starts_at}. until falls back to a scheduled window's hard end; scheduled is true and starts_at set only on the imminent form. window_path names the quiesced node, so an inherited badge points at the window itself. Advisory: a failed read never fails serialization.

Per-kind additions:

KindExtra attributeMeaning
projectproject_typeStandard (environments only) or Enterprise (environments and assets, environments holding assets). Compared case-insensitively; blank defaults to Standard at create. Immutable after creation — an asset create under a Standard project is refused by name, and the recovery is recreating the project as Enterprise.
assettask_activeWhether a node background task is currently active on the node.
assetmintmodel_validShow-only (the shown node, never lists or includes): whether a valid concretised MintModel is stored for the pinned template version's commit.
assetmintmodel_invalid_reasonShow-only; null when valid, else no_mintmodel, not_concretised, generation_failed or template_version_changed (the upstream properties_changed recheck needs a properties converge this read tier does not compute).
asseterb_file_contentShow-only; null when the pinned template version has no MintModel, else the MintModel/templates/assets/<template code>.json.erb document at the version's pinned commit (the GUI's ERB Template tab). A failed git read serves the error message as the value — the show never fails on it.
environment—No kind-specific attribute.

Registered hosts are their own resource with their own API family: an infrastructure node lives in an infrastructure/ collection inside the tree but is served as resources/infrastructure_node — see also the infrastructure nodes reference.

Relationships​

NameKindsMeaning
properties / settingsallTo-one properties/settings document, with related links /api/properties/<id>, /api/settings/<id>.
parentsallTo-many: the ancestors, root first (empty for a project).
parent / projectnon-rootsTo-one: the immediate parent and the root project (project ref carries a related link).
bookmarksallTo-many bookmark refs.
childrenproject, environmentTo-many, filtered to children the principal can read; refs the source cannot resolve stay.
template / template_versionassetThe pinned template and version (with related links).
latest_node_background_tasksassetTo-many task refs.

self and bookmarks always; changes (all kinds); actions (asset — catalog entries backed by actions.rb or MintModel — only applicable to existing MintPress customers and those using the MintPress SDK or the packs:mintpress feature — additionally carry runner_requirement: "ruby", marking that they execute as opschain-action tasks and need a Ruby-capable runner (visibility only); scheduled_activities, plus per-child-kind collection links (environments, assets), plus project-only git_remotes, templates, workflows/workflow_runs — each of these gated by read on the corresponding …/<section> rule path; asset-only converged_properties (gated), node_background_tasks, version_history, mintmodels, mintmodel_history; parent on non-roots.

Meta​

can_have_changes, can_have_children, can_have_properties (always true), can_have_settings (always true), can_have_templates, requires_template, child_node_types, can_have_workflows, can_have_actions, and an authorisations object with per-section decisions for the current principal (e.g. properties {read, update}, changes {read, execute, delete}, secrets {settings, properties, mintmodel} — superuser-only — and self {update, delete}).

Lifecycle: delete, destroy, restore, export​

The opschain admin nodes CLI family (delete, restore, destroy, export, import) drives these lanes.

  • Soft delete (DELETE) tombstones the subtree: hidden from every list and route, path reserved, new work refused, fully reversible. It refuses while runs are active beneath (named 422) and emits api:nodes:deleted.
  • Restore (POST …/restore) undoes exactly that delete and emits api:nodes:restored. Only the root of a delete resolves — a node tombstoned as part of an ancestor's delete is restored through that ancestor.
  • Destroy (POST …/destroy) is valid only on a soft-deleted node — two deliberate steps; a live node answers the named 422 ("…Destroying is a two-step operation…"). It cascades every stored row beneath except the events table (the audit persists; chains keep rendering), releases unreferenced artifact blobs and emits api:nodes:destroyed with the manifest. The response (and the GET preview) is a node_destroy_manifest resource: {path, destroyed, counts (per-type row counts), note} — the preview's note is the standing export reminder.
  • Export (GET …/export) streams a credential-free zip; with_history=true adds the properties/settings version trails.

Every lifecycle verb authorises read plus the node's deletable rule action, 404-on-deny.

API v2​

The per-object estate services serve the same rows over /api/v2 (opschain docs api-v2), authorised exactly as the v1 lanes above (404-on-deny) and audited with the same api:projects:* / api:nodes:* events:

  • ProjectService — ListProjects / GetProject(code) / CreateProject / UpdateProject / DeleteProject (the soft-delete lane; restore/destroy/export remain v1-only).
  • EnvironmentService — ListEnvironments(project_code) and the node-path-addressed GetEnvironment / UpdateEnvironment / DeleteEnvironment, plus CreateEnvironment(project_code, …).
  • AssetService — ListAssets(parent_path) rows carry the pinned template identity and task_active — and the pinned version's template_version_state / template_version_has_mintmodel and the row's latest_background_tasks (the v1 asset-list include set); GetAsset(node_path) is the server-shaped composite (MintModel validity, readable child assets, the latest background tasks, and the show-only erb_file_content); ListTemplateVersionHistory(node_path) serves the templated node's version_history windows (a non-templated node refuses with the v1 message); CreateAsset keeps the Enterprise-project gate; UpdateAsset.template_version repoints the pinned version.

Lists take a typed archived filter (the v1 filter[archived_eq]) and cursor-paginate code-ascending; list/get responses carry the v1 meta.authorisations pair for the governing rule path. Since the three gets also carry the full v1 node-show meta — the node-kind shape flags and the per-subresource authorisation sections, rendered through the one rule the v1 serializer uses — beside the gap-C secrets_authorisations triple. The estate read model is PostgreSQL-only: the embedded store answers the typed ERROR_REASON_STORE_POSTGRES_REQUIRED posture.

  • opschain docs maintenance-windows — the badge's source of truth.
  • opschain docs resources/node_comparison — comparing two nodes.
  • opschain docs resources/mintmodel — the asset's mintmodels / mintmodel_history node-path family and the generate trigger.