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 Canvas is the FlowMaster operator surface. Industrial-blueprint doctrine:
company runs. Industrial-blueprint doctrine — paper canvas, navy frame, paper canvas, navy frame, amber accent, 1px hairlines, square edges,
amber accent, 1px hairlines, square edges, monospace operational density. 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 ## Scenes
+ 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`.
**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 ## Three view-as personas
(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.
## 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 | | Persona | Title | Default hub |
|-------------|-----------|-------------------------------------------------------------------| |---------|----------------------|--------------|
| procurement | live | Purchase Requisition → PO (`pr_to_po_def` on demo.flow-master.ai) | | Mariana | Chief Executive | Finance |
| extra-1 | live | Atlas F1 Fresh (procurement variant) | | Aisha | Head of People (HR) | HR |
| extra-2 | live | Atlas F1 Fresh (procurement variant) | | Rohan | Head of IT | IT |
| ar | blueprint | AR · Customer Refund Approval |
| hcm | blueprint | HCM · New Hire Onboarding |
| gl | blueprint | GL · Period-End Close |
| service | blueprint | Service Ops · Customer Incident |
**Live** = backed by a real EA2 process definition currently in the demo ## Agent + per-tenant memory
backend, with real runtime transactions and a real work-item queue.
**Blueprint** = hand-modelled in the same typed format. Identical UI surface; `src/lib/agentMemory.ts` keeps three fact kinds (world / experience /
the backend just doesn't have a runnable definition for it yet. Internal opinion) keyed by tenant + user. The agent calls deterministic tools
metadata carries `isSynthetic: true` for provenance audits. 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 The proxy lives in `llm-proxy/main.py` (FastAPI, no streaming, no tool
calls, no images). The shape mirrors `@earendil-works/pi-ai`'s
This pass came out of an Oracle review that called out theatrical bits in the normalized completions so a forked Pi coding agent can drop in later
prior version. Safeguards now in place: without changing the browser contract.
- **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.
## Run, test, build ## Run, test, build
```bash ```bash
pnpm install pnpm install
# refresh the bundled snapshot from demo.flow-master.ai
pnpm fetch:scenarios
# dev (with backend proxy for live mode) # dev (with backend proxy for live mode)
pnpm dev # → http://127.0.0.1:5173 pnpm dev # → http://127.0.0.1:5173
# tests # tests
pnpm test # vitest, 22 tests across api, live, pnpm test # vitest
# synthetic, layout, store
# build # build
pnpm build # tsc + vite, single chunk ~225 KB gz pnpm build # tsc + vite
# 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
``` ```
## Deploy ## Deploy
Production deployment is tracked in Deployment is tracked in `FM06/flowmaster-ops`, overlay
[FM06/flowmaster-ops PR #1164](https://gitea.flow-master.ai/FM06/flowmaster-ops/pulls/1164) `manifests/overlays/demo/`. nginx in the image reverse-proxies `/api/*`
(merged), which added three resources to `manifests/overlays/demo/`: to the EA2 backend so the SPA is same-origin (no CORS).
- `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).
```bash ```bash
pnpm build # builds dist/ pnpm build
docker build -t gitea.flow-master.ai/shad/mission-control-demo:sha-<git> . docker buildx build --platform linux/amd64 \
docker push gitea.flow-master.ai/shad/mission-control-demo:sha-<git> -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. # 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). `gitea.flow-master.ai/shad/canvas-frontend` is the authoritative source
- Mutation endpoints (every action is preview-only and the toast names the for canvas.flow-master.ai. The earlier `flowmaster-mission-control-demo`
endpoint). repository is retained for history but no longer deployed.
- 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.