# 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 story’s `parameters`: ```ts export const MyStory: StoryObj = { 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 & npm run test:storybook ``` Or run `npm run test:storybook` after starting the server (it runs `node scripts/audit-storybook.js`). The audit must report **0 application errors** (console errors, page errors, unhandled network failures). On failure it **exits with code 1** so CI can fail the job. - **CI:** The workflow `.github/workflows/storybook-audit.yml` runs on changes under `apps/web`, builds Storybook, serves it on 6007, and runs the audit; the job fails if any story has errors. - **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.