Модуль 1. Введение и фундамент (с boilerplate)
Цель модуля: исключить фрустрацию на старте, дать всем студентам общую рабочую базу, чётко провести границы между UI Kit, приложением и API-слоем, и запустить локальное окружение за 10 минут.
К концу модуля у вас:
- Скопирован и запущен boilerplate-monorepo (UI Kit на Vite + Next.js App Router).
- Работают Vite Playground (
:5173), Storybook (:6006), Next.js (:3000), Vitest, Playwright, ESLint с FSD-правилами. - Понимание, что относится к UI Kit, а что нет, и почему это разделение критично.
- Зелёный
npm run verify— первый артефакт ревью-лога.
📌 Перед началом: React, TypeScript. 🛠 Инструменты: Vite, Next.js, Storybook. ⏱ Время: ~8 ч.
🔥 Инцидент: 5 кнопок в 5 стилях
Команда из 5 разработчиков пишет кнопки в 5 разных стилях. Дизайнер в ярости — каждый экран выглядит по-разному. Button из проекта A не работает в проекте B. Знакомо? Нужен UI Kit — единая библиотека компонентов с общими границами, токенами и Storybook-каноном.
📖 Теория
1.1 Что мы строим в курсе
Мы строим три слоя, которые развиваются параллельно:
| Слой | Где живёт | Технология | Зависимости |
|---|---|---|---|
| UI Kit | ui-kit/ | Vite + tsup, npm-пакет @myorg/ui-kit | только React. Никакого стейт-менеджера, fetch, бизнес-сущностей. |
| Приложение | app/ | Next.js App Router + FSD + Effector | импортирует UI Kit, держит сторы, виджеты, фичи. |
| API-слой | app/app/api/*/route.ts | Next.js Route Handlers (mock) → будущий Go-бэкенд | отдаёт данные, провалидированные по OpenAPI-контракту. |
Ключевая идея: UI Kit ничего не знает про мессенджер. Он знает только про «кнопку», «инпут», «аватар». Приложение собирает UI Kit + Effector + контракты в мессенджер. API-слой — прослойка, которую в финале (М15) заменим на Go.
Почему так: если UI Kit зависит от Effector — его нельзя переиспользовать в другом проекте на Redux/Zustand. Если UI Kit зависит от
UserEntity— его нельзя переиспользовать вне мессенджера. Нейтральность = переиспользуемость.
1.2 Глоссарий курса
| Термин | Что значит |
|---|---|
| FSD (Feature-Sliced Design) | Архитектурная методология: слои shared → entities → features → widgets → pages. Импорты идут только вниз. |
| Иерархия компонентов | Три уровня: примитивы (Box, Text, Button — простые кирпичики, не содержат других компонентов) → составные компоненты (Avatar, MessageBubble — собираются из примитивов, домен-специфичны) → виджеты (в app/widgets/ — композиция для конкретной страницы, не входят в UI Kit). |
| Design tokens | Именованные значения дизайн-системы (цвета, отступы, радиусы) в виде JS-объекта → CSS-переменных. |
| OpenAPI | Спецификация HTTP API в YAML/JSON. Единый источник правды для типов фронтенда, Next.js API и Go-хендлеров. |
| Zod | Библиотека runtime-валидации данных. TypeScript проверяет типы только при компиляции — если API вернул null вместо массива, TS это не поймает и приложение упадёт в runtime. Zod описывает схему и проверяет её при выполнении: Schema.parse(data) либо вернёт типизированный результат, либо выбросит понятную ошибку. Единая схема — источник типов для TS, моков для MSW и контракта с Go. |
| Effector | Стейт-менеджер. Модель: stores (значения), events (триггеры), effects (сайд-эффекты), sample (связка). SSR-friendly. |
| RSC (React Server Component) | Компонент, рендерящийся на сервере в Next.js App Router. Нет клиентского стейта, нет useState/useEffect. |
| Server Action | Функция на сервере, вызываемая из формы/кнопки напрямую. В курсе не используем (обоснование ниже). |
| Route Handler | HTTP-эндпоинт в Next.js App Router (app/api/*/route.ts). Возвращают Response. Наш выбор для API-слоя. |
| Service Worker | Скрипт в браузере, перехватывающий сетевые запросы. Основа PWA и офлайн-кэширования. |
| Core Web Vitals | Метрики UX: LCP (< 2.5s), CLS (< 0.1), INP (< 200ms). Измеряются Lighthouse. |
| MSW (Mock Service Worker) | Библиотека перехвата HTTP-запросов в тестах и Storybook. Один мок — для stories и unit-тестов. |
| Storybook | Изолированная среда разработки и документации компонентов. Каноническая галерея UI Kit. |
| axe-core | Движок аудита доступности (a11y). В курсе — addon в Storybook + в Playwright. |
1.3 Зачем UI Kit и где его границы
Что входит в UI Kit
- Примитивы:
Box,Text,Icon,Divider,Button. - Формы:
Input,Textarea,Select,Checkbox,Radio. - Чат-компоненты (нейтральные):
Avatar,MessageBubble,Attachment,StatusBar. - Overlay:
Modal,Toast,Tooltip,Loader,Skeleton. - Тема:
ThemeProvider,defaultTheme,lightTheme,darkTheme,brandTheme. - Утилиты форматирования:
formatDate,pluralize(i18n-нейтральные, М5).
Что НЕ входит в UI Kit
- Стейт-менеджеры: Effector, Redux, Zustand, MobX. UI Kit — controlled/uncontrolled компоненты на пропсах.
- Бизнес-сущности:
UserEntity,MessageEntity,ChatEntity. Пропсы нейтральны:{ src, alt, size }, а не{ user: User }. - Запросы к API:
fetch,axios, React Query. UI Kit только отображает данные. - Сторонние зависимости кроме React: никаких
react-spring,framer-motionкак hard-dependency (опционально через peerDep). - Локальное состояние приложения:
localStorage,sessionStorage, куки. UI Kit не ходит в браузерное хранилище.
Пример: нейтральный vs связанный пропс
❌ Плохо — UI Kit знает про бизнес:
tsx// ui-kit/src/components/Avatar/Avatar.tsx import { UserEntity } from '@myorg/app/entities/user' // 🚨 нарушение interface AvatarProps { user: UserEntity } // 🚨 бизнес-сущность
✅ Хорошо — UI Kit нейтрален:
tsx// ui-kit/src/components/Avatar/Avatar.tsx interface AvatarProps { src?: string | null alt: string size?: 'xs' | 'sm' | 'md' | 'lg' status?: 'online' | 'offline' | 'away' }
Приложение мапит UserEntity → AvatarProps:
tsx// app/widgets/chat-room/MessageRow.tsx import { Avatar } from '@myorg/ui-kit' import { type User } from '@/entities/user' function MessageRow({ user }: { user: User }) { return <Avatar src={user.avatarUrl} alt={user.name} size="sm" status={user.status} /> }
Правило: граница проходит по пропсам. Если в пропсе бизнес-тип — компонент не в UI Kit.
1.4 Next.js App Router: три модели серверного кода
В Next.js App Router есть три способа выполнить код на сервере. В курсе мы выбираем Route Handlers — и вот почему.
| Модель | Что это | Когда подходит | Почему не наш выбор в курсе |
|---|---|---|---|
| RSC (React Server Component) | Компонент рендерится на сервере, не имеет клиентского стейта | Чтение данных при рендере, статика | Не даёт явного HTTP-контракта. RSC и Effector-сторы (клиент) — конфликтуют по модели. |
| Server Action | Функция на сервере, вызывается из формы/кнопки напрямую | Мутации из форм, без написания API | Привязка к форме; нет явного URL/метода. Миграция на Go потребует переписывания вызовов. |
| Route Handler ✅ | HTTP-эндпоинт app/api/*/route.ts, возвращает Response | REST API, JSON, единый контракт | Наш выбор. Явный URL + метод + тело. Легко заменить на Go-хендлер — контракт не меняется. |
Пример Route Handler
В boilerplate уже есть два эндпоинта: smoke /api/health и /api/mentions (заглушка для М7):
ts// app/app/api/health/route.ts — smoke-эндпоинт: проверка, что Route Handlers работают import { NextResponse } from 'next/server' export async function GET() { return NextResponse.json({ status: 'ok', service: 'messenger-api', timestamp: new Date().toISOString(), }) }
ts// app/app/api/mentions/route.ts — заглушка автокомплита упоминаний import { NextResponse } from 'next/server' export async function GET(request: Request) { const { searchParams } = new URL(request.url) const q = searchParams.get('q') ?? '' // ... логика / mock return NextResponse.json({ suggestions: [...] }) }
В М7 добавим сюда Zod-валидацию ответа и переключение mock/real через env. В М15 — покажем, как тот же URL обслуживает Go-хендлер.
Мост к Yandex Cloud: Route Handlers естественным образом превращаются в Serverless Container / Cloud Functions при деплое — контракт (URL + метод + тело) сохраняется, меняется только адрес.
1.5 Архитектура проекта: FSD в Next.js
В app/ применяется Feature-Sliced Design. Слои (снизу вверх):
app/
├── shared/ # утилиты, типы, api-клиент, zod-схемы (не знают про бизнес)
├── entities/ # бизнес-сущности: Message, User, Chat + их сторы Effector
├── features/ # пользовательские сценарии: mention-autocomplete, send-message
├── widgets/ # композиция для страниц: ChatRoom, ChatList, ChatInput
└── app/ # Next.js App Router: layout.tsx, page.tsx, api/, ui-gallery/
Правило импортов: слой может импортировать только из нижележащих. widgets → features → entities → shared. Обратное запрещено и ловится ESLint (см. 0.7).
На схеме — пять слоёв и одно правило: импорт идёт только вниз.
app → widgets → features → entities → shared. Красный пунктир — попытка
импортировать снизу вверх: такой код не проходит ESLint, поэтому границы слоёв
не размываются со временем.
Что где живёт (по мере прохождения курса)
| Где | Что | Появляется в |
|---|---|---|
app/shared/api/ | HTTP-клиент, типы контракта | М7 |
app/shared/lib/ | formatDate, pluralize, debounce | М5 |
app/entities/message/ | модель Message, стор $messages | М5 |
app/entities/user/ | модель User, стор $currentUser | М5 |
app/features/mention-autocomplete/ | сторы $suggestions, эффект fetchMentionsFx | М8 |
app/features/send-message/ | стор очереди, optimistic update | М12 |
app/widgets/chat-room/ | композиция: MessageList + ChatInput | М15 |
app/app/api/mentions/route.ts | Route Handler (mock → Go) | М7, М15 |
1.6 Boilerplate: монорепо за 10 минут
Готовый starter лежит в
src/courses/ui-kit/boilerplate/. Полная структура и команды — вboilerplate/README.md.
Стек (актуален на 2026)
React 19.2, Next 15.5, Vite 7.3, TypeScript 6.0, ESLint 9.39 (flat config), Storybook 9.1, Vitest 4.1, Zod 4.4, Effector 23.4, Playwright 1.61, tsup 8.5. Node ≥ 22.
Почему не самые свежие мажоры? В 2026 произошёл архитектурный сдвиг: Vite 8 перешёл на Rolldown, Next 16 и
@vitejs/plugin-react6 требуют React Compiler, Storybook 10 требует новый peervite-plus, TS 7 не поддерживается typescript-eslint. Для курса выбраны последние стабильные мажоры, которые ставятся без peer-конфликтов и не тащат React Compiler в первый день. Подробности — вboilerplate/README.md.
Что уже настроено
| Что | Инструмент | Зачем |
|---|---|---|
| Workspaces | npm workspaces (ui-kit, app) | UI Kit доступен в Next.js как @myorg/ui-kit без публикации |
| UI Kit Playground | Vite + ui-kit/index.html + ui-kit/dev/main.tsx | Мгновенный HMR при написании компонентов на :5173 (мини-страница с переключателем тем) |
| UI Kit build | tsup (multi-entry, ESM + .d.ts) + post-build 'use client' | npm-публикация + subpath exports (./box, ./button) для tree-shaking |
| Next.js | App Router 15.5 + transpilePackages: ['@myorg/ui-kit'] + outputFileTracingRoot | Корректная обработка ESM-пакета из workspace без warning'ов |
| Storybook | @storybook/react-vite 9.1 + addon-a11y | Каноническая галерея + axe-аудит |
| Unit-тесты | Vitest 4 + Testing Library + jsdom | Тесты компонентов и сторов (порог coverage 60%) |
| e2e | Playwright 1.61 | Сценарии на собранном Next.js |
| Lint | ESLint 9.39 flat config + eslint-plugin-import-x | FSD-правила импортов + запрет Effector в UI Kit |
| Coverage | @vitest/coverage-v8 | Пороги 60% (в М13 поднимаем до 70% UI Kit) |
| Changesets | @changesets/cli | Semver + CHANGELOG (М14) |
| CI | GitHub Actions | lint → types → tests → build → e2e |
allowScripts | поле в package.json | Доверенные пакеты (esbuild, sharp, fsevents) — для npm 11+ |
Установка и первый запуск
bash# 1. Скопировать boilerplate в свой репозиторий cp -r src/courses/ui-kit/boilerplate ~/projects/my-ui-kit-course cd ~/projects/my-ui-kit-course # 2. Установить зависимости (npm workspaces тянет @myorg/ui-kit и @myorg/app) npm install # 3. Собрать UI Kit в dist/ — ОБЯЗАТЕЛЬНО перед первым `npm run dev:app` / `npm run build`, # т.к. Next.js через `exports` в package.json читает dist/, а не исходники. npm run build:ui-kit # Альтернатива (2 + 3 одной командой): npm run bootstrap # = npm install && npm run build:ui-kit # 4. Полная проверка: lint + typecheck + test + build npm run verify # должно быть всё зелёным # 5. Запустить dev (ПАРАЛЛЕЛЬНО через concurrently) npm run dev # [ui-kit] Vite Playground на :5173 + [app] Next.js на :3000 npm run storybook # отдельно на :6006 (в другом терминале)
Три уровня разработки UI Kit (подробно в §0.8):
- Playground
:5173— мгновенный HMR, мини-страница для правки компонентов- Storybook
:6006— канон: документация, states, axe-аудит- UI Gallery
:3000/ui-gallery— в реальном Next.js + реальныйfetch /api/health
Если
npm run verifyкрасный — не двигайтесь дальше. Самые частые причины:
npm installне отработал install-скрипты (npm 11+ warningallow-scripts) — проверьте полеallowScriptsвpackage.json, оно уже заполнено доверенными пакетамиbuild:ui-kitне запускали — Next.js не найдётdist/
1.7 Сборка UI Kit и его проброс в Next.js
Как Next.js видит UI Kit
В app/package.json:
json{ "dependencies": { "@myorg/ui-kit": "*" } }
В app/next.config.js:
jsconst nextConfig = { transpilePackages: ['@myorg/ui-kit'], // компилирует ESM-пакет из workspace outputFileTracingRoot: path.join(__dirname, '..'), // убирает warning про lockfiles experimental: { optimizePackageImports: ['@myorg/ui-kit'], // tree-shaking }, }
npm workspaces делает symlink node_modules/@myorg/ui-kit → ../../ui-kit. Дальше — нюанс, который часто путает:
Next.js читает
dist/, не исходники. Полеexportsвui-kit/package.jsonуказывает на./dist/index.js. Несмотря наtranspilePackages, Next следуетexports— а значитdist/должен существовать. Поэтомуnpm run build:ui-kitобязателен перед первым запуском (и после любого изменения исходников UI Kit, если вы проверяете именно собранный пакет). Командаnpm run bootstrapделаетinstall+build:ui-kitодной строкой.
Что делает сборка UI Kit
npm run build:ui-kit прогоняет tsup (multi-entry ESM + .d.ts) и затем post-build скрипт ui-kit/scripts/add-use-client.mjs, который добавляет 'use client' баннер во все .js файлы в dist/. Этот баннер обязателен: UI Kit использует React Context/Hooks (ThemeProvider), и Next.js App Router требует директиву на клиентском модуле. (Tsup banner/esbuildOptions.banner в ESM-режиме игнорируется — поэтому пост-обработка отдельным скриптом.)
Когда нужна пересборка dist/
- Перед
npm run dev:app/npm run build:app(если ещё не собирали). - Перед
npm publishUI Kit (М14). - Для проверки tree-shaking и
size-limit(М10, М14). - Для использования UI Kit в другом проекте вне этого workspace.
bashnpm run build:ui-kit # → ui-kit/dist/{index.js, box.js, button.js, ...} ls ui-kit/dist/
Важно: в dev-режиме UI Kit внутри своего workspace итерируется через Vite Playground (
:5173) и Storybook (:6006) — там HMR работает по исходникам. Next.js:3000читаетdist/, поэтому правки в UI Kit видны на:3000только после пересборки.
1.8 Три уровня разработки UI Kit: Playground, Storybook, UI Gallery
В курсе три уровня для разработки и проверки компонентов UI Kit, каждый со своей целью:
| Уровень | URL | Где код | Назначение |
|---|---|---|---|
| Playground | :5173 | ui-kit/index.html + ui-kit/dev/main.tsx | Мгновенный HMR при правке компонента. Мини-страница с переключателем dark/light/brand тем. Не требует ни Storybook, ни Next.js. |
| Storybook (канон) | :6006 | ui-kit/.storybook/ + ui-kit/stories/ | Изоляция, документация, axe-a11y addon, controls для всех variants/sizes/states. Развивается по мере добавления компонентов. |
| UI Gallery | :3000/ui-gallery | app/app/ui-gallery/page.tsx | Интеграционное превью в реальном Next.js: как UI Kit выглядит с ThemeProvider, роутингом и реальным fetch /api/health. |
Когда что использовать:
- Пишете новый компонент → Playground для скорости (HMR за миллисекунды).
- Документируете компонент для команды → Storybook (states, docs, axe).
- Проверяете интеграцию с приложением → UI Gallery (реальный Next + реальный API).
Декоратор тем в Storybook
В ui-kit/.storybook/preview.tsx каждая story оборачивается в ThemeProvider. Переключение тем — через parameters: { theme: 'light' | 'dark' | 'brand' }:
tsx// stories/Button.stories.tsx export const Primary: Story = { args: { variant: 'primary', children: 'Send' }, } export const PrimaryLight: Story = { parameters: { theme: 'light' }, args: { variant: 'primary', children: 'Send' }, }
Правило: каждый новый компонент UI Kit обязан появиться в Storybook в том же PR. Компонент без stories — не слит.
1.9 Next.js API: базовые Route Handlers
Route Handlers живут в app/app/api/<route>/route.ts. Экспортируют функции с HTTP-методами:
ts// app/app/api/mentions/route.ts import { NextResponse } from 'next/server' export async function GET(request: Request) { /* ... */ } export async function POST(request: Request) { /* ... */ } // также: PUT, PATCH, DELETE, HEAD, OPTIONS
Особенности:
- Это серверный код. Не попадает в клиентский бандл.
- Возвращает
Response(илиNextResponseс удобными хелперами). - Можно использовать Node.js API (fs, crypto) — но осторожно при деплое на edge.
- В М7 добавим: валидацию запроса/ответа через Zod, переключение
mock/realчерезprocess.env.API_SOURCE.
1.10 Линтер FSD-импортов (артефакт М1)
Это главный артефакт сдачи М1. Зелёный
npm run lint— доказательство, что границы слоёв настроены.
Конфиг живёт в eslint.config.js (ESLint 9 flat config). Используется eslint-plugin-import-x (форк eslint-plugin-import с поддержкой flat config и ESLint 9+). Ключевое правило — import-x/no-restricted-paths:
js'import-x/no-restricted-paths': [ 'error', { // В import-x 4.x используется `basePath`, а не `baseUrl`. basePath: './app', zones: [ { target: './entities', from: './features' }, // entities не знает про features { target: './entities', from: './widgets' }, { target: './features', from: './widgets' }, { target: './shared', from: './entities' }, // shared — фундамент, не знает ни про кого { target: './shared', from: './features' }, // ... ], }, ],
Для UI Kit — отдельный блок с files: ['ui-kit/**/*.{ts,tsx}']: запрет импорта доменных слоёв приложения и стейт-менеджеров:
js'no-restricted-imports': [ 'error', { patterns: [{ group: ['effector', 'effector-react', '@myorg/app/*'], message: 'UI Kit не должен зависеть от стейт-менеджеров и приложения — это нарушает нейтральность.', }], }, ], 'no-restricted-syntax': [ 'error', { selector: "CallExpression[callee.name='fetch']", message: 'UI Kit не должен делать fetch.' }, ],
Примечание о
no-undef: в конфиге правилоno-undefвыключено для TS-файлов. TypeScript сам проверяет неопределённые идентификаторы (включая DOM-типы вродеHTMLButtonElementи Node-globals вроде__dirname), а ESLint-правило даёт ложные срабатывания.
Что ловит линтер
| Нарушение | Пример | Реакция |
|---|---|---|
| Импорт вверх по FSD | app/entities/message.ts → import { ... } from '@/features/...' | error |
| Effector в UI Kit | ui-kit/src/components/Box.tsx → import { createStore } from 'effector' | error |
| fetch в UI Kit | ui-kit/src/components/Avatar.tsx → fetch('/api/avatar') | error |
| localStorage в UI Kit | ui-kit/src/utils/cache.ts → localStorage.getItem(...) | error |
| Виджет импортирует виджет | app/widgets/chat-list/index.tsx → import { ChatRoom } from '@/widgets/chat-room' | error |
В М15 эти правила войдут в чек-лист ревью как auto-критерий «Соблюдены правила FSD» (вес 4) — CI проверит автоматически.
1.11 Антипаттерны
| Антипаттерн | Почему плохо | Как правильно |
|---|---|---|
| Стейт-менеджер в UI Kit | UI Kit нельзя переиспользовать с другим стейт-менеджером | Сторы — в app/features/, UI Kit — на пропсах |
| Бизнес-сущность в пропсах UI Kit | UI Kit нельзя переиспользовать вне этого домена | Нейтральные пропсы: { src, alt }, не { user: User } |
fetch в UI Kit | UI Kit перестаёт быть предсказуемым, ломает SSR | Запросы — в эффекте Effector (app-слий) |
| CDN-ссылки в UI Kit | Зависимость от внешнего сервиса, офлайн-режим ломается | Ассеты — локально, через import |
| Виджет импортирует виджет | Нарушение FSD, циклические зависимости | Общий код — в entities/ или shared/ |
| Стор в Server Component (RSC) | RSC не имеет клиентского стейта, гидрация ломается | Сторы — только в Client Component ('use client') |
| Компонент без Storybook-историй | Нельзя изолированно проверить, нет документации | Каждый компонент UI Kit → stories в том же PR |
Компромиссы (Trade-offs)
| Решение | Плюсы | Минусы |
|---|---|---|
| Монорепо (UI Kit + App) | Общие типы, atomic-updates, один lockfile | Сложнее CI, нужно transpilePackages |
| Route Handler вместо RSC/Server Action | Явный HTTP-контракт, миграция на Go без боли | Больше шаблонного кода |
ESLint no-restricted-paths | Гарантия FSD-границ на CI | Ложные срабатывания при refactor |
'use client' пост-обработка tsup | Совместимость с App Router | Дополнительный build-шаг |
💻 1.12 Практика (пошагово)
Шаг 1. Клонировать и установить
bashcp -r src/courses/ui-kit/boilerplate ~/projects/my-ui-kit-course cd ~/projects/my-ui-kit-course npm run bootstrap # = npm install && npm run build:ui-kit
bootstrap именно тем и удобен: одна команда ставит зависимости и собирает UI Kit в dist/ (без чего Next.js не запустится — см. §0.7).
Шаг 2. Проверить окружение
bashnpm run verify # lint + typecheck + test + build — должно быть зелёным
Если что-то красное — не двигайтесь дальше, пока не почините. Самые частые причины:
Cannot find module '@myorg/ui-kit'→ не запущенnpm run build:ui-kit(илиbootstrap)- warning
allow-scripts→ проверьте полеallowScriptsвpackage.json
Шаг 3. Запустить три уровня разработки
bashnpm run dev # [ui-kit] Playground на :5173 + [app] Next.js на :3000 (параллельно) npm run storybook # Storybook на :6006 (в другом терминале)
Откройте в браузере:
http://localhost:5173— Playground: Box/Text/Button + переключатель dark/light/brandhttp://localhost:3000/ui-gallery— UI Gallery: компоненты + результатGET /api/healthhttp://localhost:6006— Storybook:Tokens/Theme preview(3 темы) +Primitives/Box,Primitives/Text,Primitives/Button(все variants/sizes/states)
Порты: если порт занят, Vite/Next автоматически берут следующий (5173 → 5174, 3000 → 3001). Смотрите лог
npm run dev.
Шаг 4. Попробовать нарушить FSD-границу
Чтобы убедиться, что линтер работает, намеренно нарушьте правило:
tsx// app/entities/message/model.ts import { something } from '@/features/mention-autocomplete' // 🚨 нарушение
Запустите npm run lint — увидите ошибку import-x/no-restricted-paths. Уберите нарушение.
Шаг 5. Попробовать нарушить нейтральность UI Kit
tsx// ui-kit/src/components/Box/Box.tsx import { createStore } from 'effector' // 🚨 нарушение
npm run lint → ошибка no-restricted-imports про Effector в UI Kit. Уберите.
Шаг 6. Зафиксировать артефакт М1
bashnpm run verify > verify-m0.txt 2>&1 # сохраните вывод — это артефакт сдачи
Приложите verify-m0.txt к сдаче М1.
1.13 Артефакты сдачи М1
| Артефакт | Как получить | Критерий |
|---|---|---|
verify-m0.txt | npm run verify > verify-m0.txt 2>&1 | Линтер, typecheck, 4 теста и сборка — все зелёные |
| Скриншот Playground | npm run dev → http://localhost:5173 | Видны Box/Text/Button + переключатель dark/light/brand |
| Скриншот Storybook | npm run storybook → http://localhost:6006 | Tokens/Theme preview (3 темы) + Primitives/{Box,Text,Button} со всеми states |
| Скриншот UI Gallery | npm run dev → http://localhost:3000/ui-gallery | Компоненты + блок «API Health» с status: ok |
GET /api/health | curl http://localhost:3000/api/health | { status: "ok", service: "messenger-api", timestamp: ... } |
1.14 Чек-лист перед Модулем 2
- Boilerplate скопирован,
npm run bootstrapпрошёл без ошибок. -
npm run verifyзелёный (lint + typecheck + 4 теста + build). -
npm run devподнимает Vite Playground на :5173 И Next.js на :3000 (параллельно, черезconcurrently). -
npm run storybookоткрывает галерею на :6006 (Tokens + Primitives). -
http://localhost:3000/ui-galleryпоказывает компоненты + результатGET /api/health. - Я понимаю разницу между UI Kit, приложением и API-слоем.
- Я могу объяснить, почему UI Kit не должен зависеть от Effector.
- Я знаю три уровня разработки UI Kit (Playground / Storybook / UI Gallery) и когда что использовать.
- Я знаю, что правки в UI Kit видны на
:3000только послеnpm run build:ui-kit(а на:5173и:6006— сразу через HMR). - Я знаю, где искать помощь:
boilerplate/README.md, глоссарий выше,app/FSD.md.
🧩 Проверь себя
🔗 Мостик к Модулю 2
Фундамент готов: монорепо поднято, FSD-границы ловятся линтером, три уровня разработки работают. Теперь наполним его: дизайн-токены, темизация (dark/light/brand), примитивы Icon и Divider.