veza/docs/STORYBOOK_CONTRACT.md

118 lines
4.6 KiB
Markdown
Raw Normal View History

# Storybook Contract (Veza Web)
This document defines the development contract for Storybook in `apps/web`: how to write and maintain stories without breaking the deterministic, zero-leak setup.
## 1. Use the global decorator only
**All stories are wrapped by `StorybookDecorator`** (see `.storybook/decorators.tsx`). It provides:
- `I18nextProvider` (i18n)
- `ThemeProvider` (light/dark via Storybook backgrounds)
- `QueryClientProvider` (React Query, `retry: false`, `staleTime: Infinity`)
- `ToastProvider`
- `AudioProvider`
- `AuthProvider` (mock logged-in user by default)
- `MemoryRouter` (initial route configurable via parameters)
**You must not:**
- Import or wrap stories with these providers yourself.
- Import app-level providers from `src/` (e.g. `AuthProvider`, `QueryClientProvider`) inside a story file.
**Why:** A single decorator avoids duplicate providers, inconsistent configs, and hooks running outside their context (`useAuth`, `useNavigate`, `useQueryClient`, `useToast`, etc.).
### Route-dependent stories
If the component under test uses `useParams()`, `useSearchParams()`, or a specific path, set the route in the storys `parameters`:
```ts
export const MyStory: StoryObj<typeof MyPage> = {
parameters: {
router: {
initialEntries: ['/tracks/123'],
},
},
};
```
Do not add a local `MemoryRouter` unless you need a different base path for that story only; the global decorator already provides `MemoryRouter` and will use `parameters.router.initialEntries` when present.
---
## 2. Mock all API calls with MSW
Storybook runs with **MSW (Mock Service Worker)** and is configured with **`onUnhandledRequest: 'error'`**. Any request that is not handled by a mock will cause an error in the console and can fail the story/audit.
**You must:**
- Ensure every API call used by your story is covered by a handler in `src/mocks/handlers.ts` (or by story-level `parameters.msw.handlers` overrides).
- Use relative API base (e.g. `VITE_API_URL=/api/v1` in Storybook scripts) so requests are same-origin and intercepted by MSW.
**Adding a mock for a new feature:**
1. Open `apps/web/src/mocks/handlers.ts`.
2. Add an `http.get()` or `http.post()` (etc.) handler for the endpoint (e.g. `*/api/v1/your/resource`).
3. Return a `HttpResponse.json(...)` with a shape that matches what your app expects.
4. If a story needs a different response (e.g. 404, empty list), override in that story:
```ts
parameters: {
msw: {
handlers: [
http.get('*/api/v1/your/resource', () => HttpResponse.json({ data: [] })),
],
},
},
```
**You must not:**
- Rely on a real backend when running or building Storybook.
- Add stories that trigger unhandled network requests; they will fail under the current strict MSW setup.
---
## 3. Hierarchy and tags
Stories are grouped in the sidebar as follows:
| Segment | Usage |
|------------------|--------|
| **App/Pages** | Full-page components (e.g. Dashboard, Login, TrackDetail). |
| **App/Layouts** | Global layout components (Header, Sidebar, DashboardLayout). |
| **Components/UI**| Atomic UI (Button, Alert, Input). |
| **Components/Features** | Feature-specific and complex components (Playlists, Chat, Studio, etc.). |
| **Docs/Failures**| Error states and error boundaries (ErrorBoundary, NotFoundPage, ServerErrorPage). |
Set the meta `title` in your `.stories.tsx` accordingly (e.g. `title: 'App/Pages/Dashboard/DashboardPage'`, `title: 'Components/UI/Button'`).
Autodocs are enabled globally; each component gets a generated docs page.
---
## 4. Verification
- **Audit:** From `apps/web`, build Storybook, serve the static build on port 6007, then run:
```bash
npm run build-storybook
npx serve -s storybook-static -p 6007 &
node scripts/audit-storybook.js
```
The audit must report **0 application errors** (console errors, page errors, unhandled network failures). MSW strict mode ensures any unhandled request is treated as an error.
- **Local run:** Use `npm run storybook` (port 6006). Ensure no console errors when opening the stories you changed.
---
## 5. Summary
| Rule | Action |
|------|--------|
| Providers | Use only `StorybookDecorator`; do not import app providers in stories. |
| Routes | Use `parameters.router.initialEntries` for route-dependent stories. |
| API | Mock every request in `handlers.ts` or per-story `parameters.msw.handlers`. |
| Hierarchy | Use `App/Pages`, `App/Layouts`, `Components/UI`, `Components/Features`, `Docs/Failures`. |
| Strict MSW | `onUnhandledRequest: 'error'` is on; add mocks for any new API used by a story. |
This contract keeps Storybook deterministic, free of network leaks, and safe for future changes.