workflows

package
v1.5.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 28, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

README

Workflow Engine Architecture

This document explains how the workflow engine operates within the Openlane platform, including the flow of data through hooks, events, and the engine itself.

Overview

The workflows capability is built on simple composable primitives that combine into complex behaviors:

Primitive Purpose Example
Trigger When to evaluate field modified, edge added
Condition Whether to proceed object.status == "DRAFT"
When (per action) Action-level gate assignments.approved >= 3
Action What to do APPROVAL, NOTIFY, FIELD_UPDATE
Operators Composition field_modified AND is_tuesday

The engine evaluates triggers → checks conditions → executes actions (respecting their When expressions, e.g. blocking on approvals until criteria met).

Any meaningful sequential vs concurrent distinction around execution emerges from how you structure the definition, not from engine constraints:

  • One approval action with multiple targets + quorum = concurrent
  • Multiple approval actions = sequential with dependencies
  • When expressions = conditional execution based on state

There is an action index as a part of the executor, but it is just tracking progression through the action list, with approvals creating natural "gates" that block until their criteria are satisfied. The engine doesn't impose ordering beyond that - the definition author controls the flow through how they structure actions and their conditions.

High level Architecture

You can simplify all of the moving parts related to workflows into 2 buckets:

  • Bucket 1: pre-commit interception, where we fork into a "proposed" change
  • Bucket 2: post-commit events, where we're responding after a transaction
Pre-Commit Interception

For workflows where we intercept the change before its applied :

User Request ──► Hook intercepts ──► Creates WorkflowProposal ──► Returns unchanged entity
                     │
                     ▼
            Proposal submitted ──► WorkflowInstance created ──► Assignments created
                                                                      │
                                                                      ▼
                                                              Users approve/reject
                                                                      │
                                                                      ▼
                                                              Quorum satisfied?
                                                                      │
                                          ┌───────────────────────────┴───────────┐
                                          │                                       │
                                          ▼                                       ▼
                                    YES: Apply                              NO: Fail
                                    proposal changes                        workflow
                                    to entity
Post-Commit Events

For workflows that react to changes:

User Request ──► Mutation commits ──► soiree event emitted ──► handleWorkflowMutation
                                                                      │
                                                                      ▼
                                                              Find matching definitions
                                                                      │
                                                                      ▼
                                                              Trigger workflows
                                                              (NOTIFY, WEBHOOK, etc.)

Key Components

Hooks
Hook Purpose Trigger
HookWorkflowApprovalRouting Intercepts mutations, routes to proposal if approval required UPDATE on workflowable schemas
HookWorkflowProposalTriggerOnSubmit Starts workflow when proposal submitted CREATE/UPDATE on WorkflowProposal
HookWorkflowProposalInvalidateAssignments Invalidates approvals when proposal changes edited UPDATE on WorkflowProposal
HookWorkflowDefinitionPrefilter Derives trigger prefilter fields from definition JSON CREATE/UPDATE on WorkflowDefinition
Approval Submission Modes

Workflow definitions with approval actions have an approvalSubmissionMode that controls when the approval process begins:

Mode Proposal Initial State Behavior
AUTO_SUBMIT SUBMITTED Approval assignments are created immediately when the mutation is intercepted. Approvers are notified right away. This is the standard flow.
MANUAL_SUBMIT DRAFT The proposal is created in DRAFT state. Assignments are NOT created until the proposal is explicitly submitted.

Current Implementation Note: AUTO_SUBMIT is the primary supported mode. The MANUAL_SUBMIT mode creates proposals in DRAFT state, but the GraphQL mutation to submit draft proposals is not yet exposed (WorkflowProposal is an internal entity with entgql.Skip(entgql.SkipAll)). When MANUAL_SUBMIT support is completed, it will enable staging changes before requesting approval.

Definition Prefiltering

WorkflowDefinition persists derived trigger fields (trigger_operations, trigger_fields) for coarse SQL prefiltering. These are computed from definition_json by HookWorkflowDefinitionPrefilter and used by FindMatchingDefinitions to reduce the candidate set before reading the full JSON and evaluating triggers.

Key properties:

  • Intentionally lossy: trigger_fields is a union across triggers and does not preserve per-trigger pairing.
  • Selectors and trigger expressions are not represented.
  • If any trigger omits fields/edges, trigger_fields is cleared (nil) to avoid false negatives.
  • The JSON definition remains the source of truth; prefiltering only excludes impossible matches.

Safe exclusion criteria:

  • eventType not in trigger_operations.
  • trigger_fields is non-empty and has no overlap with changed fields/edges.
Event Listeners
Listener Event Purpose
HandleWorkflowTriggered WorkflowTriggered Process newly triggered instance, start first action
HandleActionStarted ActionStarted Execute the action (approval, notify, etc.)
HandleActionCompleted ActionCompleted Advance to next action or complete workflow
HandleAssignmentCompleted AssignmentCompleted Check quorum, resume workflow if satisfied
HandleInstanceCompleted InstanceCompleted Mark instance as completed/failed
Workflow Engine
Component Purpose
engine.go Core engine: FindMatchingDefinitions, TriggerWorkflow, ProcessAction
executor.go Action executors: APPROVAL, NOTIFY, FIELD_UPDATE, WEBHOOK, etc
evaluator.go CEL expression evaluation for conditions and When clauses
resolver.go Target resolution (users, groups, custom resolvers)
listeners.go Event handlers and workflow state management

Approval Invalidation

When a WorkflowProposal's changes are modified after approvals have been given:

  1. HookWorkflowProposalInvalidateAssignments detects the change
  2. All APPROVED assignments are reset to PENDING
  3. Invalidation metadata is recorded (who, when, hash diff)
  4. Affected users are notified
  5. Re-approval is required

This implements GitHub-style "dismiss stale reviews" behavior.

Adding Workflow Support to a Schema

  1. Add the WorkflowApprovalMixin to your schema:
func (Policy) Mixin() []ent.Mixin {
    return []ent.Mixin{
        // ... other mixins
        WorkflowApprovalMixin{},
    }
}
  1. Register eligible fields in the workflow metadata (use the entx annotation)
  2. Add edges from WorkflowObjectRef schema if they don't already exist
  3. Run code generation / task regenerate, merge the output / changes
  4. Create workflow definitions targeting your schema type and test it out

Workflow Definition Structure

There are a few examples included in this package, and you can find the types in our models if you want to look at all the various fields, but here's a representative example of policy approvals:

{
  "name": "Policy Approval Workflow",
  "schemaType": "Policy",
  "workflowKind": "APPROVAL",
  "approvalSubmissionMode": "AUTO_SUBMIT",
  "triggers": [
    {
      "operation": "UPDATE",
      "fields": ["description", "details"],
      "expression": "object.status == 'PUBLISHED'"
    }
  ],
  "conditions": [
    {
      "expression": "object.category != 'INTERNAL'"
    }
  ],
  "actions": [
    {
      "key": "manager_approval",
      "type": "APPROVAL",
      "params": {
        "targets": [{"type": "RESOLVER", "resolver_key": "object_owner"}],
        "required_count": 1
      }
    },
    {
      "key": "notify_team",
      "type": "NOTIFICATION",
      "when": "assignments.approved >= 1",
      "params": {
        "targets": [{"type": "GROUP", "id": "policy-team-group-id"}],
        "title": "Policy {{object.name}} approved",
        "body": "The policy has been approved and changes applied."
      }
    }
  ]
}

Events and Event Topics

These are the “statuses” stored in workflow_events.event_type and payload.event_type. We only persist business-facing snapshots plus emit failure tracking. Runtime flow still uses soiree topics (WorkflowTriggered, ActionStarted, AssignmentCompleted, etc.), but not all topics are persisted.

WorkflowEventType Written by (code) Meaning / status Readers / relies-on
WORKFLOW_TRIGGERED HandleWorkflowTriggered (internal/workflows/engine/eventhandlers.go) Snapshot of the trigger context (definition_id, object, trigger) UI timeline; GraphQL filters
ASSIGNMENT_CREATED recordAssignmentsCreated (internal/workflows/engine/emit.go) Batch approval assignment creation (assignment_ids, target_user_ids, required_count) UI timeline; GraphQL filters
ACTION_COMPLETED HandleActionCompleted + HandleAssignmentCompleted Action outcome snapshot. Details include success, skipped, error_message and (for approvals) counts + assignment ids UI timeline; tests
WORKFLOW_COMPLETED HandleInstanceCompleted Final instance state (COMPLETED/FAILED) UI timeline; tests
EMIT_FAILED recordEmitFailure (internal/workflows/engine/emit.go) Emit enqueue failure; stores EmitFailureDetails Reconciler retries
EMIT_RECOVERED Reconciler.updateWorkflowEvent Emit retry succeeded Tests / GraphQL filters only
EMIT_FAILED_TERMINAL Reconciler.markTerminal Emit retry exhausted; instance state set to Failed Tests / GraphQL filters only

Legacy event types like ACTION_STARTED, ACTION_FAILED, ACTION_SKIPPED, ASSIGNMENT_RESOLVED, INSTANCE_PAUSED, and INSTANCE_RESUMED are no longer persisted; their outcomes are represented via ACTION_COMPLETED details or are purely runtime concerns.


Detailed Architecture Diagrams

The following mermaid diagrams illustrate the various flows and permutations supported by the workflow system.

Pre-Commit Approval Flow (Detailed)

This diagram shows what happens when a user updates a field that requires approval.

sequenceDiagram
    autonumber
    participant User
    participant API as GraphQL API
    participant Hook as HookWorkflowApprovalRouting
    participant Engine as WorkflowEngine
    participant DB as Database
    participant Bus as Event Bus
    participant Listener as Event Listeners

    User->>API: UpdateControl(reference_id: "NEW-123")
    API->>Hook: Pre-commit hook fires

    Note over Hook: Check for workflow bypass context
    Hook->>Engine: FindMatchingDefinitions(Control, UPDATE, [reference_id])
    Engine->>DB: Query WorkflowDefinition (prefiltered)
    DB-->>Engine: Matching definitions with APPROVAL actions

    alt Has approval actions for these fields
        Hook->>DB: Create WorkflowProposal(state: DRAFT/SUBMITTED)
        Hook->>DB: Create WorkflowObjectRef(control_id)
        Hook->>DB: Create WorkflowInstance(state: RUNNING, proposal_id)

        Note over Hook: Strip workflow fields from mutation
        Hook-->>API: Return entity with ORIGINAL values

        alt Auto-Submit Mode
            Hook->>Bus: Emit WorkflowTriggered
            Bus->>Listener: HandleWorkflowTriggered
            Listener->>Engine: Process instance, create assignments
            Engine->>DB: Create WorkflowAssignment(s)
            Engine->>DB: Create WorkflowAssignmentTarget(s)
            Engine->>DB: Update instance state: PAUSED
        else Manual Submit Mode
            Note over Hook: Proposal stays in DRAFT
            Note over Hook: User must explicitly submit
        end
    else No approval actions
        Hook-->>API: Proceed with mutation normally
        API->>DB: Commit changes
        API->>Bus: Emit mutation event
    end
Multi-Approver Quorum Flow

When a workflow requires multiple approvers with a quorum threshold.

sequenceDiagram
    autonumber
    participant User1 as Approver 1
    participant User2 as Approver 2
    participant User3 as Approver 3
    participant API as GraphQL API
    participant Engine as WorkflowEngine
    participant DB as Database

    Note over DB: Proposal requires 2 of 3 approvers<br/>(required_count: 2)

    rect rgb(240, 248, 255)
        Note right of DB: Initial State: 3 PENDING assignments
    end

    User1->>API: Approve assignment
    API->>Engine: CompleteAssignment(status: APPROVED)
    Engine->>DB: Update assignment status: APPROVED
    Engine->>Engine: Check quorum: 1 approved, 2 pending

    rect rgb(255, 255, 224)
        Note right of Engine: Quorum NOT met (1 < 2)<br/>Workflow remains PAUSED
    end

    User2->>API: Approve assignment
    API->>Engine: CompleteAssignment(status: APPROVED)
    Engine->>DB: Update assignment status: APPROVED
    Engine->>Engine: Check quorum: 2 approved, 1 pending

    rect rgb(224, 255, 224)
        Note right of Engine: Quorum MET (2 >= 2)<br/>Apply proposal changes
    end

    Engine->>DB: Apply proposal to Control
    Engine->>DB: Update proposal state: APPLIED
    Engine->>DB: Update instance state: COMPLETED

    rect rgb(245, 245, 245)
        Note right of DB: User3's assignment remains PENDING<br/>(late approval will be no-op)
    end

    User3->>API: Approve assignment (late)
    API->>Engine: CompleteAssignment(status: APPROVED)
    Engine->>DB: Update assignment status: APPROVED
    Note over Engine: Workflow already completed<br/>No additional effects
Multiple Concurrent Workflow Instances

When a single mutation triggers multiple workflow definitions.

flowchart TB
    subgraph "Single Mutation"
        Mutation["UpdateControl(reference_id, status)"]
    end

    subgraph "Matching Definitions"
        Def1["Definition 1<br/>Fields: [reference_id]<br/>Approvers: Team A"]
        Def2["Definition 2<br/>Fields: [status]<br/>Approvers: Team B"]
        Def3["Definition 3<br/>Fields: [reference_id, status]<br/>Approvers: Compliance"]
    end

    subgraph "Created Instances"
        Inst1["Instance 1<br/>Domain: reference_id<br/>State: PAUSED"]
        Inst2["Instance 2<br/>Domain: status<br/>State: PAUSED"]
        Inst3["Instance 3<br/>Domain: reference_id,status<br/>State: PAUSED"]
    end

    subgraph "Proposals"
        Prop1["Proposal 1<br/>Changes: {reference_id: NEW}"]
        Prop2["Proposal 2<br/>Changes: {status: APPROVED}"]
        Prop3["Proposal 3<br/>Changes: {reference_id: NEW, status: APPROVED}"]
    end

    subgraph "Assignments"
        Assign1A["Assignment: Team A Member 1"]
        Assign1B["Assignment: Team A Member 2"]
        Assign2A["Assignment: Team B Member 1"]
        Assign3A["Assignment: Compliance Officer"]
    end

    Mutation --> Def1
    Mutation --> Def2
    Mutation --> Def3

    Def1 --> Inst1
    Def2 --> Inst2
    Def3 --> Inst3

    Inst1 --> Prop1
    Inst2 --> Prop2
    Inst3 --> Prop3

    Inst1 --> Assign1A
    Inst1 --> Assign1B
    Inst2 --> Assign2A
    Inst3 --> Assign3A
Domain-Based Approval Isolation

Different field sets create separate approval domains, allowing concurrent workflows on the same object.

flowchart TB
    subgraph "Control Object"
        Control["Control CTL-001"]
        Field1["reference_id: REF-OLD"]
        Field2["status: DRAFT"]
        Field3["category: Technical"]
    end

    subgraph "Domain 1: Reference ID Changes"
        D1Def["Definition: Ref ID Approval<br/>Fields: [reference_id]"]
        D1Prop["Proposal 1<br/>domain_key: Control:reference_id<br/>changes: {reference_id: REF-NEW}"]
        D1Inst["Instance 1<br/>State: PAUSED"]
        D1Assign["Approver: Finance Team"]
    end

    subgraph "Domain 2: Status Changes"
        D2Def["Definition: Status Approval<br/>Fields: [status]"]
        D2Prop["Proposal 2<br/>domain_key: Control:status<br/>changes: {status: APPROVED}"]
        D2Inst["Instance 2<br/>State: PAUSED"]
        D2Assign["Approver: Compliance Team"]
    end

    Control --> D1Def
    Control --> D2Def

    D1Def --> D1Inst --> D1Prop
    D1Inst --> D1Assign

    D2Def --> D2Inst --> D2Prop
    D2Inst --> D2Assign

    Note1["These workflows proceed independently.<br/>Approving one does not affect the other."]
Post-Commit Notification Flow

For workflows that react to changes (no approval required).

sequenceDiagram
    autonumber
    participant User
    participant API as GraphQL API
    participant DB as Database
    participant Bus as Event Bus
    participant Listener as HandleWorkflowMutation
    participant Engine as WorkflowEngine
    participant Webhook as External Webhook

    User->>API: UpdateControl(status: APPROVED)
    API->>DB: Commit changes
    API->>Bus: Emit mutation event

    Bus->>Listener: HandleWorkflowMutation(payload)
    Listener->>Engine: FindMatchingDefinitions(Control, UPDATE, [status])
    Engine-->>Listener: [NotificationWorkflowDef]

    loop For each matching definition
        Listener->>Engine: TriggerWorkflow(def, object)
        Engine->>DB: Create WorkflowInstance(state: RUNNING)

        Note over Engine: Process actions sequentially

        Engine->>Engine: Execute NOTIFICATION action
        Engine->>DB: Record notification sent

        Engine->>Engine: Execute WEBHOOK action
        Engine->>Webhook: POST /webhook (payload)
        Webhook-->>Engine: 200 OK

        Engine->>DB: Update instance state: COMPLETED
    end
Parallel Approval Actions

When a workflow has multiple independent approval actions that execute concurrently.

sequenceDiagram
    autonumber
    participant Hook as Trigger Hook
    participant Engine as WorkflowEngine
    participant DB as Database
    participant User1 as Legal Approver
    participant User2 as Finance Approver

    Hook->>Engine: TriggerWorkflow(multi-approval-def)
    Engine->>DB: Create WorkflowInstance

    Note over Engine: Detect multiple approval actions<br/>with independent "when" conditions

    par Create all approval assignments concurrently
        Engine->>DB: Create Assignment (Legal Review)
        Engine->>DB: Create AssignmentTarget (User1)
    and
        Engine->>DB: Create Assignment (Finance Review)
        Engine->>DB: Create AssignmentTarget (User2)
    end

    Engine->>DB: Store parallel_approval_keys in instance context
    Engine->>DB: Update instance state: PAUSED

    Note over DB: Both approvals must complete<br/>before workflow can proceed

    User1->>Engine: Approve (Legal Review)
    Engine->>DB: Update assignment: APPROVED
    Engine->>Engine: Check: All parallel approvals satisfied?
    Note over Engine: NO - Finance still pending

    User2->>Engine: Approve (Finance Review)
    Engine->>DB: Update assignment: APPROVED
    Engine->>Engine: Check: All parallel approvals satisfied?
    Note over Engine: YES - Both approved

    Engine->>DB: Apply proposal changes
    Engine->>DB: Update instance state: COMPLETED
Approval Invalidation Flow

When a proposal is edited after approvals have been given.

sequenceDiagram
    autonumber
    participant Editor as Proposal Editor
    participant Hook as HookWorkflowProposalInvalidateAssignments
    participant DB as Database
    participant Approver as Previous Approver

    Note over DB: Proposal State: SUBMITTED<br/>Assignment 1: APPROVED (hash: abc123)<br/>Assignment 2: PENDING

    Editor->>DB: Update proposal changes
    DB->>Hook: Pre-commit hook fires

    Hook->>Hook: Detect state == SUBMITTED
    Hook->>Hook: Compare old hash vs new hash
    Note over Hook: Hash changed: abc123 != def456

    Hook->>DB: Query APPROVED assignments

    loop For each APPROVED assignment
        Hook->>DB: Reset status to PENDING
        Hook->>DB: Record invalidation metadata
        Note over DB: {reason: "proposal changes edited",<br/>previous_hash: abc123,<br/>invalidated_at: now}
    end

    Hook->>DB: Commit proposal update

    Note over Approver: Notification: "Your approval<br/>has been invalidated due to<br/>proposal changes. Please re-review."
Concurrent Approval Race Condition Handling

How the engine handles concurrent approval submissions.

sequenceDiagram
    autonumber
    participant User1 as Approver 1
    participant User2 as Approver 2
    participant Engine as WorkflowEngine
    participant DB as Database

    Note over DB: Workflow requires 2 approvals<br/>Both users click "Approve" simultaneously

    par Concurrent approval requests
        User1->>Engine: CompleteAssignment(assignment1, APPROVED)
    and
        User2->>Engine: CompleteAssignment(assignment2, APPROVED)
    end

    Note over Engine: Race condition: both check quorum

    Engine->>DB: Update assignment1: APPROVED
    Engine->>DB: Update assignment2: APPROVED

    par Both check quorum satisfaction
        Engine->>Engine: Check quorum (Thread 1)
        Note over Engine: 2 approved >= 2 required<br/>Attempt to apply proposal
    and
        Engine->>Engine: Check quorum (Thread 2)
        Note over Engine: 2 approved >= 2 required<br/>Attempt to apply proposal
    end

    Note over Engine: Idempotent completion logic

    Engine->>DB: Apply proposal (Thread 1 wins)
    Engine->>DB: Update instance: COMPLETED

    Note over Engine: Thread 2 sees instance already COMPLETED<br/>No duplicate application

    Engine->>DB: Record single INSTANCE_COMPLETED event
Event Emission and Recovery

How the system handles event emission failures and recovery.

sequenceDiagram
    autonumber
    participant Engine as WorkflowEngine
    participant Bus as Event Bus
    participant DB as Database
    participant Reconciler as Reconciler

    Engine->>Bus: Emit(WorkflowTriggered)

    alt Emit succeeds
        Bus-->>Engine: Success
        Note over Engine: Continue normally
    else Emit fails (queue unavailable)
        Bus-->>Engine: Error: enqueue failed
        Engine->>DB: Record WorkflowEvent<br/>type: EMIT_FAILED<br/>details: {topic, payload, attempts: 1}
        Note over Engine: Workflow instance created<br/>but event not published
    end

    Note over Reconciler: Periodic reconciliation job

    Reconciler->>DB: Query EMIT_FAILED events
    DB-->>Reconciler: [failed_event_1, ...]

    loop For each failed event
        Reconciler->>Bus: Retry emit(payload)

        alt Retry succeeds
            Bus-->>Reconciler: Success
            Reconciler->>DB: Record EMIT_RECOVERED event
            Reconciler->>DB: Delete EMIT_FAILED event
        else Retry fails
            alt attempts < max_attempts
                Reconciler->>DB: Update EMIT_FAILED<br/>attempts: attempts + 1
            else attempts >= max_attempts
                Reconciler->>DB: Record EMIT_FAILED_TERMINAL
                Reconciler->>DB: Update instance state: FAILED
            end
        end
    end
Field Eligibility and Proposal Routing

How the system determines which fields can be workflow-controlled.

flowchart TB
    subgraph "Schema Definition"
        Schema["Control Schema<br/>with WorkflowApprovalMixin"]
        Fields["Fields:<br/>- reference_id (workflow_eligible: true)<br/>- status (workflow_eligible: true)<br/>- description (workflow_eligible: false)<br/>- created_at (workflow_eligible: false)"]
    end

    subgraph "Mutation Request"
        Mutation["UpdateControl(<br/>  reference_id: NEW,<br/>  description: Updated<br/>)"]
    end

    subgraph "Hook Analysis"
        Check1{All changed fields<br/>workflow eligible?}
        Check2[Eligible: reference_id]
        Check3[Ineligible: description]
    end

    subgraph "Routing Decision"
        Route1["ERROR: ErrWorkflowIneligibleField<br/>Cannot mix eligible and ineligible<br/>fields in same mutation"]
        Route2["Route to WorkflowProposal<br/>Changes: {reference_id: NEW}"]
        Route3["Apply directly<br/>(no workflow)"]
    end

    Schema --> Fields
    Mutation --> Check1
    Check1 -->|Mixed| Route1
    Check1 -->|All eligible| Check2 --> Route2
    Check1 -->|All ineligible| Check3 --> Route3

Documentation

Overview

Package workflows provides minimal registry types for workflow ent templates

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrWorkflowNotFound is returned when a workflow instance cannot be found
	ErrWorkflowNotFound = errors.New("workflow instance not found")
	// ErrNoProposedChanges is returned when attempting to apply changes but none exist
	ErrNoProposedChanges = errors.New("no proposed changes to apply")
	// ErrWorkflowAlreadyActive is returned when trying to start a workflow on an object that already has one
	ErrWorkflowAlreadyActive = errors.New("workflow already active for this object")
	// ErrInvalidWorkflowState is returned when a workflow operation is attempted on an instance in an invalid state
	ErrInvalidWorkflowState = errors.New("invalid workflow state for this operation")
	// ErrInsufficientApprovals is returned when trying to complete a workflow without required approvals
	ErrInsufficientApprovals = errors.New("insufficient approvals to complete workflow")
	// ErrUnauthorizedApproval is returned when a user attempts to approve a workflow they're not assigned to
	ErrUnauthorizedApproval = errors.New("user not authorized to approve this workflow")
	// ErrFieldNotWorkflowEligible is returned when proposed changes include non-eligible fields
	ErrFieldNotWorkflowEligible = errors.New("field is not eligible for workflow modification")
	// ErrUnsupportedObjectType is returned when a workflow is triggered for an unsupported object type
	ErrUnsupportedObjectType = errors.New("object type does not support workflows")
	// ErrMissingObjectID is returned when a workflow object is missing an ID
	ErrMissingObjectID = errors.New("workflow object is missing an ID")
	// ErrFailedToBuildCELEnv is returned when the CEL environment cannot be built
	ErrFailedToBuildCELEnv = errors.New("failed to build CEL environment")
	// ErrEmitFailureDetailsMissing is returned when emit failure details are empty
	ErrEmitFailureDetailsMissing = errors.New("emit failure details are missing")
	// ErrEmitNoEmitter is returned when an emitter is required but missing
	ErrEmitNoEmitter = errors.New("workflow emit requires an emitter")
	// ErrNilClient is returned when a workflow helper requires a client
	ErrNilClient = errors.New("workflow client is required")
	// ErrMissingOrganizationID is returned when an organization id is required
	ErrMissingOrganizationID = errors.New("organization id is required")
	// ErrApprovalActionParamsInvalid is returned when approval action params are invalid
	ErrApprovalActionParamsInvalid = errors.New("approval action params are invalid")
	// ErrStringFieldMarshal is returned when string field extraction cannot marshal the node
	ErrStringFieldMarshal = errors.New("failed to marshal node for string field extraction")
	// ErrStringFieldUnmarshal is returned when string field extraction cannot unmarshal the node
	ErrStringFieldUnmarshal = errors.New("failed to unmarshal node for string field extraction")
	// ErrStringFieldNil is returned when string field extraction receives a nil node
	ErrStringFieldNil = errors.New("string field node is nil")
	// ErrStringSliceFieldInvalid is returned when a string slice field contains non-string values
	ErrStringSliceFieldInvalid = errors.New("string slice field contains non-string values")
)
View Source
var (
	// ErrTxBegin indicates the transaction failed to start.
	ErrTxBegin = errors.New("failed to begin transaction")
	// ErrTxCommit indicates the transaction failed to commit.
	ErrTxCommit = errors.New("failed to commit transaction")
)

Functions

func AllowBypassContext added in v1.4.0

func AllowBypassContext(ctx context.Context) context.Context

AllowBypassContext sets workflow bypass and allow decision for internal workflow operations.

func AllowBypassContextWithOrg added in v1.4.0

func AllowBypassContextWithOrg(ctx context.Context) (context.Context, string, error)

AllowBypassContextWithOrg returns an allow/bypass context plus the organization ID.

func AllowContext added in v1.4.0

func AllowContext(ctx context.Context) context.Context

AllowContext sets the ent privacy decision to allow for internal workflow operations. It also sets the internal request marker so FGA checks are bypassed.

func AllowContextWithOrg added in v1.4.0

func AllowContextWithOrg(ctx context.Context) (context.Context, string, error)

AllowContextWithOrg returns an allow context plus the organization ID.

func ApplyObjectFieldUpdates added in v1.3.3

func ApplyObjectFieldUpdates(ctx context.Context, client *generated.Client, objectType enums.WorkflowObjectType, objectID string, updates map[string]any) error

ApplyObjectFieldUpdates applies updates to a workflow object via generated helpers.

func ApprovalDomains added in v1.5.3

func ApprovalDomains(doc models.WorkflowDefinitionDocument) ([][]string, error)

ApprovalDomains returns the distinct field sets used by approval actions in a definition It returns an error when approval action params cannot be parsed

func BuildAssignmentContext added in v1.3.3

func BuildAssignmentContext(ctx context.Context, client *generated.Client, instanceID string) (map[string]any, error)

BuildAssignmentContext calls the registered assignment context builder to get workflow runtime state. Returns nil if no builder is registered or instanceID is empty.

func BuildCELVars added in v1.3.3

func BuildCELVars(obj *Object, changedFields []string, changedEdges []string, addedIDs, removedIDs map[string][]string, eventType, userID string, proposedChanges map[string]any) map[string]any

BuildCELVars constructs the activation map for CEL evaluation, allowing generated builders to provide typed contexts instead of ad-hoc maps

func BuildProposedChanges added in v1.5.3

func BuildProposedChanges(m utils.GenericMutation, changedFields []string) map[string]any

BuildProposedChanges materializes mutation values (including cleared fields) for workflow proposals.

func BuildWorkflowActionContext added in v1.5.3

func BuildWorkflowActionContext(instance *generated.WorkflowInstance, obj *Object, actionKey string) (map[string]string, map[string]any)

BuildWorkflowActionContext returns the replacement map and base data for notifications/webhooks.

func CollectAllChangedFields added in v1.5.10

func CollectAllChangedFields(m utils.GenericMutation) []string

CollectAllChangedFields returns the union of modified and cleared fields from a mutation without filtering by workflow eligibility.

func CollectChangedFields added in v1.5.3

func CollectChangedFields(m utils.GenericMutation) []string

CollectChangedFields returns the union of modified and cleared fields from a mutation, filtered to only include fields eligible for workflow processing.

func ComputeProposalHash added in v1.5.3

func ComputeProposalHash(changes map[string]any) (string, error)

ComputeProposalHash computes a SHA256 hash of a changes map with sorted keys

func CreateWorkflowInstanceWithObjectRef added in v1.5.3

func CreateWorkflowInstanceWithObjectRef(ctx context.Context, tx *generated.Tx, params WorkflowInstanceBuilderParams) (*generated.WorkflowInstance, *generated.WorkflowObjectRef, error)

CreateWorkflowInstanceWithObjectRef builds a workflow instance and its object ref in a single helper.

func DefinitionHasApprovalAction added in v1.5.3

func DefinitionHasApprovalAction(doc models.WorkflowDefinitionDocument) bool

DefinitionHasApprovalAction returns true if the workflow definition contains at least one approval action

func DefinitionMatchesTrigger added in v1.5.3

func DefinitionMatchesTrigger(doc models.WorkflowDefinitionDocument, eventType string, changedFields []string) bool

DefinitionMatchesTrigger reports whether the workflow definition has a trigger that matches the event type and changed fields.

func DeriveDomainKey added in v1.5.3

func DeriveDomainKey(objectType enums.WorkflowObjectType, fields []string) string

DeriveDomainKey generates a stable domain key from a sorted list of field names. A "domain key" is a canonicalized list of approval fields scoped to the object type. Format: "ObjectType:field1,field2" (fields are sorted); if fields are empty, returns the object type string.

func DeriveTriggerPrefilter added in v1.5.3

func DeriveTriggerPrefilter(doc models.WorkflowDefinitionDocument) ([]string, []string)

DeriveTriggerPrefilter extracts normalized trigger operations and fields/edges for query prefiltering. If any trigger omits fields/edges, field prefiltering is disabled

func EligibleWorkflowFields added in v1.5.3

func EligibleWorkflowFields(objectType enums.WorkflowObjectType) map[string]struct{}

EligibleWorkflowFields returns the set of fields eligible for workflow processing for a given object type.

func FieldsFromChanges added in v1.5.3

func FieldsFromChanges(changes map[string]any) []string

FieldsFromChanges returns the sorted field names present in a changes map

func FilterChangesForDomain added in v1.5.3

func FilterChangesForDomain(changes map[string]any, approvalFields []string) map[string]any

FilterChangesForDomain filters a mutation's changes to only include fields that belong to the specified approval domain

func FindProposalForObjectRefs added in v1.5.3

func FindProposalForObjectRefs(ctx context.Context, client *generated.Client, objRefIDs []string, domainKey string, priorityStates []enums.WorkflowProposalState, states []enums.WorkflowProposalState) (*generated.WorkflowProposal, error)

FindProposalForObjectRefs locates a workflow proposal for the given object refs and domain key. The lookup first honors priorityStates (each queried individually) before falling back to states (queried together).

func GetObjectUpdatedBy added in v1.5.10

func GetObjectUpdatedBy(obj *Object) string

GetObjectUpdatedBy extracts the UpdatedBy field from an Object's Node if available. Returns empty string if the object or node is nil, or if UpdatedBy is not accessible.

func IsWorkflowBypass added in v1.4.0

func IsWorkflowBypass(ctx context.Context) bool

IsWorkflowBypass checks if the context has workflow bypass enabled Used by workflow interceptors to skip approval routing for system operations

func LoadWorkflowObject added in v1.3.3

func LoadWorkflowObject(ctx context.Context, client *generated.Client, schemaType string, objectID string) (any, error)

LoadWorkflowObject loads an ent object that participates in workflows.

func MarkSkipEventEmission added in v1.5.10

func MarkSkipEventEmission(ctx context.Context)

MarkSkipEventEmission marks the context to skip emitting mutation events.

func MutationClient added in v1.5.10

func MutationClient(ctx *soiree.EventContext, payload *MutationPayload) *generated.Client

MutationClient returns the ent client associated with the mutation.

func MutationEntityID added in v1.5.10

func MutationEntityID(ctx *soiree.EventContext, payload *MutationPayload) (string, bool)

MutationEntityID derives the entity identifier from the payload or event properties.

func NewCELEnvWithConfig added in v1.4.0

func NewCELEnvWithConfig(cfg *Config) (*cel.Env, error)

NewCELEnv builds the workflow CEL environment using the provided config

func NewCelEnv added in v1.4.0

func NewCelEnv(opts ...ConfigOpts) (*cel.Env, error)

NewCelEnv builds the workflow CEL environment using the provided options parameters

func NormalizeStrings added in v1.5.3

func NormalizeStrings(input []string) []string

NormalizeStrings filters empty strings and returns unique values

func ObjectOwnerID added in v1.3.3

func ObjectOwnerID(ctx context.Context, client *generated.Client, objectType enums.WorkflowObjectType, objectID string) (string, error)

ObjectOwnerID resolves the owner ID for a workflow object via generated helpers.

func ObjectRefIDs added in v1.5.3

func ObjectRefIDs(ctx context.Context, client *generated.Client, obj *Object) ([]string, error)

ObjectRefIDs returns workflow object ref IDs matching the workflow object.

func OrganizationOwnerIDs added in v1.3.3

func OrganizationOwnerIDs(ctx context.Context, client *generated.Client, orgID string) ([]string, error)

OrganizationOwnerIDs returns user IDs for owners of an organization.

func RegisterAssignmentContextBuilder

func RegisterAssignmentContextBuilder(builder AssignmentContextBuilder)

RegisterAssignmentContextBuilder sets the assignment context builder for CEL evaluation. Only one builder is needed since the generated code provides a comprehensive implementation.

func RegisterCELContextBuilder

func RegisterCELContextBuilder(builder CELContextBuilder)

RegisterCELContextBuilder adds a CEL context builder. Last registered wins.

func RegisterEligibleFields added in v1.5.10

func RegisterEligibleFields(fields map[enums.WorkflowObjectType]map[string]struct{})

RegisterEligibleFields sets the eligible fields registry from generated code.

func RegisterObjectRefQueryBuilder

func RegisterObjectRefQueryBuilder(builder ObjectRefQueryBuilder)

RegisterObjectRefQueryBuilder adds a WorkflowObjectRef query builder to the registry.

func RegisterObjectRefResolver

func RegisterObjectRefResolver(resolver func(*generated.WorkflowObjectRef) (*Object, bool))

RegisterObjectRefResolver adds a resolver to the registry.

func RegisterObservabilityFieldsBuilder added in v1.5.10

func RegisterObservabilityFieldsBuilder(builder ObservabilityFieldsBuilder)

RegisterObservabilityFieldsBuilder sets the observability fields builder.

func ResolveOwnerID added in v1.5.3

func ResolveOwnerID(ctx context.Context, ownerID string) (string, error)

ResolveOwnerID returns the provided owner ID or derives it from the context when empty.

func ResolveUserDisplayName added in v1.5.10

func ResolveUserDisplayName(ctx context.Context, client *generated.Client, userID string) string

ResolveUserDisplayName fetches a user by ID and returns their display name (FirstName LastName). If the user cannot be found or has no name, returns the original userID as fallback.

func ShouldSkipEventEmission added in v1.5.10

func ShouldSkipEventEmission(ctx context.Context) bool

ShouldSkipEventEmission reports whether mutation event emission should be skipped.

func StringField added in v1.3.3

func StringField(node any, field string) (string, error)

StringField extracts a string field by name from a struct or pointer to struct It returns an error when decoding fails

func StringSliceField added in v1.5.3

func StringSliceField(node any, field string) ([]string, error)

StringSliceField extracts a string slice field by name from a struct or pointer to struct It returns an error when decoding fails

func ValidateCELExpression added in v1.5.3

func ValidateCELExpression(expression string) error

ValidateCELExpression ensures the expression compiles against the standard workflow CEL environment.

func WithContext added in v1.4.0

func WithContext(ctx context.Context) context.Context

WithContext sets the workflow bypass context Operations with this context will skip workflow approval interceptors

func WithSkipEventEmission added in v1.5.10

func WithSkipEventEmission(ctx context.Context) context.Context

WithSkipEventEmission installs a mutable flag in the context so inner hooks can signal that mutation events should not be emitted via MarkSkipEventEmission.

func WithTx added in v1.5.10

func WithTx[T any](ctx context.Context, client *generated.Client, scope *observability.Scope, fn func(tx *generated.Tx) (T, error)) (T, error)

WithTx runs fn inside a transaction and ensures rollback on error.

func WorkflowMetadata added in v1.3.3

func WorkflowMetadata() []generated.WorkflowObjectTypeInfo

WorkflowMetadata returns generated workflow-eligible schema metadata.

Types

type ApprovalActionParams added in v1.5.3

type ApprovalActionParams struct {
	// TargetedActionParams identifies the approval recipients
	TargetedActionParams
	// Required defaults to true when omitted
	Required *bool `json:"required"`
	// Label is an optional display label for the approval action
	Label string `json:"label"`
	// RequiredCount sets a quorum threshold (number of approvals needed) for this action
	RequiredCount int `json:"required_count"`
	// Fields lists the approval-gated fields for domain derivation
	Fields []string `json:"fields,omitempty"`
}

ApprovalActionParams defines params for APPROVAL actions

type AssignmentContextBuilder

type AssignmentContextBuilder func(ctx context.Context, client *generated.Client, instanceID string) (map[string]any, error)

AssignmentContextBuilder builds workflow runtime context (assignments, instance, initiator) for CEL evaluation. Generated code registers this to provide assignment state when evaluating NOTIFY action When expressions.

type CELConfig added in v1.4.0

type CELConfig struct {
	// Timeout is the maximum duration allowed for evaluating a CEL expression
	Timeout time.Duration `json:"timeout" koanf:"timeout" default:"100ms"`
	// CostLimit caps the runtime cost of CEL evaluation, 0 disables the limit
	CostLimit uint64 `json:"costlimit" koanf:"costlimit" default:"0"`
	// InterruptCheckFrequency controls how often CEL checks for interrupts during comprehensions
	InterruptCheckFrequency uint `json:"interruptcheckfrequency" koanf:"interruptcheckfrequency" default:"100"`
	// ParserRecursionLimit caps the parser recursion depth, 0 uses CEL defaults
	ParserRecursionLimit int `json:"parserrecursionlimit" koanf:"parserrecursionlimit" default:"250"`
	// ParserExpressionSizeLimit caps expression size (code points), 0 uses CEL defaults
	ParserExpressionSizeLimit int `json:"parserexpressionsizelimit" koanf:"parserexpressionsizelimit" default:"100000"`
	// ComprehensionNestingLimit caps nested comprehensions, 0 disables the check
	ComprehensionNestingLimit int `json:"comprehensionnestinglimit" koanf:"comprehensionnestinglimit" default:"0"`
	// ExtendedValidations enables extra AST validations (regex, duration, timestamps, homogeneous aggregates)
	ExtendedValidations bool `json:"extendedvalidations" koanf:"extendedvalidations" default:"true"`
	// OptionalTypes enables CEL optional types and optional field syntax
	OptionalTypes bool `json:"optionaltypes" koanf:"optionaltypes" default:"false"`
	// IdentifierEscapeSyntax enables backtick escaped identifiers
	IdentifierEscapeSyntax bool `json:"identifierescapesyntax" koanf:"identifierescapesyntax" default:"false"`
	// CrossTypeNumericComparisons enables comparisons across numeric types
	CrossTypeNumericComparisons bool `json:"crosstypenumericcomparisons" koanf:"crosstypenumericcomparisons" default:"false"`
	// MacroCallTracking records macro calls in AST source info for debugging
	MacroCallTracking bool `json:"macrocalltracking" koanf:"macrocalltracking" default:"false"`
	// EvalOptimize enables evaluation-time optimizations for repeated program runs
	EvalOptimize bool `json:"evaloptimize" koanf:"evaloptimize" default:"true"`
	// TrackState enables evaluation state tracking for debugging
	TrackState bool `json:"trackstate" koanf:"trackstate" default:"false"`
}

CELConfig contains CEL evaluation and validation settings for workflows

type CELContextBuilder

type CELContextBuilder func(obj *Object, changedFields []string, changedEdges []string, addedIDs, removedIDs map[string][]string, eventType, userID string, proposedChanges map[string]any) map[string]any

CELContextBuilder can override how CEL activation variables are built per object type. Codegen can register specialized builders (e.g., to expose typed fields) by calling RegisterCELContextBuilder in an init() function.

type Config added in v1.4.0

type Config struct {
	// Enabled determines if the workflows engine is enabled
	Enabled bool `json:"enabled" koanf:"enabled" default:"false"`
	// CEL contains configuration for CEL evaluation and validation
	CEL CELConfig `json:"cel" koanf:"cel"`
}

Config contains the configuration for the workflows engine

func NewDefaultConfig added in v1.4.0

func NewDefaultConfig(opts ...ConfigOpts) *Config

NewDefaultConfig creates a new workflows config with default values applied.

func (*Config) IsEnabled added in v1.4.0

func (c *Config) IsEnabled() bool

IsEnabled checks if the workflows feature is enabled

type ConfigOpts added in v1.4.0

type ConfigOpts func(*Config)

ConfigOpts configures the Config

func WithCELComprehensionNestingLimit added in v1.4.0

func WithCELComprehensionNestingLimit(limit int) ConfigOpts

WithCELComprehensionNestingLimit sets the CEL comprehension nesting limit

func WithCELCostLimit added in v1.4.0

func WithCELCostLimit(limit uint64) ConfigOpts

WithCELCostLimit sets the CEL cost limit

func WithCELCrossTypeNumericComparisons added in v1.4.0

func WithCELCrossTypeNumericComparisons(enabled bool) ConfigOpts

WithCELCrossTypeNumericComparisons toggles CEL cross-type numeric comparisons

func WithCELEvalOptimize added in v1.4.0

func WithCELEvalOptimize(enabled bool) ConfigOpts

WithCELEvalOptimize toggles CEL evaluation optimizations

func WithCELExtendedValidations added in v1.4.0

func WithCELExtendedValidations(enabled bool) ConfigOpts

WithCELExtendedValidations toggles CEL extended validations

func WithCELIdentifierEscapeSyntax added in v1.4.0

func WithCELIdentifierEscapeSyntax(enabled bool) ConfigOpts

WithCELIdentifierEscapeSyntax toggles CEL identifier escape syntax

func WithCELInterruptCheckFrequency added in v1.4.0

func WithCELInterruptCheckFrequency(freq uint) ConfigOpts

WithCELInterruptCheckFrequency sets the CEL interrupt check frequency

func WithCELMacroCallTracking added in v1.4.0

func WithCELMacroCallTracking(enabled bool) ConfigOpts

WithCELMacroCallTracking toggles CEL macro call tracking

func WithCELOptionalTypes added in v1.4.0

func WithCELOptionalTypes(enabled bool) ConfigOpts

WithCELOptionalTypes toggles CEL optional types

func WithCELParserExpressionSizeLimit added in v1.4.0

func WithCELParserExpressionSizeLimit(limit int) ConfigOpts

WithCELParserExpressionSizeLimit sets the CEL parser expression size limit

func WithCELParserRecursionLimit added in v1.4.0

func WithCELParserRecursionLimit(limit int) ConfigOpts

WithCELParserRecursionLimit sets the CEL parser recursion limit

func WithCELTimeout added in v1.4.0

func WithCELTimeout(timeout time.Duration) ConfigOpts

WithCELTimeout sets the CEL evaluation timeout

func WithCELTrackState added in v1.4.0

func WithCELTrackState(enabled bool) ConfigOpts

WithCELTrackState toggles CEL evaluation state tracking

func WithConfig added in v1.4.0

func WithConfig(cfg Config) ConfigOpts

WithConfig applies all settings from a Config struct

func WithEnabled added in v1.4.0

func WithEnabled(enabled bool) ConfigOpts

WithEnabled sets the enabled field

type DomainChanges added in v1.5.3

type DomainChanges struct {
	// DomainKey is the derived key for the approval field set
	DomainKey string
	// Fields lists the approval fields included in the domain
	Fields []string
	// Changes is the subset of proposed changes for the domain
	Changes map[string]any
}

DomainChanges represents changes grouped by approval domain

func DomainChangesForDefinition added in v1.5.3

func DomainChangesForDefinition(doc models.WorkflowDefinitionDocument, objectType enums.WorkflowObjectType, proposedChanges map[string]any) ([]DomainChanges, error)

DomainChangesForDefinition splits proposed changes by approval domains for a workflow definition

func SplitChangesByDomains added in v1.5.3

func SplitChangesByDomains(changes map[string]any, objectType enums.WorkflowObjectType, domains [][]string) []DomainChanges

SplitChangesByDomains filters changes into per-domain buckets based on approval field sets

type EmitFailureDetails added in v1.5.3

type EmitFailureDetails struct {
	// Topic is the soiree topic name
	Topic string `json:"topic"`
	// EventID is the idempotency key when available
	EventID string `json:"event_id,omitempty"`
	// Payload is the original event payload JSON
	Payload json.RawMessage `json:"payload,omitempty"`
	// Attempts is the number of emit attempts recorded
	Attempts int `json:"attempts"`
	// LastError is the most recent enqueue error
	LastError string `json:"last_error,omitempty"`
	// OriginalEventType is the workflow event type that failed
	OriginalEventType enums.WorkflowEventType `json:"original_event_type"`
	// ActionKey is the workflow action key when available
	ActionKey string `json:"action_key,omitempty"`
	// ActionIndex is the workflow action index when available
	ActionIndex int `json:"action_index"`
	// ObjectID is the workflow object id
	ObjectID string `json:"object_id,omitempty"`
	// ObjectType is the workflow object type
	ObjectType enums.WorkflowObjectType `json:"object_type,omitempty"`
}

EmitFailureDetails stores failure context for deterministic re-emission

func NewEmitFailureDetails added in v1.5.3

func NewEmitFailureDetails(topic, eventID string, payload any, meta EmitFailureMeta, err error) (EmitFailureDetails, error)

NewEmitFailureDetails builds a failure payload, including a JSON-encoded event payload

func ParseEmitFailureDetails added in v1.5.3

func ParseEmitFailureDetails(raw json.RawMessage) (EmitFailureDetails, error)

ParseEmitFailureDetails decodes failure details from raw JSON

type EmitFailureMeta added in v1.5.3

type EmitFailureMeta struct {
	// EventType is the workflow event type associated with the emit
	EventType enums.WorkflowEventType
	// ActionKey is the workflow action key when available
	ActionKey string
	// ActionIndex is the workflow action index when available
	ActionIndex int
	// ObjectID is the target object id
	ObjectID string
	// ObjectType is the target object type
	ObjectType enums.WorkflowObjectType
}

EmitFailureMeta holds structured emit metadata for recovery

type EmitReceipt added in v1.5.3

type EmitReceipt struct {
	// EventID is the event idempotency key when assigned
	EventID string
	// Enqueued reports whether the event was enqueued
	Enqueued bool
	// Err is the enqueue error when present
	Err error
}

EmitReceipt captures enqueue status for workflow events

func EmitWorkflowEvent added in v1.5.3

func EmitWorkflowEvent[T any](ctx context.Context, emitter soiree.Emitter, topic soiree.TypedTopic[T], payload T, client any) EmitReceipt

EmitWorkflowEvent wraps and emits a typed workflow event, returning enqueue status

func EmitWorkflowEventWithEvent added in v1.5.3

func EmitWorkflowEventWithEvent(ctx context.Context, emitter soiree.Emitter, topic string, event soiree.Event, client any) EmitReceipt

EmitWorkflowEventWithEvent emits a pre-built event and returns enqueue status

type FieldUpdateActionParams added in v1.5.3

type FieldUpdateActionParams struct {
	// Updates maps field names to new values
	Updates map[string]any `json:"updates"`
}

FieldUpdateActionParams defines params for FIELD_UPDATE actions

type IntegrationActionParams added in v1.5.3

type IntegrationActionParams struct {
	// Integration is the integration identifier for the operation
	Integration string `json:"integration"`
	// Provider overrides the integration identifier when set
	Provider string `json:"provider"`
	// Operation is the integration operation name
	Operation string `json:"operation"`
	// Config holds the integration-specific configuration payload
	Config map[string]any `json:"config"`

	// TimeoutMS overrides the operation timeout in milliseconds
	TimeoutMS int `json:"timeout_ms"`
	// Retries overrides the retry count when non-zero
	Retries int `json:"retries"`
	// Force requests a refresh for the provider
	Force bool `json:"force_refresh"`
	// ClientForce requests a client-side refresh for the provider
	ClientForce bool `json:"client_force"`
}

IntegrationActionParams defines params for INTEGRATION actions

type MutationPayload added in v1.5.10

type MutationPayload struct {
	// Mutation is the raw ent mutation that triggered the event
	Mutation ent.Mutation
	// Operation is the string representation of the mutation operation
	Operation string
	// EntityID is the ID of the entity that was mutated
	EntityID string
	// Client is the ent client that can be used to perform additional queries or mutations
	Client *generated.Client
}

MutationPayload carries the raw ent mutation, the resolved operation, the entity ID and the ent client so listeners can act without additional lookups

type NotificationActionParams added in v1.5.3

type NotificationActionParams struct {
	// TargetedActionParams identifies the notification recipients
	TargetedActionParams
	// Channels selects notification delivery channels
	Channels []enums.Channel `json:"channels"`
	// Topic sets an optional notification topic
	Topic string `json:"topic"`
	// Title is the notification title
	Title string `json:"title"`
	// Body is the notification body
	Body string `json:"body"`
	// Data is an optional payload merged into the notification data
	Data map[string]any `json:"data"`
}

NotificationActionParams defines params for NOTIFICATION actions

type Object

type Object struct {
	// ID is the workflow object identifier.
	ID string
	// Type is the workflow object type.
	Type enums.WorkflowObjectType
	// Node is the concrete ent entity when available.
	Node any
}

Object captures the workflow target along with its concrete ent entity when available.

func ObjectFromRef added in v1.3.3

func ObjectFromRef(ref *generated.WorkflowObjectRef) (*Object, error)

ObjectFromRef builds an Object from a WorkflowObjectRef record.

func (*Object) CELValue added in v1.3.3

func (o *Object) CELValue() any

CELValue exposes the value used inside CEL expressions. Prefer the concrete ent entity so expressions can access real fields.

func (*Object) ObservabilityFields added in v1.5.3

func (o *Object) ObservabilityFields() map[string]any

ObservabilityFields returns standard log fields for the object. Uses the registered builder if available, otherwise falls back to basic fields.

type ObjectRefQueryBuilder

ObjectRefQueryBuilder allows generated code to register WorkflowObjectRef predicates per object type.

type ObservabilityFieldsBuilder added in v1.5.10

type ObservabilityFieldsBuilder func(obj *Object) map[string]any

ObservabilityFieldsBuilder builds observability log fields for a workflow object. Generated code registers this to provide complete field coverage for all workflow-eligible types.

type TargetConfig added in v1.3.3

type TargetConfig struct {
	// Type selects how targets are resolved.
	Type enums.WorkflowTargetType `json:"type"`
	// ID identifies the target resource for static targets.
	ID string `json:"id,omitempty"`
	// ResolverKey names the resolver used for dynamic targets.
	ResolverKey string `json:"resolver_key,omitempty"`
}

TargetConfig defines who should receive workflow actions.

type TargetedActionParams added in v1.5.3

type TargetedActionParams struct {
	// Targets identifies users, groups, roles, or resolvers to receive the action
	Targets []TargetConfig `json:"targets"`
}

TargetedActionParams captures workflow action params that target recipients

type TxError added in v1.5.10

type TxError struct {
	Stage error
	Err   error
}

TxError wraps a transaction error with a stage marker.

func (*TxError) Error added in v1.5.10

func (e *TxError) Error() string

Error implements error.

func (*TxError) Is added in v1.5.10

func (e *TxError) Is(target error) bool

Is reports whether the error matches the stage sentinel.

func (*TxError) Unwrap added in v1.5.10

func (e *TxError) Unwrap() error

Unwrap returns the underlying error.

type WebhookActionParams added in v1.5.3

type WebhookActionParams struct {
	// URL is the webhook endpoint
	URL string `json:"url"`
	// Method is the HTTP method for the webhook request
	Method string `json:"method"`
	// Headers are additional HTTP headers for the webhook request
	Headers map[string]string `json:"headers"`
	// Payload is merged into the base webhook payload
	Payload map[string]any `json:"payload"`
	// TimeoutMS overrides the webhook timeout in milliseconds
	TimeoutMS int `json:"timeout_ms"`
	// Secret signs the webhook payload if provided
	Secret string `json:"secret"`
	// Retries overrides the retry count when non-zero
	Retries int `json:"retries"`

	// Optional override for the idempotency key header
	IdempotencyKey string `json:"idempotency_key"`
}

WebhookActionParams defines params for WEBHOOK actions

type WorkflowBypassContextKey added in v1.4.0

type WorkflowBypassContextKey struct{}

WorkflowBypassContextKey is the context key for workflow bypass operations Used to bypass workflow approval checks during system operations (e.g., applying approved changes)

func FromContext added in v1.4.0

func FromContext(ctx context.Context) (WorkflowBypassContextKey, bool)

FromContext retrieves the workflow bypass context

type WorkflowCreationError added in v1.5.3

type WorkflowCreationError struct {
	// Stage is the creation stage that failed
	Stage WorkflowCreationStage
	// Err is the underlying error
	Err error
}

WorkflowCreationError wraps the underlying error and indicates what stage failed.

func (*WorkflowCreationError) Error added in v1.5.3

func (e *WorkflowCreationError) Error() string

Error formats the workflow creation error

func (*WorkflowCreationError) Unwrap added in v1.5.3

func (e *WorkflowCreationError) Unwrap() error

Unwrap returns the underlying error

type WorkflowCreationStage added in v1.5.3

type WorkflowCreationStage string

WorkflowCreationStage identifies which step failed when building instances/object refs.

const (
	WorkflowCreationStageInstance  WorkflowCreationStage = "instance"
	WorkflowCreationStageObjectRef WorkflowCreationStage = "object_ref"
)

type WorkflowInstanceBuilderParams added in v1.5.3

type WorkflowInstanceBuilderParams struct {
	// WorkflowDefinitionID is the definition id for the instance
	WorkflowDefinitionID string
	// DefinitionSnapshot is the snapshot of the workflow definition
	DefinitionSnapshot models.WorkflowDefinitionDocument
	// State is the initial workflow instance state
	State enums.WorkflowInstanceState
	// Context is the workflow instance context payload
	Context models.WorkflowInstanceContext
	// OwnerID is the organization owner id
	OwnerID string
	// ObjectType is the workflow object type
	ObjectType enums.WorkflowObjectType
	// ObjectID is the workflow object id
	ObjectID string
}

WorkflowInstanceBuilderParams defines the inputs for creating a workflow instance + object ref.

Directories

Path Synopsis
Package engine is the workflow engine for orchestrating workflow execution
Package engine is the workflow engine for orchestrating workflow execution
Package main provides a workflow demonstration seed script
Package main provides a workflow demonstration seed script
Package observability provides logging and metrics wrappers and consistency for workflows there are several functions in this package that are geared towards reducing boilerplate overhead with the main callers by pre-setting common fields such as operation origin and trigger event so that inline within the workflow package we don't have crazy verbose log and metric statements making the code harder to read
Package observability provides logging and metrics wrappers and consistency for workflows there are several functions in this package that are geared towards reducing boilerplate overhead with the main callers by pre-setting common fields such as operation origin and trigger event so that inline within the workflow package we don't have crazy verbose log and metric statements making the code harder to read
Package reconciler provides workflow reconciliation helpers.
Package reconciler provides workflow reconciliation helpers.
Package resolvers provides a registry for workflow target resolution functions
Package resolvers provides a registry for workflow target resolution functions

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL