Documentation navigationNavigare documentație
ExamplesExemple · API 0.8.0
execution-trace
Each example is a fixture directory validated at build time against the released contracts: a JSON contract, a declarative transform, a template, a curl sequence and the expected output. Guides embed these files verbatim so documentation cannot drift from validated fixtures.Fiecare exemplu este un director de fixture-uri validat la build față de contractele publicate: un contract JSON, o transformare declarativă, un șablon, o secvență curl și rezultatul așteptat. Ghidurile includ aceste fișiere textual, astfel încât documentația nu poate devia de fixture-urile validate.
Files in this fixtureFișierele acestui fixture
execution-trace/curl.sh · 3407 bytes · sha256 31ee4ce4cdea48c1…#!/bin/sh
# Docula example: execution trace and artifacts.
# login -> submitExecution -> streamExecutionEvents (SSE) until completion -> getExecution -> downloadExecutionArtifact + hash check.
# Requires curl, jq and sha256sum. Environment: DOCULA_API, DOCULA_ORIGIN (defaults to DOCULA_API), DOCULA_USERNAME,
# DOCULA_PASSWORD, DOCULA_RELEASE_ID (a published document-generation release whose contract accepts the person input).
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.events"' 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. Submit (submitExecution). Idempotency-Key is required: replaying the same key and body returns the same execution (200),
# a different body under the same key is a 409.
jq --arg r "${DOCULA_RELEASE_ID:?}" '.release_id = $r' "$HERE/submit-execution.request.json" > "$JAR.body"
SUBMITTED=$(curl --fail --silent --show-error -b "$JAR" -X POST -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" \
-H "Idempotency-Key: docs-example-$(date +%Y%m%d%H%M%S)" -H 'Content-Type: application/json' \
--data-binary @"$JAR.body" "$API/api/v1/executions")
EXECUTION_ID=$(printf '%s' "$SUBMITTED" | jq -r '.execution.id')
# 2. Follow the trace (streamExecutionEvents). The stream replays persisted events, then continues live and closes itself
# after execution.completed or step.failed. Send Last-Event-ID to resume after a disconnect.
curl --fail --silent --show-error --no-buffer --max-time 120 -b "$JAR" -H 'Accept: text/event-stream' -H 'Last-Event-ID: 0' \
"$API/api/v1/executions/$EXECUTION_ID/events" | tee "$JAR.events"
grep -q '"type":"execution.completed"' "$JAR.events" || { echo "execution did not complete" >&2; exit 1; }
# 3. Read the final state (getExecution): four steps and the retained artifacts with their SHA-256 hashes.
EXECUTION=$(curl --fail --silent --show-error -b "$JAR" "$API/api/v1/executions/$EXECUTION_ID")
printf '%s' "$EXECUTION" | jq '{status, steps: [.steps[] | {name, status, duration_ms}], artifacts}'
# 4. Download one artifact (downloadExecutionArtifact is a POST with an empty JSON body because it is audited)
# and verify the bytes against the X-Content-SHA256 header and the recorded content_hash.
ARTIFACT_ID=$(printf '%s' "$EXECUTION" | jq -r '.artifacts[] | select(.kind == "pdf") | .id')
EXPECTED=$(printf '%s' "$EXECUTION" | jq -r '.artifacts[] | select(.kind == "pdf") | .content_hash')
curl --fail --silent --show-error -b "$JAR" -X POST -H "Origin: $ORIGIN" -H "X-CSRF-Token: $CSRF" \
-H 'Content-Type: application/json' --data-binary @"$HERE/download-artifact.request.json" \
-D "$JAR.headers" -o document.pdf "$API/api/v1/executions/$EXECUTION_ID/artifacts/$ARTIFACT_ID/download"
HEADER_HASH=$(tr -d '\r' < "$JAR.headers" | awk 'tolower($1) == "x-content-sha256:" { print $2 }')
ACTUAL=$(sha256sum document.pdf | cut -d ' ' -f 1)
rm -f "$JAR.headers"
[ "$ACTUAL" = "$EXPECTED" ] && [ "$ACTUAL" = "$HEADER_HASH" ] || { echo "artifact hash mismatch" >&2; exit 1; }
printf 'document.pdf sha256=%s\n' "$ACTUAL"
execution-trace/download-artifact.request.json · 3 bytes · sha256 ca3d163bab055381…{}
execution-trace/events.sse · 2884 bytes · sha256 9a061eb11628f777…retry: 1000
id: 1
event: execution
data: {"id":1,"execution_id":"55555555-5555-4555-8555-000000000001","type":"execution.submitted","correlation_id":"docs-example-correlation-id","payload":{"input_hash":"6444ce79c02f6b8557cd5def4969b6f49e0c371530e24b3d5b5eff8aeb99d700","raw_input_hash":"889007605af33b472a3f0b3e0c85826ca70cc3484d668e2cae165ebef41a04d8","release_hash":"a4d451ec23463726f72c43d64c710968f6b602cd653b4de8adee1b556240a829"},"occurred_at":"2026-08-30T09:15:00Z"}
id: 2
event: execution
data: {"id":2,"execution_id":"55555555-5555-4555-8555-000000000001","type":"step.succeeded","step":"validate","attempt":1,"correlation_id":"docs-example-correlation-id","payload":{"contract_hash":"cc8321d6375c494d043fdd0260f21bc0ec51dacc9f6abb7f909cdcd3041b78bf","contract_version_id":"11111111-1111-4111-8111-000000000001","input_hash":"6444ce79c02f6b8557cd5def4969b6f49e0c371530e24b3d5b5eff8aeb99d700"},"occurred_at":"2026-08-30T09:15:01Z"}
id: 3
event: execution
data: {"id":3,"execution_id":"55555555-5555-4555-8555-000000000001","type":"step.succeeded","step":"transform.declarative","attempt":1,"correlation_id":"docs-example-correlation-id","payload":{"input_hash":"6444ce79c02f6b8557cd5def4969b6f49e0c371530e24b3d5b5eff8aeb99d700","output_hash":"e0ee8bb50685e05fa0f47ed04203ae953fdfd055f5bd2892ea186504254f8c3a","transform_hash":"aa214ea38326805d95661c3ad1643cc07f88e2bae0438ac0448a66d93335ca6e","transform_version_id":"22222222-2222-4222-8222-000000000001"},"occurred_at":"2026-08-30T09:15:02Z"}
id: 4
event: execution
data: {"id":4,"execution_id":"55555555-5555-4555-8555-000000000001","type":"step.succeeded","step":"compose","attempt":1,"correlation_id":"docs-example-correlation-id","payload":{"artifact_id":"77777777-7777-4777-8777-000000000001","kind":"docx","media_type":"application/vnd.openxmlformats-officedocument.wordprocessingml.document","byte_size":18432,"content_hash":"584cb925e6ad45273e46037369c5ec3a5d7cfdd409ce13a69e7087f8accd1c79"},"occurred_at":"2026-08-30T09:15:04Z"}
id: 5
event: execution
data: {"id":5,"execution_id":"55555555-5555-4555-8555-000000000001","type":"step.succeeded","step":"render","attempt":1,"correlation_id":"docs-example-correlation-id","payload":{"artifact_id":"77777777-7777-4777-8777-000000000002","kind":"pdf","media_type":"application/pdf","byte_size":24576,"content_hash":"c35b21d6ca39aa7cc3b79a705d989f1a6e88b99ab43988d74048799e3db926a3"},"occurred_at":"2026-08-30T09:15:07Z"}
id: 6
event: execution
data: {"id":6,"execution_id":"55555555-5555-4555-8555-000000000001","type":"execution.completed","step":"render","attempt":1,"correlation_id":"docs-example-correlation-id","payload":{"artifact_id":"77777777-7777-4777-8777-000000000002","kind":"pdf","media_type":"application/pdf","byte_size":24576,"content_hash":"c35b21d6ca39aa7cc3b79a705d989f1a6e88b99ab43988d74048799e3db926a3"},"occurred_at":"2026-08-30T09:15:07Z"}
execution-trace/execution.json · 4083 bytes · sha256 979b2e1f98f1fc3c…{
"id": "55555555-5555-4555-8555-000000000001",
"release_id": "66666666-6666-4666-8666-000000000001",
"release_hash": "a4d451ec23463726f72c43d64c710968f6b602cd653b4de8adee1b556240a829",
"processing_kind": "document_generation",
"input": {
"first_name": "Iulia",
"last_name": "Popescu",
"email": "[email protected]"
},
"input_hash": "6444ce79c02f6b8557cd5def4969b6f49e0c371530e24b3d5b5eff8aeb99d700",
"raw_input": "{\"first_name\": \"Iulia\", \"last_name\": \"Popescu\", \"email\": \"[email protected]\"}",
"raw_input_hash": "889007605af33b472a3f0b3e0c85826ca70cc3484d668e2cae165ebef41a04d8",
"output": {
"display_name": "Iulia Popescu",
"first_name": "Iulia",
"middle_name": null,
"preferred_contact": "[email protected]",
"source": "docs-example"
},
"output_hash": "e0ee8bb50685e05fa0f47ed04203ae953fdfd055f5bd2892ea186504254f8c3a",
"status": "completed",
"submitted_by": "88888888-8888-4888-8888-000000000001",
"correlation_id": "docs-example-correlation-id",
"created_at": "2026-08-30T09:15:00Z",
"updated_at": "2026-08-30T09:15:07Z",
"completed_at": "2026-08-30T09:15:07Z",
"steps": [
{
"name": "validate",
"position": 1,
"status": "succeeded",
"attempt": 1,
"state_version": 2,
"started_at": "2026-08-30T09:15:00Z",
"finished_at": "2026-08-30T09:15:01Z",
"duration_ms": 1000,
"summary": {
"contract_hash": "cc8321d6375c494d043fdd0260f21bc0ec51dacc9f6abb7f909cdcd3041b78bf",
"contract_version_id": "11111111-1111-4111-8111-000000000001",
"input_hash": "6444ce79c02f6b8557cd5def4969b6f49e0c371530e24b3d5b5eff8aeb99d700"
}
},
{
"name": "transform.declarative",
"position": 2,
"status": "succeeded",
"attempt": 1,
"state_version": 3,
"started_at": "2026-08-30T09:15:01Z",
"finished_at": "2026-08-30T09:15:02Z",
"duration_ms": 1000,
"summary": {
"input_hash": "6444ce79c02f6b8557cd5def4969b6f49e0c371530e24b3d5b5eff8aeb99d700",
"output_hash": "e0ee8bb50685e05fa0f47ed04203ae953fdfd055f5bd2892ea186504254f8c3a",
"transform_hash": "aa214ea38326805d95661c3ad1643cc07f88e2bae0438ac0448a66d93335ca6e",
"transform_version_id": "22222222-2222-4222-8222-000000000001"
}
},
{
"name": "compose",
"position": 3,
"status": "succeeded",
"attempt": 1,
"state_version": 4,
"started_at": "2026-08-30T09:15:02Z",
"finished_at": "2026-08-30T09:15:04Z",
"duration_ms": 2000,
"summary": {
"artifact_id": "77777777-7777-4777-8777-000000000001",
"kind": "docx",
"media_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"byte_size": 18432,
"content_hash": "584cb925e6ad45273e46037369c5ec3a5d7cfdd409ce13a69e7087f8accd1c79"
}
},
{
"name": "render",
"position": 4,
"status": "succeeded",
"attempt": 1,
"state_version": 5,
"started_at": "2026-08-30T09:15:04Z",
"finished_at": "2026-08-30T09:15:07Z",
"duration_ms": 3000,
"summary": {
"artifact_id": "77777777-7777-4777-8777-000000000002",
"kind": "pdf",
"media_type": "application/pdf",
"byte_size": 24576,
"content_hash": "c35b21d6ca39aa7cc3b79a705d989f1a6e88b99ab43988d74048799e3db926a3"
}
}
],
"artifacts": [
{
"id": "77777777-7777-4777-8777-000000000001",
"kind": "docx",
"media_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"byte_size": 18432,
"content_hash": "584cb925e6ad45273e46037369c5ec3a5d7cfdd409ce13a69e7087f8accd1c79",
"created_at": "2026-08-30T09:15:04Z"
},
{
"id": "77777777-7777-4777-8777-000000000002",
"kind": "pdf",
"media_type": "application/pdf",
"byte_size": 24576,
"content_hash": "c35b21d6ca39aa7cc3b79a705d989f1a6e88b99ab43988d74048799e3db926a3",
"created_at": "2026-08-30T09:15:07Z"
}
]
}
execution-trace/fixture.json · 1795 bytes · sha256 2316e59ae8bab399…{
"schema": "docula.example-fixture/v1",
"slug": "execution-trace",
"guide": "/developers/guides/execution-trace-and-artifacts",
"title": "Execution trace and artifacts",
"summary": "A submitExecution body, the SSE transcript the API streams for a completed document-generation run (execution.submitted, four step.succeeded events, execution.completed), the final getExecution document, and the curl sequence that submits, follows the trace, downloads the PDF artifact and verifies its hash.",
"operations": ["login", "submitExecution", "streamExecutionEvents", "getExecution", "downloadExecutionArtifact"],
"related": ["release-immutability"],
"files": [
{ "path": "submit-execution.request.json", "purpose": "submitExecution body: the release to run and the raw input; release_id is a placeholder replaced by curl.sh.", "validate": { "kind": "openapi", "schema": "#/components/schemas/SubmitExecutionRequest" } },
{ "path": "events.sse", "purpose": "text/event-stream transcript of streamExecutionEvents; every data line is an ExecutionEvent.", "validate": { "kind": "sse" } },
{ "path": "execution.json", "purpose": "getExecution response after completion: steps, hashes and retained artifacts.", "validate": { "kind": "openapi", "schema": "#/components/schemas/Execution", "expect": { "/status": "completed", "/processing_kind": "document_generation" } } },
{ "path": "download-artifact.request.json", "purpose": "downloadExecutionArtifact body: an empty JSON object (the download is a POST because it is audited).", "validate": { "kind": "openapi", "schema": "#/components/schemas/EmptyObject" } },
{ "path": "curl.sh", "purpose": "Submit, stream the trace, read the execution, download and verify the artifact.", "validate": { "kind": "shell" } }
]
}
execution-trace/submit-execution.request.json · 166 bytes · sha256 a5db78f3738b7977…{
"release_id": "66666666-6666-4666-8666-000000000001",
"input": {
"first_name": "Iulia",
"last_name": "Popescu",
"email": "[email protected]"
}
}
