ADRs
ADR 0067 — Workflow section: two header tabs (Workflow + Screen), Screen as an adaptive canvas
  • Status: Accepted — §Decision.2 & invariant W2 superseded by ADR 0069 (2026-07-14; Workflow tab is the artboard Studio editor, Tela present on both tabs)
  • Date: 2026-07-14
  • Deciders: maintainer
  • Scope: apps/web — the workflow sidebar section and its header tabs

Context

The left rail (apps/web/src/components/sidebar.tsx) has a workflow section (/app/workflow, one of the two DEFAULT_TABS). Entering it today renders a single surface: the React Flow graph of screens + edges (app/app/workflow/page.tsxArtboardsCanvas, fallback WorkflowCanvas). The header (AppNavbar) is rendered with no tabs prop — so the Workflow section shows no header tabs at all.

Designers need a second way to work inside the same domain: open one screen and lay it out adaptively — the exact interaction model the Design System (Library) section already offers, where a composition fills the canvas edge-to-edge and a device-size switcher reflows it (app/app/library/page.tsx

  • components/layout-grid/BreakpointSwitcher.tsx / BreakpointContext).

A screen is a node of the workflow graph (master spec §0.8: Screen = composition of component instances; node in the workflow graph). It is therefore a view of the same Workflow domain, not a new domain — so it belongs under the Workflow section's header tabs, the same way Library groups Tokens / Components / Brand / Storybook under one section.

Decision

  1. The workflow sidebar section renders two header tabs, client-state driven through the existing AppNavbar tabs?: NavTab[] prop (components/app-navbar.tsx), identical mechanism to Library's tab strip:

    • Workflow — first tab, active on mount (default).
    • Screen — second tab. State lives on the page as view: "workflow" | "screen", initialized to "workflow".
  2. Workflow tab — unchanged. The React Flow graph of screens + edges (ArtboardsCanvas / WorkflowCanvas). No device frame, no Tela.

  3. Screen tab — a new adaptive canvas surface. It reuses the Design System canvas model:

    • The screen in its adaptive state fills the canvas area to the edges (edge-to-edge main.app-canvas-area, as Library does).
    • All Screen settings apply to that one screen.
    • A device-size switcher (Tela) sets the canvas viewport width and reflows the screen. Tela is present only on the Screen tab.
  4. Tela is the canonical device-size switcher (@arno/tela; ADR 0063 "studio-tools reusable packages", on the feat/sorg-layout branch). The in-repo analog on this worktree is layout-grid/BreakpointSwitcher (Desktop / Tablet / Mobile) + BreakpointContext; it is the interim model until Tela is wired into this surface (see Consequences).

Consequences

  • Workflow default is now explicit. The Workflow tab must render active on first mount; a regression that defaults to screen breaks the entry point. Pinned as an invariant in docs/workflow/contract.md and docs/workflow/scenarios.md.
  • Tela-only-on-Screen is a hard invariant. Workflow (the graph) never shows Tela; Screen always does. See docs/workflow/contract.md.
  • Tela dependency is cross-branch. Tela ships as @arno/tela in the sibling worktree (feat/sorg-layout, ADR 0063). Wiring it into the Workflow surface on feat/layout-grid requires the package to be reachable here — an implementation prerequisite this ADR flags but does not resolve. Screen may land first against BreakpointSwitcher and swap to Tela once integrated.
  • Docs: a surface-doc set is created under docs/workflow/ in the same change (README, _index, architecture, screen-surface, contract, scenarios). Workflow is a top-level product surface, not a dev-tools/studio/<tool>, so it is out of scope for check-doc-completeness.ts (which only scans studio tool folders) — the lighter surface set is deliberate, not a shortcut.

Alternatives considered

  • Screen as its own sidebar section — rejected. Screen is a view of one node of the Workflow graph, not an independent domain. Grouping it under the Workflow section's header tabs mirrors the Library section and keeps the rail from sprawling.
  • Reuse BreakpointSwitcher as the permanent switcher instead of Tela — rejected as the canonical end state. Tela is the canonical device-size switcher per the studio naming; BreakpointSwitcher is the DS-local analog and serves only as the interim model.
  • Route-based tabs (/app/workflow/screen) — rejected. Header tabs across /app/* are client-state driven (see AppNavbar), and the graph editor's Liveblocks / persistence mount is expensive to tear down on a route change.

Implementation (2026-07-14, feat/sorg-layout)

Landed in apps/web/src/app/app/workflow/page.tsx (WorkflowShell):

  • view: "workflow" | "screen" state, default "workflow" (W1). Tabs passed to AppNavbar via the tabs prop, same mechanism as Library.
  • Workflow tab<PersistenceLoader projectId><WorkflowCanvas /></PersistenceLoader> — the screens + edges graph. No Tela, no Studio rails (W2).
  • Screen tab → the Studio composition (StudioDndShell + <LayersSidebar/>
    • <Tela/> + canvas + <Punta/> + <Dito/>, ADR 0063), gated behind this tab. Tela is mounted here only.

The "interim BreakpointSwitcher" path from Consequences was not needed: Tela (@arno/tela) already ships on this branch, so Screen uses it directly. The two views are conditionally rendered (only the active one is mounted).

Amendment (same day): the Screen canvas is the Design System mechanic — the page is the canvas. The middle canvas is &lt;SorgenteLibraryCatalog view="tokens"/> with the same carrier tree as /app/library, a single full-width scroll container, not the pan/zoom artboard frames of ArtboardsCanvas (the first cut). The maintainer asked for parity with the Design System surface. SorgenteLibraryCatalog reads global Sorgente state (SorgenteStateProvider from app/app/layout.tsx), so Screen renders the Sorgente showroom and gates behind Sorgente auth/availability — exactly as the Library page does.