Workflow Reference
Workflow states, capabilities, revisions, lifecycle events, and generated public contracts.
Workflows model editorial state transitions separately from ordinary field edits. A workflow-enabled document can keep an editable working revision while exposing an independent public snapshot, so changing a published entry does not necessarily change what public readers see.
Use publishingWorkflow() for the standard draft → review → publish lifecycle. Define a custom workflow only when the business process genuinely has different states, capabilities, or transition rules.
States, transitions, and capabilities
A transition names its allowed source and destination states. Capabilities determine who may view drafts, submit, publish, reject, or perform other configured actions. Enforce these rules on the server; hiding an unavailable button is only presentation.
import { defineCollection, publishingWorkflow } from '@dyrected/core'
export const Articles = defineCollection({
slug: 'articles',
workflow: publishingWorkflow(),
fields: [
{ name: 'title', type: 'text', label: 'Title', required: true },
{ name: 'body', type: 'richText', label: 'Body', required: true },
],
})Revisions and concurrency
Workflow metadata includes a revision. Pass expectedRevision when transitioning from an editor that may be stale. A rejected concurrency check is preferable to silently overwriting another editor's decision.
Draft visibility
Draft visibility and public materialization are distinct concerns. Use canViewWorkflowDraft and configured capabilities rather than inferring access from a user role in frontend code. Test anonymous, author, reviewer, and publisher behavior explicitly.
Transition hooks
Use beforeTransition to validate or reject a state change before it commits. Use afterTransition for notifications and revalidation after persistence. Design external effects to tolerate retries and partial downstream failure.
See Workflows, Editorial Approval, and Migrating to Workflows.
Lifecycle events
Lifecycle events provide durable dispatch helpers for effects that should not depend on one request remaining alive. Treat event handlers as potentially retried: make them idempotent and record provider identifiers when duplicate delivery would be harmful.
SDK and REST
The SDK exposes transition and workflowHistory on fluent collection clients. REST exposes the corresponding transition and history routes only for workflow-enabled collections. Runtime OpenAPI contains project-specific paths and schemas.
Generated workflow and lifecycle contracts
availableWorkflowTransitions
Exported function from @dyrected/core.
export function availableWorkflowTransitions(
workflow: WorkflowConfig,
state: string,
user?: AuthenticatedUser,
): WorkflowTransition[]canViewWorkflowDraft
Exported function from @dyrected/core.
export function canViewWorkflowDraft(workflow: WorkflowConfig, user?: AuthenticatedUser): booleancreateLifecycleEvent
Exported function from @dyrected/core.
export function createLifecycleEvent(args: {
name: LifecycleEventName;
collection: string;
documentId: string;
actorId?: string;
payload: Record<string, unknown>;
}): LifecycleEventcreateWorkflowDocument
Exported function from @dyrected/core.
export async function createWorkflowDocument(args: {
config: DyrectedConfig;
collection: CollectionConfig;
data: Record<string, unknown>;
user?: AuthenticatedUser;
}): Promise<{ doc: BaseDocument; event: LifecycleEvent }>dispatchLifecycleEvent
Exported function from @dyrected/core.
export async function dispatchLifecycleEvent(config: DyrectedConfig, event: LifecycleEvent): Promise<void>dispatchPendingLifecycleEvents
Exported function from @dyrected/core.
export async function dispatchPendingLifecycleEvents(config: DyrectedConfig, limit = 50): Promise<number>initializeWorkflowDocument
Exported function from @dyrected/core.
export function initializeWorkflowDocument(data: Record<string, unknown>, workflow: WorkflowConfig)LIFECYCLE_EVENTS_COLLECTION
Exported constant from @dyrected/core.
export const LIFECYCLE_EVENTS_COLLECTION = "__lifecycle_events";LifecycleEvent
Exported interface from @dyrected/core.
export interface LifecycleEvent<TPayload = Record<string, unknown>> {
id: string;
name: LifecycleEventName;
collection: string;
documentId: string;
occurredAt: string;
actorId?: string;
payload: TPayload;
attempts: number;
status: "pending" | "processing" | "delivered" | "failed";
nextAttemptAt?: string;
deliveredAt?: string;
lastError?: string;
}| Member | Signature | Description |
|---|---|---|
id | id: string | |
name | name: LifecycleEventName | |
collection | collection: string | |
documentId | documentId: string | |
occurredAt | occurredAt: string | |
actorId | actorId?: string | |
payload | payload: TPayload | |
attempts | attempts: number | |
status | status: "pending" | "processing" | "delivered" | "failed" | |
nextAttemptAt | nextAttemptAt?: string | |
deliveredAt | deliveredAt?: string | |
lastError | lastError?: string |
LifecycleEventHandler
Exported type from @dyrected/core.
export type LifecycleEventHandler = (
event: LifecycleEvent,
) => void | Promise<void>;LifecycleEventName
Exported type from @dyrected/core.
export type LifecycleEventName = (typeof LIFECYCLE_EVENT_NAMES)[number];materializeWorkflowDocument
Exported function from @dyrected/core.
export function materializeWorkflowDocument(
doc: BaseDocument,
workflow: WorkflowConfig,
user?: AuthenticatedUser,
): BaseDocument | nullpublishingWorkflow
Exported function from @dyrected/core.
export function publishingWorkflow(): WorkflowConfigsaveWorkflowDraft
Exported function from @dyrected/core.
export async function saveWorkflowDraft(args: {
config: DyrectedConfig;
collection: CollectionConfig;
id: string;
originalDoc: BaseDocument;
data: Record<string, unknown>;
user?: AuthenticatedUser;
}): Promise<{ doc: BaseDocument; event: LifecycleEvent }>transitionWorkflow
Exported function from @dyrected/core.
export async function transitionWorkflow(args: {
config: DyrectedConfig;
collection: CollectionConfig;
id: string;
transitionName: string;
expectedRevision?: number;
comment?: string;
user?: AuthenticatedUser;
req: HookRequestContext;
}): Promise<BaseDocument>WORKFLOW_HISTORY_COLLECTION
Exported constant from @dyrected/core.
export const WORKFLOW_HISTORY_COLLECTION = "__workflow_history";workflowCapabilities
Exported function from @dyrected/core.
export function workflowCapabilities(workflow: WorkflowConfig, user?: AuthenticatedUser): Set<string>WorkflowConfig
Exported interface from @dyrected/core.
export interface WorkflowConfig<TDoc extends object = Record<string, unknown>> {
initialState: string;
/** State used for a new working revision created from published content. */
draftState?: string;
states: WorkflowState[];
transitions: WorkflowTransition[];
/** Maps values in `user.roles` to workflow capabilities. */
roles?: WorkflowRole[];
hooks?: {
beforeTransition?: CollectionBeforeTransitionHook<TDoc>[];
afterTransition?: CollectionAfterTransitionHook<TDoc>[];
};
}| Member | Signature | Description |
|---|---|---|
initialState | initialState: string | |
draftState | draftState?: string | State used for a new working revision created from published content. |
states | states: WorkflowState[] | |
transitions | transitions: WorkflowTransition[] | |
roles | roles?: WorkflowRole[] | Maps values in `user.roles` to workflow capabilities. |
hooks | hooks?: { beforeTransition?: CollectionBeforeTransitionHook<TDoc>[]; afterTransition?: CollectionAfterTransitionHook<TDoc>[]; } |
WorkflowMetadata
Exported interface from @dyrected/core.
export interface WorkflowMetadata {
state: string;
revision: number;
publishedRevision?: number;
publishedAt?: string;
publishedBy?: string;
/** Transitions currently allowed for the requesting user. Response-only. */
availableTransitions?: string[];
}| Member | Signature | Description |
|---|---|---|
state | state: string | |
revision | revision: number | |
publishedRevision | publishedRevision?: number | |
publishedAt | publishedAt?: string | |
publishedBy | publishedBy?: string | |
availableTransitions | availableTransitions?: string[] | Transitions currently allowed for the requesting user. Response-only. |
WorkflowRole
Exported interface from @dyrected/core.
export interface WorkflowRole {
/** Existing user role value, for example `editor` or `publisher`. */
role: string;
capabilities: string[];
}| Member | Signature | Description |
|---|---|---|
role | role: string | Existing user role value, for example `editor` or `publisher`. |
capabilities | capabilities: string[] |
WorkflowState
Exported interface from @dyrected/core.
export interface WorkflowState {
/** Stable machine-readable state key. */
name: string;
/** Label rendered in the Admin UI. */
label: string;
/** Marks the state whose revision is visible to public readers. */
published?: boolean;
/** Optional visual tone used by the Admin UI. */
color?: "neutral" | "warning" | "success" | "danger" | "info";
}| Member | Signature | Description |
|---|---|---|
name | name: string | Stable machine-readable state key. |
label | label: string | Label rendered in the Admin UI. |
published | published?: boolean | Marks the state whose revision is visible to public readers. |
color | color?: "neutral" | "warning" | "success" | "danger" | "info" | Optional visual tone used by the Admin UI. |
WorkflowTransition
Exported interface from @dyrected/core.
export interface WorkflowTransition {
/** Stable transition key used by the REST and SDK APIs. */
name: string;
label: string;
from: string | string[];
to: string;
/** Every listed capability is required. */
requiredCapabilities?: string[];
/** Require a non-empty comment when performing the transition. */
requireComment?: boolean;
/** Remove the public snapshot after this transition commits. */
unpublish?: boolean;
}| Member | Signature | Description |
|---|---|---|
name | name: string | Stable transition key used by the REST and SDK APIs. |
label | label: string | |
from | from: string | string[] | |
to | to: string | |
requiredCapabilities | requiredCapabilities?: string[] | Every listed capability is required. |
requireComment | requireComment?: boolean | Require a non-empty comment when performing the transition. |
unpublish | unpublish?: boolean | Remove the public snapshot after this transition commits. |
WorkflowTransitionContext
Exported interface from @dyrected/core.
export interface WorkflowTransitionContext<
TDoc extends object = Record<string, unknown>,
> {
transition: WorkflowTransition;
from: string;
to: string;
doc: TDoc;
user?: AuthenticatedUser;
comment?: string;
req: HookRequestContext;
db: DatabaseAdapter;
}| Member | Signature | Description |
|---|---|---|
transition | transition: WorkflowTransition | |
from | from: string | |
to | to: string | |
doc | doc: TDoc | |
user | user?: AuthenticatedUser | |
comment | comment?: string | |
req | req: HookRequestContext | |
db | db: DatabaseAdapter |