textmachine/frontend/docs/FRONTEND_SESSION_PROMPT.md

440 lines
45 KiB
Markdown
Raw 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.

# Промт: сессия ФРОНТ TextMachine — MVP веб-интерфейса
## Область ЭТОЙ сессии — этапы S0 и S1, дальше не идти
Фронт режется на шесть сессий. Ты — первая. **Твоя работа кончается на витрине токенов, до единого
экрана приложения.** Это не осторожность: без проверяемой петли обратной связи и сошедшихся токенов
все следующие этапы слепы, а смешивание инструментальной работы с интерфейсной сжигает контекст.
| Этап | Что | Сессия |
|---|---|---|
| **S0** | Планирование: как писать фронт. Пины версий, карта файлов, правила, протокол проверки | **твоя** |
| **S1** | Инструменты, скриншот-цикл, `tokens.css`, витрина | **твоя** |
| S2 | Оболочка (три панели, вкладки, статус-полоса) + слой `src/ui/` | отдельная |
| S3 | Слой данных, MSW, фикстуры всех состояний | хвост S2 или отдельная |
| S4 | Библиотека, загрузка, разбор, прогресс перевода | отдельная |
| S5 | Банк памяти и подпись (самый тяжёлый) | отдельная |
| S6 | Читалка двух колонок и замечания | отдельная |
| S7 | Метаданные, экспорт, настройки, сквозной прогон | отдельная |
**S0 лендится отдельным коммитом до первой строки кода** — иначе план останется словами.
## Обязательное чтение перед работой
1. `frontend/docs/STACK_DECISIONS.md`**пины версий и ловушки**. Все версии сверены 02.08.2026
многоагентным исследованием с адверсариальной проверкой. Не выбирай библиотеки сам,
не «обновляй» пины по памяти: твои знания об экосистеме устарели, а вся документация
в сети описывает ПРОШЛЫЕ версии этих инструментов.
2. `docs/product-requirements.md` — реестр продуктовых требований владельца.
3. `docs/glossary.md` — расшифровка проектных сокращений.
4. `frontend/references/*.png` — три скриншота, **открой и посмотри** (ты умеешь читать изображения).
## Кто ты и твоя зона
Ты фронтенд-сессия. **Зона записи — только `frontend/`.** `backend/`, `platform/`, `docs/`, `eval/` — read-only; расхождения и вопросы — пингом владельцу, не правкой чужой зоны.
### ⚠ Коммит-права и git-протокол (решение владельца 02.08, D39.88 — читать ДО первого коммита)
**Право коммита у тебя ЕСТЬ — но ровно на свою зону: «свою часть коммить, чужую не трогать НИКОГДА».**
1. **Коммить только пути внутри `frontend/`.** Ничего за её пределами — ни `docs/`, ни `backend/`, ни `platform/`, ни корневых файлов, ни `.gitignore`. Нужна правка вне зоны — пинг владельцу, её сделает оркестратор.
2. **Форма коммита — ТОЛЬКО с явным списком путей:** `git commit -- frontend/<файл> frontend/<файл>`. Это не стилистика, а механика: **голый `git commit` уносит ВЕСЬ индекс**, включая файлы, застейдженные параллельной сессией, — и чужая работа уезжает под твоим сообщением. Так уже произошло ДВАЖДЫ 02.08 (`e9a6bb2`, `b98afb5` унесли доки оркестратора). Pathspec-форма чужой индекс не трогает.
3. **НИКОГДА `git add -A`, `git add .`, `git commit -a`.** Только явные пути.
4. **Перед каждым коммитом:** `git status` (опознать чужое) → `git diff --cached --name-only`. Увидел в индексе чужой путь — **не «прибирай» его**, просто коммить pathspec-формой, и он останется на месте.
5. **Не оставляй свои файлы застейдженными** между шагами: пока они в индексе, их может унести чужой коммит. Стейдж и коммит — одной командой.
6. **НИКАКИХ** `reset --hard`, `amend`/`rebase` несвежих коммитов, `checkout` поверх грязного дерева, перезаписи истории. Параллельные сессии — норма, их незакоммиченные файлы не трогать.
7. **Чужое всё-таки уехало в твой коммит?** Историю НЕ переписывать — сообщить владельцу; содержимое цело, теряется только атрибуция.
8. Никогда не коммитить: `START_PROMT.MD` (файл владельца), `.claude/settings.local.json`.
Общие правила проекта — в `CLAUDE.md` в корне (там же эта норма в каноническом виде). Коммиты: английский, одно предложение ≤30 слов, без Co-Authored-By.
## Что за продукт
Веб-сервис перевода книг (веб-новеллы, ранобэ) с одного языка на другой через ИИ. Пользователь загружает книгу, запускает перевод, подписывает словарь терминов, читает результат, выгружает готовое.
**Бэкенда пока нет** — точнее, движок перевода есть, но HTTP-API к нему ещё не построено. Ты работаешь на моках (см. §6). Это не помеха: контракт данных зафиксирован ниже, замена моков на реальные запросы будет точечной.
> ⚠ **Поправка канона (фронт-сессия S1, 02.08).** Формулировка выше читается как «однажды у движка появится HTTP-API». Это не так, и ошибка дорогая: **API будет у платформы, не у движка**, а движок фронту не виден вообще. Прежде чем писать слой данных, прочитай `FRONTEND_PLAN.md` §0.10.2 (карта канона и два провода) и первоисточник `docs/research/23-engine-platform-seam.md`. Там же цена ошибки: моки, снятые не с того уровня контракта, разойдутся с API — ровно то, ради предотвращения чего заведена строка 95 единого бэклога.
---
## 1. Референсы — копировать, а не вдохновляться
В `frontend/references/` лежат три скриншота. **Открой их своим инструментом чтения файлов — ты умеешь смотреть изображения.** Это обязательный первый шаг, до единой строки кода.
- `fleet.png`**главная основа макета**. Копируем оболочку целиком: как устроены панели, отступы, скругления, плотность, палитра.
- `antigravity_main.png` — пустое состояние (ничего не выбрано).
- `antigravity_chat.png` — рабочее состояние с тремя колонками и правой панелью-документом.
Владелец сформулировал прямо: **«взять макет Fleet как он есть по блокам и стилю и полностью скопировать, переделав под наши нужды»**. Это не тот случай, где нужна своя эстетика. Нужна чужая, воспроизведённая точно.
### 1.1. Измеренные значения — брать эти, не выводить свои
Ниже — не оценка на глаз, а **замер пикселей** `fleet.png` (Python/PIL: гистограмма поверхностей, поиск насыщенных пикселей, срез по горизонтали, детект края скругления). Скриншот снят при масштабе **2x** — установлено по кнопкам окна macOS: шаг 40 физических пикселей против штатных 20 CSS. Все размеры ниже уже переведены в CSS-пиксели.
**Поверхности Fleet:**
| Роль | Значение | Где замерено |
|---|---|---|
| Фон оболочки: промежутки, верхняя полоса, статус-полоса | `#090909` | 10.5% площади |
| Заливка панели (все три панели одинаковы) | `#17191a` | 80.5% площади |
| Приподнятая поверхность / наведение | `#27292b` | |
| Выбранная строка, активная вкладка | `#353739` | |
| Подсветка текущей строки (синеватая) | `#152945` | |
| Выделение | `#164e8d` | |
| Основной текст | `#dfe1e3` | |
| **Акцент (фокус ввода)** | **`#746deb`** | тон 243°, насыщенность 0.76 |
| Красный индикатора | `#b82e45` | тон 350° |
**Геометрия Fleet:**
- **Промежуток между панелями — ровно 8px**, одинаковый везде: слева, между всеми панелями, справа (замер среза: четыре промежутка по 16 физических пикселей, без единого исключения).
- **Радиус скругления панели — 6px** (край выходит на прямую за ~11 физических пикселей).
- Панели не имеют ни рамок, ни теней: отделение только промежутком и разницей заливки `#090909``#17191a`.
**Antigravity — для пустого состояния и настроек** (чистый нейтральный серый, без холодного оттенка, в отличие от Fleet):
| Роль | Значение |
|---|---|
| Фон | `#101010` |
| Боковая панель | `#161616` |
| Приподнятая карточка (поле ввода) | `#1c1c1c` |
| Заливка кнопки основного действия | `#252525` |
| Разделитель / граница | `#323232` |
| Текст | `#cecece` |
**Что НЕ замерено и требует проверки скриншот-циклом:** размеры шрифтов, высота строк, внутренние отступы панелей. Их снимай сам сравнением своей витрины с `fleet.png`.
### Что именно снято с `fleet.png` (следуй этому буквально)
**Оболочка.** Очень тёмный, почти чёрный фон окна. Панели лежат на нём **отдельными скруглёнными «карточками»** (радиус ~810px) с чуть более светлой заливкой, разделённые узкими промежутками фона ~68px. Теней нет вообще — разделение только промежутком и разницей заливки. Это главная визуальная подпись Fleet, и владельцу нравится именно она.
**Верхняя полоса.** Слева кнопки сворачивания панелей (левая / нижняя / правая), по центру — название текущего контекста, справа — ряд иконок-действий. Тонкие линейные монохромные иконки.
**Левая панель.** Сверху **ряд вкладок внутри самой панели** (`Files · Search · Git · History · +`) — не отдельный сайдбар с иконками, а вкладки в шапке панели. Ниже дерево: корень, узлы с шевронами, иконки типов, у выбранной строки — светлая скруглённая подложка (~6px), а не рамка.
**Центр.** Полоса вкладок: иконка + имя + крестик; активная вкладка светлее и скруглена. Ниже содержимое с колонкой номеров строк приглушённого цвета, у текущей строки — едва заметная подсветка всей полосы. Мелкие подписи-подсказки над блоками очень тусклым серым. В правом верхнем углу — компактный индикатор проблем.
**Нижняя панель центра** — отдельная скруглённая карточка со своей вкладкой.
**Правая панель.** Вкладка с заголовком и `+`. В пустом состоянии — центрированный блок: иконка, заголовок, описание, ряды «клавиша + подпись». Внизу поле ввода с **акцентной рамкой** — единственное цветное пятно в панели.
**Нижняя статус-полоса** лежит на фоне оболочки, вне карточек: слева хлебные крошки, справа компактные метаданные состояния.
**Цвет.** Практически монохром: серый текст на тёмном. Цвет встречается редко и всегда что-то означает. Акцент — один, холодный.
**Типографика.** Компактный чистый гротеск ~13px в интерфейсе, моноширинный в содержимом. Плотные строки.
### Что снято с `antigravity_main.png` — пустое состояние
Главная область почти пустая, и по её **центру стоит один составной блок** — скруглённая карточка ввода с подсказкой внутри и рядом мелких управляющих элементов по нижнему краю. Никаких иллюстраций, никаких «начните работу» с картинками. Просто действие по центру пустоты.
В левой панели: **выделенная кнопка основного действия во всю ширину сверху**, ниже пункты навигации с иконками, ниже секция-заголовок мелким приглушённым шрифтом с иконками действий справа, ниже дерево. **`Настройки` прибиты к самому низу панели.**
### Что снято с `antigravity_chat.png` — рабочее состояние
Три колонки. В правой панели — **ряд вкладок сверху** (несколько именованных разделов) и содержимое как форматированный документ: заголовки, абзацы, **блоки-выноски с цветной левой границей** (синяя — заметка, зелёная — подсказка) и мелкие «чипы» с моноширинным текстом внутри абзацев.
**Эти выноски — наша модель для подсветки неточностей перевода** (см. §4, пункт про ненавязчивость). Цветная полоска слева и тусклая подпись — вместо заливки текста.
---
## 2. Раскладка нашего приложения
Оболочка Fleet, наполнение наше.
```
┌─────────────────────────────────────────────────────────────────┐
│ верхняя полоса: сворачивание панелей · название книги · действия │
├──────────────┬────────────────────────────────┬─────────────────┤
│ ЛЕВАЯ │ ЦЕНТР │ ПРАВАЯ │
│ │ │ │
│ вкладки: │ вкладки открытых глав │ вкладки: │
│ Книги · │ │ О книге · │
│ Банк · │ содержимое: │ Замечания │
│ Поиск │ — две колонки оригинал/перевод │ │
│ │ — или таблица банка памяти │ метаданные, │
│ дерево: │ — или пустое состояние │ выноски с
│ книга │ │ неточностями │
│ ├ глава 1 │ │ │
│ ├ глава 2 │ │ │
│ └ + глава │ │ │
│ │ │ │
│ ⚙ Настройки │ │ │
├──────────────┴────────────────────────────────┴─────────────────┤
│ статус-полоса: путь · состояние · прогресс │
└─────────────────────────────────────────────────────────────────┘
```
- **Левая панель** — вкладки в шапке (`Книги` / `Банк памяти` / `Поиск`), дерево книг и глав, `Настройки` внизу. Клик по книге открывает её состояние, клик по главе открывает главу в центре.
- **Центр** — вкладки открытых глав, как файлы в Fleet.
- **Правая панель** — вкладки `О книге` (метаданные) и `Замечания` (места, требующие внимания).
- Все три панели сворачиваются кнопками в верхней полосе.
---
## 3. Сценарий и экраны
### 3.1. Пусто — ни одной книги
Центр пустой, по центру — блок добавления книги в духе `antigravity_main.png`: скруглённая карточка, зона переноса файла с подсказкой, под ней компактный ряд полей (язык оригинала, язык перевода, жанр) и кнопка. Без иллюстраций.
### 3.2. Загрузка книги
После выбора файла: **видимое подтверждение, что файл загружен целиком и успешно** — размер, объём, определённый язык. Не молчаливый переход.
### 3.3. Разбор на главы
Дальше книга разбирается на главы. Показать прогресс разбора; по завершении главы появляются деревом в левой панели. Это отдельный видимый шаг, а не часть перевода.
### 3.4. Перевод — первый проход
Кнопка запуска перевода. Пока идёт:
- **у каждой главы в дереве — свой индикатор выполнения** (крутящийся/прогресс), главы обрабатываются не по порядку и это нормально;
- общий прогресс по книге в статус-полосе;
-**не рассказывать, что происходит внутри.** Никаких «сейчас работает редактор», «идёт добыча глоссария», никаких названий моделей. Пользователь видит «идёт перевод» и прогресс. Всё.
### 3.5. Банк памяти — подпись
По завершении первого прохода становится доступен **банк памяти**: таблица терминов книги (имена персонажей, места, термины) с предложенным переводом. Пользователь правит и подписывает.
Таблица должна быть быстрой в работе: терминов бывают сотни, идут подряд, **клавиатура важнее мыши** (перемещение по строкам, утверждение, правка без мыши). Массовые действия. Отдельная кнопка завершения подписи.
### 3.6. Перевод — финальный проход
После подписи — кнопка запуска финального перевода. Те же индикаторы, что и в 3.4.
### 3.7. Чтение и сравнение
Открытая глава в центре: **две колонки — оригинал и перевод**, пролистываются вместе. Абзацы слева и справа по количеству часто НЕ совпадают — это нормально для художественного перевода, выравнивание идёт по крупным блокам, не построчно. Возможность листать главы вперёд-назад.
### 3.8. Замечания
Места, где перевод может быть неточен, помечаются **ненавязчиво**: тонкая цветная полоска у левого края блока и тусклая подпись — по образцу выносок из `antigravity_chat.png`. Никакой заливки текста, никаких ярких маркеров, никаких иконок-восклицаний. Список всех замечаний главы — в правой панели, вкладка `Замечания`.
Правило: **если экран выглядит тревожным — он неправильный.** Замечание — это приглашение посмотреть, а не сигнал аварии.
### 3.9. Метаданные книги
Правая панель, вкладка `О книге`: название, языки, жанр, число глав, объём, даты, состояние перевода. Спокойный список пар «поле — значение», не карточки со статистикой.
⚠ Денежных полей здесь нет — см. §4.8.
### 3.10. Добавление главы
В дереве, под главами книги — действие добавления новой главы. Загруженная глава встаёт в дерево и может быть переведена отдельно.
### 3.11. Экспорт
Кнопка выгрузки текущей книги. Выбор формата, подтверждение готовности.
### 3.12. Настройки
Отдельный раздел (открывается из низа левой панели). Внутри: профиль и доступ, конфигурация моделей, параметры перевода по умолчанию. **Всё техническое живёт здесь и только здесь** — в рабочем потоке его нет.
⚠ Подписки, тарифов, остатка и счетов в MVP НЕТ — см. §4.8.
---
## 4. Жёсткие ограничения
1. **Не раскрывать устройство бэкенда.** Ни названий моделей, ни стадий конвейера, ни внутренней терминологии в рабочих экранах. Пользователю видны: загрузка, разбор, перевод, банк, готово. Всё техническое — в настройках.
2. **Цвет означает состояние и больше ничего.** Интерфейс монохромный. Цветными бывают: полоска замечания, индикатор состояния главы, акцент фокуса. Никаких зелёных кнопок «сохранить» и красных «удалить».
3. **Ненавязчивость замечаний** — §3.8. Это отдельное требование владельца, не деталь.
4. **Плотность.** Работают подолгу; лучше видеть много, чем красиво и мало. Компактные строки, небольшие отступы, маленькие скругления — как во Fleet.
5. **Только десктоп**, тёмная тема, базовая ширина 1440, работать должно и на 1920. Мобильной версии нет.
6. **Русский интерфейс**, кириллица в реальных пропорциях.
7. **Никаких готовых UI-китов** (MUI, Ant, Chakra) — они не дадут воспроизвести Fleet. Только собственные компоненты на токенах; для поведения выпадающих меню, диалогов и подсказок — headless-примитивы без своих стилей.
### Решения владельца от 02.08 — приняты, не переоткрывать
8. **Денег в интерфейсе MVP нет вообще.** Ни сумм, ни потолков, ни оценки стоимости до запуска, ни
счётчика во время прогона, ни подписки, ни остатка. Оплаты в MVP не будет, показывать нечего.
Учёт расхода остаётся внутри движка как телеметрия владельца. Если видишь денежное поле в
каком-либо разделе этого промта — это остаток прошлой редакции, его быть не должно.
9. **Подсветка сомнительных мест — только на уровне блока и главы.** Подчёркивания внутри текста
не делаем: у проверок движка нет байтовых смещений, только счётчики. Вопрос закрыт, к нему не
возвращаться.
10. **Выравнивание колонок — грубое, по единицам экспорта**, ориентир «глава целиком». Механизм в
движке уже есть (`tmctl export --pairs`), достраивать ничего не надо. Читалка обязана нормально
выглядеть и когда вся глава оказалась одним блоком.
11. **Остановка на подписи банка — параметр запуска**, задаётся галочкой в форме перед каждым
прогоном, а не глобальной настройкой.
---
## 5. Технический стек
**Стек зафиксирован в `frontend/docs/STACK_DECISIONS.md` — бери пины оттуда, не выбирай сам.**
Коротко: React 19.2.8 · TypeScript 6.0.3 (не 7 — там нет программного API) · Vite 8.2.0 (внутри
Rolldown, не Rollup) · react-router 8.3.0 в библиотечном режиме · TanStack Query 5 + Zustand 5 ·
CSS Modules + `tokens.css` · **react-aria-components 1.20.0 как ЕДИНСТВЕННАЯ библиотека
примитивов** · react-resizable-panels 4.12.2 (API v4: `Group`/`Panel`/`Separator`).
Три вещи, которые чаще всего делают неправильно, — прочитай про них в STACK_DECISIONS:
раздел про гейт «одно место для цвета», раздел про читалку без синхронизации прокруток,
и §7 «Ловушки».
**Никакого редактора текста** в этом MVP: тексты только читают и сравнивают.
Структура:
```
frontend/
references/ скриншоты (уже лежат)
docs/ этот промт и последующие заметки
src/
tokens/ tokens.css — ЕДИНСТВЕННЫЙ источник цвета и размера
api/ слой данных: сейчас моки, потом HTTP. Один вход.
mock/ фикстуры
shell/ оболочка: панели, вкладки, статус-полоса
features/ books, chapters, bank, reader, settings
ui/ кнопки, поля, таблица, дерево, выноска
```
---
## 5.1. Поддерживаемость — требование владельца, не пожелание
Владелец сформулировал прямо: **«главное, чтоб это было очень легко поддерживаемо»**. Этот код будут править другие сессии, не ты. Правила ниже — проверяемые, не лозунги.
1. **У каждой вещи одно место.** Цвет и размер — только `tokens.css`. Данные — только `src/api/`. Если значение появилось во втором месте, это ошибка, а не удобство.
2. **Плоско и скучно.** Никаких абстракций «на будущее», фабрик, слоёв ради слоёв. Проектный норматив: механизм строится там, где несёт ценность, а не ради архитектурной красоты. Дублирование двух строк лучше преждевременного обобщения.
3. **Файл = один компонент** плюс его `.module.css` рядом. Больше ~150 строк — делить.
4. **Компоненты глупые.** Данные приходят пропсами. Запросы живут на уровне экрана, не в листьях дерева.
5. **Состояние ровно в двух местах:** TanStack Query — всё серверное, Zustand — состояние интерфейса. Копий серверных данных в локальном состоянии нет. Контекстов «на всякий случай» нет.
6. **Глобальных стилей два файла:** сброс и `tokens.css`. Всё остальное — CSS Modules, они скоупятся сами.
7. **Никаких обёрток над обёртками** и никаких UI-китов.
8. **Имена человеческие, без аббревиатур** — проектная норма.
9. **Комментарии короткие:** одна-две строки «почему», не «что». Простыни не нужны.
10. **Каждый экран открывается в изоляции** — свой маршрут и своя фикстура, чтобы его можно было снять скриншотом и проверить отдельно от остальных.
**Проверка на поддерживаемость, которую применяй к своему коду:** добавление нового состояния главы или нового вида замечания должно требовать правки **одного** файла. Если требует трёх — структура неверная, переделай до того, как двинешься дальше.
## 6. Данные: моков придерживаться, API не выдумывать
HTTP-слоя ещё нет. **Весь доступ к данным — через `src/api/`, внутри которого сейчас моки.** Компоненты не знают, что данные поддельные. Когда появится сервер, меняется один модуль.
Заведи фикстуры на одну книгу целиком: метаданные, 58 глав, у каждой главы оригинал и перевод по несколько абзацев, несколько помеченных мест, таблица банка на 2030 терминов в разных состояниях, состояние прогона.
**Материал для фикстур бери реальный** — китайский текст с русским переводом, имена и термины. Выдуманный «Lorem ipsum» даст неверную плотность: кириллица длиннее латиницы, иероглифы короче всего, и колонки поедут. Пример реального фрагмента лежит в `backend/example/chapter1-zh.txt` (читать можно, править нельзя).
Состояния, которые обязаны быть в фикстурах и нарисованы: книга не начата · разбирается · переводится (первый проход) · ждёт подписи банка · переводится (финал) · готова · остановлена пользователем · отклонена (не удалось разобрать файл) · прервана ошибкой.
---
## 7. Как работать — это важнее, чем что писать
### 7.1. Смотри на то, что построил
**Заведи цикл со скриншотами первым делом, до экранов.** Скрипт `npm run shot` поднимает приложение, снимает PNG в `frontend/.shots/`, ты **открываешь этот PNG и смотришь на него** (ты умеешь читать изображения), сравниваешь с `references/fleet.png`, правишь.
Без этого цикла ты пишешь вслепую: код валиден, вид случаен. Это единственный способ выполнить требование «скопировать Fleet».
**Установка проверена на этой машине — делай ровно так, sudo не нужен ни на одном шаге.** Среда: WSL2, Ubuntu 24.04, Node 22, пароль root недоступен.
```bash
npm i -D playwright
npx playwright install chromium # БЕЗ --with-deps: он требует sudo и ставит лишнее
```
Chromium запустится не сразу: не хватает четырёх системных библиотек (`libnss3.so`, `libnssutil3.so`, `libnspr4.so`, `libasound.so.2`). Ставятся локально, без root:
```bash
mkdir -p .tooling && cd .tooling
apt-get download libnss3 libnspr4 libasound2t64
for d in *.deb; do dpkg -x "$d" root; done
rm -f *.deb && cd ..
```
Путь к ним — `.tooling/root/usr/lib/x86_64-linux-gnu`. Пропиши его прямо в команду, чтобы никто о нём больше не думал:
```json
"scripts": {
"shot": "LD_LIBRARY_PATH=$PWD/.tooling/root/usr/lib/x86_64-linux-gnu node scripts/shot.mjs"
}
```
В `.gitignore`: `.tooling/` и `.shots/` — бинарники и снимки в репозиторий не едут.
Проверка, что цикл живой (сделай её до всякого интерфейса): отрисуй страницу с панелью `#17191a` на фоне `#090909`, радиус 6, отступ 8 — сними, открой, убедись, что видишь именно это. Работает браузер headless, окна нет, графический сервер не нужен.
### 7.2. Порядок твоей сессии
**S0 — план (кода нет).** Прочитай всё из блока обязательного чтения. Напиши
`frontend/docs/FRONTEND_PLAN.md`: таблица пинов (пакет · версия · дата релиза · зачем именно нам,
сверенная по npm), карта `src/` с назначением каждой папки, правила поддерживаемости в проверяемой
форме, протокол скриншот-цикла и критерий сравнения с референсом. **Заленди отдельным коммитом.**
**S1 — инструменты и токены.**
1. Проверь `node -v` — нужно **≥ 22.22**. Установи Playwright по процедуре из §7.1 (без sudo).
2. Каркас: Vite + React + TS, ESLint + stylelint + prettier, единая команда `npm run check`.
3. Скриншот-цикл и проверка, что он живой (страница с панелью на фоне, снять, посмотреть).
4. `tokens.css` — значения из `STACK_DECISIONS`/§1.1 этого промта, с комментарием об источнике.
Задай `@layer` явно: порядок каскада между стилями React Aria, токенами и модулями — источник
тихих расхождений. Сразу стилизуй скроллбары: дефолтные на Windows толстые и светлые, они
ломают вид на трёх панелях.
5. **Витрина**: страница из панелей, вкладок, строки дерева и строки таблицы. Сними, положи рядом
с `fleet.png`, **посмотри обе**, сведи.
6. Контракт-тест токенов: рендерим корень, сверяем вычисленные значения CSS-переменных с
замеренными числами. Это заменяет визуальный гейт с эталонами.
**На витрине остановись.** Если токены не сошлись — это и есть результат сессии, честно описанный;
дальше не иди. Экраны пишут следующие сессии.
### 7.3. Ревью исполнением — обязательно
Проектная норма: любая сессия, пишущая код, обязана **проверять себя исполнением**, а не заявлением. Для тебя это значит:
- приложение реально запускается, экран реально открывается — проверено запуском, не предположением;
- скриншот снят и просмотрен, а не «должно выглядеть так»;
- расхождения с референсом названы вслух, даже если исправить не успел;
- если чего-то не сделал — сказано прямо, без «в основном готово».
Отчёт в конце: что построено, что видно на скриншотах, где отошёл от референса и почему, что осталось.
### 7.4. Чего не делать
- Не изобретать API и не ходить в `backend/` за данными — только моки.
- Не тащить UI-киты и не «улучшать» референс своим вкусом.
- Не рисовать мобильную версию, светлую тему, иллюстрации пустых состояний.
- Не раскрывать конвейер (§4.1) — это самое лёгкое требование забыть.
- Не хардкодить цвета и размеры мимо `tokens.css`.
---
## 8. Готово — это когда (для ТВОЕЙ сессии, S0+S1)
- `FRONTEND_PLAN.md` заленден отдельным коммитом до кода.
- `npm run check` зелёный и делает все четыре шага.
- `npm run shot` снимает PNG, ты его открывал и смотрел.
- `tokens.css` — единственный источник цвета и размера; гейт против хардкода включён и **проверен
на живом нарушении** (вставь `#fff` в компонент, убедись, что проверка падает, убери).
- Витрина снята и сведена с `fleet.png`; расхождения названы вслух.
- Контракт-тест токенов проходит.
**Критерий сравнения — не растровое совпадение.** JetBrains Fleet закрыт (скачивание прекращено
22.12.2025), референс снят на macOS при 2x, наша цель — Windows-Chromium с другим хинтингом
шрифтов. Пиксель-в-пиксель недостижим и не является целью. Сходиться обязаны: **замеренные цвета,
промежутки 8px, радиусы 6px, плотность строк и общее впечатление**. Кегли и интерлиньяж — подбором
на глаз до похожести, потому что померить их больше негде.
## 9. Что уже известно про движок — учесть в плане, не открывать заново
Разобрано по коду 02.08. Влияет на форму данных, поэтому знать надо уже на S0.
- **Индикатор прогресса нельзя строить на «готово N из M»**: unit становится `done` только когда
есть и черновые строки всех его членов, и строка редактуры. Во время черновой волны это ноль
почти всё время. Правильно — **пофазно**: `черновик N/M``редактура N/M`.
- **Подпись термина — не UPDATE строки.** Банк пересобирается из файлов на каждом прогоне, прямая
запись в таблицу молча стирается следующим прогоном. Форма контракта подписи это учитывает.
- **Байтовых смещений у замечаний нет** — только счётчики. Поэтому подсветка сомнительных мест
идёт **на уровне блока и главы**, а не внутри текста. Владелец это принял 02.08 (§4.9),
вопрос закрыт.
- **Гранулярность пар грубее ожидаемой**: финальный текст существует на уровне edit-unit, замерено
~1.9 блока на главу — местами вся глава окажется одним блоком. Читалка обязана нормально
выглядеть и в этом случае.
Полный список того, что достраивается в движке — `STACK_DECISIONS.md` §8.