Andrey Epifancev 82549737cc chore: архив OpenSpec agile-web-polish (#112)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:54:43 +04:00

23 KiB
Raw Blame History

Context

После выкатки #108 (25.10.2026) владелец посмотрел «Бэклог», «Спринт» и «Kanban» на живой доске AWPCA (4216, три спринта) и записал 10 замечаний в sdlc-hub#112. Владелец попросил не проводить brainstorming-вопросы и писать дизайн по тексту issue, поэтому всё, что в issue не сказано прямо, — решения агента (раздел «Decisions made without discussion»).

Текущее состояние (web/src/modules/jira/agile/): BacklogPage рисует секции Panel без свёртки, эпики идут строками наравне с задачами; SprintPage показывает один активный спринт, переключатель Segmented — только между активными; BoardColumns — flex-ряд с align-items:flex-start и overflow-x:auto; TypeIcon знает три вида (эпик — IconBoard, ошибка — IconCritical (молния), прочее — IconCheck). Фильтров нет. Все нужные данные уже приходят в GET /agile (AgileIssue: issue_type, assignee, epic_key, done, rank, status) — сервер не меняется.

Goals / Non-Goals

Цели — 10 пунктов #112 и попутно веб-маркеры из hub#111 (M-6, T10.3, T9.4, T12.2–T12.4). Не цели — правки Jira из веба, изменения API/схемы/агента/MCP, настройки доски AWPCA в Jira, серверные пункты hub#111.

Decisions

  1. Фильтры — на клиенте, чистой моделью. Новый модуль agile/filters.ts: тип состояния страницы (q, assignee, epic, hideDone, collapsed, hiddenColumns, epicsPanel), функция «видна ли задача» (поиск по key и summary без учёта регистра; assignee: "" — все, "-" — без исполнителя; epic: "" — все, "-" — без эпика, иначе epic_key === epic; hideDone), списки вариантов исполнителей и эпиков. Страницы и компоненты только рисуют. Модель покрыта unit-тестами, страницы — тестами поведения.

  2. Запоминание — один ключ sdlc-hub-agile. JSON { "<метка>": { "backlog": {...}, "sprint": {...}, "kanban": {...} } }; хранится всё, кроме q и выбора спринтов. Чтение и запись — в try/catch (закрытое хранилище, мусор, чужая форма — значения по умолчанию), как sidebarPref/legendPref. Миграция jira-hub- не нужна — ключ новый. Свёрнутые секции — по id спринта и "backlog"; id закрытых/удалённых спринтов при чтении не мешают (просто не совпадают). Скрытые колонки — по имени колонки ("Без колонки" — тоже имя).

  3. Панель фильтров — общий компонент AgileToolbar для трёх страниц, набор элементов — пропсами. Используются готовые SearchInput, Select, Checkbox/Button aria-pressed, Dropdown/Menu из web/src/ui; новые элементы UI-кита не вводятся, кроме значков (п. 7). Устаревшее значение исполнителя/эпика остаётся в списке (как withCurrent у списка задач), чтобы пустой результат объяснялся видимым фильтром.

  4. Свёртка секций «Бэклога». Заголовок секции — <button aria-expanded aria-controls> с шевроном (IconChevronDown/Up) и прежним содержимым заголовка; свёрнутая секция показывает только заголовок с итогами. «Прошлые спринты» остаются <details> (не запоминаются — как сейчас).

  5. Эпики на «Бэклоге». Эпик — задача, у которой TypeIcon определяет вид «эпик» (одна функция typeKind для значка и фильтра). Строки эпиков убираются из всех секций «Бэклога» (и из счёта «N задач» секции «Бэклог», который считается на клиенте). Панель — колонка слева шириной ~240 px в сетке страницы; при контейнере page уже 900 px — Select «Эпик» в панели фильтров. Число у эпика — задачи с этим epic_key в активных, будущих спринтах и «Бэклоге» без учёта остальных фильтров. На «Спринте» и «Kanban» эпики не трогаются (в issue речь только о бэклоге).

  6. Итоги секций — факты спринта. Заголовок спринта показывает серверные count/points/unestimated; фильтры их не меняют, добавляется «показано K», когда видно меньше задач секции. Так ретро-цифры спринта не «плавают» от фильтра. Числа в заголовках колонок доски — по видимым карточкам.

  7. Значки типов по образцу Jira. typeKind(issue_type) → epic | story | task | bug | subtask | other; значок — скруглённый квадрат 16 px цвета вида с белым символом (эпик — молния, история — закладка, задача — галочка, ошибка — круг, подзадача — два квадрата, прочее — нейтральный серый квадрат с точкой). Новые символы — в web/src/ui/icons.tsx тем же make(...); цвета — токенами дизайн-системы (эпик — --k-ui, история — --color-status-success, задача — --color-action-primary, ошибка — --color-status-error, подзадача и прочее — нейтральные), контраст белого символа проверить в обеих темах. При завершении — перенести значки в kit скилла aura-design.

  8. Выбор спринтов на «Спринте». Dropdown с отметками (активные, затем будущие по start_date, без даты — в конце), адрес ?sprint=<id>[,<id>…] с replace (без записи истории). Задачи доски — объединение задач выбранных спринтов без повторов по ключу, порядок — по rank (строка LexoRank сравнивается как строка; null — в конце, затем по ключу). Заголовков столько, сколько выбрано спринтов, компактной строкой каждый; «осталось N дн.» — только у активного. Прежний одиночный ?sprint=<id> остаётся рабочим адресом.

  9. Колонки одной высоты и прокрутка (пп. 8 и 10). Гипотеза по багу (подтвердить воспроизведением в начале задачи, superpowers:systematic-debugging): горизонтальная полоса .agile-columns есть, но лежит под самой длинной колонкой, далеко ниже окна (и скрыта macOS до прокрутки), поэтому правые колонки на 2560 px выглядят обрезанными. Исправление: страницы доски растягиваются на высоту основной области оболочки (flex:1; min-height:0 по цепочке, доска min-height:360px), .agile-columns — align-items:stretch и своя высота, у колонки прокручивается список (overflow-y:auto). Тогда полоса горизонтальной прокрутки всегда у нижнего края окна, колонки одной высоты. Если воспроизведение покажет другую причину — чинится причина, требование спеки то же.

  10. Скрытие колонок — меню «Колонки» с отметками на «Спринте» и «Kanban»; последнюю видимую снять нельзя; число скрытых — Badge на кнопке. Скрытие — только вид, columnsOf не меняется, фильтруется результат.

  11. Попутные маркеры hub#111. M-6 — fmtSp округляет до двух знаков и убирает хвостовые нули (веб-сторона; MCP :g не трогаем, расхождение для дробных до сотых исчезает). T10.3 — h3 в заголовках колонок. T9.4 — тесты загрузки и ошибки AgileGate и пункта «Kanban» kanban-проекта в меню. T12.2–T12.4 — e2e доски: фиксированный jira_updated в сиде, строгие локаторы по роли и тексту, без зависимости от порядка DOM.

  12. Тестовые данные. Сид e2e (web/scripts/test-hub.sh и фикстуры агента) дополняется так, чтобы были: эпик с задачами в спринте и бэклоге, задачи без эпика и без исполнителя, будущий спринт с задачами, доска с числом колонок и карточек, достаточным для широкой доски из сценария «Широкая доска».

Risks / Trade-offs

  • Высота доски от оболочки. Растяжение по высоте зависит от цепочки flex в shell.css/Layout.tsx; нельзя сломать прокрутку других страниц — e2e «страница без горизонтальной прокрутки» и сценарии оболочки остаются зелёными.
  • Объединение спринтов. Задача может числиться и в активном, и в будущем спринте (перенос) — без дедупликации карточка задвоится; дедупликация по ключу — в п. 8.
  • Распознавание эпика по имени типа. Тип зависит от локали Jira; список имён — один на значок и фильтр, расширяется в одном месте.

Decisions made without discussion

Все — 25.10.2026, владелец попросил писать дизайн по issue без вопросов. Нумерация рулингов R-n — с R-1 в пределах этой фичи.

  • R-1 (design #2): фильтры и свёртка запоминаются отдельно по странице (backlog/sprint/kanban) и проекту, поиск и выбор спринтов — не запоминаются. Обоснование: как в Jira — поиск разовый, выбор спринтов живёт в адресе. Цена ошибки — сделать исполнителя общим для страниц или запоминать поиск: правка одного модуля filters.ts.
  • R-2 (design #5): эпики убираются строками только на «Бэклоге»; на «Спринте» и «Kanban» остаются карточками. Обоснование: в issue речь о бэклоге. Цена ошибки — тот же фильтр на доске, одна строка.
  • R-3 (design #5): фильтр по эпику действует и на прошлые спринты; число у эпика — без учёта других фильтров и без прошлых спринтов. Цена ошибки — правка подсчёта в модели.
  • R-4 (design #6): итоги секций спринта не зависят от фильтров, добавляется «показано K»; числа колонок доски — по видимым. Цена ошибки — пересчитывать итоги на клиенте.
  • R-5 (spec): «Скрыть выполненные» не действует на прошлые спринты и на «Kanban» (у kanban последняя колонка — уже «за 14 дней»). Цена ошибки — включить флагом.
  • R-6 (design #8): выбор спринтов — несколько сразу (по умолчанию все активные), в адресе. Формулировка issue («выбор отображаемых спринтов: и активные, и будущие») допускает и одиночный выбор; множественный — надмножество. Цена ошибки — заменить список отметок одиночным выбором.
  • R-7 (spec): поиск и исполнитель — на всех трёх страницах, включая «Kanban», хотя в issue названы «Бэклог» и доска спринта: общий компонент, единообразие. Цена ошибки — скрыть два поля на «Kanban».
  • R-8 (design #7): набор видов значков и их цвета (Jira: эпик фиолетовый с молнией, история зелёная с закладкой, задача синяя с галочкой, ошибка красная с кругом, подзадача). Цена ошибки — перерисовать значки.
  • R-9 (design #9): причина бага прокрутки — гипотеза, подлежит проверке воспроизведением; починка — через растяжение доски на высоту окна, совмещённую с п. 8. Цена ошибки — другая починка того же требования.
  • R-10 (proposal): из hub#111 взяты только веб-маркеры M-6 (веб-сторона), T10.3, T9.4, T12.2–T12.4; hub#111 после merge остаётся открытой с комментарием о закрытых маркерах. Цена ошибки — взять/отложить другие пункты.
  • R-11 (spec): узкий экран — панель эпиков превращается в выбор при контейнере уже 900 px. Цена ошибки — подобрать порог.
  • R-12 (plan, Task 7): на страницах доски («Спринт», «Kanban») страница не ограничена max-width: 1440px у .page — на 2560 px колонки используют ширину окна (комментарий в agile.css уже называл «Спринт» страницей во всю ширину, а ограничение оставалось). Обоснование: замечание владельца о 2560 px. Цена ошибки — вернуть ограничение одной строкой.
  • R-13 (plan, Task 1): значок задачи без типа подписан «Тип не указан» (сейчас — «Задача»), вид — нейтральный. Цена ошибки — вернуть прежнюю подпись.
  • R-14 (controller, 25.10.2026, design #34): сид WIDE_E2E (Task 8 Step 1) делается в Task 7 Step 1 — как воспроизводящая широкая доска для баги прокрутки; Task 8 Step 1 остаётся проверкой прочих e2e и T12.2. Обоснование: без сида воспроизведение невозможно, порядок плана противоречив. Цена ошибки — сид приезжает на коммит раньше.
  • R-15 (controller, 25.10.2026, design #35): рулинги контроллера нумеруются с R-14 (R-13 занят дизайном; в плане T9 написано «R-13…»). Цена ошибки — нулевая.
  • R-16 (controller, 25.10.2026, design #36, из ревью T4.2/T4.3/T4.4): (а) у прошлого спринта при активных фильтрах в сводке добавляется « · показано K» (спека описывает «показано K» только для активных и будущих; строка сценария «Прошлый спринт» без фильтров не меняется); (б) список исполнителей строится по всем задачам-не-эпикам страницы, включая прошлые спринты (исполнитель фильтрует и их); (в) «N задач» секции спринта — серверное count (включает эпики, R-4), а строки и «показано K» считаются по задачам-не-эпикам, поэтому спринт с эпиком может показать «N задач» больше числа строк. Цена ошибки — правка двух выражений в BacklogPage.tsx.
  • R-17 (controller, 25.10.2026, design #37, Task 7 Step 1): гипотеза R-9/R-12 о причине бага прокрутки не подтвердилась воспроизведением (systematic-debugging). max-width:1440px у .page страниц доски уже снят (.page--board), доска на 2560 px шире 1440 px. Настоящая причина: у .agile-columns не было ограничения по высоте — высота доски равна самой длинной колонке (3326 px), горизонтальная полоса прокрутки лежала на y=3616 при окне 1300 px, колонки были разной высоты (align-items:flex-start), список колонки не прокручивался. Починка: .agile--wide высотой окна, колонки stretch, прокрутка у .agile-col__list, горизонтальная — у .agile-columns. R-12 в части снятия max-width теряет силу (править нечего). Цена ошибки — нулевая: снятие ограничения не делалось.
  • R-18 (controller, 25.10.2026, design #38, из отчёта Task 7): раскрытый «Бэклог (N)» на «Kanban» ограничен по высоте (40dvh) с прокруткой; меню «Колонки» включает «Без колонки», если такая есть. Цена ошибки — правка CSS/списка меню.
  • R-19 (controller, 25.10.2026, design #39, из I-1 финального ревью): цвета значков типов — эпик --k-ui, история --color-status-success, задача --k-dev, подзадача --k-analytics, ошибка --color-status-error, прочее --color-text-secondary; символ — --color-text-on-primary (в тёмной теме тёмный, контраст ≥ 3:1 во всех парах, рассчитан по tokens.css). Прежний выбор плана (задача на --color-action-primary) давал один зелёный с историей, что противоречило «у каждого вида свои цвет и символ»; фраза спеки «белый символ» заменена на «символ цвета --color-text-on-primary». Цена ошибки — пересадить два токена в agile.css.
  • R-20 (controller, 25.10.2026, design #40, из I-3): на окне уже 640 px минимальная высота доски 240 px (а не 360): при 360 px полоса прокрутки доски уходит ниже окна (810 и 838 против 800 на 390×800, замеры Task 8 и волны финального ревью), а требование «полоса прокрутки в пределах окна» важнее. Спека поправлена (240 px на узком окне). Цена ошибки — вернуть 360 px и принять полосу ниже окна.
  • R-21 (controller, 25.10.2026, design #41, из I-3): (а) последняя отмеченная позиция в выборе спринтов недоступна (нельзя снять); (б) скрытая колонка, которой нет на доске, в меню «Колонки» не показывается и на кнопке не считается, а если скрыты все колонки — не скрыто ничего (доска не пустеет молча; список имён меню строится по нефильтрованным задачам); (в) подпись поля поиска для экранного диктора — «Поиск по ключу или теме», видимая — «Ключ или тема»; (г) подпись «Исполнитель» — inline слева от выбора (подпись сверху сдвигала выбор относительно поиска). Review Focus 2 плана («значение остаётся видимым и снимаемым») для колонок трактуется так: значение, которого нет в данных, не нужно показывать, потому что оно ни на что не влияет. Цена ошибки — показывать «призрачные» колонки в меню.