# 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/<feature>/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/<feature>/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/<app>/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/<feature>/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
