Documentation navigationNavigare documentație
Guide 4 of 7Ghidul 4 din 7 · API 0.8.0
Releases and immutabilityRelease-uri și imuabilitate
A release binds exact component versions into one immutable, content-addressed manifest that every execution and submission references.Un release leagă versiuni exacte ale componentelor într-un manifest imuabil, adresat prin conținut, la care se referă fiecare execuție și solicitare.
Derived from:Derivat din: contracts/openapi/openapi.yamlcontracts/configuration/deployment-v1.schema.jsondocs/ARCHITECTURE.md
What a release bindsCe leagă un release
A release is the unit that runtime executes. A legacy document release binds contract_version_id, transform_version_id, template_version_id and the case_id that validated the combination. A canonical release adds processing_kind, either transformation or document, and ingestion_model_version_id, and records the hash of every component: contract_hash, transform_hash, template_hash, case_hash, the expected output_hash and a content_hash over the whole manifest.Release-ul este unitatea pe care o execută runtime-ul. Un release de documente în format vechi leagă contract_version_id, transform_version_id, template_version_id și case_id-ul care a validat combinația. Un release canonic adaugă processing_kind, fie transformation, fie document, și ingestion_model_version_id, și înregistrează hash-ul fiecărei componente: contract_hash, transform_hash, template_hash, case_hash, output_hash-ul așteptat și un content_hash peste întregul manifest.
publishRelease validates the combination end to end before writing: the case must validate against the contract version, the transform must evaluate on the case, and the template bindings must resolve on the transform output. Publication is idempotent under Idempotency-Key, and the request body is bounded at 1,064,960 bytes.publishRelease validează combinația de la un capăt la altul înainte de a scrie: cazul trebuie să se valideze față de versiunea contractului, transformarea trebuie să se evalueze pe caz, iar legăturile șablonului trebuie să se rezolve pe ieșirea transformării. Publicarea este idempotentă sub Idempotency-Key, iar body-ul cererii este limitat la 1.064.960 de octeți.
release-immutability/publish-release.request.json · publishRelease body; the UUIDs are placeholders replaced by curl.sh.Corpul publishRelease; UUID-urile sunt substituenți înlocuiți de curl.sh.{
"name": "Person welcome letter",
"description": "Docs example: exact contract, transform, template and validation case identities frozen into one immutable release.",
"contract_version_id": "11111111-1111-4111-8111-000000000001",
"transform_version_id": "22222222-2222-4222-8222-000000000001",
"template_version_id": "33333333-3333-4333-8333-000000000001",
"case_id": "44444444-4444-4444-8444-000000000001"
}
Immutable means immutableImuabil înseamnă imuabil
Published versions and releases never change. There is no update or delete operation; a mistake is corrected by publishing a new version and a new release and, for calendar families, by scheduling it with a new effective_from. Prior evidence stays readable, so a document produced a year ago can still be traced to the exact schema, mapping and template that produced it.Versiunile și release-urile publicate nu se schimbă niciodată. Nu există operație de actualizare sau ștergere; o greșeală se corectează publicând o versiune nouă și un release nou și, pentru familiile calendaristice, programându-l cu un nou effective_from. Dovezile anterioare rămân lizibile, așa că un document produs acum un an poate fi urmărit până la schema, maparea și șablonul exacte care l-au produs.
Canonical releases are unique by ingestion-model version, recursive node address, input mode, exact producer release identity and hash when fed by a parent node, and the component tuple. Runtime therefore never guesses the data source, and a new parent version cannot collide with an old child's provenance.Release-urile canonice sunt unice după versiunea modelului de ingestie, adresa recursivă a nodului, modul de intrare, identitatea și hash-ul exacte ale release-ului producător când sunt alimentate de un nod părinte și tuplul componentelor. Runtime-ul nu ghicește deci niciodată sursa datelor, iar o versiune părinte nouă nu poate intra în coliziune cu proveniența unui copil vechi.
release-immutability/republish-conflict.problem.json · The 409 problem returned when the identical release is published a second time.Problema 409 returnată când aceeași publicare este trimisă a doua oară.{
"type": "/problems/conflict",
"title": "Conflict",
"status": 409,
"code": "conflict",
"detail": "The resource changed. Reload and compare before retrying.",
"correlation_id": "docs-example-correlation-id"
}
Validate before you publishValidează înainte de a publica
validateCanonicalRelease runs the same checks as publication without any canonical write and returns valid plus a list of errors, each with code, stage, resource_kind and message. findPublishedRelease looks up an existing release by its exact component identity, which is the right way to make a hand-written deployment script idempotent. getRelease and listReleases return the manifest and hashes for audit.validateCanonicalRelease rulează aceleași verificări ca publicarea, fără nicio scriere canonică, și întoarce valid plus o listă de erori, fiecare cu code, stage, resource_kind și message. findPublishedRelease caută un release existent după identitatea exactă a componentelor, ceea ce este modul corect de a face idempotent un script de deployment scris manual. getRelease și listReleases întorc manifestul și hash-urile pentru audit.
Configuration deploymentsDeployment-uri de configurare
A configuration deployment applies a correlated set of families, versions and activations atomically from one manifest with schema equal to docula-configuration-deployment-v1. Each item has a local_ref, a kind, an operation, the family identity, the definition and an effective_from; items may reference earlier items by local_ref, and at most 100 local references are resolved.Un deployment de configurare aplică atomic un set corelat de familii, versiuni și activări dintr-un singur manifest cu schema egală cu docula-configuration-deployment-v1. Fiecare element are un local_ref, un kind, o operation, identitatea familiei, definiția și un effective_from; elementele pot referi elemente anterioare prin local_ref, iar cel mult 100 de referințe locale sunt rezolvate.
validateConfigurationDeployment is a dry run with the identical bounded validation and no writes. applyConfigurationDeployment is idempotent and atomic across the set: the same actor, key and manifest replays the stored result, a changed manifest under the same key conflicts, and a failure in any item leaves nothing applied. The result lists every committed item with its resource_id, version_id, activation_id, content_hash and effective_from. Manifests are bounded at 2 MiB, and only administrator and engineer sessions may validate or apply.validateConfigurationDeployment este o rulare de probă cu aceeași validare limitată și fără scrieri. applyConfigurationDeployment este idempotent și atomic peste tot setul: același actor, aceeași cheie și același manifest reiau rezultatul stocat, un manifest schimbat sub aceeași cheie intră în conflict, iar un eșec la orice element lasă nimic aplicat. Rezultatul listează fiecare element comis cu resource_id, version_id, activation_id, content_hash și effective_from. Manifestele sunt limitate la 2 MiB, iar doar sesiunile de administrator și inginer pot valida sau aplica.
What an execution keepsCe păstrează o execuție
Every execution stores release_id and release_hash, input_hash and raw_input_hash, and every submission's processing plan pins the resolved activation, version and release hashes per node. Because the release is content-addressed, any later reader can recompute and compare the hashes instead of trusting a label.Fiecare execuție stochează release_id și release_hash, input_hash și raw_input_hash, iar planul de procesare al fiecărei solicitări fixează per nod hash-urile activării, versiunii și release-ului rezolvate. Pentru că release-ul este adresat prin conținut, orice cititor ulterior poate recalcula și compara hash-urile în loc să se încreadă într-o etichetă.
release-immutability/curl.sh · Publish once, publish again, assert 409, read the immutable manifest back.Publică o dată, publică din nou, verifică 409, citește manifestul imuabil.#!/bin/sh
# Docula example: releases are immutable.
# login -> publish a release -> publish the same body again and expect HTTP 409 (Problem code "conflict").
# Requires curl and jq. Environment: DOCULA_API, DOCULA_ORIGIN (defaults to DOCULA_API), DOCULA_USERNAME, DOCULA_PASSWORD,
# and the four published identities the release freezes: DOCULA_CONTRACT_VERSION_ID, DOCULA_TRANSFORM_VERSION_ID,
# DOCULA_TEMPLATE_VERSION_ID, DOCULA_CASE_ID (a valid or boundary case of that contract version).
set -eu
API=${DOCULA_API:?set DOCULA_API to the API origin, for example http://127.0.0.1:18081}
ORIGIN=${DOCULA_ORIGIN:-$API}
HERE=$(cd "$(dirname "$0")" && pwd)
JAR=$(mktemp)
trap 'rm -f "$JAR" "$JAR.body" "$JAR.problem"' EXIT
CSRF=$(jq -n --arg u "${DOCULA_USERNAME:?}" --arg p "${DOCULA_PASSWORD:?}" '{username: $u, password: $p}' |
curl --fail --silent --show-error -c "$JAR" -H "Origin: $ORIGIN" -H 'Content-Type: application/json' \
--data-binary @- "$API/api/v1/auth/login" | jq -r '.csrf_token')
# 1. Substitute your published identities into the recorded body.
jq --arg c "${DOCULA_CONTRACT_VERSION_ID:?}" --arg t "${DOCULA_TRANSFORM_VERSION_ID:?}" \
--arg d "${DOCULA_TEMPLATE_VERSION_ID:?}" --arg k "${DOCULA_CASE_ID:?}" \
'.contract_version_id = $c | .transform_version_id = $t | .template_version_id = $d | .case_id = $k' \
"$HERE/publish-release.request.json" > "$JAR.body"
# 2. Publish (publishRelease). 201 returns the release with its content_hash and canonical manifest.
RELEASE=$(curl --fail --silent --show-error -b "$JAR" -X POST -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" \
-H 'Content-Type: application/json' --data-binary @"$JAR.body" "$API/api/v1/releases")
printf '%s' "$RELEASE" | jq '{id: .release.id, content_hash: .release.content_hash, published_at: .release.published_at}'
# 3. Publish the identical body again. The manifest hashes to the same content_hash, which is unique,
# so the API answers 409 with an application/problem+json body instead of a second release.
STATUS=$(curl --silent --show-error -b "$JAR" -X POST -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" \
-H 'Content-Type: application/json' --data-binary @"$JAR.body" -o "$JAR.problem" -w '%{http_code}' "$API/api/v1/releases")
[ "$STATUS" = 409 ] || { echo "expected 409 on republish, got $STATUS" >&2; exit 1; }
jq -e '.code == "conflict" and .type == "/problems/conflict" and .status == 409' "$JAR.problem" > /dev/null
jq '.' "$JAR.problem"
# 4. Reading the release back returns the same immutable manifest; there is no update or delete operation.
curl --fail --silent --show-error -b "$JAR" "$API/api/v1/releases/$(printf '%s' "$RELEASE" | jq -r '.release.id')" | jq -r '.content_hash'
curl sequence sketchSchiță de secvență curl
curl --request POST "$DOCULA_URL/api/v1/releases/validate" --cookie "$COOKIE_JAR" \ --header "Content-Type: application/json" --header "Origin: $DOCULA_URL" \ --header "X-CSRF-Token: $CSRF_TOKEN" --header "Idempotency-Key: $IDEMPOTENCY_KEY" \ --data-binary @release.jsoncurl --request POST "$DOCULA_URL/api/v1/releases" --cookie "$COOKIE_JAR" \ --header "Content-Type: application/json" --header "Origin: $DOCULA_URL" \ --header "X-CSRF-Token: $CSRF_TOKEN" --header "Idempotency-Key: $IDEMPOTENCY_KEY" \ --data-binary @release.jsoncurl --request GET "$DOCULA_URL/api/v1/releases/$RELEASE_ID" --cookie "$COOKIE_JAR"curl --request POST "$DOCULA_URL/api/v1/configuration-deployments/validate" --cookie "$COOKIE_JAR" \ --header "Content-Type: application/json" --header "Origin: $DOCULA_URL" \ --header "X-CSRF-Token: $CSRF_TOKEN" --header "Idempotency-Key: $IDEMPOTENCY_KEY" \ --data-binary @deployment-manifest.jsoncurl --request POST "$DOCULA_URL/api/v1/configuration-deployments" --cookie "$COOKIE_JAR" \ --header "Content-Type: application/json" --header "Origin: $DOCULA_URL" \ --header "X-CSRF-Token: $CSRF_TOKEN" --header "Idempotency-Key: $IDEMPOTENCY_KEY" \ --data-binary @deployment-manifest.json
OperationsOperații
- POST publishRelease
/api/v1/releases - POST validateCanonicalRelease
/api/v1/releases/validate - GET findPublishedRelease
/api/v1/releases/lookup - GET getRelease
/api/v1/releases/{releaseId} - GET listReleases
/api/v1/releases - POST validateConfigurationDeployment
/api/v1/configuration-deployments/validate - POST applyConfigurationDeployment
/api/v1/configuration-deployments - GET getConfigurationDeployment
/api/v1/configuration-deployments/{deploymentId} - GET listConfigurationDeployments
/api/v1/configuration-deployments
