Events & Integration
Event Publication
The approval module publishes its domain events through the framework's transactional outbox transport (see Event Bus). Every approval command writes the event record in the same transaction as the business mutation; the outbox relay then forwards them to the configured sink. Events produced within a single engine pass are published in occurrence order.
Subscribers must:
- Attach with
event.WithGroup("...")because the route resolves to an at-least-once transport. - Rely on the Inbox middleware for dedupe (it activates automatically when
event.middleware.inbox = trueand a transport advertisesAtLeastOnce).
Events are published in the order they occur within a transaction. The engine emits each event at the moment the corresponding state change happens, and the outbox relay forwards them in that occurrence order.
Approval commands publish their domain events inside the business transaction
via event.WithTx(db); the events become visible only if the transaction commits.
All approval domain events share the approval.* topic namespace.
The standalone
apv_event_outboxtable and module-privateEventOutboxStatusconstants from earlier snapshots have been retired. Approval no longer carries a private outbox — it composes with the framework one.
Domain Event Types
All approval events implement DomainEvent; AllEventTypes() is the exhaustive exported registry of their topic strings. Instance and task events embed InstanceEventBase (instanceId, instanceNo, tenantId, title, flowId, flowCode, optional businessRef, applicant, occurredTime). Task events additionally embed TaskEventBase (taskId, nodeId, nodeName). Flow events embed FlowEventBase (flowId, tenantId, code, name, occurredTime). The tables below list fields beyond those bases.
Instance lifecycle:
| Type constant | Topic | Payload / constructor | Payload fields beyond common fields | When |
|---|---|---|---|---|
EventTypeInstanceCreated | approval.instance.created | InstanceCreatedEvent, NewInstanceCreatedEvent | none | a new instance was started |
EventTypeInstanceCompleted | approval.instance.completed | InstanceCompletedEvent, NewInstanceCompletedEvent | finalStatus, finishedAt, reason (set only when finalStatus is terminated) | instance reached a terminal status |
EventTypeInstanceWithdrawn | approval.instance.withdrawn | InstanceWithdrawnEvent, NewInstanceWithdrawnEvent | operator (UserInfo), reason | applicant withdrew the instance |
EventTypeInstanceRolledBack | approval.instance.rolled_back | InstanceRolledBackEvent, NewInstanceRolledBackEvent | fromNodeId, fromNodeName, toNodeId, toNodeName, operator (UserInfo), opinion | instance was rolled back to a previous node |
EventTypeInstanceReturned | approval.instance.returned | InstanceReturnedEvent, NewInstanceReturnedEvent | fromNodeId, fromNodeName, toNodeId, toNodeName, operator (UserInfo), opinion | instance was returned to applicant |
EventTypeInstanceResubmitted | approval.instance.resubmitted | InstanceResubmittedEvent, NewInstanceResubmittedEvent | operator (UserInfo) | returned or withdrawn instance was resubmitted |
EventTypeInstanceBindingFailed | approval.instance.binding_failed | InstanceBindingFailedEvent, NewInstanceBindingFailedEvent | trigger, status, businessTable, errorMessage | an eventual business projection attempt failed after the desired state committed; the durable worker keeps retrying — this event is an operator notification, not the retry mechanism. Synchronous failures roll back the approval transaction and never emit it |
Node lifecycle:
| Type constant | Topic | Payload / constructor | Payload fields beyond common fields | When |
|---|---|---|---|---|
EventTypeNodeAutoPassed | approval.node.auto_passed | NodeAutoPassedEvent, NewNodeAutoPassedEvent | nodeId, nodeName, reason | a node auto-passed because of auto-pass execution, empty-assignee handling, or same-applicant handling |
Task lifecycle:
| Type constant | Topic | Payload / constructor | Payload fields beyond common fields | When |
|---|---|---|---|---|
EventTypeTaskCreated | approval.task.created | TaskCreatedEvent, NewTaskCreatedEvent | assignee (UserInfo), deadline, status | a task was created; sequential follow-up tasks may start with deadline omitted while waiting |
EventTypeTaskActivated | approval.task.activated | TaskActivatedEvent, NewTaskActivatedEvent | assignee (UserInfo), deadline, reason (assigned / queue_advanced / transferred / reassigned) | a task became actionable (pending); emitted when the task is assigned, promoted from a queue, transferred, or reassigned. Suppressed when the task is cleared within the same engine pass (for example, a consecutive-approver cascade that creates and immediately resolves the task) |
EventTypeTaskApproved | approval.task.approved | TaskApprovedEvent, NewTaskApprovedEvent | operator (UserInfo), opinion | task approved |
EventTypeTaskHandled | approval.task.handled | TaskHandledEvent, NewTaskHandledEvent | operator (UserInfo), opinion | handle task completed |
EventTypeTaskRejected | approval.task.rejected | TaskRejectedEvent, NewTaskRejectedEvent | operator (UserInfo), opinion | task rejected |
EventTypeTaskCanceled | approval.task.canceled | TaskCanceledEvent, NewTaskCanceledEvent | assignee (UserInfo), reason | engine canceled a task that no longer needs a decision |
EventTypeTaskTransferred | approval.task.transferred | TaskTransferredEvent, NewTaskTransferredEvent | from (UserInfo), to (UserInfo), reason | task transferred to another user |
EventTypeTaskReassigned | approval.task.reassigned | TaskReassignedEvent, NewTaskReassignedEvent | from (UserInfo), to (UserInfo), reason | admin reassigned a task |
EventTypeTaskTimedOut | approval.task.timed_out | TaskTimedOutEvent, NewTaskTimedOutEvent | assignee (UserInfo), deadline | timeout scanner fired the configured timeout action |
EventTypeAssigneesAdded | approval.task.assignees_added | AssigneesAddedEvent, NewAssigneesAddedEvent | addType, assignees ([]UserInfo) | dynamic assignees added |
EventTypeAssigneesRemoved | approval.task.assignees_removed | AssigneesRemovedEvent, NewAssigneesRemovedEvent | assignees ([]UserInfo) | dynamic assignees removed |
EventTypeTaskDeadlineWarning | approval.task.deadline_warning | TaskDeadlineWarningEvent, NewTaskDeadlineWarningEvent | assignee (UserInfo), deadline, hoursLeft | pre-warning scanner flagged an approaching deadline |
EventTypeTaskUrged | approval.task.urged | TaskUrgedEvent, NewTaskUrgedEvent | urger (UserInfo), target (UserInfo), message | the applicant or a current/former task holder (assignee or delegator) urged an assignee |
CC + Flow:
| Type constant | Topic | Payload / constructor | Payload fields beyond common fields | When |
|---|---|---|---|---|
EventTypeCCNotified | approval.cc.notified | CCNotifiedEvent, NewCCNotifiedEvent | nodeId, nodeName, recipients ([]UserInfo), isManual | a CC node or manual CC action delivered notifications |
EventTypeFlowCreated | approval.flow.created | FlowCreatedEvent, NewFlowCreatedEvent | categoryId | flow created |
EventTypeFlowUpdated | approval.flow.updated | FlowUpdatedEvent, NewFlowUpdatedEvent | none | flow updated |
EventTypeFlowDeployed | approval.flow.deployed | FlowDeployedEvent, NewFlowDeployedEvent | versionId, version | flow version deployed |
EventTypeFlowToggled | approval.flow.toggled | FlowToggledEvent, NewFlowToggledEvent | isActive | flow active flag changed |
EventTypeFlowPublished | approval.flow.published | FlowPublishedEvent, NewFlowPublishedEvent | versionId | flow version published |
Every instance and task event carries tenantId and occurredTime from
InstanceEventBase; occurredTime is the business time projected onto
Envelope.OccurredAt by event.WithOccurredAt. EventTypeTaskCreated is the
catalog constant for the approval.task.created topic.
Caller Context and Multi-Tenant Safety
Resource and command handlers resolve a CallerContext per request that bundles the tenant authority of the call. Exactly one of TenantID, IsSuperAdmin, or IsSystemInternal must be set; a zero CallerContext is fail-closed (treated as unauthorized).
| Member | Meaning |
|---|---|
TenantID | the tenant this caller acts within; all reads/writes get filtered by it |
IsSuperAdmin | the principal carries approval:super_admin; cross-tenant queries allowed |
IsSystemInternal | the call originates from framework-internal code (scanners, listeners) |
Cross-tenant attempts return approval.ErrCrossTenantAccess. IsSuperAdmin(p) reports whether a principal carries the override role. The override role itself is exposed as approval.SuperAdminRole ("approval:super_admin") for host wiring.
Lifecycle Extension Points
| Extension point | Phase | Failure semantics |
|---|---|---|
approval.InstanceLifecycleHook (FX group vef:approval:lifecycle_hooks) | synchronous, inside the engine transaction — instance creation and every status transition | returning an error rolls back the surrounding command |
approval.BusinessRefProvider | synchronous, inside the start-instance transaction | returning an error rolls back instance creation |
approval.BusinessRefResolver | synchronous, at claim time inside the start-instance transaction | returning an error rolls back instance creation |
approval.SubscribeInstance (event.SubscribeTyped wrapper) | asynchronous, after the transaction commits | the bus retries via the outbox relay; consumers must be idempotent |
approval.BindCommand (instance event → CQRS command bridge) | asynchronous, after the transaction commits | redelivery re-dispatches the command; the command handler must be idempotent |
InstanceLifecycleHook
type InstanceLifecycleHook interface {
OnInstanceCreated(ctx context.Context, db orm.DB, instance *Instance) error
OnInstanceTransition(ctx context.Context, db orm.DB, instance *Instance, from, to InstanceStatus) error
}
The hook is transition-generic — there is no completion-only variant. OnInstanceTransition(instance, from, to) runs inside the same transaction as every instance status transition — completion (to.IsFinal()), return, withdrawal, resubmission, termination. It runs after the engine-owned business projection has recorded (and, in synchronous mode, applied) the new state, so the hook observes the business table as the transition leaves it; instance.Status already carries to. Returning an error rolls back the whole transition.
Use lifecycle hooks for invariants that must hold inside the transaction (e.g. allocating a tightly-coupled business row). Use event subscriptions (or BindCommand, below) for everything else. Register hooks with vef.ProvideApprovalLifecycleHook(constructor) — the constructor must return approval.InstanceLifecycleHook, and multiple hooks compose via the vef:approval:lifecycle_hooks group. The invocation order across hooks is unspecified (FX value groups carry no ordering), so hooks must be mutually independent; any non-nil error stops the remaining hooks. approval.NewFilteredLifecycleHook(hook, filters...) wraps a hook with the same InstanceFilter vocabulary used by SubscribeInstance (below), so a hook can be scoped to specific flow codes or tenants without hand-written predicates.
BusinessRefProvider and BusinessRefResolver
type BusinessRefProvider interface {
OnInstanceCreated(ctx context.Context, db orm.DB, flow *Flow, instance *Instance) (businessRef string, err error)
}
type BusinessRefResolver interface {
ResolveRecordKey(ctx context.Context, flow *Flow, businessRef string) (BusinessRecordKey, error)
}
BusinessRefProvider supplies or allocates the opaque Instance.BusinessRef when Flow.BindingMode == BindingBusiness; inject it with vef.SupplyBusinessRefProvider. At instance start the engine resolves the ref into an approval.BusinessRecordKey — a map from every configured KeyColumns entry to its value — through BusinessRefResolver. The default resolver treats a single-column ref verbatim and decodes a multi-column ref from a JSON object; register a replacement with vef.SupplyBusinessRefResolver when BusinessRef uses another shape (business number, encoded tuple, …) or resolving the key requires a host lookup. A ref that cannot be resolved fails instance creation with ErrInvalidBusinessRef (code 40109); a business-bound flow started without a ref fails with ErrBusinessRefRequired (code 40107).
Business-State Projection
Business write-back is a durable desired-state projection, not a per-trigger write-back. A business-bound flow configures one BusinessBinding document — approval.BusinessBindingConfig, stored as jsonb on apv_flow and snapshotted immutably onto each deployed apv_flow_version; runtime instances only ever read the version snapshot:
| Field | JSON | Meaning |
|---|---|---|
TableName | tableName | business table receiving approval state |
KeyColumns | keyColumns | record key columns; must exactly match a non-null primary or unique key on the table (verified against the live schema at save time — missing table → ErrBindingTableMissing; missing column → ErrBindingColumnMissing; both surface as code 40018 / ErrBindingSchemaInvalid; non-unique key → ErrBindingKeyNotUnique) |
StatusColumn | statusColumn | column receiving the (mapped) instance status |
InstanceIDColumn | instanceIdColumn | mandatory — the compare-and-set fence that stops a stale instance from overwriting state owned by a newer approval round |
StartedAtColumn | startedAtColumn | optional; receives the instance start time |
FinishedAtColumn | finishedAtColumn | optional; receives the finish time for final statuses, NULL otherwise |
StatusMapping | statusMapping | optional InstanceStatus → host status value map; missing entries fall back to the raw status string (ErrBindingStatusMappingInvalid rejects unknown statuses and blank values) |
Convergence works in three steps:
- Claim at start. Inside the
start_instancetransaction the engine resolves the record key and claims one durable projection row per physical target (apv_business_projection, unique per table + record key). A non-final instance already owning the target blocks the claim withErrBindingTargetBusy(code40108); a final owner is superseded, and the previously applied owner is retained as the business-table CAS fence until the new desired state is actually written. The instance links to its claim viaInstance.BusinessProjectionID. - Desired state per transition. Every instance status transition bumps the projection's
DesiredRevisionand records the full desired state (status, started-at, finished-at). The projection converges on the latest desired state — intermediate statuses may be skipped, which is exactly why side effects tied to a specific lifecycle moment belong inBindCommandorSubscribeInstanceinstead. - Apply.
vef.approval.business_binding.consistencyselects when the business row is written:synchronous(default) — inside the approval transaction; a write failure rolls the approval action back.eventual— the approval action commits immediately; a background worker (scan_interval, default10s;batch_size, default100) claims due projections withFOR UPDATE SKIP LOCKEDplus a lease and applies the latest revision, retrying failures with exponential backoff (1s << attemptCount, i.e. 2s, 4s, …, capped at 1 hour). Each failed attempt publishesInstanceBindingFailedEventas an operator notification — the durable projection row, not the event, drives the retry.
The applied UPDATE sets the configured columns WHERE <key columns match> [AND <instanceIdColumn> = <applied owner>], translating the status through StatusMapping. Operators inspect and force convergence through the admin operations find_business_projections / retry_business_projection (see RPC Resources — each projection row identifies its physical target via BusinessTable and recordKey), and get_metrics reports businessProjectionCounts and pendingBusinessProjections.
The projection status enum is BindingProjectionStatus. Its values are
BindingProjectionPending (a new desired state is recorded), BindingProjectionProcessing
(the worker has claimed the projection and is applying it), BindingProjectionApplied
(the latest desired state has been written), and BindingProjectionFailed (the last
write attempt failed and will be retried).
The engine owns this projection; it is configuration-driven and not replaced by an extension hook. Hosts add behavior around it with lifecycle hooks, event subscriptions, and command bridges.
Host Subscriptions: SubscribeInstance
func SubscribeInstance[T InstanceEvent](
bus event.Bus,
handler func(ctx context.Context, evt T, env event.Envelope) error,
opts ...InstanceSubscribeOption,
) (event.Unsubscribe, error)
SubscribeInstance is the declarative wrapper over event.SubscribeTyped for instance events (any event type embedding InstanceEventBase, e.g. InstanceCompletedEvent). Routing filters are data, not predicates: InstanceSubscribeOption accepts approval.ForFlows(codes...) / approval.ForTenants(ids...) (InstanceFilter values), each OR-ing within its own dimension and AND-ing across filters passed to the same call; events that fail a filter are acknowledged without invoking the handler. Business predicates (final status, form values) belong in the handler body, not in filters.
The handler also receives the delivery event.Envelope: Envelope.ID is the Inbox dedupe key, stable across redeliveries, and therefore the key to build manual idempotency on when the route is at-least-once.
vef.Invoke(func(bus event.Bus) error {
_, err := approval.SubscribeInstance(bus,
func(ctx context.Context, evt *approval.InstanceCompletedEvent, env event.Envelope) error {
// idempotent side effect; env.ID is stable across redeliveries
return nil
},
approval.ForFlows("leave_request"),
approval.WithGroup("app:leave-writeback"),
)
return err
})
The consumer group defaults to one derived from the handler's method identity (vef:sub:<module-relative pkg>.<Type>.<method>, mirroring the vef:default:<uuid> shape used elsewhere). Anonymous handlers fail with ErrAnonymousSubscriberGroup unless approval.WithGroup(name) is given; a duplicate derived group registered twice in one process fails with ErrDerivedGroupConflict. Renaming or moving a handler changes its derived group (a new consumer group starts and the old one is orphaned) — pin the group with WithGroup before such refactors. approval.WithConcurrency(n) sets the per-subscription worker count.
Command Bridge: BindCommand
func BindCommand[E InstanceEvent, C cqrs.Action](
bus event.Bus,
commands cqrs.Bus,
mapper func(evt E, env event.Envelope) (cmd C, ok bool),
opts ...InstanceSubscribeOption,
) (event.Unsubscribe, error)
BindCommand subscribes to instance event E and dispatches the mapped command C through the host's CQRS bus — the declarative bridge from approval facts to host side effects. mapper is a pure translation: it shapes the command from the event plus its delivery envelope and reports relevance (ok=false acknowledges without dispatching). Business logic belongs in the command handler, which runs the host's full behavior pipeline (transaction, audit, validation); the handler's result is discarded — dispatch is fire-and-record.
vef.Invoke(func(bus event.Bus, commands cqrs.Bus) error {
_, err := approval.BindCommand(bus, commands,
func(evt *approval.InstanceCompletedEvent, env event.Envelope) (app.SettleOrderCmd, bool) {
if evt.FinalStatus != approval.InstanceApproved {
return app.SettleOrderCmd{}, false
}
return app.SettleOrderCmd{InstanceID: evt.InstanceID, DedupeKey: env.ID}, true
},
approval.ForFlows("order_settlement"),
)
return err
})
The consumer group defaults to the command type's identity (vef:cmd:<module-relative pkg>.<Type>) — renaming or moving the command deliberately re-keys the subscription, exactly like renaming a SubscribeInstance handler; pin with approval.WithGroup ahead of such refactors. Binding the same command type twice in one process fails with ErrDerivedGroupConflict. Two guards reject invalid bindings up front: ErrNonCommandAction (the bound action type is a query) and ErrUnnamedCommandType (anonymous struct or interface-typed C). Filters and WithConcurrency apply as in SubscribeInstance.
Delivery inherits the event route's semantics: on an at-least-once transport the command handler must be idempotent — copy Envelope.ID into the command when it needs its own dedupe key. Unlike the eventual business projection — which converges on the latest desired state and may skip intermediate statuses — every instance transition dispatches its own command, making BindCommand the lane for side effects tied to a specific lifecycle moment.
Business Identifier Validation
Flow.BindingMode == BindingBusiness flows carry SQL identifiers (BusinessBindingConfig.TableName, every KeyColumns entry, StatusColumn, InstanceIDColumn, and the optional timestamp columns) that the engine-owned projection interpolates directly into an UPDATE template. To prevent SQL injection, the framework whitelists identifiers against ^[A-Za-z_][A-Za-z0-9_]{0,62}$:
if err := approval.ValidateBusinessIdentifier(table); err != nil {
return err
}
Empty / whitespace-only strings pass — the caller decides whether absence itself is an error. Anything outside the whitelist returns approval.ErrInvalidBusinessIdentifier. Admin-side Flow CRUD should bubble this up so operators see meaningful errors.
Delegation
Users can delegate their approval authority to others:
type Delegation struct {
DelegatorID string // Who delegates
DelegateeID string // Who receives delegation
FlowCategoryID *string // Optional: limit to category
FlowID *string // Optional: limit to specific flow
StartsAt timex.DateTime // Delegation window start
EndsAt timex.DateTime // Delegation window end
IsActive bool
Reason *string // Optional: why the delegation exists
}
Supporting Public API Map
| Area | Public API |
|---|---|
| caller safety | CallerContext, SystemCaller, IsSuperAdmin, SuperAdminRole, ErrCrossTenantAccess |
| form data | FormData, NewFormData, FormSchemaParser, FormFieldDefinition, FormSnapshot, ValidationRule, StorageMode, StorageJSON, StorageTable, FieldKind, FieldInput, FieldNumber, FieldDate, FieldTextarea, FieldSelect, FieldUpload, FieldTable, FieldOption, ColumnDataType, ColumnString, ColumnText, ColumnInteger, ColumnDecimal, ColumnBoolean, ColumnDate, ColumnDatetime, ColumnJSON |
| table storage | FormTable, FormTableColumn (FormTable.SourceFieldKey is "" for the main table, or the owning table field's key for a detail-table child projection) |
| flow models | FlowCategory, Flow, FlowVersion, FlowNode, FlowEdge, FlowInitiator, FlowNodeAssignee, FlowNodeCC, VersionStatus, VersionDraft, VersionPublished, VersionArchived, ActionLog, UrgeRecord, DefaultTenantID |
| node design | FlowDefinition, NodeDefinition, EdgeDefinition, Position, NodeData, BaseNodeData, StartNodeData, ApprovalNodeData, HandleNodeData, ConditionNodeData, CCNodeData, EndNodeData, ErrUnknownNodeKind, ErrNodeDataUnmarshal |
| conditions | ConditionKind, ConditionField, ConditionExpression, Condition, ConditionGroup, ConditionBranch, EvaluationContext, ConditionEvaluator, InstanceGlobalsResolver, AggregateKind, AggregateSum, AggregateCount, AggregateAvg, Aggregator |
| initiators and assignees | InitiatorKind, InitiatorUser, InitiatorRole, InitiatorDepartment, AssigneeKind, AssigneeDefinition, AssigneeService, ResolvedAssignee, UserInfo, UserInfoResolver, RoleMembershipChecker, AddAssigneeType, AddAssigneeBefore, AddAssigneeAfter, AddAssigneeParallel |
| CC | CCKind, CCUser, CCRole, CCDepartment, CCFormField, CCTiming, CCTimingAlways, CCTimingOnApprove, CCTimingOnReject, CCDefinition, CCRecord (CCRecord.VisitID scopes the record to one node traversal, mirroring Task.VisitID) |
| business binding & projection | BusinessBindingConfig, BusinessRecordKey, BusinessProjection (model, table apv_business_projection), BindingProjectionStatus (BindingProjectionPending / Processing / Applied / Failed), BindingTrigger, BindingTriggerStarted, BindingTriggerCompleted, BindingTriggerReturned, BindingTriggerWithdrawn, BindingTriggerResubmitted |
| instance subscriptions | SubscribeInstance, BindCommand, InstanceEvent, InstanceFilter, InstanceSubscribeOption, ForFlows, ForTenants, WithGroup, WithConcurrency, NewFilteredLifecycleHook, ErrAnonymousSubscriberGroup, ErrDerivedGroupConflict, ErrNonCommandAction, ErrUnnamedCommandType |
| node behavior | ApprovalMethod, TaskNodeData, ExecutionType, ExecutionManual, ExecutionAutoPass, ExecutionAutoReject, ConsecutiveApproverAction, ConsecutiveApproverNone, ConsecutiveApproverAutoPass, SameApplicantAction, SameApplicantSelfApprove, SameApplicantAutoPass, SameApplicantTransferSuperior, Permission, PermissionVisible, PermissionEditable, PermissionRequired, PermissionHidden, DefaultExecutionType, DefaultApprovalMethod, DefaultPassRule, DefaultEmptyAssigneeAction, DefaultSameApplicantAction, DefaultConsecutiveApproverAction, DefaultRollbackType, DefaultRollbackDataStrategy, DefaultTimeoutAction, DefaultCCTiming, DefaultHandleApprovalMethod, DefaultHandlePassRule, DefaultUrgeCooldownMinutes |
| rollback and timeouts | RollbackType, RollbackNone, RollbackPrevious, RollbackStart, RollbackAny, RollbackSpecified, RollbackDataStrategy, RollbackDataClear, RollbackDataKeep, EmptyAssigneeAction, EmptyAssigneeAutoPass, EmptyAssigneeTransferAdmin, EmptyAssigneeTransferSuperior, EmptyAssigneeTransferApplicant, EmptyAssigneeTransferSpecified, TimeoutAction, TimeoutActionNone, TimeoutActionAutoPass, TimeoutActionAutoReject, TimeoutActionNotify, TimeoutActionTransferAdmin |
| action and status enums | ActionType, InstanceStatus, TaskStatus, NodeKind, StorageMode, VersionStatus |
| pass rules | PassRule, PassRuleContext, PassRuleStrategy, PassRuleResult, PassRulePending, PassRulePassed, PassRuleRejected |
| progress views | TimelineEntryKind, TimelineEntry, NodeVisitStatus, NodeProgressStatus, InstanceFlowGraph, FlowGraphNode, FlowGraphNodeData, FlowGraphEdge, NodeParticipant, Activity, ActivityUrge, CCRecipient |
| events | all New...Event constructors, DomainEvent, InstanceEventBase, TaskEventBase, FlowEventBase, NewInstanceEventBase, NewTaskEventBase, NewFlowEventBase, PayloadOccurredAt, AllEventTypes, TaskActivationReason, TaskActivationAssigned, TaskActivationQueueAdvanced, TaskActivationTransferred, TaskActivationReassigned, and the EventType... constants |
| extension interfaces | InstanceLifecycleHook, BusinessRefProvider, BusinessRefResolver, InstanceNoGenerator, ConditionEvaluator, InstanceGlobalsResolver, PrincipalTenantResolver, PrincipalDepartmentResolver, RoleMembershipChecker |
DI helpers (package vef) | SupplyBusinessRefProvider, SupplyBusinessRefResolver, ProvideApprovalLifecycleHook, ProvideApprovalAggregator, ProvideApprovalFormSchemaParser |
| admin DTOs | package approval/admin: Instance, InstanceDetail, InstanceDetailInfo, Task, ActionLog, Metrics, BusinessProjection |
| user DTOs | package approval/my: PendingTask, CompletedTask, CCRecord, InitiatedInstance, AvailableFlow, InstanceDetail, InstanceInfo, PendingCounts, StartForm, ViewerTask, RollbackTarget, RemovableAssignee |
Next: back to the Overview for wiring and configuration, or RPC Resources for the API surface these events originate from.