644 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Design System Foundation Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Создать внутренний пакет `@moex-vibe/design-system` с трёхуровневыми токенами, MUI light theme, согласованным UI-каталогом, Storybook и опубликованными правилами.
**Architecture:** Platform-neutral токены хранятся как JSON-compatible TypeScript records и разрешаются собственным проверяемым resolver. MUI-адаптер переводит semantic/component tokens в CSS-variable theme; React-компоненты доступны только через public exports пакета. Storybook служит локальным/CI workbench, Docusaurus — единственной опубликованной документацией.
**Tech Stack:** TypeScript 5, React 18, MUI 6.5, TanStack Table 8, Vitest 4 browser mode, Storybook 10.2 (`@storybook/react-vite`), Playwright Chromium, Docusaurus 3.7.
---
## Зафиксированные интерфейсы
Пакет предоставляет subpath exports:
```json
{
".": "./dist/index.js",
"./tokens": "./dist/tokens/index.js",
"./theme": "./dist/theme/index.js"
}
```
Token source использует плоские DTCG-подобные записи:
```ts
type TokenType = 'color' | 'dimension' | 'fontFamily' | 'fontWeight' | 'duration' | 'cubicBezier' | 'shadow';
type TokenValue = string | number | readonly number[] | readonly string[];
type TokenDefinition = { readonly $type: TokenType; readonly $value: TokenValue };
type TokenCollection = Readonly<Record<string, TokenDefinition>>;
// Primitive содержит абсолютное значение.
'color.green.700': { $type: 'color', $value: '#176747' }
// Semantic/component содержит alias и никогда не дублирует primitive.
'color.action.primary': { $type: 'color', $value: '{color.green.700}' }
```
Публичный React API:
```ts
type Tone = 'default' | 'secondary' | 'positive' | 'negative' | 'muted';
type Density = 'balanced' | 'compact';
type ActionVariant = 'primary' | 'secondary' | 'tertiary' | 'danger';
type TextProps = { variant?: 'body' | 'caption' | 'label' | 'numeric'; tone?: Tone };
type HeadingProps = { level: 1 | 2 | 3 | 4 | 5 | 6; size?: 'display' | 'title' | 'section' | 'subsection' };
type ButtonProps = { variant?: ActionVariant; size?: 'small' | 'medium'; loading?: boolean };
type IconButtonProps = { label: string; size?: 'small' | 'medium' };
type SurfaceProps = { padding?: 'none' | 'sm' | 'md' | 'lg'; elevation?: 'none' | 'sm' | 'md' };
type DataTableProps<T> = { table: Table<T>; density?: Density; loading?: boolean; empty?: ReactNode; caption: string };
type MoneyProps = { value: number; currency?: string; locale?: string; signDisplay?: 'auto' | 'always' | 'never' };
type PriceChangeProps = { value: number; format?: 'percent' | 'money'; currency?: string; locale?: string };
type MetricProps = { label: string; value: ReactNode; supportingText?: ReactNode; trend?: ReactNode };
```
Остальные контракты фиксированы так:
- `Link`: MUI Link без `color`, `variant`, `sx`; добавляет `tone` и сохраняет polymorphic `component`.
- `TextField`: MUI TextField без `color`, `variant`, `size`, `sx`; всегда `variant="outlined"` и
`size="medium"`.
- `Select`: `label`, `value`, `onChange(value: string)`, `options: { value; label; disabled? }[]`,
`error?`, `helperText?`, `disabled?`.
- `Checkbox`: `label`, `checked`, `onChange(checked: boolean)`, `disabled?`, `error?`.
- `Card`: Surface props плюс `header?`, `actions?`, `children`; не знает маршруты и домен.
- `Chip`: `label`, `tone: neutral|info|success|warning|error`, `onDelete?`.
- `Badge`: `value`, `max?`, `label`; decorative badge запрещён без accessible label.
- `Alert`: `severity: info|success|warning|error`, `title?`, `children`, `action?`.
- `Dialog`: `open`, `onClose`, обязательные `title`, `children`, `actions?`.
- `Skeleton`: `width?`, `height?`, `shape: text|rectangular|rounded|circular`.
- `Progress`: `label`, `value?`; отсутствие value означает indeterminate.
- `FormField`: `label`, `htmlFor`, `helperText?`, `error?`, `required?`, `children`.
- `FilterBar`: `children`, `actions?`; отвечает только за responsive layout.
- Page states: обязательный `title`, optional `description/action`; `LoadingState` дополнительно имеет
`label` и `size: section|page`.
Все wrappers запрещают произвольные `color`, `variant`, `size` и `sx`, где они обходят контракт.
`Box`, `Stack`, `Grid` остаются полным и единственным прямым MUI allowlist во frontend.
## Карта файлов
- `packages/design-system/src/tokens/` — schema, три token collections, resolver и guards.
- `packages/design-system/src/theme/` — MUI augmentation, theme factory, provider, component overrides.
- `packages/design-system/src/components/` — Core UI и product patterns; один каталог на компонент.
- `packages/design-system/.storybook/` — единый provider, a11y и browser-test annotations.
- `apps/frontend/src/app/providers/AppProviders.tsx` — подключение provider пакета без миграции страниц.
- `apps/docs/docs/design-system/` — канонические правила; `apps/docs/docs/adr/ADR-016-design-system.md` — архитектурное решение.
### Task 1: Pre-flight и workspace shell
**Files:**
- Modify: `package.json`
- Create: `packages/design-system/package.json`
- Create: `packages/design-system/tsconfig.json`
- Create: `packages/design-system/vitest.config.ts`
- Create: `packages/design-system/.eslintrc.cjs`
- Create: `packages/design-system/src/test/setup.ts`
- Create: `packages/design-system/src/index.ts`
- [ ] **Step 1: Проверить pre-flight до любых implementation edits**
Run:
```bash
git branch --show-current
git status --short
npm run test:backend
npm run test:frontend
npm run lint
npm run build:backend
npm run build:frontend
```
Expected: ветка `codex/design-system-foundation`, чистый worktree и все команды PASS. При сбое
остановиться и классифицировать его до изменения кода.
- [ ] **Step 2: Добавить workspace и root scripts**
В `package.json` добавить `packages/design-system` в `workspaces` и scripts:
```json
{
"build:design-system": "npm run build -w packages/design-system",
"test:design-system": "npm run test -w packages/design-system",
"lint:design-system": "npm run lint -w packages/design-system",
"storybook": "npm run storybook -w packages/design-system",
"build:storybook": "npm run build-storybook -w packages/design-system",
"test:storybook": "npm run test:storybook -w packages/design-system"
}
```
- [ ] **Step 3: Создать package manifest и TypeScript build**
`packages/design-system/package.json` должен быть private ESM package версии `0.1.0`, иметь `files:
["dist"]`, exports из раздела выше, peer dependencies на React 18, MUI 6 и TanStack Table 8, dev
dependencies Storybook `^10.2.9`, `@vitest/browser-playwright`/Vitest `^4.1.8` и Playwright, scripts
`build: tsc -p tsconfig.json`, `test: vitest run --project unit`, `storybook: storybook dev -p 6006
--no-open`, `build-storybook: storybook build`, `test:storybook: vitest run --project storybook`,
`lint: eslint "src/**/*.{ts,tsx}"`.
`tsconfig.json` компилирует `src` в `dist`, включает declarations, `jsx: react-jsx`, strict и
`moduleResolution: bundler`. `vitest.config.ts` сначала содержит unit project с jsdom и
`passWithNoTests: true`; флаг удаляется после Task 2. Test setup подключает jest-dom и matchMedia mock.
Package ESLint config проверяет TypeScript/React hooks, но не включает frontend FSD zones. Root `lint`
дополняется `lint:design-system`.
- [ ] **Step 4: Установить зависимости и проверить пустой пакет**
Run:
```bash
npm install
npm run build:design-system
npm run test:design-system
```
Expected: package-lock обновлён, build PASS, Vitest PASS с `passWithNoTests: true`.
- [ ] **Step 5: Commit**
```bash
git add package.json package-lock.json packages/design-system
git commit -m "build(design-system): add workspace package"
```
### Task 2: Token schema и resolver (TDD)
**Files:**
- Create: `packages/design-system/src/tokens/types.ts`
- Create: `packages/design-system/src/tokens/resolveToken.ts`
- Test: `packages/design-system/src/tokens/resolveToken.test.ts`
- [ ] **Step 1: Написать failing tests**
```ts
it('resolves an alias chain and preserves the declared type', () => {
const tokens = {
base: { $type: 'color', $value: '#176747' },
semantic: { $type: 'color', $value: '{base}' },
component: { $type: 'color', $value: '{semantic}' },
} satisfies TokenCollection;
expect(resolveToken(tokens, 'component')).toEqual({ type: 'color', value: '#176747' });
});
it.each([
['missing alias', { a: { $type: 'color', $value: '{missing}' } }, /Unknown token/],
['cycle', { a: { $type: 'color', $value: '{b}' }, b: { $type: 'color', $value: '{a}' } }, /cycle/i],
['type mismatch', { a: { $type: 'color', $value: '#fff' }, b: { $type: 'dimension', $value: '{a}' } }, /type/i],
])('rejects %s', (_name, tokens, error) => expect(() => resolveToken(tokens, 'a')).toThrow(error));
```
- [ ] **Step 2: Запустить тест и подтвердить RED**
Run: `npm run test:design-system -- resolveToken.test.ts`
Expected: FAIL, module/functions отсутствуют.
- [ ] **Step 3: Реализовать schema и resolver**
Resolver распознаёт только полную alias-строку `/^\{([^}]+)\}$/`, хранит visited path, проверяет
существование target и равенство `$type`, возвращает `{ type, value }`. Смешанные строки вроде
`calc({space.2} * 2)` запрещены.
- [ ] **Step 4: Запустить тест и commit**
Run: `npm run test:design-system -- resolveToken.test.ts`
Expected: PASS.
```bash
git add packages/design-system/src/tokens
git commit -m "feat(design-system): add token contracts"
```
### Task 3: Три уровня токенов
**Files:**
- Create: `packages/design-system/src/tokens/primitives.ts`
- Create: `packages/design-system/src/tokens/semantic.light.ts`
- Create: `packages/design-system/src/tokens/components.ts`
- Create: `packages/design-system/src/tokens/index.ts`
- Test: `packages/design-system/src/tokens/tokens.test.ts`
- [ ] **Step 1: Написать token integrity tests**
Тест объединяет три collections, резолвит каждый token, проверяет уникальные имена и инварианты:
```ts
expect(Object.keys(primitiveTokens).every((name) => !isAlias(primitiveTokens[name].$value))).toBe(true);
expect(Object.keys(semanticLightTokens).every((name) => isAlias(semanticLightTokens[name].$value))).toBe(true);
expect(Object.keys(componentTokens).every((name) => isAlias(componentTokens[name].$value))).toBe(true);
for (const name of Object.keys(allTokens)) expect(() => resolveToken(allTokens, name)).not.toThrow();
```
- [ ] **Step 2: Запустить тест и подтвердить RED**
Run: `npm run test:design-system -- tokens.test.ts`
Expected: FAIL, collections отсутствуют.
- [ ] **Step 3: Добавить минимальный полный набор foundations**
Primitive groups: `color.neutral.{0,50,100,200,400,600,800,900}`, `color.green.{50,100,600,700,800}`,
`color.red.{50,600,700}`, `color.amber.{50,600}`, `color.blue.{50,600}`, `space.{0,1,2,3,4,5,6,8,10,12}`
на 4px grid, `radius.{none,sm,md,lg,pill}`, `font.family.{sans,mono}`, `font.size.{100..700}`,
`font.weight.{regular,medium,semibold,bold}`, `lineHeight.{tight,normal,relaxed}`, `shadow.{none,sm,md}`,
`duration.{instant,fast,normal}`, `easing.standard`, `size.control.{sm,md}`.
`font.family.sans` использует Inter с system-ui fallback. Webfont weights 400/500/600/700 подключаются
один раз во frontend shell в Task 10; Roboto не становится частью нового foundation.
Semantic groups: `color.canvas`, `color.surface.{default,subtle,raised}`, `color.text.{primary,secondary,
disabled,inverse}`, `color.border.{subtle,default,strong,focus}`, `color.action.{primary,primaryHover,
secondary,danger}`, `color.feedback.{info,success,warning,error}`, `color.finance.{positive,negative,
neutral}`, plus semantic typography, focus ring, spacing and control sizes.
Component groups cover только API v1: button, iconButton, field, checkbox, surface, card, chip, badge,
alert, dialog, skeleton, progress, table, metric и pageState.
- [ ] **Step 4: Проверить GREEN и запрет hardcoded values вне primitives**
Run: `npm run test:design-system -- tokens.test.ts`
Expected: PASS. Дополнительный test scan подтверждает, что `semantic.light.ts` и `components.ts` не
содержат hex/rgb/px literals.
- [ ] **Step 5: Commit**
```bash
git add packages/design-system/src/tokens
git commit -m "feat(design-system): define three-level tokens"
```
### Task 4: MUI adapter и provider (TDD)
**Files:**
- Create: `packages/design-system/src/theme/createMoexVibeTheme.ts`
- Create: `packages/design-system/src/theme/MoexVibeThemeProvider.tsx`
- Create: `packages/design-system/src/theme/mui.d.ts`
- Create: `packages/design-system/src/theme/index.ts`
- Test: `packages/design-system/src/theme/createMoexVibeTheme.test.ts`
- [ ] **Step 1: Написать failing theme contract tests**
```ts
const theme = createMoexVibeTheme();
expect(theme.cssVarPrefix).toBe('mv');
expect(theme.colorSchemes.light.palette.primary.main).toBe(resolveValue('color.action.primary'));
expect(theme.typography.body1.fontFamily).toContain('Inter');
expect(theme.shape.borderRadius).toBe(resolveValue('radius.md'));
expect(theme.components?.MuiButton?.defaultProps).toMatchObject({ disableElevation: true });
```
- [ ] **Step 2: Подтвердить RED**
Run: `npm run test:design-system -- createMoexVibeTheme.test.ts`
Expected: FAIL, factory отсутствует.
- [ ] **Step 3: Реализовать adapter**
Использовать `createTheme({ cssVariables: { cssVarPrefix: 'mv' }, colorSchemes: { light: ... } })`.
Theme получает palette, typography, spacing, shape, shadows, transitions и component overrides только
через `resolveValue`. `mui.d.ts` включает `themeCssVarsAugmentation` и добавляет `finance` palette roles.
- [ ] **Step 4: Реализовать provider**
`MoexVibeThemeProvider` оборачивает MUI `ThemeProvider` и `CssBaseline`, принимает только `children`;
mode API в v1 не экспортируется.
- [ ] **Step 5: Проверить и commit**
Run: `npm run test:design-system -- createMoexVibeTheme.test.ts && npm run build:design-system`
Expected: PASS.
```bash
git add packages/design-system/src/theme packages/design-system/src/tokens
git commit -m "feat(design-system): add MUI theme adapter"
```
### Task 5: Storybook и automated story checks
**Files:**
- Create: `packages/design-system/.storybook/main.ts`
- Create: `packages/design-system/.storybook/preview.tsx`
- Create: `packages/design-system/.storybook/vitest.setup.ts`
- Modify: `packages/design-system/vitest.config.ts`
- Modify: `packages/design-system/package.json`
- [ ] **Step 1: Настроить Storybook 10.2**
```ts
const config: StorybookConfig = {
framework: '@storybook/react-vite',
stories: ['../src/**/*.stories.@(ts|tsx)'],
addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],
};
```
`preview.tsx` добавляет decorator `MoexVibeThemeProvider`, background `color.canvas` и параметры
`a11y.test = 'error'`, layout `centered` по умолчанию.
- [ ] **Step 2: Добавить Storybook Vitest browser project**
Использовать `storybookTest`, `@vitest/browser-playwright` и headless Chromium; setup регистрирует
`@storybook/addon-a11y/preview` и project annotations через `setProjectAnnotations`.
- [ ] **Step 3: Проверить стенд**
Run:
```bash
npx playwright install chromium
npm run build:storybook
```
Expected: static Storybook build PASS. Первый `test:storybook` запускается после появления stories в
Task 6.
- [ ] **Step 4: Commit**
```bash
git add package.json package-lock.json packages/design-system
git commit -m "build(design-system): configure Storybook workbench"
```
### Task 6: Typography и actions (TDD)
**Files:**
- Create: `packages/design-system/src/components/{Text,Heading,Link,Button,IconButton}/`
- Test: colocated `*.test.tsx`
- Stories: colocated `*.stories.tsx`
- [ ] **Step 1: Написать failing interaction/type tests**
Проверить semantic heading level, tone mapping, external link rel, loading button disabled state и
progress label, обязательный accessible label IconButton. Type tests отклоняют `color`, произвольный
`variant` и `sx`.
- [ ] **Step 2: Подтвердить RED**
Run: `npm run test:design-system -- Text Heading Link Button IconButton`
Expected: FAIL, exports отсутствуют.
- [ ] **Step 3: Реализовать компоненты по public contracts**
Каждый каталог содержит component, props и index. `Button loading` сохраняет ширину, блокирует повторный
click и имеет `aria-busy`; `IconButton` всегда устанавливает `aria-label={label}`.
- [ ] **Step 4: Добавить stories и проверить GREEN**
Stories: все variants/sizes/tones, disabled, loading, long Russian label, keyboard focus reference.
Run: `npm run test:design-system && npm run test:storybook && npm run build:storybook`
Expected: PASS без a11y violations.
- [ ] **Step 5: Commit**
```bash
git add packages/design-system/src
git commit -m "feat(design-system): add typography and actions"
```
### Task 7: Inputs, surfaces и feedback (TDD)
**Files:**
- Create: `packages/design-system/src/components/{TextField,Select,Checkbox,Surface,Card,Chip,Badge,Alert,Dialog,Skeleton,Progress}/`
- Test/Stories: colocated `*.test.tsx`, `*.stories.tsx`
- [ ] **Step 1: Написать failing contract tests**
Проверить label/helper/error association, Select options и keyboard opening, Checkbox label click,
Surface padding/elevation mapping, Dialog focus/escape/label, Alert role, determinate/indeterminate
Progress accessible name и Skeleton `aria-hidden`.
- [ ] **Step 2: Подтвердить RED**
Run: `npm run test:design-system -- TextField Select Checkbox Surface Card Chip Badge Alert Dialog Skeleton Progress`
Expected: FAIL, components отсутствуют.
- [ ] **Step 3: Реализовать ограниченные wrappers**
`Select` принимает `{ value: string; label: string; disabled?: boolean }[]`; `Checkbox` требует `label`;
`Dialog` требует `title` и управляется через `open/onClose`; Surface/Card не принимают raw elevation.
- [ ] **Step 4: Stories, GREEN и commit**
Stories покрывают default/focus/disabled/error/loading, длинный русский текст и narrow viewport.
Run: `npm run test:design-system && npm run test:storybook && npm run build:storybook`
Expected: PASS.
```bash
git add packages/design-system/src
git commit -m "feat(design-system): add controls and feedback"
```
### Task 8: Финансовые data patterns (TDD)
**Files:**
- Create: `packages/design-system/src/components/{DataTable,Metric,Money,PriceChange}/`
- Test/Stories: colocated `*.test.tsx`, `*.stories.tsx`
- Test: `packages/design-system/src/visual/financial-patterns.visual.test.ts`
- [ ] **Step 1: Написать failing tests**
Проверить table caption, semantic headers, sortable button `aria-sort`, balanced/compact density, loading
и empty states; `Money` через `Intl.NumberFormat`; `PriceChange` знак, текстовое направление и не только
цвет; `Metric` composition.
- [ ] **Step 2: Подтвердить RED**
Run: `npm run test:design-system -- DataTable Metric Money PriceChange`
Expected: FAIL.
- [ ] **Step 3: Реализовать patterns**
`DataTable` принимает готовый TanStack `Table<T>` и не владеет server pagination/sorting. Defaults:
`density="balanced"`, locale `ru-RU`, currency `RUB`. Negative/positive output включает видимый знак и
screen-reader label.
- [ ] **Step 4: Stories, visual baselines и commit**
Canonical screenshot cases: balanced table, compact table, positive/negative metrics, empty/loading.
Browser test запускает portable stories через `composeStories`, затем делает
`expect(page.getByTestId('visual-root')).toMatchScreenshot('<stable-name>.png')`; baselines коммитятся
рядом с visual test. Обновление baseline допустимо только вместе с объяснением визуального изменения.
Run: `npm run test:design-system && npm run test:storybook`
Expected: interaction, a11y и screenshot checks PASS.
```bash
git add packages/design-system/src
git commit -m "feat(design-system): add financial data patterns"
```
### Task 9: Form и page-state patterns (TDD)
**Files:**
- Create: `packages/design-system/src/components/{FormField,FilterBar,EmptyState,ErrorState,LoadingState}/`
- Test/Stories: colocated `*.test.tsx`, `*.stories.tsx`
- [ ] **Step 1: Написать failing tests**
Проверить `htmlFor`/description/error association FormField, wrapping and action placement FilterBar,
semantic heading/action для Empty/Error, `aria-live="polite"` LoadingState и reduced-motion rendering.
- [ ] **Step 2: RED, implementation, GREEN**
Run before: `npm run test:design-system -- FormField FilterBar EmptyState ErrorState LoadingState`
Expected before: FAIL. Реализовать только layout/semantics без API/domain knowledge.
Run after: `npm run test:design-system && npm run test:storybook`
Expected after: PASS.
- [ ] **Step 3: Commit**
```bash
git add packages/design-system/src
git commit -m "feat(design-system): add form and page-state patterns"
```
### Task 10: Frontend integration и MUI boundary
**Files:**
- Modify: `apps/frontend/package.json`
- Modify: `apps/frontend/tsconfig.json`
- Modify: `apps/frontend/vite.config.ts`
- Modify: `apps/frontend/src/app/providers/AppProviders.tsx`
- Modify: `apps/frontend/.eslintrc.cjs`
- Delete: `apps/frontend/src/app/styles/theme.ts`
- Test: `apps/frontend/src/app/providers/AppProviders.test.tsx`
- [ ] **Step 1: Написать failing provider test**
Render `AppProviders`, assert generated `--mv-palette-primary-main` exists and Query/Session providers
по-прежнему доступны. Test не проверяет редизайн страниц.
- [ ] **Step 2: Подключить workspace package**
Добавить dependency, `@fontsource/inter` и aliases к source для dev/test; заменить MUI
ThemeProvider/CssBaseline на `MoexVibeThemeProvider`. Удалить старый локальный theme и импортировать
Inter 400/500/600/700 в provider entry ровно один раз.
- [ ] **Step 3: Зафиксировать ESLint allowlist**
Во frontend запретить root import `@mui/material` и subpaths через `no-restricted-imports`; исключить
только `@mui/material/Box`, `Stack`, `Grid`. Сам пакет design-system использует отдельный lint config.
- [ ] **Step 4: Проверить отсутствие визуальной миграции**
Run:
```bash
npm run test:frontend
npm run lint -w apps/frontend
npm run build:design-system
npm run build:frontend
```
Expected: PASS; legacy `styles.css` и product component markup не изменены.
- [ ] **Step 5: Commit**
```bash
git add apps/frontend packages/design-system package.json package-lock.json
git commit -m "feat(frontend): connect design system foundation"
```
### Task 11: Docusaurus и ADR
**Files:**
- Create: `apps/docs/docs/design-system/{overview,foundations,tokens,components,patterns,accessibility,governance}.md`
- Create: `apps/docs/docs/adr/ADR-016-design-system.md`
- Create: `packages/design-system/CHANGELOG.md`
- Modify: `apps/docs/sidebars.ts`
- Modify: `apps/docs/docs/adr/index.md`
- Modify: `apps/docs/docs/frontend/styling.md`
- [ ] **Step 1: Написать канонические правила**
Документы фиксируют light-only v1, balanced density, три token levels, MUI allowlist, каталог,
component-card template, WCAG 2.2 AA и promotion/change process. Components page содержит матрицу
«задача → компонент → не использовать» и полную карточку обязательного шаблона для каждого public
export. `CHANGELOG.md` начинается с `0.1.0` и документирует public API foundation; governance описывает
обязательную migration note для будущих breaking changes.
- [ ] **Step 2: Добавить ADR-016**
ADR содержит Context, варианты theme-only/hybrid/full-wrapper, решение hybrid, последствия, Storybook
роль и будущие DTCG/Android adapters.
- [ ] **Step 3: Обновить sidebar и проверить docs**
Run: `npm run build:docs`
Expected: PASS без broken links; новый раздел виден как отдельная категория «Дизайн-система».
- [ ] **Step 4: Commit**
```bash
git add apps/docs packages/design-system/CHANGELOG.md
git commit -m "docs(design-system): publish usage guidelines"
```
### Task 12: CI, visual checks и финальная верификация
**Files:**
- Modify: `.gitea/workflows/ci.yml`
- Modify: `README.md`
- Modify: `docs/features/design-system-foundation/tasks.md`
- [ ] **Step 1: Добавить CI gates**
После `npm ci` установить Chromium `npx playwright install --with-deps chromium`; добавить design-system
unit/story tests, Storybook build, design-system build и docs build. Сохранять Storybook static build и
visual diff через `actions/upload-artifact@v4` с `if: failure()`.
- [ ] **Step 2: Обновить команды README**
Добавить `npm run storybook`, `build:storybook`, `test:design-system`, `test:storybook`,
`build:design-system` и пояснить, что Docusaurus — published docs, Storybook — engineering workbench.
- [ ] **Step 3: Запустить полный DoD**
```bash
npm run format:check
npm run lint
npm run test:backend
npm run test:frontend
npm run test:design-system
npm run test:storybook
npm run build:backend
npm run build:design-system
npm run build:storybook
npm run build:frontend
npm run build:docs
git diff --check
git status --short
```
Expected: все команды PASS; status содержит только намеренные изменения до финального commit.
- [ ] **Step 4: Обновить SDD tasks и запросить code review**
Отметить выполненные checkbox в `tasks.md`, применить `superpowers:requesting-code-review`, исправить
только подтверждённые scope issues и повторить полный DoD.
- [ ] **Step 5: Final commit**
```bash
git add .gitea/workflows/ci.yml README.md docs/features/design-system-foundation
git commit -m "ci(design-system): enforce foundation quality gates"
```