# Dossier — automation-flows

Files: `routes/Automation.tsx` (37L), `routes/automation.css` (244L),
`routes/automation/AutomationFlows.tsx` (73L), `FlowsHome.tsx` (400L),
`FlowRunsTab.tsx` (170L), `FlowCanvasScreen.tsx` (709L), `flow-graph.ts` (523L),
`flow-summary.ts` (162L), `useGraphHistory.ts` (89L), plus
`flows-home.css` (175L), `flow-canvas-screen.css` (254L). None of these are in
`LEGACY_BASELINE` — confirmed NEW cm-* surfaces, required at zero legacy
markers. Zero hex/rgba found in the two new CSS sheets; zero raw
`<input>/<select>/<textarea>` in the tsx (all go through `CmInput`/`CmSelect`).
**Marker count: 0** — genuinely swept, this is a tokens/copy pass, not a
rebuild-from-legacy problem. The gap is entirely interaction maturity.

## Screen: Flows home (`FlowsHome.tsx`)

- **IA**: low — folders, a table, a state pill, a "+ New flow" menu. One screen, one concept.
- **Interaction**: no row-level quick actions beyond the State selector — no
  duplicate, no rename-inline, no drag-to-reorder-folders, no multi-select /
  bulk actions, no search or sort on the table. Folder chips have no edit/delete/rename,
  and no drag-drop-to-folder — ManyChat lets you drag a flow into a folder;
  here folder assignment isn't even visible or settable after creation.
  "+ New flow" is a click-to-toggle custom menu (not a native `<menu>`/Popover),
  closed only by a full-screen scrim button — works, but reimplements a
  primitive Radix would give for free (the project's own roadmap already says
  a headless behavior layer is coming).
- **Content/copy**: plain words throughout, no engineering vocabulary, CTR
  cell explicitly explains itself rather than faking a number — good practice matching DECISIONS.
- **Visual/tokens**: clean, all `--cm-*`.
- **a11y/responsive**: no `@media` query in `flows-home.css` at all — the
  folders bar wraps but the table has no horizontal-scroll wrapper or
  narrow-width behavior; untested at 320px. Modal-based folder/live-confirm
  flows use the shared `Modal` (assume it's accessible — outside this group).
- **Verdict: polish.** Concept is right-sized and copy is strong; it is
  missing the row-level and folder ergonomics a mature list view has.

## Screen: Runs (`FlowRunsTab.tsx`)

- **IA**: low — one flow picker, totals, a paginated table.
- **Interaction**: "Load more" button only, no infinite-scroll despite using
  `useInfiniteQuery` (which supports it trivially); no filter by status/date/contact;
  no click-through from a run row to the contact or a step detail; flow picker
  is a plain select, not searchable (fine at current flow counts, will not scale).
- **Content/copy**: status labels are already humanized (`Handed to the agent`,
  `Timed out`) — good, no enum leakage.
- **Visual/tokens**: clean.
- **a11y/responsive**: same as above — table has no responsive treatment.
- **Verdict: keep.** Small, honest, functional; not worth redesign investment now.

## Screen: Flow canvas (`FlowCanvasScreen.tsx`) — the ManyChat-gap screen

- **IA**: medium-high for a first-time user — trigger card, step cards, ports,
  wires, undo/redo, draft/published mode split, publish confirm, node
  inspector panel, trigger picker modal. Justified by the domain, but it is a
  lot to hold with none of the affordances that normally make a canvas legible.
- **Interaction — this is where "took the functionality without what makes it
  feel good" shows concretely**:
  - **No zoom UI.** `CmCanvas` *does* implement pan (drag/wheel) and zoom
    (Ctrl/Cmd+wheel) at the primitive level, but the screen exposes no
    zoom-in/out buttons, no percentage readout, and no "fit to screen" — a
    first-time user has no visible way to discover zoom exists.
  - **Dragging desyncs from the cursor at any non-1x zoom.** `onCardPointerMove`
    (`FlowCanvasScreen.tsx:358-362`) sets card position directly from
    `e.clientX/clientY` (screen space), but positions are rendered inside
    `cm-canvas__world`, which is scaled by the zoom transform (`CmCanvas.tsx:88`).
    Drag a card while zoomed in/out and it moves faster/slower than the pointer
    — a real bug, not just a missing feature, once zoom is used at all.
  - **No inline rename, no double-click-to-open.** Opening a step requires the
    small "Open settings" text button inside the card; there's no click-the-card
    or double-click affordance a canvas user expects.
  - **No multi-select, no copy/paste, no keyboard node deletion.** The `×`
    button is the only way to delete a step; `useCanvasShortcuts` explicitly
    defers deletion to "React Flow's own delete key inside the canvas" — but
    this screen does not use react-flow at all (it's the custom `CmCanvas`
    primitive), so that comment is stale and the delete key does nothing.
  - **No drag-from-palette.** Adding a step is click-port → panel → click item
    (functionally fine), but there's no drag a palette item onto the canvas,
    no right-click context menu on empty canvas or on a card.
  - **Auto-arrange exists** (`positionsFor` + `autoArrange`, applied by default
    to any unplaced node, with an explicit "Auto-arrange" reset button) — this
    is a genuine positive the operator may not have registered; it's just not
    incremental/animated, it's a hard reset.
  - Undo/redo and Ctrl+S are real and covered by a shortcuts hook — good.
- **Content/copy**: excellent — `STATS_NOTE` and `PLACEMENT_NOTE` proactively
  explain what numbers mean and don't fake data; the publish/live confirms
  read like a person wrote them.
- **Visual/tokens**: clean, all `--cm-*`, card geometry is computed not
  measured (documented tradeoff, reasonable).
- **a11y/responsive**: no `@media` in `flow-canvas-screen.css`; canvas-style
  editors are conventionally desktop-only so this may be an accepted
  tradeoff, but it should be a stated decision, not a silent gap. Ports and
  buttons have `:focus-visible` styling — good baseline keyboard visibility —
  but there is no documented keyboard path to move a card, connect a port, or
  navigate between steps without a mouse.
- **Verdict: redesign** (interaction layer only — the data model, autosave,
  draft/publish split, and copy are sound and should NOT be rebuilt). The gap
  is entirely ergonomics: zoom controls, non-broken drag-at-zoom, inline
  rename, multi-select/copy/paste, keyboard node ops, drag-from-palette,
  context menus — the layer that makes a canvas "feel good" versus merely work.

## Dead weight: `routes/automation.css`

244 lines surviving from the deleted four-tab shell (Rules/Run log/Reminders/Flows,
killed per commit `81dcbe8`); only `.au-wrap` (8 lines) is still referenced
anywhere (`grep -rn "au-tab\|au-toolbar\|au-seg\|au-wrap" apps/web/src --include=*.tsx`
→ one hit). Not a legacy-marker violation (no hex/no raw tags), but pure dead
CSS that should be deleted down to the one rule it still needs — a
same-scope cleanup, not a design fork.

## FORKS

1. **Canvas ergonomics scope size** — the redesign verdict above is a
   real work-package (zoom UI, drag-at-zoom fix, multi-select, keyboard node
   ops, context menus, drag-from-palette). Does this get its own dedicated
   kickoff before or alongside the Sequences fast-follow, or ride in the same
   scope as this design sweep's mockup round? *Recommend: its own scope —
   it's canvas-primitive work, not a copy/token pass, and touches
   `components/canvas` which other screens may come to share.*
2. **Zoom controls placement** — ManyChat puts zoom +/−/fit in a bottom-right
   HUD over the canvas. Adopt that pattern here, or route it through the
   existing top toolbar (`cm-fc__bar`) alongside Undo/Redo? *Recommend:
   floating HUD — keeps the top bar from growing and matches where users'
   attention already is while dragging.*
3. **Canvas mobile support** — is a read-only (view published graph, no edit)
   mobile mode in scope, or is the canvas explicitly desktop/tablet-only by
   product decision? *Recommend: explicit desktop-only ruling in
   `docs/DECISIONS.md` so it stops reading as an oversight in future sweeps.*
