# Frontend work shape How frontend work — components, pages, media UI, anything visual — flows through the agent-first workflow. For the broader workflow context see [`docs/architecture/agent-first-workflow-and-conformance.md`](../architecture/agent-first-workflow-and-conformance.md). ## When this guide applies You're working on: - A new or existing component (atom / molecule / organism / template / page) - A page in `apps/web-next` or `apps/web-tanstack` - A visual or interactive change in `@repo/core-ui` or `features//src/ui/` - Storybook stories or visual regression tests If you're working on a backend use case (factory, repository, manifest entry, event handler, job, realtime channel), use the default backend shape documented in the architecture doc — not this guide. ## Where frontend code lives | Surface | Location | When to use | |---|---|---| | Atomic-design primitives | `@repo/core-ui/src/{atoms,molecules,organisms,templates}/` | Cross-feature reusables. Generated via `pnpm turbo gen core-ui-component`. | | Feature-scoped UI | `features//src/ui/` | Components and queries specific to a feature. Exported behind the feature's `./ui` subpath, never the root barrel (see CLAUDE.md). | | Pages | `apps//src/...` (Next.js: `app/`, TanStack: `routes/`) | Page-level composition. Calls use cases via tRPC controllers; composes components. | ## Atomic design conventions Tier rules (enforced by the `atomic-tier-import-direction` ESLint rule): | Tier | May import from | May NOT import from | |---|---|---| | `atoms` | nothing else in `core-ui` | molecules / organisms / templates / pages / features | | `molecules` | atoms | organisms / templates / pages / features | | `organisms` | atoms, molecules | templates / pages / features | | `templates` | atoms, molecules, organisms | pages / features | | `pages` | all of the above | other pages | Feature-scoped UI (`features//src/ui/`) follows the same tier order internally, and may import from `@repo/core-ui` at any tier. ## Storybook is the spec Every component has a sibling `.stories.tsx`. The story file: - Declares one story per AC bullet (or one variant per AC bullet) - Uses Storybook's `play` function for interaction tests where applicable - Becomes the shared visual contract between human, implementer agent, reviewer agent **Acceptance criteria for a frontend task map directly to story variants:** ```markdown ## Acceptance criteria - [ ] Renders default variant - [ ] Renders loading state - [ ] Renders error state with `message` slot - [ ] Renders disabled state - [ ] Click handler fires with event payload ``` Each bullet becomes one `Story` export (or one `play` step on a story). ## Test gates | Gate | What it covers | Tool | Latency | When it runs | |---|---|---|---|---| | Component test | behavior, props, interactions | Vitest + Testing Library, or `play` on stories | <5s | pre-commit, CI | | Visual regression | rendered appearance vs. baseline | Playwright screenshot tests | 30–120s | CI only; blocks merge on unapproved diffs | The visual regression infrastructure ships as part of the `work-system-v1` epic. Until it's in place, frontend work relies on component tests + manual visual review. ## Adapted four-step ordering For a pure UI slice (no backend coupling): 1. **Story file** — write or extend `.stories.tsx`; declare the variant for this slice's AC bullet. *This is the visual spec — analogous to the manifest entry for backend work.* 2. **Contracts** — props interface in the component file (factory body / render body may still throw `not implemented`) 3. **Tests (red)** — component test + the new story (the rendered output is asserted as part of the visual regression baseline, or via Testing Library) 4. **Implementation (green)** — render JSX, wire interactions, satisfy AC For a UI slice that consumes a backend use case (e.g. a form component calling `auth.signUp`), the use case lives in a separate story with its own four steps; the UI story `depends-on` the use-case story. ## Reviewer integration The reviewer agent for frontend tasks uses two extra inputs beyond the standard diff: 1. **Storybook MCP** at `http://localhost:6006/mcp` — query existing components, list variants, fetch the metadata for stories that already exist. The reviewer can `list-all-documentation` to verify no duplicate component was created. 2. **Playwright screenshot CI verdict** — the visual diff status from CI. Unapproved diffs trigger `reject` regardless of code quality. Reviewer checklist for frontend tasks: - [ ] Every AC bullet has a matching story or `play` step - [ ] No accidental cross-tier imports (lint already catches this, but verify) - [ ] Component test exercises each AC bullet - [ ] Visual regression diff is either zero or human-approved - [ ] No new component created without checking for an existing equivalent via Storybook MCP ## Story split for page-level features A user-facing feature like "sign up" decomposes into multiple stories under one epic: ``` Epic: auth-v1 ├── Story (user-story): auth.signUp use case ├── Story (technical-story): SignUpForm component │ depends-on: signUp use case └── Story (technical-story): /sign-up page depends-on: SignUpForm ``` Each story has its own AC checklist; the `depends-on` edges enforce sequential dispatch by the orchestrator. The page story typically includes the Playwright E2E test for the full flow. ## Conformance for frontend New ESLint rules added under the frontend work-shape: - `component-must-have-story` — every `.tsx` file exporting a default OR named React component must have a sibling `.stories.tsx` - `component-must-have-test` — every component must have a sibling `.test.tsx` (or be covered by a `play` function on its story) - `atomic-tier-import-direction` — tier imports must respect the table above - `story-must-cover-all-prop-variants` (advisory) — discriminated-union props should have a story per variant ## Common pitfalls - **Stale stories.** A component changes prop shape; stories don't get updated. The `component-must-have-story` rule catches missing stories but not stale ones. Reviewer should flag this; visual regression catches the rendered consequence. - **Visual-only changes without story update.** A CSS tweak that doesn't change behavior still needs the story to be re-snapshotted. Treat the visual regression diff approval as part of the slice. - **Cross-tier creep.** Tempting to import an organism from inside an atom for "convenience". The lint rule blocks it; refactor the shared bit down to an atom or molecule. - **Duplicate components.** An agent creates a `Button` in a feature's `ui/atoms/` when one already exists in `core-ui`. Reviewer queries Storybook MCP for `Button` before approval; if duplicated, rejects. ## Open items (filled in as we ship) - Playwright screenshot infrastructure — exact setup, baseline storage, approval flow - Visual regression PR check — GitHub workflow + diff hosting - Storybook test integration (`test:stories`) — current status and what we extend