Merge pull request 'Consolidate product, UI, and deployment plans' (#60) from feature/documentation-consolidation into main
CI / tests-and-images (push) Successful in 2m12s
Runner smoke test / runner-smoke (push) Successful in 2s

This commit was merged in pull request #60.
This commit is contained in:
agent committed 2026-11-03 06:08:33 +00:00
commit f19faf628e
10 files changed
+546 -718

No files matched your search

+5
View File
@@ -1,5 +1,6 @@
# Local credentials and secrets
credentials.json
codex.json
# Python/runtime artifacts (for the upcoming bot implementation)
__pycache__/
@@ -17,3 +18,7 @@ data/
# Local runtime logs
logs/
# Local generated reports; deliberately publish reviewed/sanitized evidence with git add -f
/reports/
/tmp/
+6
View File
@@ -2,6 +2,12 @@
## Не выпущено
- Документация: объединены продуктовый, UI- и deployment-планы; уточнены
внешняя backup-retention политика и обязательный owner-approved maintenance
window для cold backup. Передача корпуса требует атомарной публикации
проверенного staging в `DATA_ROOT`; безопасное возобновление либо fail-closed
при прерывании остаётся release gate. Механизм атомарной публикации ещё не
реализован.
- Backend `0.13.4` / Frontend `0.3.4`, алгоритм поиска `search-8`: для явно
заданного multi-index поиска включена глобальная статистика DFS; signed review
snapshots сохраняют полный index scope, а пустую выдачу можно сохранить с
+16 -18
View File
@@ -66,10 +66,11 @@ spacing:
## Overview
**Статус: утверждено пользователем 10 октября 2026 года.** Это целевая
**Статус: утверждено пользователем 10 октября 2026 года.** Это нормативная
дизайн-система портала и внутренней лаборатории проверки поисковой выдачи.
Она ещё не внедрена в работающий интерфейс. Утверждение дизайна не означает
готовность публичного сервиса или разрешение на deployment.
Часть ресурсов и правил уже присутствует в исходном коде, но полное визуальное
соответствие и доступность не подтверждаются одним наличием кода. Утверждение
дизайна не означает готовность публичного сервиса или разрешение на deployment.
**Creative North Star: "Түндүк — спокойное пространство для работы с правом".**
@@ -80,20 +81,14 @@ spacing:
Это единственная нормативная спецификация дизайна проекта. Требования
исходного brief перенесены сюда; отдельный brief и ранние варианты удалены.
Визуальный ориентир — утверждённый пользователем
[концептуальный экран](docs/design/tunduk-desktop-concept.png).
Точные токены и правила этой спецификации важнее случайных деталей
генеративного изображения. Название продукта — **Акылдаш**; «УКУК» из
ранних концепций не используется.
Название продукта — **Акылдаш**; «УКУК» из ранних концепций не используется.
Изображение определяет целевую композицию, пропорции панелей и расположение
элементов поискового экрана. Эта спецификация определяет семантические токены,
шрифты, доступность и правила поведения. Расхождения между ними фиксируются
до реализации; утверждённые токены не заменяются цветами, взятыми пипеткой
из растрового изображения. Изменения постоянных правил вносятся сюда явно.
Этапы работ, исходные измерения и критерии визуальной приёмки находятся в
[едином плане корректировки UI/UX](docs/product/interface-correction-plan.md).
План не является второй дизайн-системой и не означает завершение реализации.
Целевые редактируемые состояния, композиция, измерения и критерии приёмки
собраны в [плане реализации и приёмки](docs/product/implementation-roadmap.md).
Макеты задают визуальное направление, но не источник юридических данных и не
доказательство работающих функций. Утверждённые токены не заменяются цветами,
взятыми пипеткой из растрового изображения. Изменения постоянных правил
вносятся сюда явно.
**Key Characteristics:**
@@ -141,8 +136,11 @@ spacing:
**Заголовки документа и разделов:** Noto Serif, веса 600 и 700.
**Интерфейс и основной текст:** Noto Sans, веса 400, 500 и 600.
Шрифты подключаются штатным способом, предпочтительно локальными WOFF2
с `font-display: swap`. До поставки проверить лицензии и символы
`Ө ө Ү ү Ң ң`. Файлы шрифтов пока не добавлены.
с `font-display: swap`. В исходном коде на сверенном `main` есть локальные
Noto Sans/Serif WOFF2 и OFL-лицензии в `backend/search/static/fonts/`;
`review.html` объявляет `font-display: swap`. Это подтверждает наличие ресурсов
и CSS, но не их загрузку на production и не полный визуальный аудит символов
`Ө ө Ү ү Ң ң`. См. [план реализации и приёмки](docs/product/implementation-roadmap.md).
| Элемент | Размер | Межстрочный интервал |
|---|---|---|
+12 -6
View File
@@ -9,9 +9,10 @@ Telegram-бот — только часть рабочего окружения
## Текущее состояние
Сейчас реализованы Telegram-бот-секретарь версии `0.2.2`, backend версии
`0.13.4` и frontend `0.3.4` с поисковым экраном, внутренней лабораторией и
согласованным отображением доступных действий учетной записи.
В исходном коде находятся Telegram-бот-секретарь версии `0.2.2`, Search API
версии `0.13.4` (алгоритм поиска `search-8`) и frontend `0.3.4` с поисковым
экраном, внутренней лабораторией и согласованным отображением доступных
действий учетной записи.
Авторизация хранится в
SQLite; первый пользователь `admin` создаётся интерактивной CLI-командой.
Поиск расширяет аббревиатуры организационно-правовых форм, применяет узкий
@@ -19,13 +20,18 @@ SQLite; первый пользователь `admin` создаётся инт
действующий Налоговый кодекс для запросов о налоге на прибыль. Ограничения
текущего индекса и подтверждённые тестовые ошибки описаны в
[отчёте о релевантности](docs/product/search-relevance-findings-2026-11-03.md).
Версии описывают код, а не установленный production-релиз; актуальное
подтверждённое состояние среды см. в
[`docs/operations/CURRENT_STATE.md`](docs/operations/CURRENT_STATE.md).
| Компонент | Версия | Состояние |
|---|---:|---|
| Telegram-бот | `0.2.2` | на Synology работает `0.2.1`; обновление после слияния |
| Backend | `0.13.4` | авторизация, серверная capability управления пользователями, поиск и статические ресурсы |
| Telegram-бот | `0.2.2` | исходный код; последняя заметка о Synology указывает `0.2.1`, актуальность не перепроверена |
| Search API | `0.13.4` | авторизация, серверная capability управления пользователями, поиск и статические ресурсы |
| Frontend | `0.3.4` | поиск по правовой базе, просмотр редакций, внутренняя лаборатория и контекстная навигация кабинета |
| Сбор и обработка правовых данных | `0.8.0` | добавлены relevance set и оценка выдачи |
| Загрузчик архива Минюста (`backend/ingestion/minjust_cbd.py`) | `0.9.3` (`APP_VERSION`) | версия CLI и User-Agent в исходном коде |
| Нормализатор корпуса (`backend/normalization/minjust_cbd.py`) | CLI `0.10.0` (`APP_VERSION`); формат/алгоритм `1.1.0` (`NORMALIZER_VERSION`) | версия инструмента и версия нормализатора в manifest — разные значения |
| Оценка релевантности | формат набора `relevance-set-v1` | отдельная версия компонента не задана; CLI использует Search API `0.13.4` |
| RAG и база знаний | — | ещё не созданы |
## Структура репозитория
+7 -2
View File
@@ -1,11 +1,16 @@
# Backend Акылдаш
Версия: `0.13.0`
Версия загрузчика `minjust_cbd.py`: `0.9.3`
Первая backend-область проекта — загрузка правовых документов из официального
Open Data API ЦБД Минюста Кыргызской Республики. Код расположен в
`ingestion/minjust_cbd.py`: его можно запускать как CLI сейчас и импортировать
из будущего планировщика backend без запуска отдельного процесса.
Для передачи корпуса в production обязательна отдельная процедура
[CORPUS_HANDOFF.md](../docs/operations/CORPUS_HANDOFF.md); она проверяет
source/staging, inventory и checksum, решение по code 6, публикацию и
готовность индекса. Этот runbook — release gate; команды передачи здесь не
дублируются.
## Пробная загрузка
@@ -315,4 +320,4 @@ PYTHONPATH=backend python3 -m search.query "ЖЧК ачуу тартиби" --la
---
Акылдаш · Backend v0.13.0 · Frontend v0.2.3
Акылдаш · Search API v0.13.4 · Frontend v0.3.4 · Telegram-бот v0.2.2
+11 -1
View File
@@ -6,10 +6,15 @@
типографика, компоненты и правила адаптивности портала и лаборатории.
- [Обзор проекта](product/project-overview.md) — назначение, основные области и
правила работы с данными.
- [Стратегическое сравнение с Токтом](product/platform-development-plan-toktom-2026-10-24.md) —
продуктовая гипотеза и конкурентный анализ; это не план исполнения задач.
- [План frontend поисковой СПС](product/frontend-search-sps-plan.md) — границы
MVP, зависимости и спринты.
- [Готовность к проектированию frontend](product/frontend-design-readiness-plan.md) —
обязательные работы и критерии перехода к frontend.
- [План реализации и приёмки](product/implementation-roadmap.md) — единая
очередность UI и deployment gates, со статусом доказательств; не дублирует
продуктовую стратегию или эксплуатационные процедуры.
- [План интерфейса оценки поисковой выдачи](product/search-relevance-review-interface-plan.md) —
внутренняя лаборатория сбора оценок юристов для настройки OpenSearch.
- [Разметка relevance set](../backend/search/RELEVANCE_ANNOTATION.md) — подготовка
@@ -30,6 +35,11 @@
состояние production и оставшиеся проверки.
- [Инфраструктура и эксплуатация](operations/INFRASTRUCTURE.md) — схема,
доступы, deployment, backup, rollback и recovery.
- [Операционные процедуры](operations/DEPLOYMENT.md) — связанные инструкции по
deployment, [backup](operations/BACKUP.md), [rollback](operations/ROLLBACK.md),
[recovery](operations/RECOVERY.md), обязательная процедура
[передачи корпуса](operations/CORPUS_HANDOFF.md) и
[пакет владельца](operations/DEPLOYMENT_OWNER_PACKET.md).
- [План Telegram-пространства](operations/telegram-workspace-plan.md) — темы,
роли и этапы развития командного окружения.
@@ -45,4 +55,4 @@
---
Акылдаш · Telegram-бот v0.2.2 · Backend v0.13.0 · Frontend v0.2.3
Акылдаш · Telegram-бот v0.2.2 · Backend v0.13.4 · Frontend v0.3.4
+27 -2
View File
@@ -168,8 +168,33 @@ backed up, resolve the raw code `6` finding, and approve the exact normalized
corpus to use. Transfer only `minjust-normalized/`; keep the raw source archive
offline. Do not preserve the source's Windows/WSL file permission bits. Copy
to a new staging location with owner-approved permissions, verify the copied
manifest and files there, and only then consider placing it under `DATA_ROOT`.
Never overwrite an existing corpus or OpenSearch volume.
manifest and files there, and only then consider publishing it under
`DATA_ROOT/minjust-normalized`.
### Atomic publication gate for `DATA_ROOT`
The verified staging tree must be published to
`DATA_ROOT/minjust-normalized` as one all-or-nothing operation, using an
owner-approved atomic mechanism or a separately documented equivalent. An
in-place copy into the live target is not an acceptable publication method.
Preserve the current published corpus until the candidate is fully verified and
ready for the atomic switch; never overwrite its contents in place.
The publication mechanism and its interrupted-operation recovery have not yet
been specified or tested; this is a release gate, not a claim that atomic corpus
publication is implemented. Until that gate is completed, do not publish or
replace a corpus in `DATA_ROOT`.
If preparation is interrupted before publication, keep the current target
untouched. Resume only from the isolated staging tree after a full rehash and
source comparison; if that cannot be established, fail closed and prepare a
new staging candidate. If interruption makes the outcome of the final
publication ambiguous, do not retry or replace anything automatically. Verify
the target against the approved manifest and resolve the state with the owner
before any retry. Never overwrite an existing corpus or OpenSearch volume.
The atomic filesystem publication of the approved corpus into `DATA_ROOT` and
the OpenSearch alias switch are separate gates. A successful corpus publish
does not authorize indexing or alias changes; do not conflate the two.
The bulk importer now refuses alias publication until all Bulk item results
are successful, the full staged index is refreshed, its fragment count exactly
-355
View File
@@ -1,355 +0,0 @@
# План точного воспроизведения поискового интерфейса
Дата: 23 октября 2026 года.
Статус: основная реализация и локальная приёмка выполнены в
`feature/frontend-pixel-perfect`; после первичного прогона скорректированы
навигация, плотность результатов, заголовок документа, fixture-контент,
клавиатурный trap для диалогов и компактные позиционируемые подсказки
лаборатории. Скриншоты, покропленные сравнения и расширенный
Playwright-сценарий находятся в репозитории; см. [отчёт](visual-review/README.md).
Локальные тесты и guards из CI прошли. Ожидают runner: проверки Compose/Caddy и
сборка production images. Независимый review запускает владелец. Скринридер и
реальный корпус всё ещё требуют проверки.
## 1. Цель, границы и источники истины
Привести существующую авторизованную поисковую страницу `/` к композиции
утверждённого изображения «Акылдаш · Түндүк», сохранив реальные API,
авторизацию, безопасность и отдельный сценарий лаборатории `/review`.
Источники:
- [DESIGN.md](../../DESIGN.md) — единственная нормативная дизайн-система:
токены, типографика, доступность, постоянные правила компонентов.
- [Исходный концепт](../design/tunduk-desktop-concept.png) — визуальный
эталон композиции. Вложение пользователя 1280×800 визуально соответствует
этому сохранённому изображению более высокого разрешения.
- [План frontend СПС](frontend-search-sps-plan.md) — продуктовый контекст.
- [Readiness plan](frontend-design-readiness-plan.md) — отдельные условия
готовности публичного продукта, которые этот план не отменяет.
Изображение задаёт композицию и пропорции; `DESIGN.md` задаёт токены,
шрифты и ограничения. До реализации фиксировать расхождения, а не молча
изменять палитру, шрифты или доступность ради совпадения растровых пикселей.
Временные задачи и результаты измерений остаются здесь; новые постоянные
правила добавляются в `DESIGN.md` без копирования всей дизайн-системы.
Не входят: публичный запуск, изменение прав доступа, ранжирования, корпуса,
индекса, production, регистрация, аналитика, сравнение редакций, переход
на новый frontend framework. Содержимое демонстрационного документа
не становится юридическими данными продукта.
Figma не является обязательной зависимостью: сохранённого эталона достаточно.
При необходимости совместного редактирования можно подготовить отдельный
Figma-макет с Auto Layout и переменными, ссылающийся на эти же правила;
это не заменяет проверку фактической вёрстки в браузере.
## 2. Исходное состояние до реализации
Таблица ниже фиксирует базовую проверку до реализации, выполненную по коду и
изображениям без браузера; строки не описывают текущее состояние. Последующие
результаты Playwright сохранены в [отчёте визуальной приёмки](visual-review/README.md).
Они относятся к локальному UI со стабильными fixture-ответами и не подтверждают
состояние production или актуального OpenSearch.
Основные файлы:
- `backend/search/review.html` — разметка, встроенные CSS и JavaScript обоих
сценариев, footer и авторизация.
- `backend/search/api.py` — выдача страницы для `/` и `/review`, API поиска,
фильтров и редакций.
- `backend/test_search_api.py` — существующие проверки API.
- `.gitea/workflows/ci.yaml` — обязательные проверки и сборка образов.
| Проблема | Подтверждение в реализации | Требуемый результат |
|---|---|---|
| Другая шапка | Общая `.review__header`, поиск отдельной формой ниже | Бренд, поиск и язык в одной верхней строке |
| Нет второй строки эталона | Нет общей полосы навигации и активных фильтров | Навигация и удаляемые фильтры под шапкой |
| Другие пропорции | `.search__layout`: `230px / .9fr / 1.2fr`, `min-height: 65vh` | Измеренная сетка и корректная высота рабочей области |
| Не тот вид фильтров | Все справочники выводятся radio-списками, даты вертикально | Компактные группы, select органа, даты рядом |
| Выбранный результат неполон | Есть только фоновое выделение | Фон, рамка, подпись «Открыт», точные отступы |
| Неполная панель документа | Есть заголовок, select редакции/языка, метаданные и текст | Полная иерархия и работающие действия эталона |
| Смешаны стили документа | Объявлен `.search__document-body`, статья использует `.review__document-body` | Одна корректная область стилей поискового документа |
| Шрифты не поставляются | Noto указаны в CSS, локальные файлы не найдены | Проверенная загрузка локальных шрифтов |
| Нет фирменных ресурсов | Знак сделан CSS-кружком; орнамент и favicon отсутствуют | SVG-знак, орнамент, favicon |
| Лабораторная панель на поиске | `.review__actions` вне скрываемого `<main>`; для `/` не скрывается | Оценивание только на `/review` |
| Счётчик вводит в заблуждение | Выводится `payload.results.length`; API не возвращает total | Явное число на странице либо отдельно реализованный total |
| Нет визуального контроля | Найденные тесты проверяют API, не геометрию страницы | Воспроизводимые браузерные снимки и сравнение |
Это исходное описание состояния до реализации. Сейчас переключатель RU/KY,
отдельный язык поиска, реальные редакции и язык документа, оглавление, поиск
по тексту документа, разворачивание, печать и отдельный маршрут `/review`
реализованы. Подробности текущей локальной приёмки и её ограничения приведены
в [отчёте](visual-review/README.md); оставшиеся непроверенные состояния не
считаются принятыми только потому, что чекбоксы плана перечислены ниже.
## 3. Этап 0 — воспроизводимый эталон
- [x] Перед реализацией перечитать актуальные инструкции, `DESIGN.md`,
реализацию маршрутов и обязательные проверки; использовать установленный
Ponytail согласно правилам репозитория.
- [x] Сохранить чужие незакоммиченные изменения, создать тематическую
`feature/` ветку и не переносить посторонние изменения в PR.
- [x] Зафиксировать основной viewport 1280×800 CSS px, браузер и его версию,
ОС, масштаб 100%, device scale factor и остальные viewport в отчёте.
- [ ] Получить исходный снимок текущего интерфейса на тех же размерах.
- [x] Подготовить детерминированные тестовые данные: запрос «налог на прибыль»,
три результата из изображения, выбран первый, открыта соответствующая
демонстрационная редакция, фильтр статуса и исходная прокрутка.
- [x] Изолировать fixture от реального режима и пометить демонстрационное
содержимое только в тестовом сценарии. Не добавлять подмену юридических данных
в production-путь.
- [x] Нормализовать сохранённое изображение до 1280×800 без изменения
пропорций и сохранить параметры подготовки эталона.
- [x] Записать конфликты изображения с нормативной типографикой и токенами;
согласованные ограничения приведены в отчёте.
Критерий завершения: один и тот же тестовый сценарий воспроизводится
независимо от состояния OpenSearch и текущей реальной выдачи; реальный режим
продолжает использовать API. Авторизация не ослабляется ради снимков.
## 4. Этап 1 — карта геометрии
Эталон 1586×992 пропорционально вписан в 1280×800; фактические значения
сверены с Playwright при device scale factor 1. Допуск границ крупных зон —
около 1 CSS px.
| Область | Нормализованный эталон | Реализация |
|---|---:|---:|
| Шапка и строка навигации | y ≈ 0–126 px | y = 0–127 px |
| Рабочая область | y ≈ 126–744 px | y = 127–744 px |
| Footer | y ≈ 744–800 px | y = 744–800 px |
| Фильтры | x ≈ 0–226 px | x = 0–226 px |
| Результаты | x ≈ 226–648 px | x = 226–648 px |
| Документ | x ≈ 648–1280 px | x = 648–1280 px |
Внутренние контрольные координаты и ограничения см. в
[отчёте визуальной приёмки](visual-review/README.md); там же есть overlay и
разница по каждой крупной области.
- [x] Измерить крупные границы, основную навигацию и ключевые элементы
документа по исходнику; фактические значения записаны в отчёте.
- [ ] Измерить все внутренние отступы, размеры полей и кнопок, межстрочные
интервалы и разделители по всем областям.
- [x] Зафиксировать адаптивные точки и проверить сетку на 1440/1024/390/320 px;
реальные длинные данные ещё не проверены.
- [ ] Разделить метрики повторяемых элементов и высоты, зависящие от текста.
Не выравнивать принудительно высоту всех результатов или разделов.
- [ ] Определить владельца прокрутки каждой области, поведение footer
при коротком содержимом и доступность длинного документа.
Критерий завершения: геометрия описана измерениями и адаптивными правилами,
а не независимыми приблизительными настройками каждого блока.
## 5. Этап 2 — разделение сценариев и базовых стилей
- [x] Разделить композиции поиска и лаборатории, сохранить маршруты,
авторизацию, кабинет, управление пользователями, обучение и черновики.
- [x] Ограничить лабораторные элементы маршрутом `/review`, включая
панель проверяющего и сохранения; маршрут проверен браузерным тестом.
- [ ] Использовать общий слой семантических токенов и базовых элементов;
стили поискового экрана изолировать BEM-классами.
- [ ] Устранить дублирующие и неиспользуемые правила, исправить класс статьи.
- [ ] Убрать зависимость шапки и footer поиска от лабораторного layout.
- [ ] Если CSS/JS/ресурсы выносятся из HTML, добавить ограниченную выдачу
static-файлов с MIME, защитой от обхода путей и сохранением защитных
заголовков. Убедиться, что ресурсы входят в production-образ.
Ожидаемые зоны изменений: `backend/search/review.html`, при необходимости
каталог static-ресурсов рядом с ним и `backend/search/api.py`.
Не вводить Next.js, React или новый сборщик только ради этой задачи.
Критерий завершения: оба сценария работают независимо, общие CSS не меняют
их композицию случайным образом; существующие права доступа сохранены.
## 6. Этап 3 — шрифты, знак, орнамент и favicon
- [ ] Поставить локальные WOFF2 Noto Sans 400/500/600 и Noto Serif 600/700
с лицензиями; исключить случайное синтетическое начертание.
- [x] Проверить загрузку, `font-display`, кириллицу и `Ө ө Ү ү Ң ң`.
Визуальные снимки выполнять после `document.fonts.ready`.
- [ ] Подготовить SVG-знак по визуальному направлению референса;
сверить размер, толщину линий и положение относительно названия.
- [ ] Подготовить отдельный симметричный золотистый SVG-орнамент,
`aria-hidden`, без перекрытия управления и текста.
- [x] Подготовить favicon SVG и растровый fallback 32×32; подключить
в `<head>`, проверить выдачу и MIME. Масштабирование SVG проверено визуально.
- [ ] Подготовить единые SVG-иконки поиска, очистки, календаря, печати,
оглавления, разворачивания и стрелок; иконкам-кнопкам дать доступные имена.
- [ ] Перенести значения в токены, не размножать HEX по компонентам.
Критерий завершения: шрифты реально загружены, знак и орнамент являются
ресурсами, favicon отображается; нет CSS-заглушек вместо фирменной графики.
## 7. Этап 4 — сборка композиции
Работать от крупных областей к деталям; сначала геометрия, затем типографика.
- [ ] Шапка: знак, название, разделитель, подпись продукта, поле с подписью
и очисткой, «Найти», язык интерфейса. Служебные действия доступны компактно.
- [ ] Вторая строка: «Поиск», «Об источниках», удаляемые фильтры;
демонстрационная подпись только для fixture. «Об источниках» открывает
реальные сведения о происхождении данных, а не пустую заглушку.
- [ ] Три панели: непрерывные границы, правильные фоны и пропорции,
отсутствие лишнего свободного ряда статуса в стабильном состоянии.
Сообщения для скринридера сохраняются.
- [ ] Фильтры: заголовок, текстовый сброс, статус, вид, орган, даты рядом,
орнамент в свободной нижней части без перекрытия длинного содержимого.
- [ ] Результаты: заголовок и честный счётчик, компактная сортировка,
строки выдачи, выбранная строка с рамкой/фоном/«Открыт», метаданные,
безопасная подсветка выдержки, пагинация.
- [ ] Документ: breadcrumbs и разворачивание, отдельная роль заголовка,
компактные метаданные, язык, действия, поиск внутри, поле чтения.
- [ ] Footer: бренд слева, фактические версии frontend/backend справа;
не копировать устаревшую backend-версию и слово «макет» из изображения.
Критерий завершения: порядок, вложенность и пропорции всех крупных зон
соответствуют эталону; нет лишних лабораторных блоков.
## 8. Этап 5 — рабочее поведение и интеграция
- [ ] Сохранить поиск, сортировку, пагинацию, загрузку редакций и языков.
- [x] Синхронизировать фильтры с URL и удалять отдельный фильтр без сброса
остальных; сохранение второго фильтра проверяется Playwright.
- [ ] Проверить восстановление и историю навигации через прямые ссылки и Back/Forward.
- [ ] Согласовать вид фильтров с контрактом: текущий API принимает одиночные
значения. Не имитировать множественный выбор checkbox без поддержки API.
Если нужен multiselect, отдельно описать и проверить расширение контракта.
- [ ] Разделить язык интерфейса, поиска и текста документа. Для RU/KY
перевести подписи, статусы и ошибки; смена UI не подменяет текст редакции.
- [ ] Не выдавать число на странице за общее: использовать явную подпись
либо отдельно реализовать достоверный total с проверкой его семантики.
- [ ] Построить оглавление по реальным заголовкам, с корректными якорями;
при отсутствии структуры показать понятное состояние.
- [ ] Реализовать поиск по текстовым узлам документа: ввод/очистка,
подсветка, активное совпадение, счётчик, предыдущий/следующий,
прокрутка и состояние нулевого результата. Не повреждать HTML,
ссылки и таблицы; не вставлять пользовательский запрос через `innerHTML`.
- [ ] Реализовать разворачивание/возврат с сохранением выбранной редакции,
прокрутки и корректного фокуса.
- [x] Добавить печать через print CSS: документ, его реквизиты и источник
без поисковых и служебных панелей; служебные элементы проверены в print media.
- [ ] Защитить смену запроса/документа/редакции от запоздавших ответов
через отмену запроса или проверку актуальности результата.
- [ ] Сохранить безопасный вывод очищенного документного HTML и ссылок,
обработку ошибок и ограничения авторизации.
Критерий завершения: каждый видимый элемент эталона выполняет действие;
нет декоративных кнопок, фиктивных языков и выдуманных юридических статусов.
## 9. Этап 6 — адаптивность, типографика и состояния
- [ ] Настроить размеры, веса, line-height и отступы после фиксации сетки.
Сверить переносы названия документа, результатов и плотность абзацев.
- [x] Проверить 1280×800 и ширины 1440/1024/390 px; дополнительно 320 px.
Высоты и параметры окружения записаны в отчёте.
- [ ] Проверить реальные длинные редакции, длинные названия на RU/KY и подобрать
breakpoints на реальных данных корпуса.
- [x] На узких экранах открывать фильтры отдельной доступной панелью,
документ — отдельным представлением с возвратом к результатам; проверено на 390 px.
- [x] Сокращать/убирать орнамент на телефоне; сохранять текст без
горизонтальной прокрутки, широкие таблицы — в собственной области прокрутки.
Проверено синтетической широкой таблицей; реальные таблицы корпуса остаются открыты.
- [x] Проверить длинные названия, отсутствие редакций, широкую таблицу и
широкое изображение синтетическими данными.
- [ ] Проверить одноязычные реальные редакции, ссылки, много фильтров и
длинный контент из реального корпуса.
- [x] Проверить загрузку редакции, empty, search/edition error, retry,
disabled-состояние без редакции и focus-visible; query сохраняется при ошибке.
- [ ] Проверить hover и сценарии ошибок авторизации/администрирования.
- [x] Проверить Tab/Shift+Tab/Escape, возврат фокуса мобильной панели и
диалогов, а также `prefers-reduced-motion`.
- [ ] Проверить доступные имена всех элементов, live-сообщения, контраст,
масштабирование, скринридер и touch-области на поддерживаемых устройствах.
Критерий завершения: точность desktop не приводит к переполнению,
недоступности действий или потере контекста на узком экране.
## 10. Этап 7 — визуальная приёмка
Выполнить один пакет первичных снимков всех контрольных размеров,
собрать дефекты по областям, исправить одним пакетом и выполнить один
подтверждающий проход. Новые циклы обосновывать конкретными оставшимися
дефектами или замечаниями независимого reviewer, не бесконечной полировкой.
- [x] Дождаться шрифтов и стабильных fixture-данных, задать исходную
прокрутку; снимки делаются после `document.fonts.ready`.
- [x] Проверить, что снимки показывают загруженный поисковый сценарий, а не
login, ошибку или другой маршрут.
- [x] Для 1280×800 подготовить overlay 50%, difference image и отдельные
сравнения шапки, фильтров, результатов, документа и footer.
- [x] Сохранить снимки остальных размеров и отчёт с условиями, отклонениями,
исправлениями и известными ограничениями.
- [ ] Передать независимому reviewer запрос пользователя, эталон,
`DESIGN.md`, этот план, diff и снимки всех проверенных размеров.
Критерии для детерминированного fixture при 1280×800:
| Проверка | Условие приёмки |
|---|---|
| Границы крупных зон | Отклонение от зафиксированной карты до 2 CSS px |
| Отступы и размеры управления | Отклонение до 2 CSS px от измерений |
| Ключевые заголовки | Совпадают переносы при согласованных шрифтах; исключения объяснены |
| Композиция | Все зоны и элементы эталона присутствуют, порядок совпадает |
| Ресурсы | Загружены шрифты, знак, орнамент, favicon, единые иконки |
| Рабочий сценарий | Поиск, фильтры, редакции, действия и навигация работают |
| Адаптивность | Нет перекрытий, обрезанного управления и общей горизонтальной прокрутки |
| Изоляция | Нет лабораторного оценивания на поиске, `/review` без регрессий |
Нулевая попиксельная разница не является критерием: сглаживание текста,
растровая природа концепта и нормативные токены дают объяснимые различия.
Один процент сходства всего экрана не заменяет проверки каждой области.
Достижение допусков подтверждается измерениями, а не общей оценкой «похоже».
## 11. Этап 8 — проверки, версия и PR
Этот этап относится к реализации в feature-ветке. Frontend повышен до `0.2.3`,
backend — до `0.13.0` для allowlist-выдачи локальных шрифтов. Контракт Search
API v1 не менялся.
- [x] Выполнить доступные локально проверки из `AGENTS.md` и CI: backend,
Telegram bot, backup, deploy, host/root/verifier/audit/Compose/production
config/runner guards, shell syntax и Playwright.
- [ ] Получить успешный CI на назначенном runner: `docker compose config`,
проверка Caddyfile и сборка backend/OpenSearch production images.
- [x] Добавить проверки фактических изменений: static/favicon, браузерные
сценарии поиска/редакций/поиска внутри/навигации и регрессии лаборатории;
визуальное сравнение использует стабильный fixture.
- [x] Повысить версии для совместимого функционального изменения;
frontend/backend версии согласованы в footer.
- [x] Выполнить push и найти существующий PR ветки через `gitea-api`;
изменения остаются в одном PR #53.
- [ ] После каждого push независимый reviewer проверяет полный текущий PR,
прежние исправления и оставляет краткий PR-комментарий с явным выводом
о наличии или отсутствии блокирующих замечаний; reviewer не редактирует код.
- [ ] Исправить обоснованные замечания в той же ветке/PR, повторить проверки,
commit/push и независимый review.
- [ ] После успешных проверок и устранения блокирующих замечаний обновить
существующий changelog, записав значимые изменения для пользователя.
- [ ] Commit/push changelog в тот же PR, повторить обязательные проверки
и независимый review окончательного состояния.
Готовность к merge: проверки проходят, финальный review не содержит
блокирующих замечаний, changelog и версии согласованы, визуальные доказательства
доступны reviewer. Не сливать автоматически и не развёртывать production.
## 12. Порядок выполнения и итоговые материалы
Зависимости: эталон → измерения → разделение сценариев → ресурсы → композиция
→ поведение → адаптивность и состояния → визуальная приёмка → финальный PR.
Не начинать микроподгонку кнопок до исправления общей геометрии.
Ожидаемые материалы реализации:
- обновлённая поисковая страница и сохранённый сценарий лаборатории;
- локальные шрифты с лицензиями, SVG-знак, орнамент, favicon и иконки;
- детерминированный тестовый сценарий и воспроизводимый способ снимков;
- карта измерений, снимки, overlay/diff и отчёт приёмки;
- результаты обязательных проверок и независимого review;
- версии, changelog и один PR без автоматического merge.
Чекбоксы отмечать только после выполнения и проверки. Локальные проверки,
которые реально выполнены, зафиксированы в отчёте visual-review.
Этот документ не подтверждает готовность API, публичного продукта или
production.
+462
View File
@@ -0,0 +1,462 @@
# План реализации и приёмки Акылдаш
Дата актуализации: **2 ноября 2026 года**. Основа сверки: `main` на
`7ece39f212b67e497a8dfb360d5d271ab088ef57`. Это единый план работ по продукту,
интерфейсу и переходу к production. Он не заменяет эксплуатационные runbooks
и не подтверждает состояние живого сервиса.
## 1. Статус и границы достоверности
Различаем три вида сведений:
- **В коде** — наличие исходного кода на указанном commit; это не доказывает,
что функция развёрнута или доступна пользователям.
- **Историческое наблюдение** — результат конкретного аудита, дата и пределы
которого указаны рядом. Оно не является повторной проверкой текущего сайта.
- **Цель / gate** — требование, которое нужно выполнить и подтвердить до
следующего этапа.
На сверенном commit источники кода показывают Backend `0.13.3`
(`backend/search/minjust_opensearch.py`), Frontend `0.3.3`
(`backend/search/review.html`) и Telegram-бот `0.2.2`
(`tools/telegram-bot/bot.py`). Это версии исходного кода, а не подтверждение
установленных production-версий. В этом PR согласованы версии в корневом и
общем документационном README; `backend/README.md` отдельно называет версию
загрузчика `minjust_cbd.py` (`0.9.3`). При новых изменениях сверять версию
компонента с соответствующим исполняемым кодом.
В Search API и frontend реализованы поиск RU/KY, фильтры, карточка документа,
редакции, поиск в тексте, внутренняя лаборатория, вход и административные
действия. В коде также есть локальные Noto Sans/Serif с лицензиями, favicon и
встроенный SVG-знак бренда. Наличие файлов и ссылок в HTML не подтверждает,
что они загрузились в live-браузере. Результаты браузерной проверки приведены
только в [отчёте визуальной приёмки](visual-review/README.md).
Production readiness не следует из наличия Compose, release workflow или
deploy-кода. Подтверждённое состояние и ограничения находятся в
[CURRENT_STATE.md](../operations/CURRENT_STATE.md); статус релиза — в
[DEPLOYMENT.md](../operations/DEPLOYMENT.md), ограничения backup/restore — в
[BACKUP.md](../operations/BACKUP.md), rollback — в
[ROLLBACK.md](../operations/ROLLBACK.md), аварийное восстановление — в
[RECOVERY.md](../operations/RECOVERY.md). Этот план не повторяет команды из
этих runbooks.
## 2. Очерёдность работ
### 2.1 Продукт и качество правовых данных
1. Поддерживать воспроизводимое получение и нормализацию официальных
правовых материалов с сохранением источника, редакции и контрольных сумм.
2. Подтвердить полноту и актуальность RU/KY корпуса, правила для отсутствующих
текстов и одноязычных редакций; не выдумывать перевод или реквизиты.
3. Развивать замороженный relevance set и измерять качество на одной и той же
выборке до и после изменений ранжирования.
4. Развивать версионируемые API и справочники, сохраняя совместимость
существующих клиентов.
5. Публичный frontend, персональные функции и RAG остаются отдельными
продуктовыми решениями и readiness gates. Сверяться с [обзором проекта](project-overview.md),
[планом frontend](frontend-search-sps-plan.md) и
[готовностью публичного frontend](frontend-design-readiness-plan.md). Конкурентная
гипотеза и сегмент рынка отдельно описаны в
[стратегическом сравнении с Токтом](platform-development-plan-toktom-2026-10-24.md).
### 2.2 Интерфейс: датированный реестр UI-01—UI-33
Реестр ниже сохраняет исходные наблюдения аудита **23 октября 2026 года** и
критерии приёмки; это не список текущих открытых дефектов. Актуальный план на
`main` указывает, что все UI-01—UI-33 реализованы в PR #54. Он также описывает
follow-up по поиску, кабинету и лаборатории, локальную браузерную проверку и
синтетические regression fixtures. Их результаты привязаны к указанным в
исходном документе commits и окружению, а не являются повторным live-аудитом в
этой документационной задаче. Сверяться с [отчётом visual-review](visual-review/README.md);
не открывать снова выполненные пункты без нового воспроизводимого свидетельства.
Источники по состоянию на базовый commit этого PR сохранены постоянными
ссылками: [UI-план на `7ece39f`](https://git.vakanaut.ru/admin/akyldash/src/commit/7ece39f212b67e497a8dfb360d5d271ab088ef57/docs/product/interface-correction-plan.md)
и [план pixel-perfect на `7ece39f`](https://git.vakanaut.ru/admin/akyldash/src/commit/7ece39f212b67e497a8dfb360d5d271ab088ef57/docs/product/frontend-pixel-perfect-plan.md).
UI-01—UI-33 вошли в [PR #54](https://git.vakanaut.ru/admin/akyldash/pulls/54)
(merge commit [`01380d3c`](https://git.vakanaut.ru/admin/akyldash/commit/01380d3c09d71e32c965d974a39a4d82de0a15c5));
последующий follow-up поиска, кабинета и лаборатории записан в
[commit `e5a8326a`](https://git.vakanaut.ru/admin/akyldash/commit/e5a8326a5e3def1bf5d5dc94794da82a2af801ab).
В исходном реестре **P1** означает обязательное исправление до визуальной
приёмки/выпуска, **P2** — существенное улучшение понятности и
последовательности. Отсутствие функции само по себе не считается багом;
обозначенные целевые корректировки требуют подтверждения по коду и дизайну.
| ID | Приоритет | Историческое наблюдение 23.10.2026 | Требование / критерий |
|---|---|---|---|
| UI-01 | P1 | При пустом запросе одновременно показывались подсказка и empty-состояние | Разделить initial/loading/results/empty/error; empty показывать после завершённого поиска |
| UI-02 | P1 | До выбора документа были доступны действия и пустые select | До загрузки документа показывать понятное приглашение; действия доступны после выбора |
| UI-03 | P1 | Фильтры имели горизонтальное переполнение (`clientWidth=194`, `scrollWidth=231` при 1064 px) | Исключить переполнение; длинные списки раскрывать по запросу |
| UI-04 | P1 | Действие «Сбросить» обрезалось заголовком | Заголовок и действие видны целиком на поддерживаемых размерах |
| UI-05 | P1 | Счётчики отрывались от подписей, переносы растягивали панель | Разделить колонки выбора/подписи/числа; переносить только длинные названия |
| UI-06 | P1 | Все 28 видов и 8 статусов были раскрыты, орган и даты находились ниже первого экрана | Показывать основные значения и сворачиваемые группы, сохраняя доступ ко всему каталогу |
| UI-07 | P1 | Ширины около 78 px не хватало для RU/KY названий языка | Подбирать размер по самой длинной локализованной подписи без обрезки |
| UI-08 | P1 | На 390 px навигация прокручивалась горизонтально, кабинет и фильтры уходили за край | Адаптивно показывать поиск, фильтры и кабинет без горизонтальной прокрутки основных действий |
| UI-09 | P2 | Кабинет был малозаметной иконкой во второй строке | Подписанная desktop-кнопка; на mobile — доступное имя и достаточная touch-область |
| UI-10 | P1 | Три колонки оставались тесными на 1024/1064 px | Перейти к двухпанельному режиму и скрытию фильтров, не сжимать колонки бесконечно |
| UI-11 | P2 | Название документа повторялось в breadcrumb, заголовке и тексте | Breadcrumb обозначает контекст; официальный текст не переписывать |
| UI-12 | P1 | Ссылка на источник и toolbar переполнялись на промежуточной ширине | Переносить действия группами без обрезки; сохранять подписи редакции и языка |
| UI-13 | P2 | Пустые абзацы и синие ссылки конфликтовали с оболочкой | Нормализовать отступы и ссылки без потери структуры официального текста |
| UI-14 | P1 | Таблицы в документе шире панели (`clientWidth=412`, `scrollWidth=834`) | Дать таблице отдельную обозначенную прокрутку; не прокручивать всю страницу по горизонтали |
| UI-15 | P1 | Встречались Temp-пути и HTTP-ссылки исходного редактора | Классифицировать ссылки безопасно, не удалять юридический текст; не считать локальные/IP-ссылки проверенными |
| UI-16 | P2 | Развёрнутый документ терял поиск, совпадение и toolbar | Сохранять редакцию, язык, позицию и навигацию; обеспечить очевидный возврат |
| UI-17 | P2 | Часть KY-интерфейса оставалась на русском | Инвентаризировать строки интерфейса; не заменять переводом язык документа |
| UI-18 | P1 | На `/review` отображались два footer, общий footer был выше сохранения | Один footer после основного содержимого и панели сохранения |
| UI-19 | P1 | Шапка, формы, панели и footer лаборатории имели разные направляющие | Единая оболочка и совпадающие границы контента |
| UI-20 | P1 | Высокая шапка лаборатории отодвигала работу на mobile | Компактный заголовок и помощь; поиск и рабочая область доступны сразу |
| UI-21 | P1 | Заголовок кабинета был пустым | Видимый заголовок и доступное имя диалога |
| UI-22 | P1 | Не было постоянного крестика; закрытие находилось внизу формы | Крестик 44×44, доступное имя, Escape и возврат фокуса; отмена редактирования остаётся |
| UI-23 | P1 | Навигация, выход, профиль и смена пароля были смешаны | Разделить «Профиль» и «Безопасность», отделить выход от формы |
| UI-24 | P1 | Окно пользователей открывалось поверх кабинета | Не оставлять конкурирующие модальные окна; сохранять контекст и корректный фокус |
| UI-25 | P1 | Список пользователей был длинным модальным окном с закрытием ниже экрана | Отдельный экран списка и короткие диалоги для создания/сброса |
| UI-26 | P2 | Создание, удаление, сброс и входные данные смешивались | Действия на строке, отдельное подтверждение удаления, не раскрывать лишние формы |
| UI-27 | P2 | Бренд, навигация, шрифты и ссылки различались между экранами | Общие header, logo, button, link, dialog и footer |
| UI-28 | P2 | Диалоги закрывались разными способами | Единая модель окна и доступного закрытия |
| UI-29 | P2 | Обучение появлялось с задержкой и перехватывало ввод | Запуск по запросу или ненавязчиво до начала ввода; не отбирать фокус |
| UI-30 | P2 | Шкала 0–3 переносилась, комментарии всегда занимали место | Полные подписи; допустима сетка 2×2; раскрываемый комментарий без потери текста |
| UI-31 | P2 | Пустой экран лаборатории выглядел готовым к отправке оценки | Явное состояние снимка, прогресс и статус черновика; не менять смысл пустой оценки |
| UI-32 | P2 | Footer live-сайта показывал «Концепция Түндүк» | Рабочий интерфейс показывает продукт и реальные версии; концепция подписывается только в макете/демо |
| UI-33 | P1 | Документ растягивал лабораторию до y≈636935 px, сохранение уходило ниже | Ограничить высоту области чтения и прокручивать её отдельно; сохранение доступно независимо от длины текста |
Дополнительные целевые критерии исходного аудита:
- **Сетка и ресайз колонок:** desktop — три колонки с доступными разделителями;
ориентиры 1440 px: `280 / 408 / 736` плюс два захвата по 8 px, 1280 px:
`256 / 384 / 624` плюс захваты. Рекомендуемые пределы фильтров 256–360 px,
выдачи от 360 px, документа от 560 px. При недостатке ширины сначала скрыть
фильтры, затем показывать документ отдельно.
- Разделители должны иметь `role=separator`, доступное имя, min/max/current
значения, pointer drag и управление стрелками клавиатуры. Отдельные кнопки
скрытия/показа фильтров и сброса ширины обязательны; двойной клик не заменяет
доступный сброс. Сохранённая ширина ограничивается текущим viewport.
- Остальные правила сетки: фильтры не становятся постоянно прокручиваемой
узкой колонкой; полный каталог значений всегда достижим; API single-select не
изображается множественными checkbox. Длинное название органа читается в
панели выбора полностью. Поля дат имеют постоянные «От» / «До» и переходят
в столбец, когда не помещаются. На desktop выдача и документ могут иметь
отдельную вертикальную прокрутку с доступными заголовком/toolbar; на mobile
основной поток вертикальный с отдельными панелями. Footer использует
растущий main (`min-height: 100dvh`), не перекрывает контент и следует за ним;
панель сохранения имеет собственное место.
- **Панели и формы:** понятный заголовок и крестик 44×44; именованный modal
dialog, фокус внутри, Tab/Shift+Tab без выхода в фон, Escape там, где закрытие
допустимо, возврат фокуса инициатору; фон не интерактивен. Не наслаивать
кабинет и пользователей. Профиль и безопасность — отдельные разделы; права
по-прежнему проверяет сервер. В форме пароля постоянные подписи, требования,
доступное показать/скрыть и подтверждение нового пароля. Пароли не
предзаполнять и не сохранять в материалах аудита; ввод выполняет человек.
- Основное действие одно; отмена вторична, выход отдельно; Enter отправляет
только активную форму. Ошибка у поля и в доступном сообщении, допустимый ввод
сохраняется, loading исключает повторную отправку. Несохранённое редактирование
защищено от случайной потери, обычный просмотр закрывается без лишнего
подтверждения. После успеха сообщается результат, при ошибке есть путь
восстановления; состояние не кодируется одним цветом.
- Правила применяются к кабинету, входу, обязательной смене пароля, источникам,
созданию/сбросу/удалению пользователя, обучению и просмотру документа.
- **Приёмка:** единая оболочка/header/footer; нет общей горизонтальной
прокрутки; initial не сообщает об empty до поиска; действия документа
активируются по состоянию; keyboard и touch работают; RU/KY подписи и язык
документа независимы; таблицы прокручиваются отдельно; тестируются contrast
WCAG AA, видимый focus, reduced motion, zoom/reflow и доступные имена.
- Viewport: **1440×900, 1280×800, 1024×768, 390×844**, дополнительно 320 CSS px
для reflow. Визуальное сравнение — детерминированное fixture; нулевой
pixel-diff не является критерием. Авторизация и destructive-сценарии
проверяются только в безопасном тестовом контуре.
Исторически выполненные браузерные сценарии и ограничения аудита 23.10.2026:
| Область | Выполнено в том аудите | Не проверено тогда |
|---|---|---|
| Начальная страница и поиск RU | Пустой запрос, фильтры, footer; поиск «налог на прибыль», открытие кодекса | Экспертная оценка юридической релевантности |
| Фильтры, сортировка, страницы | Статус, chip, снятие фильтра, дата/релевантность, страница 2 и сброс на страницу 1 | Все комбинации справочников |
| Пустая выдача и документ | Контрольный заведомо пустой запрос, реальные текст и редакции, язык, разворот | Искусственное создание серверного сбоя, реальная печать/PDF |
| Поиск в документе и локализация | Совпадения, переход к следующему, переключение RU/KY и чтение подписей | Поиск после смены редакции; полная проверка всех переводов |
| Источники и мобильные фильтры | Открытие/закрытие панели и раздела источников | Внешний сайт Минюста, полный touch на физическом устройстве |
| Кабинет и пользователи | Профиль, поля смены пароля, Escape/возврат фокуса; просмотр списка | Ввод пароля, создание/удаление пользователя, сброс пароля |
| `/review` | Пустое состояние, поиск, шкала, документ, обучение | Отправка оценки и подтверждение серверного сохранения |
| Авторизация | Наличие локальной реализации | Live login, истечение сессии и обязательная смена пароля |
Этот перечень описывает только прежний браузерный сеанс. Не использовать его
как подтверждение текущих production-сценариев.
#### Реализация, зафиксированная в текущем плане `main`
UI-план, находившийся на базовом commit этого PR, отмечает UI-01—UI-33
реализованными в PR #54 и связывает группы изменений с
регрессионными сценариями:
| Пункты | Изменение, зафиксированное в плане `main` | Regression evidence, указанное там |
|---|---|---|
| UI-01—02 | Разделены initial/loading/results/empty/error; действия документа зависят от выбранной редакции | Empty, API error и редакция без текста |
| UI-03—08 | Компактные/сворачиваемые фильтры, счётчики, локализованные языковые select и адаптивная навигация | Reflow 320/390/640/1024/1280/1440; на 640 px проверены основные действия `/`, `/review`, `/users` |
| UI-09—10 | Подписанный кабинет и адаптивный layout вместо бесконечного сжатия трёх колонок | Геометрия и overflow на 640/1024/1280/1440 |
| UI-11—16 | Breadcrumb, toolbar, отдельный scroll таблиц, очистка небезопасных URL-атрибутов и разворот документа в панели | Синтетические private-IP/relative/HTTP ссылки; ошибки и гонки редакций A/B |
| UI-17 | Перевод интерфейсных подписей RU/KY с независимым языком документа | Переключение языка; полный ручной лингвистический review остаётся открытым |
| UI-18—20 | Один footer, общие направляющие и ограниченная по высоте лаборатория | Один footer и длинный синтетический документ с собственным scroll |
| UI-21—24 | Имя и разделы кабинета, безопасный переход к пользователям без наложенных диалогов | ARIA name, Escape, focus trap/return и отдельные маршруты |
| UI-25—28 | Отдельный экран пользователей, целевые окна для действий, общий способ закрытия | Только фиктивный `fixture-created`; реальные аккаунты/API не использовались |
| UI-29 | Обучение запускается пользователем | Локальный regression scenario |
| UI-30—31 | Оценка 2×2, раскрываемый комментарий, disable до результата и draft state | Фиктивное сохранение и сохранность оценок при ошибке/устаревшем ответе |
| UI-32—33 | Версии в footer и отдельная прокрутка длинного текста лаборатории | Footer versions и длинный fixture, сохранение остаётся доступно |
Тот же план `main` фиксирует локальный browser run на **320×800, 390×844,
640×450, 1024×900, 1280×800 и 1440×900 CSS px**; на 1280 px измерена
сетка 256 / 384 / 640 px. Экран лаборатории с длинным текстом имел собственную
панель прокрутки, а сохранение/footer оставались доступны. Встроенная
проверка fixture не использовала production API или реальные учётные записи.
Это точная передача прежнего отчёта; её не следует трактовать как результат
нового прогона в этом PR. Полный screen-reader review, 200–400% zoom,
физический touch и полный ручной лингвистический review в исходном плане
оставлены непроверенными.
Отдельный follow-up в плане `main` описывает реализованные после PR #54
корректировки и regression coverage:
- **Поиск:** «Открыт» сбрасывается при смене результата/редакции и ставится
только после успешной загрузки. Оглавление распознаёт самостоятельные
заголовки RU/KY из структурированных абзацев (`p > b > span`), задаёт
уникальные якоря и вложенность, не принимает обычные упоминания за заголовки.
Выбор языка поиска находится в фильтрах и не обрезается; декоративный SVG и
пустое резервное место удалены; активная навигация использует палитру.
Проверены ошибки и гонки загрузки, структура заголовков, splitter и
доступность диапазона его ширины.
- **Кабинет:** ссылки действий сохраняют `<a>` семантику, крестик остаётся
подписанной SVG-кнопкой 44×44, значения профиля стоят в парах «поле—значение»,
длинные значения переносятся, заголовок компактнее; администратору явно
доступно «Управление пользователями». Проверены RU/KY, отсутствие ссылки у
не-администратора, фокус/закрытие и ширина.
- **Лаборатория:** имя показывается без дублирующей роли; ссылки навигации имеют
вид кнопок; оболочка, форма, рабочая область, сохранение и footer выровнены.
Пустой live status не резервирует высоту, результаты и документ образуют
общую поверхность с внутренней прокруткой на desktop, заголовок использует
доступную ширину, а mobile возвращается к естественному потоку. Проверены
desktop/mobile, пустой status, сохранение после длинного документа и page
overflow.
Исходный план сообщает о локальной проверке этих изменений 24 октября 2026
года и повышении frontend до `0.3.0` из-за регулируемой ширины панелей. Текущий
source footer и версия кода — `0.3.3`. Его отметка «ожидаются CI и review»
относилась к конкретному pushed SHA и не задаёт статус этого или любого нового
PR.
#### Общие критерии окон и форм
- Desktop-окно обычно 480–640 px и не шире viewport; на mobile — отступ 16 px
или полноэкранный режим для длинной формы. Заголовок и закрытие остаются
доступны при прокрутке.
- Диалог именуется через заголовок, держит фокус внутри и не делает фон
интерактивным. Escape закрывает обычные окна; исключения (например,
обязательная смена пароля) должны объясняться, а не маскироваться.
- Профиль и безопасность разделены. Удаление требует отдельного подтверждения;
создание/сброс не раскрывают дополнительные формы без запроса.
- Поля имеют постоянные подписи; пароль не предзаполняется и не записывается
в отчёт. Ошибки объясняют восстановление, допустимый ввод сохраняется,
повторная отправка во время loading исключена.
- «Отмена» вторична, выход не смешивается с сохранением; несохранённое
редактирование защищено от случайной потери. Обычный просмотр закрывается
без лишнего подтверждения.
#### Последовательность при возобновлении UI-работ
1. Зафиксировать актуальные SHA и версии; читать маршрут, API, `DESIGN.md`,
UI tests и CI. Не переносить состояние live-сайта без новой проверки.
2. Исправить общую оболочку и разделение поиска, лаборатории и служебных
экранов; затем initial/loading/empty/error и жизненный цикл документа.
3. Исправить фильтры, адаптивные минимумы и RU/KY; после этого — регулируемые
колонки и скрытие фильтров.
4. Привести формы/диалоги к общей модели с сохранением серверной авторизации,
прав, валидации, снимков оценок и черновиков.
5. Проверить текст, таблицы, ссылки, редакции, печать, адаптивность,
локализацию, доступность и состояния на реальном корпусе, где доступен.
6. Сделать детерминированный fixture-проход и независимый review; обновить
версию только при изменении кода, а changelog — после зелёных проверок и
разрешения blocking findings.
Не переносить существующий Python frontend на React/Next.js ради визуальной
корректировки. UI-работа не меняет ранжирование, корпус или права доступа.
| Приёмка | Условие |
|---|---|
| Оболочка | Один header/footer на маршруте, единые границы и порядок контента |
| Фильтры | Нет общей горизонтальной прокрутки; подписи/действия/счётчики видны полностью |
| Начальное состояние | До первого завершённого запроса empty-сообщение не показано |
| Документ | До выбора неактивные действия не вводят в заблуждение |
| Колонки | Pointer и клавиатура; min/max; скрытие/возврат; reset; адаптация сохранённой ширины к viewport |
| Телефон | Основные действия без горизонтального скролла; понятный возврат из фильтров/документа |
| Окна | Заголовок, крестик, Escape, trap/return focus; окна не конкурируют слоями |
| Лаборатория | Поиск → чтение → оценка → черновик → сохранение; текст не теряется, панель доступна при длинном документе |
| Локализация | RU/KY labels и символы; язык UI не подменяет язык документа |
| Геометрия | При 1280×800 границы основных зон и отступы/размеры controls отличаются от измеренного fixture не более чем на 2 CSS px; согласованные исключения описаны |
| Типографика и таблицы | Noto действительно загружается; читаемый длинный текст; у широкой таблицы собственный скролл |
| Доступность | Контраст AA, focus, Tab/Shift+Tab/Enter/Escape, zoom/reflow, reduced motion и touch targets |
| Авторизация | Неверный пароль, expired session и обязательная смена проверены только в безопасном тестовом контуре |
| Снимки | 1440×900, 1280×800, 1024×768, 390×844 и 320 CSS px; стабильные fixture и объяснённые различия |
Допуск **до 2 CSS px** для границ крупных зон и отступов/размеров controls при
1280×800 перенесён из исторического pixel-perfect плана по стабильной ссылке
выше. Он применяется к одинаковым детерминированным fixture; расхождения
растра, вызванные сглаживанием текста или содержимым, сами по себе не дают
основания обрезать или уплотнять юридический текст.
#### Нормативный орнамент и фактическое состояние
`DESIGN.md` нормативно требует небольшой золотистый SVG-орнамент в свободной
нижней части desktop-панели фильтров, не перекрывающий длинные списки и не
резервирующий место за счёт управления. Follow-up из commit `e5a8326a` удалил
предыдущий декоративный SVG и его пустой резерв; в `backend/search/review.html`
на базовом `main` целевого орнамента нет. Это не выполненное требование, а
подтверждённое расхождение между `DESIGN.md` и реализацией. Дизайн остаётся
нормативным до отдельного решения владельца: UI-задача должна либо вернуть
орнамент в свободную область без влияния на управление, либо получить явное
одобрение на изменение `DESIGN.md` и подтвердить его визуальной приёмкой.
### 2.3 Инфраструктура и переход к production
Инфраструктурные источники содержали повторяющиеся этапы deployment и
устаревшие снимки VPS. В этом плане оставлены только gates; актуальные
подтверждённые данные и процедуры находятся в операционных документах.
1. **Аудит:** сверить commit `main`, CI, Compose, зависимости, порты, volumes,
healthchecks, данные и перечень env-переменных без вывода секретов. Для VPS
пользоваться только read-only инвентаризацией, разрешённой
[правилами доступа](../operations/ACCESS.md). Не переносить IP, версии,
DNS-статус или ресурсы из старых планов как текущие факты.
2. **Данные и конфигурация:** установить источник и допустимость корпуса,
формат, состав, checksum/manifest, размер и воспроизводимую цепочку импорта.
Обязательный gate любой передачи/публикации корпуса — процедура
[CORPUS_HANDOFF.md](../operations/CORPUS_HANDOFF.md): source → staging →
inventory/manifest и checksum comparison → атомарная публикация
проверенного staging-корпуса в `DATA_ROOT/minjust-normalized` → отдельная
проверка и импорт в индекс → OpenSearch alias switch. Runbook требует
непустые source и staging, явное решение по исключению code 6 и fail-closed
при неполных/несовпадающих данных. Атомарная файловая публикация и
возобновление/отказ после прерывания — обязательный, но ещё не реализованный
gate; до описания и проверки all-or-nothing механизма не заменять им
действующий корпус. Не смешивать его с атомарным переключением OpenSearch
alias. Следовать runbook без копирования его команд сюда; до прохождения
gates корпус в production не передавать и не индексировать. Не подменять
корпус пустым каталогом. Production env/секреты создаются вне Git; в
репозитории остаются только имена переменных и шаблоны без значений.
3. **Build/CI:** PR-проверки не получают production secrets и Docker socket.
Публикация образов должна фиксировать digest и provenance; release workflow
не равен deployment. Production CD не включать до прохождения owner gates,
безопасной сборки, backup и отдельного restore.
4. **Контролируемое изменение существующего production:** последняя датированная
проверка `https://akyldash.kg/review` вернула HTTP 200 25 октября 2026 года
([CURRENT_STATE](../operations/CURRENT_STATE.md)); установленный на хосте
SHA остался неизвестен. План относится к безопасному
обновлению существующего сервиса, а не к первому развёртыванию. До изменения
проверять реальные данные и конфигурацию, доступное место, опубликованные
порты, права, совместимость схем и backup readiness. Выполнять через
существующую ограниченную процедуру; не добавлять общие sudo/Docker-
привилегии. Базы данных и внутренние сервисы не публиковать в интернет.
DNS, reverse proxy и TLS
проверять до выпуска; для Cloudflare применять Full (strict). SSH/UFW и
сетевые ограничения меняются только после owner approval.
5. **Проверка и recovery:** проверять health/API, RU/KY canaries, доступность
HTTPS, сохранность данных и rollback в пределах его документированных
ограничений. Data restore — отдельная процедура в staging, не автоматический
побочный эффект отката образа.
6. **Автоматизация:** только после одобренного отдельного bootstrap и
end-to-end проверки; serial deployment, digest verification, backup ACK,
health gates и отказ без destructive cleanup. Не включать триггер только
потому, что workflow завершился зелёным.
**Backup/maintenance gate:** настройки CI, проверка конфигурации и подготовка
release provenance должны быть отделены от production cutover. Production CD
в `CURRENT_STATE.md` остаётся неактивным. Перед каждым фактическим production
изменением, включая миграции, создать и проверить внешний pre-change backup.
Полный cold backup требует остановки Compose и может выполняться только в
заранее согласованное с владельцем окно.
Ни полный архив, ни его временная копия никогда не записываются на VPS. По
текущей утверждённой схеме архив передаётся напрямую на фиксированный
`D:\Dev\akyldash\.backups`; фактическая готовность D:, SSH и отдельное
восстановление всё ещё не подтверждены. На VPS остаётся только secret-free
идентификатор/manifest согласно `BACKUP.md`. Политика — одна retained,
проверенная внешняя копия. При замене прежняя копия сохраняется до тех пор,
пока новый candidate не опубликован и не проверен; на время этой проверки две
копии могут сосуществовать. После подтверждения новой копии retention может
изменить только владелец явным решением; автоматическая очистка запрещена.
При неудачной публикации или проверке прежняя подтверждённая копия остаётся.
Локальные VPS cold-backup команды из старых документов superseded и
использоваться не должны.
#### Локальные generated reports
`/reports/` и `/tmp/` игнорируются по умолчанию, чтобы generated bulk не
попадал в обычный `git status`. Уже отслеживаемые historical evidence остаются
отслеживаемыми. Если конкретный отчёт нужен в Git, сначала проверить его
содержимое, удалить секреты, персональные данные, production corpus и
временные файлы, затем добавить только предназначенный к публикации файл
явной командой `git add -f reports/<path>`. Не добавлять каталоги целиком.
Нынешний статус не переопределяется этим roadmap: на сверенной документации
production CD остаётся неактивным, а backup/restore и внешний bootstrap имеют
непроверенные owner prerequisites. Все точные блокировки сверять с
`CURRENT_STATE.md` и `DEPLOYMENT.md` перед планированием действий.
## 3. Визуальные материалы и исходная база
### Макеты Figma
Целевые редактируемые экраны — гипотезы компоновки, а не работающий интерфейс,
источник юридических данных или доказательство доступности.
| Экран | Макет |
|---|---|
| 01. Поиск с документом, 1440×900 | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=3-2) |
| 02. Фильтры скрыты | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=3-173) |
| 03. Начальный поиск | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=3-288) |
| 04. Лаборатория и сохранение | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=3-395) |
| 05. Кабинет: профиль и закрытие | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-30) |
| 06. Кабинет: безопасность | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-229) |
| 07. Источники | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-428) |
| 08. Пользователи: отдельный экран | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-605) |
| 09–11. Телефон: выдача, чтение и фильтры (общий Figma-узел) | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-670) |
| 12. Эталон 1280×800 | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=7-74) |
| 13. Планшет: две панели | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=7-245) |
| 14. Кабинет на телефоне | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=7-360) |
| 15. Вход, создание и подтверждение удаления | [Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=8-118) |
Локальные target exports: [поиск](../design/tunduk-search-target.png),
[лаборатория](../design/tunduk-review-target.png),
[кабинет](../design/tunduk-account-target.png). Это изображения цели; они не
заменяют браузерную проверку.
В Figma экраны собраны из редактируемого текста, Auto Layout, SVG, локальных
переменных цвета/отступов и общих экземпляров кнопок; это не один растр.
Состояния 09–11 ведут на один общий мобильный узел, как в исходном плане.
Прокрутка длинной выдачи/текста показывает продолжение содержимого.
Splitter, закрытие и формы описывают целевое поведение, но не являются
работающим web-кодом.
### Исторические свидетельства
Аудит UI выполнен **23 октября 2026 года** в авторизованной сессии на
`https://akyldash.kg/`, где footer показывал Frontend `0.2.3`, Backend
`0.13.0`. Сверка SHA сервиса с checkout не выполнялась. Проверены
1440×900, 1280×800, 1024×768, 390×844 CSS px и дополнительный browser viewport
1064×1244. Пароли не вводились; создание/удаление пользователей и отправка
оценки не выполнялись; полный физический touch, screen-reader и принтерный
прогоны не выполнялись. Существующие локальные browser evidence и screenshots
собраны в [отчёте visual-review](visual-review/README.md). Ветка `main` не
содержит отдельный архив live screenshots этого аудита. Любое использование
результатов требует повторной проверки актуальной версии и окружения.
## 4. Постоянные правила дизайна и полномочия
[DESIGN.md](../../DESIGN.md) остаётся нормативной дизайн-системой: цветовые
токены, типографика, бренд, композиционные принципы и доступность не
дублируются здесь. Этот roadmap задаёт работы, исторические критерии и gates;
он не утверждает новый дизайн и не разрешает production deployment.
Все пункты плана отмечать выполненными только при наличии актуального
свидетельства. Изменения приложения проходят обычные тесты, версионирование,
CI и независимое review. Инфраструктурные изменения отражаются в
`CURRENT_STATE.md` только по фактическим проверкам. Никакие действия с
production, секретами, пользователями или правовым корпусом не следуют из
наличия этого документа. Root-only bootstrap и предоставление секретов
выполняет/утверждает владелец в защищённой среде; DEV готовит проверяемый код
и точный план, reviewer независимо проверяет безопасность и failure paths.
-334
View File
@@ -1,334 +0,0 @@
# Единый план корректировки интерфейса «Акылдаш»
Дата аудита: **23 октября 2026 года**.
Базовые пункты UI-01—UI-33 исправлены и вошли в `main` через PR #54.
На 24 октября 2026 года отдельный follow-up по замечаниям владельца для поиска,
личного кабинета и лаборатории реализован; локальный браузерный набор пройден.
Ожидаются CI и ручное PR review для pushed SHA.
Этот файл заменяет `frontend-pixel-perfect-plan.md` и является единственным
рабочим планом исправления UI/UX поиска, лаборатории и служебных окон.
Продуктовый roadmap и требования к юридической готовности остаются отдельными
документами: они не являются конкурирующими планами исправления интерфейса.
## 1. Источники истины и границы
- [DESIGN.md](../../DESIGN.md) — нормативная система «Түндүк».
- [Утверждённая композиция](../design/tunduk-desktop-concept.png) — визуальный
ориентир, а не образец юридических данных или текущих функций.
- [Целевые редактируемые макеты Figma](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB)
— предлагаемая компоновка поиска, лаборатории, кабинета и адаптивных видов.
- Этот файл — дефекты, требования к поведению, порядок исправления и приёмка.
Проверялся работающий `https://akyldash.kg/` в авторизованной сессии,
версии в интерфейсе: Frontend **0.2.3**, Backend **0.13.0**.
Локальный checkout содержит более ранние версии; код и live-сайт нельзя
считать одинаковыми без сверки SHA перед реализацией. Инфраструктурные
документы не заменяют результаты этой браузерной проверки.
В этой задаче исправляются frontend и доступ к статическому экрану `/users`.
Backend-проверки ролей и операций управления пользователями не меняются.
Production, пользователи, пароли, сохранённые оценки, ранжирование и правовой
корпус не меняются. Реальные учётные записи не используются в регрессионном
fixture.
## 2. Что проверено
Проверка включала клики и чтение DOM, снимки и измерение переполнения.
Контрольные viewport: **1440×900, 1280×800, 1024×768, 390×844**;
дополнительно исходный viewport браузера 1064×1244. Изображения пользователя
с более широким desktop учитываются как дополнительные свидетельства,
но не выдаются за собственный браузерный прогон.
| Поверхность / сценарий | Выполнено | Ограничение |
|---|---|---|
| Начальный `/` | Пустой запрос, доступные действия, фильтры, footer | Ошибочное empty-состояние подтверждено |
| Поиск RU | Запрос «налог на прибыль», загрузка выдачи, открытие кодекса | Не экспертная проверка юридической релевантности |
| Фильтры | Выбор статуса, появление chip, снятие фильтра | Все комбинации справочников не перебирались |
| Сортировка / страницы | Выбор даты / релевантности, переход на страницу 2, сброс на страницу 1 | Оценивалось состояние UI и URL |
| Пустая выдача | Запрос `zzzzqwerty987654321` | Серверный сбой не провоцировался |
| Документ | Реальный текст, список редакций, переключение редакции и языка, разворот | Печать на принтер / в PDF не запускалась |
| Поиск в документе | Ввод фразы, подсветка, кнопка следующего совпадения | Поиск после смены редакции требует отдельного теста |
| RU/KY интерфейс | Переключение и чтение подписей | Найдены непереведённые подписи; полнота всех строк не подтверждена |
| Мобильные фильтры | Открытие и закрытие панели | Полный touch-прогон на физическом устройстве не выполнен |
| «Об источниках» | Открытие, чтение, закрытие | Внешний сайт Минюста не является частью этого аудита |
| Личный кабинет | Открытие, профиль, поля смены пароля, Escape и возврат фокуса | Пароли не вводились и не менялись |
| Пользователи | Открытие из кабинета и из лаборатории, чтение структуры | Создание, удаление и сброс пароля не выполнялись |
| `/review` | Пустое состояние, поиск, шкала оценок, открытие документа, обучение | Оценки не отправлялись; серверное сохранение не подтверждено |
| Авторизация / истёкшая сессия | Установлено наличие в локальной реализации | Live login и принудительная смена пароля не проверялись: действующую сессию не завершали |
Снимки: [каталог аудита](../design/audit-2026-10-23/).
Участки с реальными списками пользователей не переносятся в макеты Figma;
там используются явно условные примеры. Часть снимков лаборатории сделана
с длинной страницей; снимок не гарантирует корректность всех скрытых участков.
## 3. Реестр недостатков
**P1** — исправить до визуальной приёмки / выпуска; **P2** — существенное
улучшение понятности и последовательности. Предложения обозначены отдельно
от подтверждённых дефектов. Отсутствие функции само по себе не означает баг.
| ID | Приоритет | Подтверждённый недостаток / свидетельство | Корректировка и условие приёмки |
|---|---|---|---|
| UI-01 | P1 | В начальном поиске одновременно «Введите запрос» и «Документы не найдены» | Разделить initial/loading/results/empty/error; empty только после завершённого поиска |
| UI-02 | P1 | До выбора документа доступны печать/разворот/содержание, видны пустые селекты | До выбора — только понятное приглашение открыть результат; инструменты появляются после загрузки |
| UI-03 | P1 | У фильтров горизонтальный и вертикальный скроллы; при 1064 px `clientWidth=194`, `scrollWidth=231` | Горизонтальное переполнение исключено; компактные группы, достаточная ширина, длинные списки раскрываются по запросу |
| UI-04 | P1 | «Сбросить» обрезается заголовком панели | Заголовок и действие полностью видны на всех поддерживаемых размерах |
| UI-05 | P1 | Счётчики отрываются от названий, частые переносы превращают фильтры в длинную колонку | Отдельные колонки выбора/подписи/числа; числа с разделителями; перенос только длинного названия по словам |
| UI-06 | P1 | Все 28 видов и 8 статусов развёрнуты; орган и даты далеко ниже первого экрана | Основные варианты + «Все виды»/«Все статусы», сворачиваемые группы; сохранять доступ ко всем значениям |
| UI-07 | P1 | Язык поиска имеет ширину около 78 px; «Русский»/«Кыргызский» обрезаются | Размер по самой длинной локализованной подписи и стрелке; проверка RU/KY без ellipsis |
| UI-08 | P1 | На 390 px строка навигации горизонтально прокручивается, кабинет и фильтры уходят за край | Адаптивная перестройка: видимые поиск, фильтры, кабинет; ни одна основная кнопка не требует горизонтального скролла |
| UI-09 | P2 | Кабинет — малозаметная иконка в правом конце второй строки; слева большой неинформативный промежуток | На desktop подписанная кнопка «Кабинет» в шапке; на mobile узнаваемая иконка с доступным именем и достаточной областью |
| UI-10 | P1 | На 1024/1064 три колонки остаются тесными; название кодекса занимает большую часть панели | Адаптивный двухпанельный режим, скрытие фильтров, ограничения ширин; не сжимать все три колонки бесконечно |
| UI-11 | P2 | Длинное название документа повторено в breadcrumb, заголовке и исходном тексте | Breadcrumb обозначает контекст; в заголовке короткое название при наличии отдельного поля, реквизиты ниже; официальный текст не переписывать |
| UI-12 | P1 | Source link и toolbar переполняются на промежуточных ширинах; при 1064 px toolbar `412/427` | Действия переносятся группами, без обрезки; размер по содержимому, подписи редакции и языка постоянные |
| UI-13 | P2 | В исходном тексте большие пустые абзацы и синие ссылки конфликтуют с оболочкой | Нормализовать отображение пустых блоков без потери структуры; безопасно унифицировать ссылки и отступы в scope документа |
| UI-14 | P1 | В тексте есть широкие таблицы: например, `clientWidth=412`, `scrollWidth=834` | Таблицы — самостоятельная обозначенная область прокрутки; документ и весь экран не получают горизонтальный скролл |
| UI-15 | P1 | В DOM документа обнаружены относительные ссылки на старые локальные Temp-пути и HTTP URL исходного редактора | Не показывать их как рабочие внутренние переходы; безопасно разрешать/классифицировать ссылки, не удаляя юридический текст; локальные/IP-ссылки не открывались |
| UI-16 | P2 | Разворот открывает ещё одно окно с текстом; поиск, выбранное совпадение и toolbar не представлены в нём | Целевой режим чтения сохраняет редакцию, язык, положение и средства навигации; возврат очевиден |
| UI-17 | P2 | Часть KY-интерфейса остаётся русской: например заголовки групп и служебные доступные подписи | Инвентаризировать все UI-строки; контент документа переводом интерфейса не подменять |
| UI-18 | P1 | На `/review` два видимых footer; общий footer находится до сохранения | Ровно один видимый footer после основного контента и панели сохранения |
| UI-19 | P1 | В лаборатории шапка, формы, панели и footer имеют разные границы и ширины | Общая оболочка и единые горизонтальные направляющие, совпадающие поля и ширины контейнеров |
| UI-20 | P1 | Шапка лаборатории слишком высокая; на mobile рабочие результаты вытеснены далеко вниз | Компактный заголовок и помощь рядом; поиск и начало работы доступны без большого вступительного блока |
| UI-21 | P1 | У кабинета фактически пустой `account-heading`, нет видимого заголовка | «Личный кабинет» в заголовке, корректное имя диалога для скринридера |
| UI-22 | P1 | В кабинете нет крестика; «Закрыть» только внизу формы смены пароля | Единый крестик 44×44 справа сверху, доступное имя, Escape, возврат фокуса; нижняя отмена при редактировании |
| UI-23 | P1 | Навигация, выход, профиль и смена пароля смешаны в одном неструктурированном окне | Отдельные разделы «Профиль» / «Безопасность»; служебные действия и выход отделены от формы |
| UI-24 | P1 | «Пользователи» из кабинета открывает `users-dialog`, когда `account-dialog` остаётся открытым поверх него | Не оставлять конкурирующие модальные окна: закрыть кабинет с сохранением контекста и открыть целевой экран/диалог; фокус соответствует видимому окну |
| UI-25 | P1 | Управление пользователями — длинный модальный список, закрытие ниже видимой области | Предпочтительно отдельный экран с таблицей; создать/сбросить — короткие отдельные диалоги с фиксированным заголовком и крестиком |
| UI-26 | P2 | Удаление, сброс пароля, создание и данные входа перемешаны без ясной иерархии | Действия на строке пользователя; удаление отдельно и с подтверждением; не раскрывать все формы сброса постоянно |
| UI-27 | P2 | Различаются оформление бренда/навигации/шрифтов, есть стандартные синие ссылки в лаборатории и кабинете | Единые header, logo, button, link, dialog и footer на всех поверхностях |
| UI-28 | P2 | Диалоги закрываются разными кнопками в разных местах | Одна модель окна и доступного закрытия, описанная ниже |
| UI-29 | P2 | Обучение автоматически появляется с задержкой и перехватывает фокус уже начатого ввода | Не перехватывать ввод; запуск по «Как это работает» либо ненавязчивому предложению до начала работы |
| UI-30 | P2 | Шкала 0–3 на длинной выдаче создаёт плотный набор переносов; комментарии всегда занимают место | Полные подписи без обрезки, допускается сетка 2×2; комментарий раскрывается, введённый текст не теряется |
| UI-31 | P2 | На пустом лабораторном экране «Сохранить оценку» выглядит готовой к отправке | Состояние зависит от наличия снимка; явное объяснение, прогресс и статус черновика; не менять смысл отсутствующей оценки |
| UI-32 | P2 | В footer работающего сайта остаётся «Концепция Түндүк» | В рабочем режиме название продукта и реальные версии; подпись концепции только в макете/демо |
| UI-33 | P1 | Открытие кодекса в лаборатории растягивает страницу: footer оказался на y≈636935 px, сохранение — внизу после него | Ограничить область чтения по высоте viewport и дать ей собственную вертикальную прокрутку; сохранение доступно независимо от длины документа, без сотен экранов прокрутки |
Escape и возврат фокуса кабинета на `search-account-open` проверены и работают.
Это поведение сохранить. Механизм Tab/Shift+Tab всех окон, ошибки API,
контраст всех состояний, печатная вёрстка и поведение на 200–400% zoom
требуют отдельного приёмочного прогона; здесь они не объявлены проверенными.
## 4. Целевая сетка, изменение ширины и фильтры
Это согласованное направление корректировки, а не уже существующие функции.
1. Шапка, навигация, main и footer принадлежат одной оболочке. Поисковый
и лабораторный контент не вставляются друг в друга и не дублируют footer.
2. На широком desktop три колонки с двумя доступными разделителями.
Базовый ориентир при 1440: **280 / 408 / 736 px + два захвата по 8 px**.
При 1280: **256 / 384 / 624 px + два захвата по 8 px**. Это размеры
целевых макетов, а не требование сжимать эти колонки ниже удобных минимумов.
3. Предлагаемые пределы: фильтры 256–360 px, выдача от 360 px,
документ от 560 px. Если окно не вмещает минимумы, фильтры уходят
в отдельную панель, затем документ становится отдельным представлением.
Пользовательское растягивание не может сломать соседнюю колонку.
4. Разделители: узнаваемый захват, `col-resize`, роль `separator`,
доступное имя, текущая/минимальная/максимальная ширина. Перетаскивание
и стрелки клавиатуры; отдельные «Скрыть фильтры» / «Показать фильтры»
и «Сбросить ширину». Двойной клик может дополнять, но не заменяет
видимый и клавиатурный способ сброса. Положение хранится локально;
при восстановлении ограничивается фактическим viewport.
5. На desktop у фильтров нет отдельной постоянно прокручиваемой узкой
колонки: краткие группы и раскрытие длинных справочников. Полный
каталог доступен через поиск/раскрытие; нельзя скрыть значения навсегда.
Одиночный выбор API не выдаётся за множественный checkbox.
6. Длинные названия органов открываются в панели выбора с полными строками;
основное поле не становится бессмысленной обрезанной подписью.
7. Даты имеют постоянные «От» / «До»; если два поля не помещаются,
ставятся друг под другом. Перенос текста внутри input недопустим.
8. На desktop самостоятельная вертикальная прокрутка выдачи и длинного
документа допустима. Их заголовки/toolbar доступны при чтении.
Фильтры и всё приложение не должны требовать горизонтальной прокрутки.
На телефоне — одна основная вертикальная прокрутка и отдельные панели.
9. Footer внизу короткой страницы через layout с `min-height: 100dvh`
и растущим main, а не `position: fixed` поверх содержимого. При длинном
контенте footer следует после него. Панель сохранения имеет собственное
место; sticky допускается только без перекрытия последней строки.
## 5. Единые правила всех окон и форм
- Видимый короткий заголовок и крестик в правом верхнем углу, область 44×44.
Закрытие не спрятано в конце длинного содержимого.
- Desktop: ширина по задаче, обычно 480–640 px, максимум относительно
viewport; mobile: отступ 16 px либо полноэкранная форма для длинного ввода.
Заголовок/закрытие остаются доступны при прокрутке содержимого.
- `dialog` / `aria-modal`, имя через заголовок; фокус при открытии внутри,
Tab/Shift+Tab не уходят в фон, Escape закрывает обычное окно, фокус
возвращается на инициатор. Фон не интерактивен. Исключения для
обязательной смены пароля объясняются пользователю, не маскируются.
- Не наслаивать кабинет и пользователей. Переход между задачами — замена
поверхности с понятным возвратом. Подтверждение удаления — короткое
целевое окно, а не второй длинный редактор за первым.
- «Профиль» — просмотр сведений; «Безопасность» — смена пароля. Доступ
к администрированию определяется сервером, редизайн не меняет права.
- В форме пароля постоянные подписи, подсказка требований, показать/скрыть
пароль с доступным именем; подтверждение нового пароля как защита от
опечатки. Никакие реальные пароли не предзаполняются и не записываются
в материалы аудита. Изменение пароля выполняет человек.
- Основное действие одно; «Отмена» вторична; «Выйти» отдельно от сохранения.
Enter отправляет только активную форму. Ошибки рядом с полем и в
доступном сообщении, введённые допустимые данные сохраняются.
- При несохранённом редактировании — понятная защита от случайной потери;
обычное закрытие окна просмотра не требует лишнего подтверждения.
- Loading исключает повторную отправку; при успехе сообщается результат;
при ошибке есть путь восстановления. Валидация не ограничивается цветом.
- Эти правила распространяются на кабинет, вход, обязательную смену пароля,
источники, создание/сброс/удаление пользователя, обучение и документный viewer.
Основания для доступного поведения:
[WAI-ARIA Dialog](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/),
[Window Splitter](https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/)
(паттерн APG находится в разработке; использовать как ориентир),
[WCAG Reflow](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html).
Крестик и структура кабинета — также прямое требование пользователя.
## 6. Реализация и проверяемое покрытие
Кодовая реализация сгруппирована по общей причине, а не по числу замечаний.
Ниже перечислены все UI-01—UI-33, привязанные к коду и регрессионному
сценарию. Playwright fixture использует только условные записи `admin`,
`fixture-user` и `fixture-created`; browser requests полностью перехватываются
тестом и не обращаются к приложению, Gitea или production API. Локальный browser
run завершился успешно.
| Пункты | Изменение | Регрессионное покрытие |
|---|---|---|
| UI-01—02 | Разделены initial/loading/results/empty/error; панель документа показывает инструменты после выбора редакции | Пустой результат, API ошибка и редакция без текста |
| UI-03—08 | Скомпонованы фильтры и сворачиваемые группы, читаемые счётчики и языковые select; навигация адаптируется на промежуточной ширине | Reflow 320/390/640/1024/1280/1440 CSS px; на 640 px проверены кабинет, выход и создание пользователя на `/`, `/review`, `/users` |
| UI-09—10 | Кабинет подписан на desktop; экран переходит от трёх колонок к адаптивной компоновке | Геометрия действий и отсутствие page overflow на 640 px; layout измерен на 1024/1280/1440 px |
| UI-11—16 | Breadcrumb не дублирует заголовок; toolbar переносится; широкие таблицы имеют собственный scroll; URL-атрибуты очищаются; разворот остаётся в панели документа | Fixture удаляет `srcset`, `ping`, private-IP `href/src`, относительные и HTTP ссылки, сохраняя текст и официальную HTTPS-ссылку; лаборатория проверяет A → ошибка B → успешная B и устаревший ответ A |
| UI-17 | Переведены подписи поиска, фильтров, кабинета и `/users`; язык документа остаётся независимым | Переключение RU/KY и язык редакции; полный ручной лингвистический review остаётся открытым |
| UI-18—20 | Убрано дублирование footer, согласованы контейнеры, лаборатория ограничена по высоте документа | Fixture проверяет один видимый footer; панель 612 px при viewport 900 px и scrollHeight 41027 px |
| UI-21—24 | Кабинет имеет имя и разделы профиля/безопасности; переход к пользователям закрывает кабинет и открывает отдельный маршрут | ARIA имя, Escape, focus trap/return и отдельные маршруты |
| UI-25—28 | Управление пользователями — отдельный экран; создание и удаление — отдельные окна; сброс и история раскрываются по запросу; общие крестики | Fixture выполнил смену пароля, создание, сброс пароля и удаление только `fixture-created`; production учётные записи и API не использовались |
| UI-29 | Обучение запускается пользователем, без автоматического перехвата фокуса | Регрессионный сценарий обучения |
| UI-30—31 | Оценка 2×2, комментарий скрываемый; сохранение выключено до выбора результата, есть состояние черновика | Fixture проверяет черновик и фиктивное сохранение; рейтинг и комментарий сохраняются при переключении документа, включая ошибку B и устаревший ответ A |
| UI-32—33 | Footer содержит продукт и версии; документ лаборатории имеет собственную прокрутку до панели сохранения | Версии в обоих footer; длинный текст прокручивается внутри панели, сохранение и footer остаются ниже неё |
Локальный Playwright run прошёл на **320×800, 390×844, 640×450, 1024×900,
1280×800 и 1440×900 CSS px**; горизонтального переполнения документа нет.
При 640 CSS px кабинет, выход и создание пользователя остаются видимыми и
помещаются в viewport на трёх маршрутах. Это проверка reflow, не проверка
browser zoom: в доступном headless Chromium Ctrl+Plus не меняет CSS viewport;
реальный zoom 200–400% остаётся непроверенным.
При 1280 px сетка измерена как 256 / 384 / 640 px. Для длинной лабораторной
редакции панель ограничена 544 px при viewport 800 px, scrollHeight 27278 px;
сохранение и footer остаются ниже неё в DOM и доступны независимо от текста.
Снимки, overlay и pixel-difference с целевым изображением сохранены в
[каталоге visual review](visual-review/). Растровый diff является обзорной
диагностикой, а не пороговой проверкой: макет и fixture-контент различаются.
Ручной лингвистический review всех скрытых KY-подписей, физический touch,
200–400% zoom и операции с реальными пользователями/паролями не выполнялись.
Не мигрировать существующий Python frontend на React/Next.js ради этих
исправлений. Не менять ранжирование, корпус или права доступа в UI-задаче.
## 9. Follow-up замечания владельца: поиск, кабинет и лаборатория
Повторный просмотр трёх экранов выявил отдельные проблемы уже после PR #54.
Исправления остаются в этом плане, чтобы не создавать параллельный список:
| Поверхность | Наблюдение | Реализация и проверка |
|---|---|---|
| Поиск: выдача и чтение | Метка «Открыт» ставилась до ответа, могла оставаться после ошибки и дублироваться; оглавление пропускало структурные заголовки из жирных `p > b > span`; выбор языка был обрезан и расположен в навигации; в фильтрах оставался декоративный SVG с пустым резервом; активный пункт «Поиск» визуально смещался | Метка очищается при смене результата/редакции и появляется только после успешной загрузки; оглавление распознаёт самостоятельные заголовки раздела/главы/статьи на RU/KY, назначает уникальные якоря и строит вложенные списки; язык поиска находится в фильтрах с полной шириной; SVG и его место удалены; ссылки навигации используют палитру Акылдаш. Проверка: ошибки и гонки загрузки, заголовки RU/KY и обычные упоминания, уникальные якоря, диапазон и доступность splitter |
| Личный кабинет | Навигация выглядела ссылкой браузера; закрытие занимало строку текстом; подписи и значения профиля стояли в столбик; заголовок был крупным; появлялось горизонтальное переполнение; действие управления пользователями было неочевидным | Ссылки кабинета оформлены как действия с сохранением семантики `<a>`; крестик остаётся SVG-кнопкой 44×44 с доступной подписью; профиль выровнен в пары «поле — значение»; заголовок компактнее; длинные значения переносятся; администратор получает явную ссылку «Управление пользователями». Проверка: RU/KY, скрытие ссылки для не-администратора, фокус/закрытие диалога и ширина содержимого |
| Лаборатория | Дублировалась роль рядом с именем; ссылки навигации не имели вида кнопок; оболочка, форма, рабочая область, сохранение и footer имели разные границы; пустое сообщение резервировало высоту; панели выглядели разрозненными карточками; основной заголовок переносился; мобильный экран наследовал искусственную высоту | В шапке показывается только имя, роль остаётся в профиле; навигация сохраняет ссылки и получает единый вид кнопок; все участки выровнены по общему shell; пустой live status не добавляет зазор; результаты и документ образуют общую поверхность с внутренней прокруткой на desktop; заголовок использует доступную ширину и размеры по макету Figma; mobile возвращается к естественному потоку с прокруткой документа. Проверка: desktop/mobile, пустой status, сохранение после длинного документа и отсутствие page overflow |
Frontend повышен до **0.3.0** из-за добавления доступного изменения ширины
панелей. Backend и его API не менялись. Fixture данные искусственные; preview
слушает только loopback, запрещает запросы за пределы своего origin и не
использует авторизационные cookies или production API. Браузерный прогон прошёл
на 24 октября 2026 года; пять скриншотов сохранены в `current-progress` рядом
с отчётом assignment. CI и независимое ревью проверяются для конкретного pushed
SHA.
## 7. Приёмка: что значит «вылизанный интерфейс»
| Проверка | Условие |
|---|---|
| Оболочка | Один видимый header и footer на каждом маршруте, единые границы блоков |
| Фильтры | Нет горизонтального скролла; полный текст действий, читаемые подписи и счётчики |
| Начальное состояние | Не сообщает об отсутствии результатов до первого поиска |
| Документ | Нет пустых селектов и активных бесполезных действий до выбора |
| Колонки | Drag и клавиатура работают; min/max соблюдаются; скрытие/возврат и сброс сохраняют контекст |
| Телефон | Основные действия видимы без горизонтального скролла, есть возврат из документа/фильтров |
| Окна | Заголовок, крестик, Escape, trap/return focus; нет невидимого окна поверх целевого |
| Лаборатория | Поиск → чтение → оценка → черновик → сохранение, панель до footer, данные не теряются |
| Локализация | RU/KY-подписи, Ө ө Ү ү Ң ң, язык UI не подменяет язык документа |
| Типографика | Реально загрузились Noto, основной текст 17–18 px / 1.6–1.7, длинные названия читаемы |
| Таблицы | Собственная обозначенная прокрутка, основной текст и controls без обрезки |
| Доступность | Контраст WCAG AA, видимый фокус, Tab/Shift+Tab/Enter/Escape, zoom/reflow, reduced motion |
| Авторизация | Проверены вход, неверный пароль, истечение сессии и обязательная смена в безопасном тестовом окружении |
| Снимки | 1440×900, 1280×800, 1024×768, 390×844; дополнительно 320 CSS px для reflow |
Для визуального сравнения использовать изолированный детерминированный fixture
и одинаковые состояния, а не изменчивую выдачу. Fixture не включается в
production-путь и не обходит авторизацию. Сравнивать отдельно шапку,
фильтры, выдачу, документ, окна, сохранение и footer. Сглаживание текста
не требует нулевого pixel diff; совпадение растра не оправдывает обрезку,
неработающий control или нечитаемый реальный контент.
Локальные проверки, указанные в PR, включая Playwright, прошли. Changelog
обновлён в этой ветке. Дальше остаются CI и ручное PR review по обычному
процессу репозитория; автоматический reviewer не запускается. Production не
меняется автоматически.
## 8. Материалы и оставшаяся проверка
Figma содержит целевые редактируемые состояния, а не исправленный live-сайт
и не доказательство работоспособности функций. Учётные записи в ней
обезличены, текст документа помечен как пример оформления.
| Figma-экран | Ссылка |
|---|---|
| 01. Поиск с документом, 1440×900 | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=3-2) |
| 02. Фильтры скрыты | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=3-173) |
| 03. Начальный поиск | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=3-288) |
| 04. Лаборатория и доступное сохранение | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=3-395) |
| 05. Кабинет: профиль и закрытие | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-30) |
| 06. Кабинет: безопасность | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-229) |
| 07. Источники | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-428) |
| 08. Пользователи: отдельный экран | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-605) |
| 09–11. Телефон: выдача, чтение, фильтры | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=5-670) |
| 12. Эталон 1280×800 | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=7-74) |
| 13. Планшет: две панели | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=7-245) |
| 14. Кабинет на телефоне | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=7-360) |
| 15. Вход, создание и подтверждение удаления | [Открыть](https://www.figma.com/design/3PE98PJYOXo7a35u2X5VqB?node-id=8-118) |
Макеты построены редактируемыми текстами, Auto Layout, SVG, локальными
переменными цветов/отступов и экземплярами общих кнопок; целый интерфейс
не вставлен одной картинкой. Прокрутка длинной выдачи/текста в Figma
обозначает намеренное продолжение содержимого. Drag-разделители,
закрытие и формы — спецификация будущего поведения, не работающий web-код.
Локальные экспорты целевых экранов для просмотра без Figma:
[поиск](../design/tunduk-search-target.png),
[лаборатория](../design/tunduk-review-target.png),
[кабинет](../design/tunduk-account-target.png).
Контрольные свидетельства live-сайта:
[поиск с кодексом](../design/audit-2026-10-23/search-document-1440.png),
[мобильный поиск](../design/audit-2026-10-23/search-mobile-390.png),
[фильтры телефона](../design/audit-2026-10-23/filters-mobile-390.png),
[кабинет](../design/audit-2026-10-23/account-desktop.png),
[кабинет телефона](../design/audit-2026-10-23/account-mobile-390.png),
[лабораторный документ](../design/audit-2026-10-23/review-document-1440.png).
Browser evidence текущей ветки:
[desktop 1280×800](visual-review/desktop-1280x800.png),
[mobile 390 px](visual-review/mobile-390px.png),
[Figma overlay](visual-review/overlay-50.png) и
[pixel difference](visual-review/pixel-difference.png). Overlay показывает
различия компоновки между live-target frame и deterministic fixture; pixel
diff не используется как pass/fail.
Регрессия UI10: сетка поиска остаётся двухпанельной на ширине 1101 и 1175 px;
третья панель включается при 1176 px, когда минимальные ширины трёх колонок
помещаются. Проверка также меняет ширину окна при скрытых фильтрах и проверяет
отсутствие горизонтального переполнения. Реальные browser zoom и экспертиза
юридической корректности по законодательству не подтверждены этими тестами.
Не проверялись реальные destructive/auth-сценарии: вход с неверным паролем,
смена пароля, удаление/создание пользователей и отправка оценки в production.
Наличие макета не считается доказательством этих функций.