docs(readme): align with shipped canvas product (#1)
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled

This commit was merged in pull request #1.
This commit is contained in:
2026-06-14 21:14:52 +00:00
parent 3deb1b8888
commit 32bf8260e3
+77 -134
View File
@@ -1,168 +1,111 @@
# FlowMaster — Mission Control
# FlowMaster — Canvas
**Live at https://canvas.flow-master.ai** · [source on Gitea](https://gitea.flow-master.ai/shad/flowmaster-mission-control-demo)
**Live at https://canvas.flow-master.ai** · operations cockpit for every process the company runs.
The proper FlowMaster frontend: an operations cockpit for every process the
company runs. Industrial-blueprint doctrine — paper canvas, navy frame,
amber accent, 1px hairlines, square edges, monospace operational density.
Canvas is the FlowMaster operator surface. Industrial-blueprint doctrine:
paper canvas, navy frame, amber accent, 1px hairlines, square edges,
monospace operational density. People, Finance, Procurement, and IT in
one frame.
## What this is (and isn't)
## What it is
**Is:**
- React 19 single-page app (Vite + ReactFlow + cmdk + framer-motion +
zustand + dagre + leaflet).
- Connected directly to EA2 in the browser via the API client at
`src/lib/api.ts`. EA2 is the runtime source of truth.
- Microsoft SSO is the primary sign-in path. The login screen probes
`/api/v1/auth/microsoft/login` on mount and only enables the SSO
button when the redirect is wired; the dead-button state is honest
("not configured" / "not wired") instead of silently failing.
Developer dev-login remains as a fallback for the demo lane.
- A single-page React 19 app (Vite + ReactFlow + cmdk + framer-motion + zustand
+ dagre).
- Polished command-center for any FlowMaster process: graph, queue, inspector,
tour, command palette, live-mode toggle, run history.
- Two data modes:
- **SNAPSHOT** (default): bundled `src/scenarios.json`, captured from
`demo.flow-master.ai`. Fast, offline, deterministic.
- **LIVE**: in-browser fetch from the same backend via the API client at
`src/lib/api.ts` (dev-login → bearer → `/api/ea2/work-items`
`/api/ea2/process-definitions/{k}/graph``/api/runtime/transactions/{id}`).
Loading and error states are wired through `src/scenes/MissionControl.tsx`.
## Scenes
**Isn't:**
- Landing — entry surface with persona switcher and recent processes.
- Mission Control — live work-items + reactflow process graph + inspector.
- Approvals — work waiting on the signed-in operator.
- Run History — recent runtime transactions and outcomes.
- Process Studio (Wizard) — the Process Creation Wizard, ported from
dev.flow-master.ai. Intake → analyze → generate → validate → publish.
Writes to EA2 at every step via `src/lib/wizardApi.ts`.
- Hubs (HR / Finance / Procurement / IT) — department lenses over the
EA2 catalog. Each hub focuses Mission Control, surfaces hub-specific
KPIs, and exposes the start-process actions the hub head can take.
- Geo Attendance — leaflet map (OpenStreetMap tiles) showing per-site
attendance status from `src/lib/attendanceApi.ts`.
- Chat — internal employee ↔ manager messaging (`src/lib/chatApi.ts`),
threaded, text-only. Replaces booting Teams for "what laptop?" type
questions.
- Command Assistant (Agent) — chat surface with deterministic tools
(`src/lib/agentTools.ts`) for navigation, process start, chat send,
retain / recall against per-tenant memory. When the LLM proxy
(`llm-proxy/`) is configured the assistant also synthesises fluent
natural-language replies; when it isn't, the deterministic path
still works.
- Documents — data shapes per process.
- Explainer — "What is FlowMaster?" recalled from the FlowMaster
explainer and rendered in-product.
- Settings — identity, theme, polling cadence, console default.
- Login / SSO callback.
- Not a replacement for the existing demo at https://demo.flow-master.ai
(Next.js fm-shell). This is a separate command-center experience.
- Not multi-tenant. No auth UI, no tenancy switcher, no settings.
- Not wired to actually mutate state. Every action button (start runtime,
dispatch agent, approve, decline, confirm) is **preview-only** and fires a
toast naming the endpoint that would make it real.
## Three view-as personas
## Scenarios in the catalog
Bundled in `src/data/personas.ts`. Switching persona re-signs in under
the persona's email so the operator UI reflects that seat.
| id | mode | source |
|-------------|-----------|-------------------------------------------------------------------|
| procurement | live | Purchase Requisition → PO (`pr_to_po_def` on demo.flow-master.ai) |
| extra-1 | live | Atlas F1 Fresh (procurement variant) |
| extra-2 | live | Atlas F1 Fresh (procurement variant) |
| ar | blueprint | AR · Customer Refund Approval |
| hcm | blueprint | HCM · New Hire Onboarding |
| gl | blueprint | GL · Period-End Close |
| service | blueprint | Service Ops · Customer Incident |
| Persona | Title | Default hub |
|---------|----------------------|--------------|
| Mariana | Chief Executive | Finance |
| Aisha | Head of People (HR) | HR |
| Rohan | Head of IT | IT |
**Live** = backed by a real EA2 process definition currently in the demo
backend, with real runtime transactions and a real work-item queue.
## Agent + per-tenant memory
**Blueprint** = hand-modelled in the same typed format. Identical UI surface;
the backend just doesn't have a runnable definition for it yet. Internal
metadata carries `isSynthetic: true` for provenance audits.
`src/lib/agentMemory.ts` keeps three fact kinds (world / experience /
opinion) keyed by tenant + user. The agent calls deterministic tools
defined in `src/lib/agentTools.ts`. When `OPENAI_API_KEY` or
`ANTHROPIC_API_KEY` is set on the `llm-proxy/` sidecar, the agent layers
LLM responses on top of the tool output; otherwise it falls back to the
deterministic display strings.
## How honesty is enforced in this code
This pass came out of an Oracle review that called out theatrical bits in the
prior version. Safeguards now in place:
- **No invented numbers.** `src/components/Telemetry.tsx` derives every value
from the active scenarios (`SLA = 1 - errored / cases`, agent acceptance =
fraction of agent runs not in `proposed`). The throughput sparkline plots
the actual `running` rollup over time, not a sine wave. The "ui tick" dot
is labelled as a UI heartbeat and tooltip-named as such.
- **No fake buttons.** Every preview-only action fires a toast that names the
endpoint that would make it real, and carries a `preview` marker.
- **No misleading tour copy.** Blueprint tours frame the scenario as an
industry blueprint, not "we don't have this yet".
- **Mode is always visible.** Topbar has a `SNAPSHOT`/`LIVE` pill, last-fetch
age, and a refresh button when live.
## Live-mode mechanics (the CORS gotcha)
`demo.flow-master.ai` does not advertise CORS headers for arbitrary origins.
`src/lib/api.ts` therefore uses an **empty `baseUrl` everywhere** (both dev
and prod). All `/api/*` requests are same-origin from the browser's
perspective; whatever is serving the page is responsible for proxying them
to the backend.
- **Dev** (`pnpm dev`): `vite.config.ts` proxies `/api/*` to
`${VITE_FM_BASE:-https://demo.flow-master.ai}`.
- **Prod** (Docker image): the bundled `nginx.conf` reverse-proxies `/api/*`
to `https://demo.flow-master.ai`. The image is intended to sit behind the
`canvas.flow-master.ai` ingress (see `FM06/flowmaster-ops` overlay).
- **Anywhere else**: set `VITE_FM_BASE=https://your-backend` at build time
and accept that browsers will reject the cross-origin call. Live mode then
fails gracefully — `setMode("live")` catches the error, raises an
`mc-banner-err` banner + error toast, and falls back to snapshot.
The proxy lives in `llm-proxy/main.py` (FastAPI, no streaming, no tool
calls, no images). The shape mirrors `@earendil-works/pi-ai`'s
normalized completions so a forked Pi coding agent can drop in later
without changing the browser contract.
## Run, test, build
```bash
pnpm install
# refresh the bundled snapshot from demo.flow-master.ai
pnpm fetch:scenarios
# dev (with backend proxy for live mode)
pnpm dev # → http://127.0.0.1:5173
# tests
pnpm test # vitest, 22 tests across api, live,
# synthetic, layout, store
pnpm test # vitest
# build
pnpm build # tsc + vite, single chunk ~225 KB gz
# end-to-end smoke + screenshots
pnpm qa:smoke # playwright headless, 28 assertions
# DOM layout audit
pnpm qa:layout
```
## File map
```
src/
├── data/ # ProcessScenario domain + snapshot + blueprint catalog
├── lib/ # API client + live-scenario builder (+ tests)
├── state/store.ts # zustand: scene, mode, scenario, tour, recents, toasts
├── graph/layout.ts # dagre LR auto-layout (+ tests)
├── components/ # ProcessGraph, Inspector, LeftRail, CommandBar, Tour,
│ # Telemetry, Toaster, icons
├── scenes/ # Landing, MissionControl, RunHistory
├── App.tsx # shell: topbar (mode pill / refresh / tour / ⌘K)
├── index.css # design system (~700 lines)
├── main.tsx
└── scenarios.json # cached snapshot of demo.flow-master.ai
qa/
├── smoke.mjs # Playwright e2e + 9 screenshots
└── layout_audit.mjs # programmatic clipping/overlap check
vite.config.ts # /api → demo.flow-master.ai proxy for dev
fetch_scenarios.mjs # Node script to refresh src/scenarios.json
pnpm build # tsc + vite
```
## Deploy
Production deployment is tracked in
[FM06/flowmaster-ops PR #1164](https://gitea.flow-master.ai/FM06/flowmaster-ops/pulls/1164)
(merged), which added three resources to `manifests/overlays/demo/`:
- `mc-deployment.yaml` — 2-replica nginx Deployment in the `demo` namespace
- `mc-service.yaml` — ClusterIP service on port 80
- `mc-ingress.yaml` — Traefik ingress at `canvas.flow-master.ai` with cert-manager DNS-01 cert
Cloudflare A record `canvas.flow-master.ai → 65.21.71.186` was added at the
same time. The cluster certifies with cert-manager (Let's Encrypt DNS-01)
and Traefik fronts the nginx pods. nginx reverse-proxies `/api/*` to
`https://demo.flow-master.ai` so the SPA is same-origin (no CORS).
Deployment is tracked in `FM06/flowmaster-ops`, overlay
`manifests/overlays/demo/`. nginx in the image reverse-proxies `/api/*`
to the EA2 backend so the SPA is same-origin (no CORS).
```bash
pnpm build # builds dist/
docker build -t gitea.flow-master.ai/shad/mission-control-demo:sha-<git> .
docker push gitea.flow-master.ai/shad/mission-control-demo:sha-<git>
pnpm build
docker buildx build --platform linux/amd64 \
-f Dockerfile.runtime \
-t gitea.flow-master.ai/shad/canvas-frontend:sha-<git> \
--load .
docker push gitea.flow-master.ai/shad/canvas-frontend:sha-<git>
# Then bump the image pin in manifests/overlays/demo/mc-deployment.yaml.
```
## What's intentionally not here
## Source
- Authentication UI (dev-login is used because this is a demo lane).
- Mutation endpoints (every action is preview-only and the toast names the
endpoint).
- Mobile layout (1440px-and-up demo surface).
- Route persistence / deep linking (scene + scenario live in memory).
- i18n (English only).
Small, well-scoped follow-ups — not architectural changes.
`gitea.flow-master.ai/shad/canvas-frontend` is the authoritative source
for canvas.flow-master.ai. The earlier `flowmaster-mission-control-demo`
repository is retained for history but no longer deployed.