Модуль 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 Kitui-kit/Vite + tsup, npm-пакет @myorg/ui-kitтолько React. Никакого стейт-менеджера, fetch, бизнес-сущностей.
Приложениеapp/Next.js App Router + FSD + Effectorимпортирует UI Kit, держит сторы, виджеты, фичи.
API-слойapp/app/api/*/route.tsNext.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 HandlerHTTP-эндпоинт в 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, возвращает ResponseREST 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).

Слои FSD и разрешённое направление импортов

На схеме — пять слоёв и одно правило: импорт идёт только вниз. 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.tsRoute 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-react 6 требуют React Compiler, Storybook 10 требует новый peer vite-plus, TS 7 не поддерживается typescript-eslint. Для курса выбраны последние стабильные мажоры, которые ставятся без peer-конфликтов и не тащат React Compiler в первый день. Подробности — в boilerplate/README.md.

Что уже настроено

ЧтоИнструментЗачем
Workspacesnpm workspaces (ui-kit, app)UI Kit доступен в Next.js как @myorg/ui-kit без публикации
UI Kit PlaygroundVite + ui-kit/index.html + ui-kit/dev/main.tsxМгновенный HMR при написании компонентов на :5173 (мини-страница с переключателем тем)
UI Kit buildtsup (multi-entry, ESM + .d.ts) + post-build 'use client'npm-публикация + subpath exports (./box, ./button) для tree-shaking
Next.jsApp 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%)
e2ePlaywright 1.61Сценарии на собранном Next.js
LintESLint 9.39 flat config + eslint-plugin-import-xFSD-правила импортов + запрет Effector в UI Kit
Coverage@vitest/coverage-v8Пороги 60% (в М13 поднимаем до 70% UI Kit)
Changesets@changesets/cliSemver + CHANGELOG (М14)
CIGitHub Actionslint → 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+ warning allow-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:

js
const 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 publish UI Kit (М14).
  • Для проверки tree-shaking и size-limit (М10, М14).
  • Для использования UI Kit в другом проекте вне этого workspace.
bash
npm 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:5173ui-kit/index.html + ui-kit/dev/main.tsxМгновенный HMR при правке компонента. Мини-страница с переключателем dark/light/brand тем. Не требует ни Storybook, ни Next.js.
Storybook (канон):6006ui-kit/.storybook/ + ui-kit/stories/Изоляция, документация, axe-a11y addon, controls для всех variants/sizes/states. Развивается по мере добавления компонентов.
UI Gallery:3000/ui-galleryapp/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-правило даёт ложные срабатывания.

Что ловит линтер

НарушениеПримерРеакция
Импорт вверх по FSDapp/entities/message.ts → import { ... } from '@/features/...'error
Effector в UI Kitui-kit/src/components/Box.tsx → import { createStore } from 'effector'error
fetch в UI Kitui-kit/src/components/Avatar.tsx → fetch('/api/avatar')error
localStorage в UI Kitui-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 KitUI Kit нельзя переиспользовать с другим стейт-менеджеромСторы — в app/features/, UI Kit — на пропсах
Бизнес-сущность в пропсах UI KitUI Kit нельзя переиспользовать вне этого доменаНейтральные пропсы: { src, alt }, не { user: User }
fetch в UI KitUI 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. Клонировать и установить

bash
cp -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. Проверить окружение

bash
npm 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. Запустить три уровня разработки

bash
npm run dev          # [ui-kit] Playground на :5173 + [app] Next.js на :3000 (параллельно)
npm run storybook    # Storybook на :6006 (в другом терминале)

Откройте в браузере:

  • http://localhost:5173 — Playground: Box/Text/Button + переключатель dark/light/brand
  • http://localhost:3000/ui-gallery — UI Gallery: компоненты + результат GET /api/health
  • http://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

bash
npm run verify > verify-m0.txt 2>&1    # сохраните вывод — это артефакт сдачи

Приложите verify-m0.txt к сдаче М1.


1.13 Артефакты сдачи М1

АртефактКак получитьКритерий
verify-m0.txtnpm run verify > verify-m0.txt 2>&1Линтер, typecheck, 4 теста и сборка — все зелёные
Скриншот Playgroundnpm run dev → http://localhost:5173Видны Box/Text/Button + переключатель dark/light/brand
Скриншот Storybooknpm run storybook → http://localhost:6006Tokens/Theme preview (3 темы) + Primitives/{Box,Text,Button} со всеми states
Скриншот UI Gallerynpm run dev → http://localhost:3000/ui-galleryКомпоненты + блок «API Health» с status: ok
GET /api/healthcurl 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: дизайн-токены, темизация, примитивы.


🧩 Проверь себя

1. Монорепозиторий для UI Kit + App — когда выгодно?
2. FSD — главное правило слоёв?
3. Boilerplate-репозиторий в курсе — для чего?
4. Public API (index.ts) на слайсе — зачем?
5. Turborepo / Nx в монорепо — зачем?

🔗 Мостик к Модулю 2

Фундамент готов: монорепо поднято, FSD-границы ловятся линтером, три уровня разработки работают. Теперь наполним его: дизайн-токены, темизация (dark/light/brand), примитивы Icon и Divider.