From ec13fa8ca2f668344f76d49142b3cbcec6381e3f Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Sun, 21 Jun 2026 09:13:19 +0300 Subject: [PATCH] docs(design-system): add foundation implementation plan --- .../features/design-system-foundation/plan.md | 643 ++++++++++++++++++ .../features/design-system-foundation/spec.md | 2 +- .../design-system-foundation/tasks.md | 68 ++ 3 files changed, 712 insertions(+), 1 deletion(-) create mode 100644 docs/features/design-system-foundation/plan.md create mode 100644 docs/features/design-system-foundation/tasks.md diff --git a/docs/features/design-system-foundation/plan.md b/docs/features/design-system-foundation/plan.md new file mode 100644 index 0000000..5f6454c --- /dev/null +++ b/docs/features/design-system-foundation/plan.md @@ -0,0 +1,643 @@ +# 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>; + +// 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 = { table: Table; 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` и не владеет 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('.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" +``` diff --git a/docs/features/design-system-foundation/spec.md b/docs/features/design-system-foundation/spec.md index 9091099..308f7e3 100644 --- a/docs/features/design-system-foundation/spec.md +++ b/docs/features/design-system-foundation/spec.md @@ -2,7 +2,7 @@ ## Статус -Draft — ожидает ревью пользователя. +Approved — утверждена пользователем 2026-06-21. ## Цель diff --git a/docs/features/design-system-foundation/tasks.md b/docs/features/design-system-foundation/tasks.md new file mode 100644 index 0000000..cc07d8d --- /dev/null +++ b/docs/features/design-system-foundation/tasks.md @@ -0,0 +1,68 @@ +# Design System Foundation — Tasks + +Исполнять по `plan.md` последовательно, используя TDD и отмечая checkbox только после успешной +проверки соответствующего шага. + +## 1. Pre-flight и workspace + +- [ ] Подтвердить ветку, чистый worktree и зелёные baseline tests/lint/build. +- [ ] Добавить `packages/design-system` в npm workspaces и root scripts. +- [ ] Создать package manifest, TypeScript/Vitest/ESLint configs и test setup. +- [ ] Установить зависимости; проверить пустой package build/test/lint. +- [ ] Закоммитить workspace shell. + +## 2. Tokens + +- [ ] Написать RED-тесты alias resolver: chain, missing target, cycle, type mismatch. +- [ ] Реализовать token schema и resolver; получить GREEN. +- [ ] Написать RED-тесты целостности трёх token levels. +- [ ] Добавить primitive/reference tokens. +- [ ] Добавить light semantic tokens только через aliases. +- [ ] Добавить component tokens только через semantic aliases. +- [ ] Проверить guards, build и отсутствие hardcoded values вне primitives. +- [ ] Закоммитить token foundation. + +## 3. MUI adapter и Storybook + +- [ ] Написать RED-тесты MUI theme contract. +- [ ] Реализовать `createMoexVibeTheme`, type augmentation и provider; получить GREEN. +- [ ] Настроить Storybook React/Vite с общим theme decorator. +- [ ] Подключить addon-a11y и Vitest browser project с Playwright Chromium. +- [ ] Проверить package и static Storybook build. +- [ ] Закоммитить theme adapter и Storybook workbench. + +## 4. Core UI + +- [ ] Реализовать через TDD `Text`, `Heading`, `Link`, `Button`, `IconButton`. +- [ ] Добавить их stories, type checks и a11y checks. +- [ ] Реализовать через TDD `TextField`, `Select`, `Checkbox`. +- [ ] Реализовать через TDD `Surface`, `Card`, `Chip`, `Badge`. +- [ ] Реализовать через TDD `Alert`, `Dialog`, `Skeleton`, `Progress`. +- [ ] Добавить обязательные states, responsive stories и visual baselines. +- [ ] Проверить unit/story/a11y/build gates и закоммитить Core UI. + +## 5. Product patterns + +- [ ] Реализовать через TDD `DataTable`, включая caption, sorting semantics и density variants. +- [ ] Реализовать через TDD `Metric`, `Money`, `PriceChange` без color-only semantics. +- [ ] Добавить financial stories и стабильные screenshot baselines. +- [ ] Реализовать через TDD `FormField` и `FilterBar`. +- [ ] Реализовать через TDD `EmptyState`, `ErrorState`, `LoadingState`. +- [ ] Проверить unit/story/a11y/visual gates и закоммитить patterns. + +## 6. Интеграция и governance + +- [ ] Написать RED-тест frontend provider integration. +- [ ] Подключить workspace package и Inter во frontend shell; удалить локальную MUI theme. +- [ ] Enforce ESLint allowlist для `Box`, `Stack`, `Grid`. +- [ ] Подтвердить, что product pages и legacy CSS не мигрированы. +- [ ] Создать Docusaurus-раздел с foundations, catalog, rules и accessibility. +- [ ] Создать ADR-016 и changelog `0.1.0`. +- [ ] Обновить sidebar, styling docs и README; собрать docs. + +## 7. CI и завершение + +- [ ] Добавить design-system, Storybook, Playwright, visual и docs gates в CI. +- [ ] Запустить полный DoD из Task 12 `plan.md`. +- [ ] Запросить code review и устранить подтверждённые scope issues. +- [ ] Повторить полный DoD, отметить все tasks и сделать финальный commit.