# @leumas/workflows-web — Leumas Workflows at workflows.leumas.tech

Leumas Workflows at workflows.leumas.tech — triggers, actions and workflows: build them in the browser, dry-run them free, run them with a key.


When this happens, do that. The workflow engine inside Leumas Studio, on the web: a member-grade
builder over the same eight node types, the same validator and the same stepper, with a free dry run
in front and a metered, owner-scoped run lane behind.

**Status: built.** Blueprint: [`products/TODOS/workflows.leumas.tech.md`](../TODOS/workflows.leumas.tech.md)
(§6a records the decisions made while building).

## What is where

| Piece | Lives in |
|---|---|
| The vocabulary, validator, stepper, templates | `@leumas/workflows` (`shared/packages/workflows`) — unchanged |
| The dry run (echo runner, isomorphic) | `@leumas/workflows/dryrun` |
| What a member's graph may reach (isomorphic) | `@leumas/workflows/member-policy` |
| The builder, the trace, the gallery glyph | `@leumas/workflows/react` (`WorkflowBuilder`, `RunTrace`, `FlowGlyph`) |
| The member lane | `products/leumas-api/src/{controllers,routes}/workflowsSite.js` → `/api/workflows/{status,catalogue,templates,dryrun,mine/*}` |
| The money | `PLAN_CATALOG` `workflows` $15 · `policy.js` `workflows.*` (floor: build + dryrun; plan: saves, run, monthlySteps, arm, webhook, keys, runRetentionDays) |
| The SDK | `@leumas/workflows-sdk` |
| This site | `src/content/pages.js` (the prose as data) · `src/content/catalogue.generated.js` (from the registries at build) · `src/screens/*` |
| Guards | `pnpm check:workflows-public` · `pnpm check:workflows-metered` · `pnpm smoke:workflows-site` |

## The catalogue is generated

`scripts/gen-catalogue.mjs` reads `createTriggerRegistry().listManifests()`,
`createActionRegistry().listManifests()`, the connectors registry and every workflow catalogue, and
writes `src/content/catalogue.generated.js`. One page per trigger, action, app and template is
derived from it; `check:workflows-public` holds the page table to the file both ways. Never type a
count.

## Three doors, one meter

A run from the browser, from a key (`POST /api/workflows/mine/:id/run`, `Authorization: Bearer lk_…`
with the `workflows` scope) and from an armed rule (`run-workflow`, bound in `app.js` to the site's
`runForOwner`) all pass `walk()` in the controller: reserve against `workflows.monthlySteps`, step,
record a `workflow_runs` row. `check:workflows-metered` asserts the connections. The dry run is the
one door that stays free, because it executes nothing.

## Why this can read a visitor's session with no configuration

`workflows.leumas.tech` is a platform-owned Imperium site row
(`shared/services/index/src/workflowsSite.js`), served by the Imperium worker behind the IIS
`*.leumas.tech` wildcard. That worker forwards `/api` and the auth prefixes to leumas-api preserving
the visitor's Host header and cookies, so every call is same-origin.

[warning] **Never set `VITE_API_BASE`.** The session cookie is httpOnly and same-origin.

## Running it

```bash
pnpm dev:api                                  # :3000
pnpm dev:workflows                            # :5080
pnpm --filter @leumas/workflows-web build
pnpm check:workflows-public && pnpm check:workflows-metered && pnpm smoke:workflows-site
```

[warning] `pnpm deploy:workflows` copies files but carries **no release stamp**. Only `pnpm ship` applies.


---
Source: products/leumas-workflows/README.md
Canonical: https://docs.leumas.tech/p/products/workflows-web
