# FlowMaster — Mission Control **Live at https://canvas.flow-master.ai** · [source on Gitea](https://gitea.flow-master.ai/shad/flowmaster-mission-control-demo) 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. ## What this is (and isn't) **Is:** - 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`. **Isn't:** - 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. ## Scenarios in the catalog | 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 | **Live** = backed by a real EA2 process definition currently in the demo backend, with real runtime transactions and a real work-item queue. **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. ## 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. ## 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 # 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 ``` ## 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). ```bash pnpm build # builds dist/ docker build -t gitea.flow-master.ai/shad/mission-control-demo:sha- . docker push gitea.flow-master.ai/shad/mission-control-demo:sha- # Then bump the image pin in manifests/overlays/demo/mc-deployment.yaml. ``` ## What's intentionally not here - 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.