# Storybook Contract — Veza Design System ## Purpose This document defines the mandatory structure and conventions for all Storybook stories in the Veza frontend. It is referenced by `.cursorrules` and must be followed by all contributors and AI assistants. ## Story Requirements ### 1. Feature Components Every **Feature component** (components in `src/features/`) must have the following story variants: | Story Name | Description | Required | |---|---|---| | `Default` | Component with typical data | Yes | | `Loading` | Component in loading state (using Skeleton components) | Yes | | `Error` | Component displaying an error fallback | Yes | | `Empty` | Component with no data (empty list/state) | Yes, if applicable | ### 2. UI Components Every **UI component** (components in `src/components/ui/`) must have: | Story Name | Description | Required | |---|---|---| | `Default` | Default variant/state | Yes | | `Variants` | All visual variants (size, color, etc.) | If applicable | | `Disabled` | Disabled state | If applicable | | `WithIcon` | With icon prop | If applicable | ### 3. Layout Components Layout components (`src/components/layout/`) should demonstrate: - Responsive behavior (mobile, tablet, desktop) - Light and dark modes ## Decorators ### Global Decorator All stories automatically receive the global `StorybookDecorator` configured in `.storybook/preview.tsx`. This provides: - Theme provider (dark/light mode) - i18n provider - Router context (MemoryRouter) - Toast provider - MSW request interception ### Do NOT Import Application Providers Never import application-level providers directly in stories: ```tsx // BAD — do not do this import { AuthProvider } from '@/providers/AuthProvider'; export const MyStory = () => ( ); // GOOD — the global decorator handles providers export const MyStory = () => ; ``` ## Data Mocking ### Use MSW Handlers All API data should be mocked via MSW handlers in `src/mocks/handlers.ts`: ```tsx // In the story file import type { Meta, StoryObj } from '@storybook/react'; import { http, HttpResponse } from 'msw'; const meta: Meta = { component: MyComponent, parameters: { msw: { handlers: [ http.get('*/api/v1/my-endpoint', () => { return HttpResponse.json({ success: true, data: { items: [] }, }); }), ], }, }, }; ``` ### Loading States Use `delay: 'infinite'` in MSW handlers to simulate loading: ```tsx export const Loading: StoryObj = { parameters: { msw: { handlers: [ http.get('*/api/v1/my-endpoint', async () => { await new Promise(() => {}); // Never resolves }), ], }, }, }; ``` ### Error States Return error responses from MSW handlers: ```tsx export const Error: StoryObj = { parameters: { msw: { handlers: [ http.get('*/api/v1/my-endpoint', () => { return HttpResponse.json( { success: false, error: { message: 'Server error' } }, { status: 500 }, ); }), ], }, }, }; ``` ## File Naming Convention - Story files: `ComponentName.stories.tsx` - Co-located with their component file - Example: `src/components/ui/button.tsx` → `src/components/ui/button.stories.tsx` ## Story File Template ```tsx import type { Meta, StoryObj } from '@storybook/react'; import { MyComponent } from './MyComponent'; const meta: Meta = { title: 'Features/MyFeature/MyComponent', component: MyComponent, tags: ['autodocs'], }; export default meta; type Story = StoryObj; export const Default: Story = { args: { // Default props }, }; export const Loading: Story = { // Loading state configuration }; export const Error: Story = { // Error state configuration }; export const Empty: Story = { // Empty state configuration }; ```