NatsPublish (CodeActivity) publishes a UTF-8 body to a subject with optional
Nats-Msg-Id dedup and ExpectedStream assertion. NatsTrigger (Trigger<string>)
starts a workflow per message on a specified stream/subject.
A single BackgroundService scans the trigger store for indexed NatsTriggers,
groups by (stream, subject), and runs one durable pull consumer per pair with
Explicit ack, so multiple Elsa instances share the workload at-least-once. A
mediator handler on WorkflowTriggersIndexed refreshes subscriptions when
workflows are published.
Wired via Nats:Url/User/Password (env-var overrides Nats__*, or short
NATS_URL/NATS_USER/NATS_PASSWORD fallbacks). Uses the NATS.Net v2 client so
wss:// works transparently.
Captures everything that took a debug cycle to figure out: server-vs-Studio
version divergence (3.5 vs 3.7), the two competing login stacks and which
one to keep, the admin password-hash trap, Traefik forwarded-headers, the
SPA fallback carving out /elsa/api, SQLite pinning to App_Data, and the
Coolify quirks (git_repository truncation, dockercompose→service, base64
raw compose). Future sessions read this first before touching versions
or auth wiring.
The classic Elsa.Studio.Login.BlazorWasm.AddLoginModule and the newer
Elsa.Studio.Authentication.ElsaIdentity.UI.AddElsaIdentityUI both register
a '/login' page, which errored out on first render:
The following routes are ambiguous:
'login' in Elsa.Studio.Login.Pages.Login.Login
'login' in Elsa.Studio.Authentication.ElsaIdentity.UI.Pages.Login.Login
Drop the classic module (package + AddLoginModule call + Login.HttpMessageHandlers
namespace) and switch the API auth handler to
ElsaIdentityAuthenticatingApiHttpMessageHandler from the new stack.
- appsettings.json: bake in the reference HashedPassword/HashedPasswordSalt so
admin/password actually validates (the previous empty strings could never match)
- Program.cs: pin the SQLite DB into App_Data so the mounted volume persists it,
and route /elsa/api/{**rest} to a JSON 404 so unknown API paths stop returning
the Studio SPA HTML with a 200
- Elsa.Studio.Wasm project (net9.0): WASM shell with Login/Dashboard/Workflows modules,
reads its backend URL from a JS-injected window.getClientConfig() so the same build
can point at any origin without a rebuild.
- Elsa.CustomServer:
- references Elsa.Studio.Wasm as a project so `dotnet publish` emits its wwwroot/
- UseBlazorFrameworkFiles + MapFallbackToPage('/_Host') serve the WASM app + SPA routes
- Pages/_Host.cshtml renders the Studio shell and injects apiUrl at request time
- Bumped Elsa server packages to 3.5.3, Studio packages to 3.7.0 (Studio release train
moved ahead of server; 3.7 Studio is compatible with 3.5 server API)
- Dockerfile: SDK/runtime 9.0, restores both csprojs before copying sources
- src/Elsa.CustomServer: minimal ASP.NET Core 8 host referencing Elsa 3.5 NuGets
- Activities auto-registered via AddActivitiesFrom<Program>() — drop new files under Activities/
- Sqlite persistence for workflow definitions + runtime
- Multi-stage Dockerfile targeting linux/amd64, ASP.NET 8 runtime, port 8080
- Forwarded-headers configured so URLs come out https:// behind Traefik
- CORS wide-open so the standalone Studio (different origin) can talk to us