engine

package
v0.20.0 Latest Latest
Warning

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

Go to latest
Published: Mar 9, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// Engine errors.
	ErrNoMatchingEdge    = errors.New("no matching outgoing edge for node")
	ErrProcessorNotFound = errors.New("node processor not found for node kind")
	ErrMaxNodeDepth      = errors.New("max node processing depth exceeded")

	// Approval node errors.
	ErrNoAssignee                   = errors.New("no assignee resolved for node")
	ErrAssigneeServiceNotConfigured = errors.New("assignee service is not configured")

	// Condition node errors.
	ErrNoBranches       = errors.New("condition node has no branches")
	ErrNoMatchingBranch = errors.New("no matching branch and no default branch")
)
View Source
var InstanceStateMachine = buildInstanceStateMachine()

InstanceStateMachine defines valid instance state transitions.

View Source
var Module = fx.Module(
	"vef:approval:engine",

	fx.Provide(
		fx.Annotate(NewStartProcessor, fx.ResultTags(`group:"vef:approval:node_processors"`)),
		fx.Annotate(NewEndProcessor, fx.ResultTags(`group:"vef:approval:node_processors"`)),
		fx.Annotate(NewConditionProcessor, fx.ResultTags(`group:"vef:approval:node_processors"`)),
		fx.Annotate(NewApprovalProcessor, fx.As(new(NodeProcessor)), fx.ResultTags(`group:"vef:approval:node_processors"`)),
		fx.Annotate(NewHandleProcessor, fx.As(new(NodeProcessor)), fx.ResultTags(`group:"vef:approval:node_processors"`)),
		fx.Annotate(NewCCProcessor, fx.As(new(NodeProcessor)), fx.ResultTags(`group:"vef:approval:node_processors"`)),

		fx.Annotate(
			NewFlowEngine,
			fx.ParamTags(``, `group:"vef:approval:node_processors"`, ``, ``),
		),
	),
)

Module provides the flow engine and node processors.

View Source
var TaskStateMachine = buildTaskStateMachine()

TaskStateMachine defines valid task state transitions.

Functions

func NormalizePassRatio

func NormalizePassRatio(ratio float64) float64

NormalizePassRatio normalizes pass ratio to 0-100 scale. Values in (0, 1] range are treated as proportions and converted to percentage. E.g., 0.6 → 60, 1.0 → 100. Values > 1 are kept as-is (already percentage). Negative values are clamped to 0, values above 100 are clamped to 100.

func ResolveCCUserIDs

func ResolveCCUserIDs(cfg approval.FlowNodeCC, formData approval.FormData) ([]string, error)

ResolveCCUserIDs resolves CC recipients from static IDs or form fields.

Types

type ApprovalProcessor

type ApprovalProcessor struct {
	// contains filtered or unexported fields
}

ApprovalProcessor handles approval nodes.

func NewApprovalProcessor

func NewApprovalProcessor(assigneeService approval.AssigneeService) *ApprovalProcessor

NewApprovalProcessor creates a new approval processor.

func (*ApprovalProcessor) NodeKind

func (*ApprovalProcessor) NodeKind() approval.NodeKind

func (*ApprovalProcessor) Process

type CCProcessor

type CCProcessor struct{}

CCProcessor handles CC (carbon copy) notification nodes.

func NewCCProcessor

func NewCCProcessor() *CCProcessor

NewCCProcessor creates a CCProcessor.

func (*CCProcessor) NodeKind

func (*CCProcessor) NodeKind() approval.NodeKind

func (*CCProcessor) Process

func (p *CCProcessor) Process(ctx context.Context, pc *ProcessContext) (*ProcessResult, error)

type ConditionProcessor

type ConditionProcessor struct{}

ConditionProcessor evaluates condition branches and selects the matching branch.

func (*ConditionProcessor) NodeKind

func (*ConditionProcessor) NodeKind() approval.NodeKind

func (*ConditionProcessor) Process

type EndProcessor

type EndProcessor struct{}

EndProcessor handles end nodes by completing the flow as approved.

func (*EndProcessor) NodeKind

func (*EndProcessor) NodeKind() approval.NodeKind

func (*EndProcessor) Process

type FlowEngine

type FlowEngine struct {
	// contains filtered or unexported fields
}

FlowEngine is the core engine for processing approval workflows.

func NewFlowEngine

func NewFlowEngine(registry *strategy.StrategyRegistry, processors []NodeProcessor, pub *dispatcher.EventPublisher, userResolver approval.UserInfoResolver) *FlowEngine

NewFlowEngine creates a new flow engine.

func (*FlowEngine) AdvanceToNextNode

func (e *FlowEngine) AdvanceToNextNode(ctx context.Context, db orm.DB, instance *approval.Instance, fromNode *approval.FlowNode, branchID *string) error

AdvanceToNextNode finds the matching edge from the current node and advances to the next one. BranchID is used by condition nodes to select the edge matching the branch.

func (*FlowEngine) EvaluateNodeCompletion

func (e *FlowEngine) EvaluateNodeCompletion(ctx context.Context, db orm.DB, instance *approval.Instance, node *approval.FlowNode) (approval.PassRuleResult, error)

EvaluateNodeCompletion evaluates whether a node is complete based on its tasks and pass rule.

func (*FlowEngine) EvaluatePassRuleWithTasks

func (e *FlowEngine) EvaluatePassRuleWithTasks(node *approval.FlowNode, tasks []approval.Task) (approval.PassRuleResult, error)

EvaluatePassRuleWithTasks evaluates the pass rule for a node using the provided tasks. This is used for simulation (e.g., checking if removing an assignee would deadlock the node).

func (*FlowEngine) ProcessNode

func (e *FlowEngine) ProcessNode(ctx context.Context, db orm.DB, instance *approval.Instance, node *approval.FlowNode) error

ProcessNode dispatches a node to the appropriate processor.

func (*FlowEngine) StartProcess

func (e *FlowEngine) StartProcess(ctx context.Context, db orm.DB, instance *approval.Instance) error

StartProcess starts a flow process by finding the start node and processing it.

type HandleProcessor

type HandleProcessor struct {
	// contains filtered or unexported fields
}

HandleProcessor handles handle nodes (claim mode). Unlike approval nodes, handle nodes create all tasks with sortOrder=0, allowing any candidate to claim and complete the task.

func NewHandleProcessor

func NewHandleProcessor(assigneeService approval.AssigneeService) *HandleProcessor

NewHandleProcessor creates a new handle processor.

func (*HandleProcessor) NodeKind

func (*HandleProcessor) NodeKind() approval.NodeKind

func (*HandleProcessor) Process

type NodeAction

type NodeAction int

NodeAction represents the result action of node processing.

const (
	NodeActionWait     NodeAction = iota // Wait for user action
	NodeActionContinue                   // Auto-advance to next node
	NodeActionComplete                   // Flow ends
)

type NodeProcessor

type NodeProcessor interface {
	// NodeKind returns the node kind this processor handles (approval, handle, cc, condition, etc.).
	NodeKind() approval.NodeKind
	// Process executes the node logic and returns the action to take (wait, continue, or complete).
	Process(ctx context.Context, pc *ProcessContext) (*ProcessResult, error)
}

NodeProcessor processes a specific node kind.

func NewConditionProcessor

func NewConditionProcessor() NodeProcessor

NewConditionProcessor creates a ConditionProcessor.

func NewEndProcessor

func NewEndProcessor() NodeProcessor

NewEndProcessor creates an EndProcessor.

func NewStartProcessor

func NewStartProcessor() NodeProcessor

NewStartProcessor creates a StartProcessor.

type ProcessContext

type ProcessContext struct {
	DB            orm.DB
	Instance      *approval.Instance
	Node          *approval.FlowNode
	FormData      approval.FormData
	ApplicantID   string
	ApplicantName string
	UserResolver  approval.UserInfoResolver
	Registry      *strategy.StrategyRegistry
}

ProcessContext provides context for node processing.

type ProcessResult

type ProcessResult struct {
	Action      NodeAction
	FinalStatus *approval.InstanceStatus // Only set when Action == NodeActionComplete
	BranchID    *string                  // Only set when Action == NodeActionContinue (condition node)
	Events      []approval.DomainEvent   // Events to publish after processing
}

ProcessResult contains the outcome of node processing.

type StartProcessor

type StartProcessor struct{}

StartProcessor handles start nodes by auto-advancing to the next node.

func (*StartProcessor) NodeKind

func (*StartProcessor) NodeKind() approval.NodeKind

func (*StartProcessor) Process

type State

type State interface {
	comparable

	// String returns the string representation of this state.
	String() string
	// IsFinal returns true if this is a terminal state with no further transitions.
	IsFinal() bool
}

State represents a state that can be used in a state machine.

type StateMachine

type StateMachine[S State] struct {
	// contains filtered or unexported fields
}

StateMachine manages state transitions.

func NewStateMachine

func NewStateMachine[S State](name string) *StateMachine[S]

NewStateMachine creates a new state machine with the given name.

func (*StateMachine[S]) AddTransition

func (sm *StateMachine[S]) AddTransition(from, to S, event string) *StateMachine[S]

AddTransition registers a valid state transition.

func (*StateMachine[S]) AvailableTransitions

func (sm *StateMachine[S]) AvailableTransitions(from S) []S

AvailableTransitions returns all valid target states from the given state.

func (*StateMachine[S]) CanTransition

func (sm *StateMachine[S]) CanTransition(from, to S) bool

CanTransition checks if a transition from one state to another is valid.

func (*StateMachine[S]) Transition

func (sm *StateMachine[S]) Transition(from, to S) error

Transition performs a state transition, returning an error if invalid.

type Transition

type Transition[S State] struct {
	From  S
	To    S
	Event string
}

Transition defines a state transition.

Jump to

Keyboard shortcuts

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