ContentTemplateFetchModule Migration Guide
Overview
ContentTemplateFetchModule is a retired compatibility shell. Version 1.0 read an arbitrary ContentData identifier from opaque task configuration, returned content regardless of publication status, described strings as generic objects, omitted its input and configuration contract, and swallowed missing, invalid, unreadable, and runtime failures. A workflow could therefore appear successful with stale output or disclose a draft template to later tasks.
Version 2.0 keeps the Java class and Spring bean loadable so saved workflows can be inspected and migrated. It is hidden from backend and Workflow Studio discovery, performs no ContentData lookup, and deterministically returns MODULE_RETIRED. Use ApprovedContentTemplateModule for an ACL-visible source whose publication status, content type, subject, and immutable version are verified before its body enters workflow state.
Usage
- Find saved tasks whose class is
com.valkyrlabs.workflow.modules.transform.ContentTemplateFetchModule. - Remove any template body, subject, or ContentData fields copied into general workflow input.
- Replace the task with
ApprovedContentTemplateModule. - Set
contentIdto a ContentData record visible through generated ACL enforcement. - Require the exact publication status and allow only the intended content types.
- Set the versioned subject template and retain
contentVersiondownstream so approvals and deliveries bind to immutable content.
Inputs
The retired shell reads no workflow input. It ignores every supplied value and never includes it in output or logs.
The replacement reads its source contract from normalized workflow configuration. Do not pass credentials, raw ACLs, owner fields, or private content through the input map.
Outputs
The retired module always returns:
| Output | Type | Description |
|---|---|---|
status | string | Always error. |
error | object | Safe MODULE_RETIRED, retryable:false, the migration target, and required action. |
It never returns a template, subject, title, subtitle, content type, ContentData identifier, owner data, audit fields, or record-not-found details.
ApprovedContentTemplateModule returns contentDataId, contentVersion, contentType, template, and subject only after its guards pass.
IntegrationAccount Requirements
No IntegrationAccount is required or read by either the retired shell or ApprovedContentTemplateModule. The replacement uses the current authenticated principal and generated ContentData ACL service. A returned record is not made public and no ACL grant is created by the module.
Any downstream delivery module remains responsible for its own READY IntegrationAccount, recipient authorization, approval, idempotency, rate limits, and provider receipt.
Configuration
The retired shell recognizes these legacy field names only for migration and ignores their values:
| Field | Type | Active behavior |
|---|---|---|
contentId | UUID | Ignored; no record is resolved. |
subject | string | Ignored; never emitted. |
A governed replacement configuration resembles:
{
"contentId": "11111111-1111-1111-1111-111111111111",
"requiredStatus": "PUBLISHED",
"allowedContentTypes": ["markdown", "text/markdown"],
"subject": "Welcome {{firstName}}"
}
Use the actual ACL-visible ContentData UUID. The example UUID is not a fixture record.
Operations
ContentTemplateFetchModule supports one compatibility operation: reject execution and identify ApprovedContentTemplateModule as the migration target. It does not parse a UUID, query ContentData, inspect record state, copy content, or suppress a lookup failure.
The replacement performs one generated-service read, requires the configured status and an allowlisted content type, rejects a blank body, and hashes source identity, state, modification time, subject, and body into contentVersion.
Errors and Failure Modes
| Failure | Behavior | Recovery |
|---|---|---|
| Any legacy execution | Returns MODULE_RETIRED with retryable:false. | Replace the task; retries cannot re-enable legacy reads. |
| Source is missing or not ACL-visible | Replacement fails without returning content. | Verify ownership or an explicit READ grant; do not bypass generated ACL. |
| Source is not in the required publication state | Replacement fails before copying the body. | Complete the governed editorial workflow or select the correct approved record. |
| Content type is not allowlisted | Replacement fails before output. | Correct the source type or narrowly update the allowlist. |
| Template body is blank | Replacement fails before output. | Publish a non-empty approved template. |
| Source changes after approval | contentVersion changes. | Repeat approval and downstream binding against the new immutable version. |
Example
A saved legacy task reaches the compatibility shell:
{
"contentId": "11111111-1111-1111-1111-111111111111",
"subject": "Welcome {{firstName}}"
}
Expected result:
{
"status": "error",
"error": {
"code": "MODULE_RETIRED",
"message": "ContentTemplateFetchModule is retired; use ApprovedContentTemplateModule",
"retryable": false,
"migrationTargets": ["ApprovedContentTemplateModule"]
}
}
Notes
- Pagination: not applicable; neither module lists ContentData records.
- Limits: the retired shell emits a constant two-field response. The replacement reads one ContentData record and requires a non-blank body.
- Idempotency: the retired response is deterministic and side-effect free. The replacement is naturally idempotent for the same ACL-visible record version and configuration.
- Rate limits: no external provider is called. Repository and database limits still apply to the generated ContentData read.
- API constraints: visibility comes only from generated owner/ACL enforcement. Published status, category, or a public-looking route is not an authorization grant.
- Destructive behavior: none. Neither module writes ContentData or changes grants.
- Secret handling: ignored legacy values and replacement content are not copied into error output. Do not store credentials in a template body or subject.
- Runtime boundary: merged source and published documentation do not update the deployed Workflow Studio catalog until a backend release hides version 2 from
/v1/modules/metadata. - Unverified boundary: deterministic tests prove fail-closed output, input/config non-disclosure, repeatability, discovery exclusion, and direct compatibility lookup. Production ACL behavior remains the responsibility of the generated ContentData service used by the replacement.