20 KiB
20 KiB
Бэклог фронта (зонный)
Ведёт зона
frontend/(решение владельца 02.08, D39.84: фронт и платформа держат СВОИ бэклоги; единый бэклогdocs/PROGRESS.md— трекер движка/полигона/доков, фронт-строк не принимает). Нормы те же: ID стабилен навсегда, каждая петля получает диспозицию. Запросы к ДВИЖКУ сюда не пишутся — они заходят строками единого бэклога через оркестратора (пример: строки 99–102 — пофазный прогресс · манифест глав · машиночитаемая таблица подписи · трасса). Засеян оркестратором при лендинге D39.84 — дальше правят фронт-сессии.
| ID | Хвост | Вес | Источник |
|---|---|---|---|
| Ф-1 | Этапы S2–S7 (FRONTEND_SESSION_PROMPT.md): S2 оболочка + слой src/ui/ · S3 слой данных/MSW/фикстуры всех состояний · S4 библиотека/загрузка/разбор/прогресс · S5 банк памяти и подпись (самый тяжёлый) · S6 читалка двух колонок и замечания · S7 метаданные/экспорт/настройки/сквозной прогон |
по очереди сессий (S0/S1 — текущая) | FRONTEND_SESSION_PROMPT |
| Ф-2 | React Compiler — включить ОТДЕЛЬНЫМ шагом после заморозки интерфейса, с CI-проверкой, что вставки реально попали в бандл (в MVP выключен; совместимость держит линт eslint-plugin-react-hooks) | после заморозки UI | STACK_DECISIONS §1 |
| Ф-3 | Пересмотр TS 6 → TS 7 после выхода TS 7.1 с программным API (~октябрь 2026); решение обратимо — тайпчек не участвует в сборке | триггер: релиз TS 7.1 | STACK_DECISIONS §1 |
var(--…); 0, auto и inherit легальны (это не размеры), calc() намеренно запрещён: составное выражение из литералов проверить нечем, а если размер понадобился новый — его место в tokens.css. Свойства взяты регулярками, поэтому длинные формы (border-top-left-radius, padding-inline) закрыты тоже. Обкатка потребовала трёх токенов, которых не хватало: --radius-round, --radius-bar, --row-inset. Проверено шестью живыми нарушениями и тремя легальными формами (перечень — FRONTEND_PLAN.md §5.4) |
закрыт | STACK_DECISIONS §3 | |
/* eslint-disable */ в TSX@eslint-community/eslint-plugin-eslint-comments 4.7.2 (no-unlimited-disable + require-description + disable-enable-pair). Голое отключение падает тремя ошибками, точечное подавление с причиной проходит. Урок: не выносить владельцу технический вопрос, не поискав отраслевую практику |
закрыт | адверсариальное ревью S1 | |
fill/stroke/color/stopColor/floodColor/lightingColor — только none, currentColor, inherit, transparent, var(--…)) · значение CSS-переменной в style={{…}} обязано быть числом или токеном · носитель style внутри объектного литерала запрещён, и тем самым закрыт JSX-спред · системные цветовые ключевые слова закрыты declaration-property-value-disallowed-list по ВСЕМ свойствам, то есть и в сокращённых записях outline/box-shadow/border. Перечень проверенных форм (15 TSX + 14 CSS) — FRONTEND_PLAN.md §5.4.1. Граница названа честно и там же: гейт цветных атрибутов ловит литерал и шаблон, но не вычисленное значение (const c = 'red'; <svg fill={c}/>) — синтаксически это не берётся, и объявлять строку «закрытой без остатка» было бы ровно тем переобещанием, из-за которого она и заведена |
закрыт для литеральных форм, граница названа | адверсариальное ревью S1 | |
cssModules.test.ts строит пары по ИМПОРТАМ, а не по совпадению имён файлов, видит деструктуризацию const { name } = styles и выкидывает url(...) и строковые литералы до поиска классов; проверка сиротства стала «модуль, который никто не импортирует». tokens.test.ts получил замок полноты: каждый токен обязан попасть либо в замеры, либо в явный список подобранных, и обратно — список не может ссылаться на исчезнувший токен. Плюс новое: числа для виртуализатора живут в src/tokens/measures.ts и сверяются с одноимёнными токенами. Семь живых нарушений, перечень — FRONTEND_PLAN.md §5.4 |
закрыт | адверсариальное ревью S1 | |
| Ф-11 | Контраст ниже порога WCAG на 5 узлах (приглушённый текст #707479 и #8a8e91 на #17191a). Это прямое следствие копирования палитры Fleet, которую владелец принял; axe отчитывается о них отдельно и команду не валит. Решение владельца: оставить как есть ради верности референсу или поднять приглушённые тона |
решение владельца | ревью S1 №2 |
| Ф-12 | Масштаб списков — главное закрыто 04.08 в S2 замером, а не обещанием. Заведён маршрут /scale: та же оболочка на настоящем масштабе — 2284 раздела и банк на 1200 терминов (src/mock/scale.ts через getScaleFixture()). Дерево и банк виртуализованы по умолчанию (RAC Virtualizer + ListLayout), и это измерено в живом браузере: на 2293 узлах дерева в DOM держится 31 строка, scrollHeight 59 618px, кадр при прокрутке — медиана 22 мс, p95 31 мс; банк на 1200 терминах — 30 строк в DOM, медиана 16,7 мс. Прокрутка до конца и обратно счётчик строк не растит. Замечания намеренно НЕ виртуализованы: их список пер-главный, а юнитов на главу ≈1,9 (ПТ-21) и флаг у юнита один — 10³ там не бывает по построению; сводный вид по книге, если он появится, придёт с S6 и получит тот же примитив ui/List. Два хвоста строки НЕ сделаны и получают диспозицию, а не зачёркивание (нашло адверсариальное ревью S2): дерево осталось плоским без группировки по сотням — это работа экрана глав (S4), у оболочки для неё нет ни данных, ни требования; банк без разделения «подписано / ждёт решения» — это работа подписного экрана (S5), справочному виду в 320px разделение только мешает |
масштаб закрыт; группировка — S4, разделение банка — S5 | ревью S1 №2 |
| Ф-14 | Вход фронта в контракт API (единый бэклог, строка 95) — собрать одним списком то, что фронт уже знает и обязан подать автору контракта: язык кодами (не именами) · состояние прогона отдельно от выполнения главы · прогресс пофазно по ЮНИТАМ · ревизия/Last-Event-ID для докачки SSE · трёхзначный статус подписи термина (`auto |
draft | approved), а не булев signed · поля банка, без которых подпись не работает (type/sense/since_ch). **Своим решением фронт это не заводит** (BACKLOG.md` шапка: запросы к движку идут строками единого бэклога через оркестратора) — строка держит список готовым к дизайн-промту 95 |
| Ф-15 | src/api/ синхронен, состояний загрузки и ошибки в типах нет — диспозиция: НЕ чинить сейчас. Два независимых скептика показали, что S2 данных не читает вовсе, а асинхронность приезжает на S3 вместе с MSW и TanStack Query, до первого продуктового экрана; самодельный хук сегодня = работа S3, которую S3 выбросит. Строка держит обязательство S3: ветки ожидания/ошибки/пустоты появляются вместе с MSW, а не после первого экрана |
S3 | ревью S1 №3 |
| Ф-13 | eslint-plugin-jsx-a11y не встаёт на ESLint 10 (peer ^3..^9, проверено --dry-run → ERESOLVE). Статическую половину доступности держит axe в скриншот-цикле; плагин подключить, когда выйдет совместимый мажор |
триггер: мажор плагина | ревью S1 №2 |
| Ф-7 | Хвосты сведения витрины с референсом (FRONTEND_PLAN.md §5.2). Часть S2 закрыта 04.08: + стоит в ряду вкладок ЛЕВОЙ панели и запускает «Добавить книгу» (решение владельца 04.08); дублирующая строка «+ Добавить книгу» из дерева убрана — одна вещь, одно место. В центре и справа + нет и не будет: наборы вкладок там фиксированные, пользователь их не расширяет, и кнопка вышла бы декоративной — ровно то, что эта строка запрещает. Состояния наведения перестали быть «непроверенными»: они сняты не статичным кадром, а прогоном браузера (data-hovered/data-selected/data-focus-visible у кнопки, вкладки, строки дерева и списка). Осталось на S6: приглушённая колонка оригинала — решение, а не замер, пересмотреть на настоящей читалке |
S1, сверка с fleet.png | |
| Ф-16 | Выгрузка книги (§3.11) ушла из верхней полосы. В витрине S1 там висела иконка загрузки без действия; по правилу Ф-7 («кнопка только вместе с действием») она снята до S7, который строит экспорт. Вернуть иконку вместе с самим действием | S7 | S2 |
| Ф-17 | Закрытие вкладки с клавиатуры не объявлено скринридеру. Крестик у вкладки-документа сознательно НЕ кнопка: у роли tab дети презентационные (ARIA), вложенный фокусируемый элемент выпал бы из дерева доступности, оставшись в порядке табуляции (это же ловит axe правилом nested-interactive). Мышь закрывает крестиком, клавиатура — Delete на выбранной вкладке. Объявить сочетание нечем: aria-keyshortcuts не входит в типизированный API Tab/TabList в react-aria-components 1.20.0. Пересмотреть при обновлении библиотеки либо при появлении палитры команд |
триггер: мажор RAC или экран горячих клавиш | S2 |
| Ф-19 | Переключение вкладки размонтирует её содержимое, и прокрутка длинного списка теряется. Нашло адверсариальное ревью S2 и подтвердило независимым прогоном: react-aria-components не рендерит невыбранную TabPanel (dist/private/Tabs.mjs:276 — if (!isSelected && !shouldForceMount) return null), поэтому на /scale прокрутка дерева scrollTop=9000 → вкладка «Поиск» → обратно даёт scrollTop=0, а пересборка коллекции из 2284 узлов стоит 70–140 мс (два независимых замера). Ф-12 это не переоткрывает: там речь про поведение списка при 10³, и оно держится. Чинить сейчас не стали: shouldForceMount не лечит (панель остаётся видимым div и легла бы поверх соседней в той же ячейке грида), а настоящее лекарство — keep-alive либо запоминание офсета на вкладку — это решение об устройстве оболочки, и принимать его вслепую, до настоящих экранов, значит строить механизм не под задачу |
S4 (экран глав) либо раньше, если владелец увидит потерю места | адверсариальное ревью S2 |
| Ф-20 | Мёртвый шрифт и мёртвые токены в поставке. @fontsource-variable/jetbrains-mono грузится в бандл, но --font-mono не выбран ни одним правилом: художественную прозу моноширинным не набирают, а во Fleet на этом месте был код. Туда же несколько токенов, которые ни разу не используются (--color-current-line, --color-hint). Замок полноты токенов (S2) требует классифицировать токен, но не требует его использовать. Решать на S6, когда читалка станет настоящей: либо моноширинный находит работу, либо импорт и токены уходят |
S6 | адверсариальное ревью S2 |
| Ф-21 | Ступень замечания различается только цветом полоски (attention синяя, glance серая). Зрячему разница читается ещё и светлотой, но скринридеру приоритет не достаётся вовсе. Лечение — слово, как это уже сделано для состояния прогона книги; какое именно слово, решает владелец: словарь замечаний продуктовый (ПТ-33), а §3.8 требует, чтобы экран не выглядел тревожным, так что «важно/неважно» не годится |
решение владельца | адверсариальное ревью S2 |
| Ф-18 | Бандл 545 КБ (168 КБ gzip) одним куском — замер 04.08 после установки react-aria-components; Rolldown предупреждает про порог 500 КБ. Для десктопного SPA за логином это не авария (индексации нет, сеть локальная), но одним куском едут и экраны, которых пользователь ещё не открыл. Лечение — разбиение по маршрутам, и делать его осмысленно после S4–S7, когда экраны появятся: сейчас резать нечего |
после S7 либо при жалобе на первый экран | S2, замер |
| Ф-5 | Tauri 2.x вторым шагом — по явным триггерам (трей · глобальные горячие клавиши · распространяемый .exe · офлайн · хранилище учёток ОС); до того — установимое PWA, только браузерные API | триггеры названы | STACK_DECISIONS §6, D39.84 |
| Ф-6 | @tanstack/react-virtual — в резерве, подключать только по замеру (дефолт виртуализации — RAC Virtualizer). Замер сделан 04.08 (S2) и триггер НЕ наступил: RAC Virtualizer держит 2284 раздела на 31 строке в DOM при медиане кадра 22 мс и 1200 терминов на 30 строках при 16,7 мс. Вторая библиотека виртуализации сейчас была бы платой без выигрыша; пересматривать — если появится список с переменной высотой строки (читалка S6) и estimatedRowSize не справится |
по замеру; замер 04.08 отрицательный | STACK_DECISIONS §2 |