sozday-analiz-rashodov-s-uka/design-system/CHECKLIST.md

23 KiB
Raw Permalink Blame History

KT AI — Definition of Done (единый гейт качества)

Это — единственный чек-лист системы. Прогоняй его при ЛЮБОМ изменении UI, а не только при новом прототипе. Раньше чек-листы жили в трёх местах (docs/PRINCIPLES.md, docs/DESIGN.md, docs/ELEVENLABS_DESIGN.md) и расходились — теперь канон тут, остальные доки ссылаются сюда. «Почему так» — docs/PRINCIPLES.md + docs/ELEVENLABS_DESIGN.md; «чем строить» — docs/DESIGN.md + COMPONENTS.md.

[auto] = проверяет scripts/validate_product.py или сборка (машина не забывает — это и есть «соблюдается каждый раз»). [review] = глазами/в showcase (машина пока не ловит; см. «Что нельзя автоматизировать» внизу).

Когда что прогонять

Момент Что прогнать
Новый продукт из материалов весь чек-лист (G0–G8); G8 обязателен — сверка с источником
Новая фича G7 (машинный гейт) + гейты затронутых поверхностей + «Красные флаги»; добавляет сущность/выход → ещё G8
Правка существующего затронутый гейт + G0 (токены/темы) + «Красные флаги»; трогал оба рантайма → ещё G7-паритет

G0 · Токены и темы (фундамент)

  • [review] Нет сырых hex в продуктовом CSS/JSX — только var(--kt-ai-*) (декоративный orb-canvas — единственное намеренное исключение, помечено в коде).
  • [review] Геометрия не зависит от темы: темы меняют ТОЛЬКО цвет, не радиусы/отступы/размеры.
  • [auto] Контраст — python3 scripts/build_tokens.py (гейт падает и называет пары). Пороги: текст ≥7:1, приглушённый ≥4.5:1, фокус и заливка состояния ≥3:1. Раньше пункт стоял с меткой [review], и три нарушения прожили несколько мажорных версий: 2,8:1 на кегле 11px глаз читает не как «нечитаемо», а как «тихо».
  • [review] Обе темы проверены переключателем в showcase.html — глазами проверяется соразмерность и иерархия, а не контраст.
  • [auto] Менял tokens.json/kt-ai-components.css → прогнал python3 scripts/build_tokens.py (+ scripts/visual_check.mjs при наличии chromium).
  • [auto] Статика адресуется ktAsset() (в HTML-рантайме — ktAiAsset()), а не путём от корня сайта. Под префиксом развёртывания (/cons) путь /kt-ai-orb.js уходит мимо приложения; ломается только на развёртывании, в корне домена всё работает. Гейт 18 в doctor.py.

G1 · Высота и иерархия

  • [auto] Один primary на зону (scenario.control); [review] кнопки названы глаголами действия, не «Да/ОК».
  • [review] Page-title 24–26px semibold БЕЗ лого + muted-подпись; лого живёт в сайдбаре.
  • [auto] KPI отвечают на вопрос пользователя на экране; на view: operational — без ROI/FTE/экономии (это management-view).
  • [auto] Лейблы коротко: filter ≤2 слов, status ≤4, header колонки ≤2–3; [review] детали — в drawer/help, не в лейбле.
  • [review] Размер/вес/цвет ведут глаз: title → секции → body → meta; один акцент на зону.
  • [review] KPI-плашка читается четырьмя уровнями сверху вниз: подпись → значение → .hint (знаменатель, доля, период) → .note (оговорка: чем число НЕ является). Значение идёт сразу под подписью и НЕ прижимается к низу; полоса выравнивает карточки по верху — иначе в соседних карточках с уточнением и без числа встают на разной высоте.
  • [auto] Три места для трёх разных текстов, и они не путаются: banner — из-за чего число соврёт (до чисел), kpis[].note — что число значит (у самого числа), conclusion — что из чисел следует (после таблицы). Валидатор предупреждает, когда баннер длиннее 200 знаков: это абзац до первого числа, и почти всегда там лежит чужой текст.
  • [review] Текста на экране столько, сколько нужно для решения. Поясняющая строка, оговорка и подзаголовок сперва пробуются как свойство самого элемента (подпись пилюли, подсказка у метки, название колонки) и живут рядом с ним, а не отдельной строкой над списком. Строка, которая не меняется от данных, — кандидат на удаление; если она нужна для честности (непроверенное правило, тестовые данные, пробел в данных), она остаётся, но переезжает к элементу.
  • [review] Ориентация: экран отвечает где я / куда пойти / что здесь / как выйти (крошка, активный nav, заголовок, Esc). Лейблы конкретны (nav по содержимому, не «зонтик»); контролу не нужен поясняющий лейбл.
  • [auto] Подпись сочетания стоит там, где сочетание работает, и называет клавишу этой машины (⌘K / Ctrl K). Подпись без обработчика — обещание, обработчик без подписи — незаявленная горячая клавиша; включаются одним полем. Гейт 19.
  • [auto] У подписи поля есть for= или обёртка <label class="kt-ai-field">. Подпись рядом с контролом выглядит подписью, но без связи диктор объявляет поле безымянным, а щелчок по подписи не ставит фокус. Гейт 22.
  • [auto] Кит показывает контракт целиком: npm run kit:render (гейт 23). Типы и гейты читают код и не ловят главное — когда рантайм молча не читает блок контракта. Проверка рендерит кит в строку и сверяет содержимое с контрактом.
  • [auto] Архетип реализован в том рантайме, где вы строите: runtimes в archetypes/registry.json. status: stable про рантайм не говорит. Гейт 21 + заметка валидатора.
  • [auto] id разметки не совпадают с id символов вшитого спрайта: спрайт стоит выше, и getElementById вернёт <symbol> — элемент останется мёртвым молча, без единой ошибки. Гейт 20.
  • [review] Кнопки create/«Новый X» начинаются с ведущего «+». Один фильтрующий поиск на экран (глобальная ⌘K-палитра и табличный фильтр — разные роли, но два одинаково фильтрующих поля — нет). AI-кнопка Төре — в топбаре рядом с поиском. Не добавляй input/селект, если прямой кнопки достаточно.

G2 · Язык ElevenLabs (эстетика и плотность)

  • [review] Структуру задают hairline-границы 1px, а не тени; тени — шёпот (карточки приподняты, не парят).
  • [review] Поверхности нейтральные (white/near-white/near-black); цвет — только статус/ошибка/акцент, не украшение.
  • [review] Статус = пилюля со скруглением radius-tag (5px) и тоном; число/текст остаются нейтральными (не цвет текста).
  • [review] Радиусы 8–12px для карточек/кнопок/инпутов; полный радиус — только pill/toggle/chip.
  • [review] Контент важнее хрома: сайдбар/топбар тонкие и тихие, рабочая область доминирует.
  • [auto] Ширина колонок — по содержимому (colw/ktColWidth), не «на глаз»; короткие колонки не растянуты, длинные не зажаты.
  • [review] Нет карточки-в-карточке (две рамки спорят за группировку).
  • [review] Ритм блоков — из шкалы, и он группирует: регионы экрана (шапка / баннер / содержимое) — stack-group (24); панель управления ближе к тому, чем управляет — stack-block (16); внутри группы (фильтры ↔ вкладки, карточка ↔ карточка) — stack-tight (12); интерьер карточки — pad-card (20); поля области и отрыв от топбара — stack-region (32). Выражается kt-ai-v[data-gap]; собственный app-stack-* в продукте — сигнал, что группировку обошли.
  • [review] Проверка ритма: пройди по вертикали и назови каждый зазор. Все числа разные (три и больше на отношение «блок ↔ блок») — фейл, читается как небрежность. Все числа одинаковые — фейл ровно такой же: экран плоский, группы не читаются. Чисел должно быть столько, сколько уровней вложенности.

G3 · Состояния и обратная связь

  • [review] Каждое действие даёт отклик ≤100мс (toast / смена статуса / состояние кнопки); лоадер на всём, что дольше 300мс — skeleton, не спиннер.
  • [review] Нарисованы empty / loading / error; пустота — осознанный empty-state («что здесь будет»), не голая белизна.
  • [review] Лестница состояний контрола: default → hover → active/selected → focus-visible → disabled; у инпута — focus + error.
  • [review] Микроинтеракция подтверждает результат (copy → чип «скопировано», не только hover).
  • [review] Движение: отклик на pointer-down (не на отпускании); появление от scale(.95), не из ниоткуда; переходы прерываемы/обратимы; overlay растёт из триггера и уходит тем же путём; анимируются только transform/opacity. Подробно — docs/DESIGN.md §Движение.

G4 · Честность данных и копирайт

  • [review] Только подтверждённые материалами факты; цифр «с потолка» нет; ПДн маскированы (ИИН •••4821, без реальных ФИО).
  • [auto] Нет debug-языка генерации в UI (fallback, модель вернула, JSON, prompt, shell, не проходит дизайн-систему).
  • [review] Поля поиска пусты по умолчанию — не префилл произвольными примерами.
  • [auto] Статусы строк — только из объявленных в statuses; scenario/drawer/chart ссылаются на существующие ключи.
  • [review] AI-контент атрибутирован («Сгенерировано ИИ» / орб) там, где это генерация.
  • [auto] Без дисклеймеров и нравоучений в UI («это прототип», «данные иллюстративны», «AI не действует сам», «решение подтверждает человек») — решение показывают контролы, а не объяснения. [review] Лейблы-секции — нейтральные существительные, не лозунги капсом («Решение», не «РЕШЕНИЕ — ЗА ВАМИ»). Продукт-специфичный текст живёт в контракте (scenario.aiSummary), а НЕ зашит в shell.

G5 · Законы взаимодействия

  • [review] Выход из любого состояния: Esc / назад / закрытие работают; деструктив — глаголом + подтверждением, необратимое — вводом имени объекта.
  • [auto] Первичные фильтры ≤4 + «Все», только workflow-status (не confidence/risk-type/системы); [review] остальное — прогрессивным раскрытием.
  • [review] Прогрессивное раскрытие: детали в drawer/modal, редкие действия — в hover/popover/kebab, не вшиты в UI навсегда.
  • [review] Shell неприкосновенен: sidebar, topbar, theme-toggle, AI-кнопка Төре — системный контракт, не творческая зона.

G6 · Адаптивность и локализация

  • [review] <lg → icon-rail, <md → sidebar-drawer; на 360/390/393px нет горизонтального скролла (documentElement.scrollWidth ≤ clientWidth) и топбар влезает.
  • [review] Сенсорная цель ≥44px на ≤768px. Порог задаёт ДС: токен --kt-ai-control-h-touch и правило-порог в kt-ai-components.css (условие (pointer: coarse), (max-width: 767.98px)). Своими руками высоты не поднимай — проверь, что элемент попадает под правило: компоненты через классы .kt-ai-*, разметка кита — через [data-kt-ai-kit]. Осознанно меньший контрол помечается data-kt-touch="off"; молча — нельзя.
  • [review] Колонка не шире отведённого: у прямых детей сеток (.kt-ai-cols это делает сам) min-width: 0. Без него 1fr = minmax(auto,1fr) и одна длинная строка распирает страницу — сворот в одну колонку это НЕ лечит.
  • [review] Длинные казахские строки (≈+20%) — truncate + tooltip; фикс-ширины под текст кнопок/чипов/пунктов запрещены.
  • [auto] Icon-only кнопка — с tooltip и aria-label (гейт 16 в doctor.py; title за имя не считается — диктор его не обязан читать). У кнопки-переключателя подпись зависит от состояния: «Свернуть меню» в свёрнутом виде — ложь.
  • [review] Кнопка, за которой слой, сообщает состояние: aria-expanded, aria-haspopup, aria-controls. Фокус виден с клавиатуры на всём пути.
  • [review] Модальный слой закрывается по Esc — через общий хук кита useKTEscape, а не своей копией слушателя: копий было две, и они успели разойтись (window против document), а два слоя Esc не имели вовсе.
  • [review] Учтены prefers-reduced-motion (обнуление длительностей), prefers-contrast: more (толще фокус/границы) и prefers-reduced-transparency (blur снят, фон плотный).

G7 · Контракт и паритет (машинный гейт)

  • [auto] python3 scripts/validate_product.py "<config>.json" --strict → 0 ошибок, 0 предупреждений.
  • [review] HTML ↔ React выглядят и ведут себя идентично (если трогал оба рантайма) — один контракт, одно поведение.
  • [auto] Прототип собран python3 scripts/build_prototype.py — НЕ инлайнен руками.
  • [auto] Менял DS/ → синхронизировал Töре + integrity.test без падений (0 failed; число тестов не фиксируем — оно растёт).
  • [review] Правил гейт в doctor.py → сломай его намеренно снова и убедись, что он падает. Одной проверки при написании мало: рефакторинг 5.9.1 молча вырезал тело гейта 16, и doctor.py остался зелёным.
  • [auto] Добавил компоненту рантайм-ресурс (<script src="/…">, спрайт, шрифт) → он лежит в бандле как public/…. Проверяет гейт 15 в doctor.py: компонент без своего файла собирается и типизируется чисто, а у потребителя даёт 404 и пустое место.

G8 · Соответствие источнику (сборка из материалов / Төре-интервью)

Закрывает разрыв «UI ≠ то, что обещали материалы». Не про пиксели — про содержание. Обязателен, когда продукт собран из PRD/ТЗ или из интервью Төре.

  • [review] Есть карта источника (source-map): выписаны ВСЕ сущности, выходные артефакты (документы, которые продукт производит: ТС, отчёт, СЗ…), роли, сценарии (S-xx) и критерии приёмки (A-xx) из материалов.
  • [review] Трассировка: каждый пункт карты → UI-дом (nav-секция / поле или артефакт в drawer / явный «вне v1»). Правило: представлен или осознанно отложен — никогда молча не выброшен.
  • [review] Каждый named output из PRD (раздел «первая версия» / «данные» / «сценарии») имеет видимое место в UI — не зарыт в _flags.
  • [review] Роли из материалов отражены (кто решает, кто согласует, кто получает) — экран собран под пользователя, принимающего решение.
  • [review] Доменные термины (ТС, ОБ/БКВ, СЗ, ЕНС ТРУ…) — как первоклассные сущности/артефакты, а не обезличенный текст.

Красные флаги (мгновенный фейл ревью)

Лого в page-header · заголовок 30–32px bold (надо 24–26 semibold) · два тоггла сворачивания · гигантская пустота над/под контентом · вертикальные сепараторы в таблице · статус сырым текстом/цветом вместо пилюли · сырой hex вместо var(--kt-ai-*) · карточка-в-карточке · спиннер вместо skeleton · >1 primary в зоне · разнобой отбивок между блоками (три и больше значений на одно отношение) · один зазор на всё — плоский экран без групп · плотный экран, растянутый во всю ширину монитора (нет content-table-клампа) · цвет ради украшения · синий как заливка primary-кнопки · ROI/FTE на рабочем экране · debug-язык генерации в UI · самодельные глифы вместо иконок спрайта · разная геометрия в темах · дисклеймер/мета-копирайт («это прототип», «данные иллюстративны») · нравоучение про human-in-the-loop («AI не действует сам», «решение подтверждает человек») · лозунг-лейбл капсом («РЕШЕНИЕ — ЗА ВАМИ») · продукт-специфичный текст зашит в shell вместо контракта · два одинаково фильтрующих поиска · кнопка create без ведущего «+».

Что нельзя автоматизировать (всегда [review])

Валидатор ловит структуру и честность контракта (статусы, один primary, ROI на operational, debug-язык, длину лейблов, иконки, chart, паритет схемы). Он НЕ видит пиксели: иерархию, ритм отступов, тени-vs-hairline, состояния hover/empty/error, паритет тем, адаптив. Это — обязательный глазами-проход в showcase.html/preview. «Зелёный валидатор» ≠ «прошло DoD».