diff --git a/doc/wiki/bpmn-workflows.md b/doc/wiki/bpmn-workflows.md new file mode 100644 index 000000000..76593c912 --- /dev/null +++ b/doc/wiki/bpmn-workflows.md @@ -0,0 +1,99 @@ +# BPMN Workflows + +Elsa supports running BPMN 2.0 processes as first-class workflow activities. Two modules provide this capability: + +| Module | Package | Role | +| --- | --- | --- | +| [Elsa.Bpmn](../../src/modules/Elsa.Bpmn) | `Elsa.Bpmn` | BPMN process execution: `BpmnProcess` activity, work ledger, scope signals, scope host. | +| [Elsa.Bpmn.Interchange](../../src/modules/Elsa.Bpmn.Interchange) | `Elsa.Bpmn.Interchange` | XML import, work binder, and the `elsa:` vendor extension format. | + +## Enabling BPMN + +```csharp +// Execution support only (use when you build BpmnProcess in code). +elsa.AddBpmn(); + +// Execution + XML interchange (use when importing .bpmn files). +elsa.AddBpmnInterchange(); +``` + +`BpmnInterchangeFeature` depends on `BpmnFeature`; calling `AddBpmnInterchange()` pulls in both. + +## BpmnProcess Activity + +`BpmnProcess` is a `Container` that wraps one BPMN scope. It drives the `Bpmn.Semantics` interpreter and applies the continuations the interpreter returns to its own `ActivityExecutionContext`. Key properties: + +- **`Process`** — the `BpmnProcessDefinition` from the `Bpmn.Interchange` reader. +- **`WorkBindings`** — a `Dictionary` mapping each BPMN binding ref to an Elsa activity id. The scope host uses this map to look up child activity execution contexts when the interpreter signals work completion, faulting, or escalation. +- **`Activities`** — the Elsa activities bound to this scope (one per `BpmnWorkBinding`). +- **`IsRootScope`** — left `false` on every scope the binder produces; the caller sets it to `true` to mark the outermost scope as a workflow entry point. + +`BpmnProcess` completes with the interpreter's outcome name (e.g. `BpmnInterpreter.DoneOutcomeName`). It does **not** complete with `Outcomes.Default`, so connections from it must target explicit outcome ports. + +## Work Ledger + +The `BpmnWorkLedger` lives in `ActivityExecutionContext.Properties` of the scope's own context. It is the scope's record of work it has started but not yet finished — a handle-to-context map keyed by scope-local handles. + +Rules that matter for contributors: + +- Work that **completes or faults** must be removed from the ledger *before* the scope makes its callback, or a rearmed non-interrupting listener can key onto the same `(binding ref, iteration id)` slot and a later teardown hits the finished work. +- Work that **signals** (e.g. escalation from a still-running scope) must remain in the ledger, because removing it causes the interpreter to believe the work has already gone. +- Each `(binding ref, iteration id)` pair must be unique within one scope. Multi-instance bodies share a binding ref and are distinguished by their iteration id. + +The ledger is serialized to JSON as part of the scope's `ActivityExecutionContext.Properties` when the workflow suspends, so it survives persistence and resume. + +## Work Binding Model + +`BpmnWorkBinder` in `Elsa.Bpmn.Interchange` translates a `BpmnProcessDefinition` (from the `Bpmn.Interchange` reader) into a `BpmnProcess`. The seven binding kinds: + +| Binding kind | BPMN element | Elsa activity | +| --- | --- | --- | +| `TimerWait` | Timer event | `Delay` (ISO-8601 duration) | +| `MessageWait` | Message catch event | `Event` | +| `SignalWait` | Signal catch event | `Event` | +| `MessagePublish` | Message throw event | `PublishEvent` | +| `CallProcess` | Call activity | `DispatchWorkflow` | +| `NestedProcess` | Embedded subprocess | Recursively bound `BpmnProcess` | +| `UnboundTask` | Service / send / user / script task | Author-declared via `elsa:activityBinding` (see below) | + +BPMN describes *what* a task is for, not *how* to perform it. An unbound task gets its implementation from an `elsa:activityBinding` vendor extension inside the BPMN element's ``. + +## The `elsa:` Vendor Extension + +Namespace URI: `https://elsaworkflows.io/schemas/bpmn/v1`, conventional prefix `elsa`. + +```xml + + + + {"typeName":"String","expression":{"type":"JavaScript","value":"getMessage()"}} + + + +``` + +- `activityType` — the Elsa activity type name as the activity registry keys it (`IActivity.Type`, not a CLR name). +- `` — one element per configured input. The element text is the input value serialized by Elsa's own activity serializer: an `Input`-typed property carries the `{"typeName":…,"expression":…}` wrapper; a plain `[Input]`-attributed property carries the value's own JSON shape (e.g. an array for `Switch.Cases`). +- A duplicate input name is refused. An input name the activity type does not declare is refused. An unregistered `activityType` is refused. + +An exported `.bpmn` is self-contained: all binding configuration, including input expressions, travels verbatim in the document. Handle exported files with the same care as the workflow definitions they represent. + +**The names in this format are a compatibility surface.** Changing `NamespaceUri`, `BindingElementName`, `ActivityTypeAttributeName`, `InputElementName`, or `InputNameAttributeName` breaks every previously exported `.bpmn` file. Studio and any other tooling that reads or writes this extension must agree on these constants. + +## Execution State Persistence + +The BPMN interpreter's execution state (`BpmnExecutionState`) and the scope's `BpmnWorkLedger` are both serialized as JSON strings in `ActivityExecutionContext.Properties` when the workflow suspends. The state is pruned before each persist: consumed tokens are removed so the serialized size stays bounded regardless of how many evaluations a long-running scope has processed. + +Test coverage: `test/integration/Elsa.Bpmn.IntegrationTests/Scenarios/HostPort/BpmnPersistenceTests.cs` proves that state size stays flat across a multi-iteration loop. + +## Composing BPMN Into an Elsa Workflow + +A `BpmnProcess` is a `Container` and can be nested inside any Elsa composite activity (e.g. a `Flowchart`). The workflow that hosts it is responsible for marking the outermost scope as the entry point (`IsRootScope = true`). Nested BPMN scopes — embedded subprocesses, event subprocesses — are themselves `BpmnProcess` instances bound as child work by the binder and need no special treatment from the containing workflow. + +To find code fast: + +```bash +rg "class BpmnProcess" src/modules +rg "class BpmnWorkLedger" src/modules +rg "elsa:activityBinding" test/ +``` diff --git a/doc/wiki/repository-map.md b/doc/wiki/repository-map.md index faaf24419..193a46178 100644 --- a/doc/wiki/repository-map.md +++ b/doc/wiki/repository-map.md @@ -28,13 +28,18 @@ Elsa Core is organized as a large multi-project .NET solution. The repo favors s | Workflow engine | [Elsa.Workflows.Core](../../src/modules/Elsa.Workflows.Core) | Activities, execution contexts, pipelines, serialization, variables, bookmarks, graphs, flowchart primitives. | | Workflow management | [Elsa.Workflows.Management](../../src/modules/Elsa.Workflows.Management) | Definitions, instances, stores, import/export, materializers, validation, descriptors. | | Workflow runtime | [Elsa.Workflows.Runtime](../../src/modules/Elsa.Workflows.Runtime) and [Elsa.Workflows.Runtime.Distributed](../../src/modules/Elsa.Workflows.Runtime.Distributed) | Dispatch, triggers, bookmark queues, runtime logs, background activity scheduling, recovery, distributed runtime support. | +| Alterations | [Elsa.Alterations](../../src/modules/Elsa.Alterations), [Elsa.Alterations.Core](../../src/modules/Elsa.Alterations.Core) | Bulk alteration of running workflow instances: alteration plans, jobs, dispatching, and in-memory stores; EF Core and vNext persistence packages live alongside the core. | | Workflow API | [Elsa.Workflows.Api](../../src/modules/Elsa.Workflows.Api) and [Elsa.Api.Common](../../src/common/Elsa.Api.Common) | FastEndpoints registration, workflow endpoints, real-time workflow updates, API serialization. | | Expression languages | [Elsa.Expressions](../../src/modules/Elsa.Expressions), [CSharp](../../src/modules/Elsa.Expressions.CSharp), [JavaScript](../../src/modules/Elsa.Expressions.JavaScript), [Python](../../src/modules/Elsa.Expressions.Python), [Liquid](../../src/modules/Elsa.Expressions.Liquid) | Expression evaluation and language-specific activities/descriptors. | -| Transport/activity packages | [Elsa.Http](../../src/modules/Elsa.Http), [Elsa.Scheduling](../../src/modules/Elsa.Scheduling), [Elsa.Resilience](../../src/modules/Elsa.Resilience) | HTTP triggers and calls, scheduled triggers, resilience strategies. | +| Transport/activity packages | [Elsa.Http](../../src/modules/Elsa.Http), [Elsa.Http.Webhooks](../../src/modules/Elsa.Http.Webhooks), [Elsa.Scheduling](../../src/modules/Elsa.Scheduling), [Elsa.Resilience](../../src/modules/Elsa.Resilience) | HTTP triggers and calls, outbound webhook sinks and activity-driven webhook sources (`WebhooksFeature`), scheduled triggers, resilience strategies. | +| BPMN | [Elsa.Bpmn](../../src/modules/Elsa.Bpmn), [Elsa.Bpmn.Interchange](../../src/modules/Elsa.Bpmn.Interchange) | BPMN 2.0 process execution: `BpmnProcess` scope activity, work ledger, scope signals; and the `elsa:` XML interchange format that binds BPMN document elements to Elsa activities. See [bpmn-workflows.md](bpmn-workflows.md). | | Persistence (EF Core) | [Elsa.Persistence.EFCore](../../src/modules/Elsa.Persistence.EFCore), provider packages under `Elsa.Persistence.EFCore.*`, and structured-log persistence packages | EF Core stores and provider-specific configuration/migrations. | | Persistence vNext | [Elsa.Persistence.VNext](../../src/modules/Elsa.Persistence.VNext), [Extensions](../../src/modules/Elsa.Persistence.VNext.Extensions), [Runtime](../../src/modules/Elsa.Persistence.VNext.Runtime), [Relational](../../src/modules/Elsa.Persistence.VNext.Relational), [Sqlite](../../src/modules/Elsa.Persistence.VNext.Sqlite), [PostgreSql](../../src/modules/Elsa.Persistence.VNext.PostgreSql), [SqlServer](../../src/modules/Elsa.Persistence.VNext.SqlServer), [MongoDb](../../src/modules/Elsa.Persistence.VNext.MongoDb) | Next-generation provider-neutral persistence: module-owned storage manifests, portable document/index store, schema versioning, and physicalization for relational and document databases. | +| Key-value store | [Elsa.KeyValues](../../src/modules/Elsa.KeyValues) | Generic key-value storage (`IKeyValueStore`) with a default in-memory backing store; used by other modules for ephemeral or cross-request state. | +| Caching | [Elsa.Caching](../../src/modules/Elsa.Caching) | `ICacheManager` and `IChangeTokenSignaler`; provides memory-cache helpers and signal-based cache invalidation used internally by other Elsa modules. | | Security and tenancy | [Elsa.Identity](../../src/modules/Elsa.Identity), [Elsa.Tenants](../../src/modules/Elsa.Tenants), [Elsa.Tenants.AspNetCore](../../src/modules/Elsa.Tenants.AspNetCore), [Elsa.SasTokens](../../src/modules/Elsa.SasTokens) | Users, applications, roles, API keys, tenants, tenant-aware routing, SAS tokens. | -| Secrets | [Elsa.Secrets](../../src/modules/Elsa.Secrets) | Named secrets with pluggable stores, extensible secret types (text, RSA key, X.509 certificate), versioning, rotation, revocation, secret resolver, and management endpoints. | +| External authentication | [Elsa.ExternalAuthentication](../../src/modules/Elsa.ExternalAuthentication), [Elsa.ExternalAuthentication.OpenIdConnect](../../src/modules/Elsa.ExternalAuthentication.OpenIdConnect), [Elsa.ExternalAuthentication.Secrets](../../src/modules/Elsa.ExternalAuthentication.Secrets), and EF Core provider packages (`Sqlite`, `SqlServer`, `PostgreSql`, `MySql`, `Oracle`) | Server-brokered external identity providers: Identity Provider Connections, OpenID Connect adapter, linked identity resolution, configurable unlinked-identity policies, Elsa credential issuance, and EF Core persistence. See [specs/012-external-authentication/spec.md](../../specs/012-external-authentication/spec.md). | +| Secrets | [Elsa.Secrets](../../src/modules/Elsa.Secrets), [Elsa.Secrets.Persistence.EFCore](../../src/modules/Elsa.Secrets.Persistence.EFCore), [Elsa.Secrets.Persistence.VNext](../../src/modules/Elsa.Secrets.Persistence.VNext), [Elsa.Secrets.JavaScript](../../src/modules/Elsa.Secrets.JavaScript) | Named secrets with pluggable stores, extensible secret types (text, RSA key, X.509 certificate), versioning, rotation, revocation, secret resolver, management endpoints, EF Core and vNext persistence, and JavaScript expression access. | | Diagnostics | [Elsa.Diagnostics.StructuredLogs](../../src/modules/Elsa.Diagnostics.StructuredLogs), [Relational](../../src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational), [Sqlite](../../src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite), [Elsa.Diagnostics.ConsoleLogs](../../src/modules/Elsa.Diagnostics.ConsoleLogs) | Structured `ILogger` capture, raw console capture, live feed, REST/SignalR endpoints, in-memory and SQLite storage. | | Shells and modular hosting | [Elsa.Shells.Api](../../src/modules/Elsa.Shells.Api), CShells-facing shell feature classes throughout modules | Runtime-configurable feature loading for modular hosts. | | Operational dashboard | [Elsa.Dashboard.Api](../../src/modules/Elsa.Dashboard.Api) | Read-only aggregate endpoints for the Studio operational dashboard: overview, trends, needs-attention findings, recent activity, and workflow hotspots. | diff --git a/doc/wiki/specs-and-adrs.md b/doc/wiki/specs-and-adrs.md index efe3b5bf9..bcbf168b5 100644 --- a/doc/wiki/specs-and-adrs.md +++ b/doc/wiki/specs-and-adrs.md @@ -47,6 +47,8 @@ Current ADRs: | [010 workflow JSON hardening](../../specs/010-workflow-json-hardening/spec.md) | Workflow core | Introduces dedicated type aliases for workflow JSON, rejects unknown/unsafe CLR names, and preserves backward-compatible reads for selected legacy identifiers. | | [011 persistence vNext](../../specs/011-persistence-vnext/spec.md) | Persistence | Provider-neutral module-owned storage manifests, portable document/index store, relational and MongoDB physicalization, and schema versioning without per-provider migration packages. | | [012 output converters](../../specs/012-output-converters/spec.md) | Workflow core | Extensible, explicitly-identified output converters that transform an activity's native output at the binding boundary before writing the destination variable or workflow output. | +| [012 external authentication](../../specs/012-external-authentication/spec.md) | Security | Server-brokered external identity providers: Identity Provider Connections, OpenID Connect adapter, linked identity resolution, configurable unlinked-identity policies, and EF Core persistence across all providers. | +| [012 weaver grounding tools](../../specs/012-weaver-grounding-tools/spec.md) | AI | Grounds Weaver in real Elsa server data: activity registry discovery, workflow definition inspection, instance and incident investigation, and proposal-based workflow authoring with validation. | Each spec folder usually contains: @@ -120,6 +122,24 @@ For runtime behavior, read in this order: 5. `Elsa.AI.Copilot` adapter and options 6. AI unit and integration tests +## Reading Order For External Authentication Work + +1. [specs/012-external-authentication/spec.md](../../specs/012-external-authentication/spec.md) +2. [specs/012-external-authentication/plan.md](../../specs/012-external-authentication/plan.md) +3. [Identity, Tenancy, And Security](identity-tenancy-security.md) +4. `Elsa.ExternalAuthentication` feature and contracts +5. `Elsa.ExternalAuthentication.OpenIdConnect` adapter +6. `Elsa.ExternalAuthentication.Persistence.EFCore` and provider packages + +## Reading Order For BPMN Work + +1. [bpmn-workflows.md](bpmn-workflows.md) +2. `Elsa.Bpmn/Activities/BpmnProcess.cs` — the scope activity +3. `Elsa.Bpmn/Hosting/BpmnWorkLedger.cs` and `BpmnWorkBinder.cs` — work tracking and binding +4. `Elsa.Bpmn.Interchange/Binding/BpmnActivityBindingFormat.cs` — `elsa:` vendor extension +5. `Elsa.Bpmn.Interchange/Features/BpmnInterchangeFeature.cs` — feature registration +6. `test/integration/Elsa.Bpmn.IntegrationTests` and `Elsa.Bpmn.Interchange.IntegrationTests` + ## Reading Order For Persistence vNext Work 1. [Persistence wiki page](persistence.md) — Persistence vNext section