Andrey Epifancev 45ff5fac23 Спека: решение 19 — итоги финального ревью (#65)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:57:58 +04:00

34 KiB
Raw Blame History

Context

main 57bf1fa. Материалы дизайн-системы (вне репозитория, ~/projects/jira-bridge/design/):

  • DESIGN-SYSTEM-RULES.md, STYLE-INVENTORY.md, REACT-COMPONENT-CATALOG.md — правила и инвентарь AURA;
  • AURA-xlsx-tool-handoff-2026-09-29.zip — исходники AURA: design-system/tokens.json (канон токенов), src/styles/tokens.css (сгенерированные CSS-переменные), src/styles.css, design-system/foundations.md;
  • Overview.svg, Универсалки-2…7.svg — экспорт Figma «Универсалки»: основы (цветовые роли, типографика, геометрия), загрузка файлов, составные компоненты (плитки выбора, сообщения, панель действия), макеты, контейнер контента, базовые компоненты (кнопки, табы, шаги, тема, навигация приложений).

Что важно из системы:

  • Цвета (светлая): канва #f8f8f6, поверхность #fdfdfc, приглушённый фон #fafaf8, текст #17171a, вторичный #818190, плейсхолдер #5c6260, граница #e5e5e0, сильная граница #cfcfc8, действие #568d32 (hover/active #477729), выбранное — фон #f4faf5 и граница #568d32, ошибка #b42318 / фон #fff1f0, предупреждение #d89614 / фон #fffbe6 / граница #ffe58f, фокус rgb(42 122 70 / 35%). Тёмная: канва #181818, поверхность #1f1f1f, приглушённый #272727, текст #f2f4f2, вторичный #d6dcd7, плейсхолдер #aab2ac, границы rgb(232 238 233 / 10%) и / 17%, действие #69a93d (hover #83c657), текст на действии #112016, ошибка #e26c67 / фон #402725, предупреждение #e8c17a / фон #382f20 / граница #8a6d1d, фокус rgb(116 184 255 / 55%).
  • Типографика: заголовок раздела Bold 20/28, текст Regular 14/20, подпись Semibold 14/20, мелкий текст 12/16, крупный 16/24.
  • Геометрия: шаг 4 px; контрол 32 px (крупный 40), радиус контрола 10; кнопки — «таблетки» (радиус 999); панели — радиус 16, отступ 16–24; окно/канва — радиус 20–24; флажок 16×16 радиус 4; контейнер контента 1440 px; переходы 180 ms ease, нажатие 100 ms.
  • Компоненты из Figma: кнопки (основная зелёная, вторичная контурная, опасная, с загрузкой), сегментный переключатель на сером треке с белой активной «таблеткой» и зелёным текстом («Навигация приложений»), переключатель темы (солнце / луна), сообщения успеха и ошибки (иконка в круге, заголовок, пояснение), плитки выбора, плашки файлов, шаги процесса.

Приложение сейчас (web/src): глобальные стили styles/{theme,base,controls}.css (переменные --bg, --fg, --muted, --line, --card, --panel, --soft, --accent синий #1f6f8b, палитра видов работ --k-*, приоритетов --p-*, стрелок --edge*, --guide), стили страниц board/board.css (165 строк, в нём же вход, список, карточка), issues/issues.css, projects/projects.css, shell/shell.css. Шрифт IBM Plex Sans/Mono из @fontsource. Иконки — символы текста (⋯ ⇄ ⚑ ▥ ✕ ▼). Обновление из Jira, ход пакета и тема живут в board/useBoardSource.ts и board/components/Toolbar.tsx; тема — shell/theme.ts (ключ graph-theme: "" системная, light, dark).

Goals / Non-Goals

Goals: приложение выглядит как AURA в обеих темах; каждый экран собран из одних компонентов и токенов; общие действия (обновление из Jira, тема, токен) — в оболочке; фильтры доски и списка сгруппированы и не перегружают экран; поведение, адреса, ключи localStorage и логика доски — прежние.

Non-Goals: см. proposal.md.

Decisions

  1. Без Ant Design. Приложение на своих компонентах; тянуть antd ради внешнего вида — тяжёлая зависимость и переписывание всех контролов. Токены AURA переносятся в web/src/styles/tokens.css вручную с пометкой источника (tokens.json 29.09.2026); скрипта синхронизации нет.
  2. Токены — два слоя. Семантические имена AURA (--color-bg-canvas, --color-text-secondary, --color-action-primary, --space-*, --radius-*, --font-size-*, --component-control-height …) для светлой и тёмной темы плюс токены приложения, которых в AURA нет: палитра видов работ --k-*, приоритеты --p-*, стрелки --edge, --edge-strong, --guide, дорожки доски. Старые имена (--bg, --fg, --muted, --line, --card, --panel, --soft, --accent, --accent-fg) на время перехода — псевдонимы семантических; после переноса всех страниц псевдонимы удаляются. --edge-strong и --accent становятся зелёными; --guide (передачи, критический путь) остаётся оранжевым — его роль — выделение поверх зелёного. Палитра --k-* подбирается заново под тёплую канву, оттенки остаются различимыми между собой и с зелёным действием.
  3. Цвета только из токенов. Вне tokens.css в CSS нет литералов цвета (#…, rgb(…), hsl(…), именованных, кроме transparent, currentColor, inherit); проверка — тест Vitest, который читает все *.css в web/src. Так новая страница не может «забыть» тему.
  4. Шрифт — Mulish (@fontsource/mulish 5.3.0, начертания 400/600/700, подмножества с кириллицей): ближайшая свободная гарнитура к Proxima Nova по пропорциям; Montserrat шире и съедает место в плотных таблицах. Моноширинный — IBM Plex Mono (ключи задач, код, исходник разметки), как сейчас. IBM Plex Sans удаляется из зависимостей.
  5. Иконки — свои SVG в web/src/ui/icons.tsx (линейные 16/20 px, обводка 1.5, currentColor), набор под нужды приложения: обновить, загрузка/файл, меню (⋯), закрыть, шеврон, поиск, фильтр, солнце, луна, внешняя ссылка, предупреждение, галочка, ошибка, передачи, критический путь, по датам, соседи, связи, сетка, сброс, легенда. Без новой зависимости; текстовые символы в интерфейсе заменяются иконками.
  6. Компоненты web/src/ui/: Button (варианты primary, secondary, danger, ghost; размеры 32 и 40; «таблетка»; состояние загрузки — крутилка вместо иконки, кнопка недоступна), IconButton (32×32, радиус 10, имя — aria-label), Segmented (трек --color-bg-subtle/серый, активный сегмент — поверхность и зелёный текст; ссылки или кнопки), ThemeSwitch (солнце/луна), Field (подпись Semibold 14/20 над контролом), TextInput, SearchInput (иконка поиска, очистка), Select (родной <select>, 32 px, радиус 10, своя стрелка), Checkbox (16×16, радиус 4, зелёный при отметке), Badge (статус, сосед, счётчик), Chip (снимаемая плашка фильтра: «Спринт: X ✕»), Notice (успех / ошибка / предупреждение / сведения: иконка, текст, необязательное действие), Panel (поверхность, граница, радиус 16), PageHeader (заголовок 20/28, подзаголовок 14/20 вторичным, место для действий справа), Dialog (родной <dialog>, радиус 20, тень канвы), Menu (выпадающее меню на основе нынешнего Dropdown), Popover. Компоненты держат только вид и доступность; логика страниц остаётся в страницах.
  7. Состояние «предупреждение» разрешено. В AURA его нет в контролах, но токены warning в системе есть, а хабу нужно отличать «агент офлайн», «хаб не отвечает — прежние данные» от ошибок. Используется только в Notice, Badge и тексте состояния; у полей ввода состояния warning нет.
  8. Контейнер. Страницы «Задачи», «не найдено», вход — контейнер до 1440 px по центру с боковым отступом 24 px (16 px уже 640 px). Доска — во всю ширину окна с отступом 24 px: графу нужна ширина. Верхняя панель — во всю ширину, её содержимое выровнено по тем же отступам.
  9. Верхняя панель (оболочка), высота 64 px, поверхность, нижняя граница; слева направо: название «Хаб Jira» (Bold 16/24), выбор проекта (Select), разделы — Segmented из ссылок «Доска связей» / «Задачи» (активный — aria-current="page"), растяжка, блок данных Jira, ThemeSwitch, меню IconButton ⋯ с пунктом «Сменить токен». Уже 1100 px блок данных переносится второй строкой панели; уже 640 px — название скрыто, разделы на всю ширину.
  10. Блок данных Jira: точка и подпись агента («агент на связи» зелёной точкой / «агент офлайн» — предупреждение; GET /agent при старте и раз в 60 с, подсказка — время последнего выхода на связь), текст «данные на ДД.ММ ЧЧ:ММ» (last_sync.finished_at из снимка доски текущего проекта; «полного обновления не было»), кнопка primary «Обновить из Jira» с иконкой; во время пакета — состояние загрузки и текст хода «пакет #N в очереди / выполняется, ~N с»; итог (выполнен / не выполнен: текст / отменён / потерян) — текстом с цветом статуса до следующего события или 10 с для «выполнен». Тексты событий — нынешние statusText для пакетных событий.
  11. Обновление из Jira переезжает в оболочку (web/src/shell/refresh.ts — хук и контекст): постановка POST /refresh {full: true, author: "viewer"} с проверкой GET /agent, один опрос GET /batches/{id} раз в 3 с, остановка на терминальном статусе, 4xx, 404 и после 5 ошибок «хаб не отвечает» подряд — правила прежние (M-2…M-4 #20). Подхват незавершённого пакета viewer с первой командой refresh — при входе в приложение и после каждой успешной загрузки снимка доски (подписка на кэш запросов), кроме перечитывания после своего пакета. По завершении пакета инвалидируются снимки всех досок (["board"]), списки задач (["issues"]), карточки (["issue"]) и проекты (["projects"], счётчики задач). Доска, показывающая файл, файл не заменяет (M-1). «Новый проект» отдаёт batch_id созданного пакета прямо в оболочку — опрос начинается сразу, без подхвата.
  12. Доска после переезда (useBoardSource): источник (хаб / файл), reload, loadFile, события снимка (загрузка, хаб не отвечает, файл не разобран, JSON применён, ошибка) — как были; пакетных событий нет. Строка состояния доски показывает только свои события, пакетные — в оболочке.
  13. Шапка доски (липкая, как сейчас): PageHeader «Доска связей», подзаголовок — счётчики («42 задачи из 120 · +5 соседей · 60 связей из 80 · скрыто без связей: 3»), источник — Badge («хаб» не показывается; «из файла: имя» с кнопкой ✕ = «Перечитать»), событие доски — текстом под заголовком; справа — Button secondary «Проблемы» со счётчиком (Badge ошибки, если > 0) и меню ⋯: «Перечитать», «Загрузить файл…», «Экспорт JSON», «Таблица связей» (переключатель), «Привязка к сетке» (переключатель), разделитель, «Сбросить раскладку» (с прежним подтверждением). Темы в меню доски нет.
  14. Панель управления доски — Panel в одну строку (перенос по ширине): «Спринты» и «Исполнители» — мультиселекты (нынешний MultiSelect, кнопка в виде Select с подписью внутри), разделитель, группа «Показать»: переключатели «Соседи по связям», «Только передачи», «Скрыть без связей»; группа «Режим»: «Критический путь», «По датам». Переключатель — кнопка-«таблетка» с иконкой, включённый — стиль «выбрано» (фон --color-bg-selected-green, зелёная граница и текст), aria-pressed. Подсказки (title) — нынешние.
  15. Легенда — под панелью, сворачивается кнопкой «Легенда» (aria-expanded); свёрнута — видно число скрытых видов работ и типов связей («скрыто: 2»), если они есть. Состояние свёртки — localStorage ключ jira-hub-legend ("0" свёрнута; по умолчанию развёрнута). Поведение пунктов (щелчок скрывает вид / тип) — прежнее.
  16. Карточки на доске: радиус 12, граница --color-border-default, поверхность; ключ — моно, цвет действия; статус — Badge; размеры, ручки перетаскивания, растяжка и измерение высоты — прежние (меняются только цвета, радиусы и шрифт; высота по содержимому считается тем же слоем измерения, поэтому смена шрифта не ломает раскладку, а сохранённые размеры карточек остаются). Дорожки — чередование через --color-bg-subtle.
  17. Список задач. PageHeader «Задачи», подзаголовок «показано N» (и «есть ещё», если следующая порция есть). Под ним Panel фильтров: строка 1 — SearchInput «Ключ или тема» (широкий), Segmented «Открытые | Все» (замена флажка «скрыть закрытые», адрес тот же: «Все» — closed=1), переключатель-«таблетка» «Только соседи» (neighbor=1), кнопка «Фильтры» со счётчиком выбранных из шести списков; строка 2 (при выбранных) — Chip «Спринт: X ✕» на каждый выбранный список и «Сбросить» (снимает шесть списков, поиск и переключатели не трогает); панель «Фильтры» раскрывается под строкой сеткой Field+Select по 3 в ряд (спринт, исполнитель, вид работы, статус Jira, метка, эпик). Раскрыта ли панель — в sessionStorage (jira-hub-issue-filters). Подписи и варианты списков, «(нет на доске)» — как сейчас.
  18. Таблица задач — в Panel без внутреннего отступа, шапка липкая; колонки: Ключ (моно, ссылка; рядом Badge «сосед»), Тема, Статус Jira (Badge), Исполнитель, Срок (просрочено — цветом ошибки, по правилу карточки), Спринт, Эпик, Вид работы, Тип. Строка 44 px, при наведении — приглушённый фон; щелчок по строке (кроме ссылок и выделения текста) открывает карточку тем же переходом, что ключ. «Показать ещё» — Button secondary по центру под таблицей. Пусто — Notice сведений «По этим фильтрам задач нет».
  19. Карточка задачи — Dialog 1000 px, радиус 20; шапка: ключ (моно), Badge статуса, справа Button secondary «Открыть в Jira» с иконкой внешней ссылки и IconButton «Закрыть»; тема — 20/28 Bold; строка фактов — 14/20 вторичным, «просрочено» — Badge ошибки. Разделы — заголовки 16/24 Semibold (без верхнего регистра); правая колонка — Panel приглушённого фона: заметки, прочие поля, команды. Форма заметок — Field/Select/textarea системы, «Сохранить» primary, «Отмена» secondary. Содержание, порядок и поведение разделов — прежние.
  20. Вход — Panel 480 px по центру канвы: заголовок 20/28, пояснение, поле 40 px, Button primary «Войти» (40 px); ошибка — Notice ошибки. «Новый проект» — Dialog 480 px с Field-полями, «Создать» primary, «Отмена» secondary, ошибка хаба — Notice у кнопок. «Не найдено», ошибка отрисовки, проект не найден, нет проектов — Notice в контейнере с действием.
  21. Тема — ThemeSwitch в оболочке, два положения. Ключ graph-theme прежний: без сохранённого выбора (или "") — тема системы, переключатель показывает её; щелчок сохраняет light или dark. Пункта «Тема: системная» больше нет: вернуть «как в системе» — убрать выбор нельзя, это осознанное упрощение (вторичный сценарий).
  22. Фокус и доступность: видимое кольцо фокуса 2 px --color-focus-ring со смещением 2 px у всех интерактивных элементов; цвет не единственный признак состояния (включённые переключатели — aria-pressed и иконка-галочка или заливка; ошибки — иконка); prefers-reduced-motion отключает переходы.
  23. Проверка вида. Скриншоты Playwright на тестовом хабе (web/scripts/test-hub.sh) 1920×1080 и 390×844 в светлой и тёмной темах: доска, задачи с раскрытыми фильтрами, карточка, вход, «Новый проект» — прикладываются к PR (в репозиторий не попадают, снимаются скриптом web/e2e/screens.spec.ts по флагу SCREENS=1). Пиксельных эталонов в наборе тестов нет: вид будет меняться по замечаниям владельца.
  24. Тесты. Логика доски и golden-эталоны не меняются. Тесты, привязанные к разметке (Toolbar, BoardPage, IssuesPage, LoginScreen, projects, e2e), переписываются под новые роли и подписи; тесты опроса пакета переезжают из useBoardSource.test.tsx в тест хука оболочки. Новые: компоненты ui/ (роли, aria-*, состояния), тест «цвета только из токенов», тест переключателя темы.

Risks / Trade-offs

  • Шрифт меняет ширину текста → сохранённые высоты карточек на доске могут обрезать текст. Смягчение: высота «по содержимому» пересчитывается двойным щелчком по уголку, как сейчас; «Сбросить раскладку» доступна.
  • Переезд обновления в оболочку затрагивает отработанные правила опроса (M-1…M-5 #20). Смягчение: перенос кода и тестов почти без изменений, меняется только владелец состояния и набор инвалидируемых запросов.
  • Большой дифф стилей → регрессии вида на редких состояниях (ящик «Проблемы», режим «по датам», экспорт). Смягчение: скриншоты всех экранов в PR, владелец смотрит живое приложение.

Decisions made without discussion

Владелец 21.10.2026 отдал редизайн и UX на усмотрение агента («сделай редизайн и проработай UX сам, потом будем отталкиваться»); его входные данные — только: «и то и то» (родство с AURA и исправление неудобств), примеры неудобств (обновление из Jira только с доски, перегрузка фильтрами, «падинги не те»), сценарий (раз в спринт граф, затем поиск и перепроверка задач), «фильтры все нужны». Всё ниже — решения агента.

# Дата Решение Обоснование Цена ошибки
1 21.10.2026 Без Ant Design, токены вручную (решение 1) antd — замена всех контролов и тяжёлая зависимость ради вида низкая: вид тот же, antd можно добавить позже
2 21.10.2026 Mulish вместо Proxima Nova (решение 4) Proxima Nova платная; Mulish ближе по пропорциям, с кириллицей низкая: замена шрифта — одна строка токена и пакет
3 21.10.2026 Свои SVG-иконки без библиотеки (решение 5) ~20 иконок, зависимость не нужна низкая
4 21.10.2026 Предупреждение разрешено вне контролов (решение 7) хабу нужно отличать «офлайн» и «прежние данные» от ошибок низкая
5 21.10.2026 Доска во всю ширину, прочее — контейнер 1440 (решение 8) графу нужна ширина, таблице и карточке — ограничение строки низкая
6 21.10.2026 Обновление из Jira и ход пакета — в оболочке, инвалидация всех данных (решения 10–12) пример неудобства владельца; после обновления устаревают и список, и карточка средняя: правила опроса переносятся, регрессии ловят перенесённые тесты
7 21.10.2026 Редкие действия доски — в меню ⋯, режимы — группами «Показать» / «Режим» (решения 13–14) «перегрузка фильтрами»; доска нужна раз в спринт, режимы — основное, файл/экспорт — редко низкая: перестановка кнопок
8 21.10.2026 Легенда сворачивается, состояние в localStorage (решение 15) легенда занимает строку, нужна для чтения цветов — свёрнута по выбору низкая
9 21.10.2026 Список: поиск и «Открытые / Все» на виду, шесть списков — в панели «Фильтры» с плашками (решение 17) частые действия на виду, редкие — по запросу; выбранное видно плашками низкая
10 21.10.2026 Щелчок по строке таблицы открывает карточку (решение 18) основной сценарий списка — открыть и перепроверить задачу низкая
11 21.10.2026 Тема — два положения, системная только без сохранённого выбора (решение 21) переключатель AURA двухпозиционный низкая: вернуть третье положение — пункт меню
12 21.10.2026 Проверка вида скриншотами в PR, без пиксельных эталонов (решение 23) вид будет меняться по замечаниям, эталоны мешали бы низкая
13 22.10.2026 Задача 1: тёмные --color-action-danger #ffaea5 и hover #ffcbc5 взяты из tokens.json AURA; --color-status-error остаётся #e26c67; затемнение фона окон везде --color-overlay 45% (у проектов было 40%); палитра --k-*/--p-* подобрана на глаз, --k-test малиновый (#a63d78 / #e07fb0), чтобы не сливаться с зелёным действием токены AURA — канон; один overlay вместо двух значений; различимость видов задач на доске низкая: правка значений в tokens.css
14 22.10.2026 Задача 4: регресс T4.1 (счётчик skipPickup не уменьшается при ошибке перечитывания) чинится в Задаче 5, без отдельного раунда ревью; в Задаче 4 пропуск подхвата сделан счётчиком вместо флага, подхват коалесцируется, тоны refreshText: error для batch-lost/failed/hub-down/error, warning для cancelled регресс мелкий и в том же модуле, что правится в Задаче 5 низкая: один пропущенный подхват чужого пакета до следующей загрузки снимка
15 22.10.2026 Задача 5: высота верхней панели min-height: 64 (не фиксированная), чтобы вторая строка данных переносилась при ширине <1100 px; панель не sticky перенос без обрезки низкая: заменить на фиксированную высоту и скролл строки
16 22.10.2026 Задача 8: ниже 1100 px таблица списка прокручивается по горизонтали внутри панели, шапка таблицы там не липкая; от 1100 px липкая overflow на предке отключает position: sticky; широкая таблица на узком экране важнее липкой шапки низкая: на узком экране шапку не видно при прокрутке вниз
17 22.10.2026 Задача 9: в окне карточки текст Notice 14 px основным цветом (локальный оверрайд .issue .ui-notice__text, общий компонент не тронут); ui/Dialog пропускает остальные атрибуты <dialog> и принимает onNativeClose; классы .who → c-head, .confirm → note-confirm из-за протечки глобальных правил board.css/controls.css 12 px вторичным плохо читается на фоне ошибки; IssueModal сохраняет прежнюю логику закрытия низкая: вернуть размер текста / переименовать классы
18 22.10.2026 Задача 10: --lane-alt светлый #f5f5f2, тёмный #252525 (свёрнутая дорожка в тёмной отличается рамками, не фоном); заголовки «не найдено» и ошибки отрисовки — h2 внутри Notice; текст Notice основным цветом 12/16 (в карточке 14/20); на 390 px в верхней панели проект, тема и меню в одной строке, переключатель разделов — ниже палитра AURA ограничена; различимость дорожек, контраст текста сообщений низкая: правка значений токенов и order в shell.css
19 22.10.2026 Финал: задача 11 принята без отдельного ревью задачи (покрыта финальным ревью); фикс-волна по финальному ревью — кнопка в loading сохраняет вид своего варианта, текст предупреждений на светлом color-mix(warning 55%, text-primary), статус пакета в верхней панели от 1100 px лежит у нижней границы (макс. 560 px, многоточие, полный текст в title), role=status — постоянный контейнер; «агент офлайн» и событие при офлайн-агенте — предупреждение снизить дрейф раскладки и поднять контраст; соответствие решению 10 низкая: правка CSS панели/Button/Notice