feat: normalize Ministry of Justice documents
Add a resumable standard-library normalization pipeline for the downloaded CBD archive. It produces canonical bilingual metadata, sanitized HTML, plain text, deterministic fragments, checksums, quality markers, and an SQLite processing manifest while preserving the raw source. Recover document-list pagination when the Ministry API exhausts request retries, and cover that scenario with a regression test. Document the normalization workflow and frontend-search MVP plan, include the source functional specification, ignore local runtime logs, and bump the backend version to 0.2.1.
This commit is contained in:
261
docs/product/frontend-search-sps-plan.md
Normal file
261
docs/product/frontend-search-sps-plan.md
Normal file
@@ -0,0 +1,261 @@
|
||||
# План реализации frontend поисковой СПС
|
||||
|
||||
Основание: `docs/Функциональные_возможности_поисковой_СПС.docx`.
|
||||
|
||||
Документ с требованиями описывает не только frontend, но и поиск, юридическую
|
||||
обработку, персональные данные, уведомления и внешние источники. Поэтому
|
||||
frontend следует начинать после появления нормализованной базы, поискового API
|
||||
и API документов.
|
||||
|
||||
Требования необходимо адаптировать под Кыргызскую Республику: в исходном
|
||||
документе используются примеры ТК РФ и деление
|
||||
«федеральный/региональный/муниципальный», которое нельзя переносить без
|
||||
изменений.
|
||||
|
||||
## Задачи до начала frontend-разработки
|
||||
|
||||
### Обязательные для MVP
|
||||
|
||||
1. Нормализовать архив Минюста:
|
||||
- очистить HTML;
|
||||
- выделить структуру документа и редакций;
|
||||
- унифицировать статусы, органы, виды документов и даты;
|
||||
- сохранить ссылки на официальный источник и дату получения;
|
||||
- определить правила отображения документов без текста.
|
||||
2. Подготовить backend API:
|
||||
- `GET /search`;
|
||||
- `GET /search/filters`;
|
||||
- `GET /documents/{code}`;
|
||||
- `GET /documents/{code}/editions`;
|
||||
- `GET /documents/{code}/editions/{edition}`;
|
||||
- описание API в OpenAPI;
|
||||
- серверную пагинацию, фильтрацию и сортировку.
|
||||
3. Развернуть поисковый сервис. Рекомендуемый вариант — self-hosted OpenSearch:
|
||||
- отдельные поля и анализаторы для русского и кыргызского текстов;
|
||||
- русский морфологический анализ;
|
||||
- ICU-нормализация кыргызского текста;
|
||||
- словари синонимов и сокращений;
|
||||
- подсветка совпадений;
|
||||
- индексирование всех редакций.
|
||||
4. Подготовить тестовый набор из 50–100 реальных запросов на русском и
|
||||
кыргызском языках и вручную отметить ожидаемые результаты.
|
||||
5. Утвердить справочники:
|
||||
- виды документов;
|
||||
- органы принятия;
|
||||
- статусы;
|
||||
- уровни действия;
|
||||
- тематический классификатор первой версии.
|
||||
|
||||
OpenSearch имеет встроенный
|
||||
[русский морфологический анализатор](https://docs.opensearch.org/latest/analyzers/language-analyzers/russian/),
|
||||
поддерживает [синонимы и нечёткий поиск](https://docs.opensearch.org/latest/query-dsl/full-text/match/)
|
||||
и [подсветку результатов](https://docs.opensearch.org/latest/search-plugins/searching-data/highlight).
|
||||
Встроенного кыргызского морфологического анализатора в перечне нет, поэтому
|
||||
нужно отдельно проверить ICU и словари на реальных запросах.
|
||||
[ICU-анализатор](https://docs.opensearch.org/latest/analyzers/language-analyzers/icu/)
|
||||
обеспечивает Unicode-нормализацию, но сам по себе не гарантирует кыргызскую
|
||||
морфологию.
|
||||
|
||||
### Сторонние сервисы, не нужные для MVP
|
||||
|
||||
Их не следует подключать заранее:
|
||||
|
||||
- Keycloak или другой OIDC-провайдер — перед закладками, папками и ролями;
|
||||
- SMTP, Telegram или Web Push — перед «документами на контроле»;
|
||||
- LibreOffice или Gotenberg — перед экспортом в Word, PDF и RTF;
|
||||
- поставщики судебной практики и экспертных комментариев — после проверки
|
||||
лицензий;
|
||||
- источники курсов, календарей и справочных данных — перед соответствующим
|
||||
разделом;
|
||||
- Sentry или аналог — опционально перед публичным запуском.
|
||||
|
||||
## Граница MVP
|
||||
|
||||
MVP — публичная справочно-поисковая система без регистрации и персональных
|
||||
функций.
|
||||
|
||||
В MVP входят:
|
||||
|
||||
- интерфейс на русском и кыргызском языках;
|
||||
- строка полнотекстового поиска;
|
||||
- исправление распространённых опечаток;
|
||||
- базовые синонимы и сокращения;
|
||||
- список результатов с подсвеченными фрагментами;
|
||||
- фильтры по языку, виду документа, органу, статусу и дате;
|
||||
- сортировка по релевантности и дате;
|
||||
- пагинация;
|
||||
- карточка документа;
|
||||
- актуальная редакция, статус и дата актуальности;
|
||||
- переключение между доступными языками;
|
||||
- поиск внутри открытого документа;
|
||||
- список редакций и открытие выбранной редакции;
|
||||
- ссылка на официальный источник и сведения о происхождении данных;
|
||||
- адаптивность, доступность, состояния загрузки и ошибок.
|
||||
|
||||
Сравнение редакций, аккаунты, заметки, уведомления, RAG и судебная практика в
|
||||
MVP не входят.
|
||||
|
||||
Интерфейс не должен предполагать наличие обоих языков. На момент полного
|
||||
скачивания архива распределение следующее:
|
||||
|
||||
- только русский язык — 29 432 документа;
|
||||
- только кыргызский язык — 98 797 документов;
|
||||
- оба языка — 80 901 документ;
|
||||
- нет HTML-текста — 681 документ.
|
||||
|
||||
## Рекомендуемая основа frontend
|
||||
|
||||
- Next.js App Router и TypeScript;
|
||||
- CSS Modules с BEM-именованием;
|
||||
- дизайн-токены для цветов, отступов, типографики и состояний;
|
||||
- серверный `fetch` и URL-параметры вместо отдельного глобального хранилища;
|
||||
- Playwright для основных пользовательских сценариев;
|
||||
- адаптивный web-интерфейс без отдельного мобильного приложения.
|
||||
|
||||
Next.js App Router поддерживает серверные компоненты, маршрутизацию и
|
||||
TypeScript в стандартной конфигурации. См.
|
||||
[официальную документацию](https://nextjs.org/docs/app).
|
||||
|
||||
## Дизайн-процесс и внешние ориентиры
|
||||
|
||||
При проектировании и проверке интерфейса используются следующие источники:
|
||||
|
||||
- [jakubkrehel/skills](https://github.com/jakubkrehel/skills) — обязательная
|
||||
комплексная проверка интерфейса через `better-interface`, включая UI,
|
||||
типографику, цвета, доступность, layout и тексты;
|
||||
- [UI Skills](https://www.ui-skills.com/) — каталог практик и узких skills,
|
||||
которые подключаются только под конкретную задачу после проверки их
|
||||
содержания и лицензии;
|
||||
- [Refero Styles](https://styles.refero.design/) — библиотека визуальных
|
||||
направлений и примеров `DESIGN.md` для поиска референсов.
|
||||
|
||||
Правила применения:
|
||||
|
||||
1. До разработки экранов выбрать в Refero не более трёх подходящих направлений
|
||||
и на их основе утвердить одно собственное направление Акылдаша.
|
||||
2. Не копировать чужую дизайн-систему целиком. Цвета, типографика, плотность и
|
||||
компоненты должны учитывать длинные юридические тексты, два языка и
|
||||
доступность.
|
||||
3. Зафиксировать утверждённое направление в `frontend/DESIGN.md` и перенести
|
||||
значения в дизайн-токены проекта.
|
||||
4. Дизайн-токены и компоненты Акылдаша являются источником истины. Внешние
|
||||
рекомендации не могут отменять BEM, доступность, требования безопасности и
|
||||
продуктовые ограничения проекта.
|
||||
5. Каждый завершённый пользовательский сценарий проходит `better-interface`
|
||||
review. Перед выпуском MVP выполняется полный review поиска, фильтров и
|
||||
просмотра документа.
|
||||
6. UI Skills используется для точечного поиска решения, а не для одновременного
|
||||
смешивания нескольких визуальных стилей.
|
||||
|
||||
Эти ресурсы используются на этапе проектирования и review и не являются
|
||||
runtime-зависимостями frontend. Регистрация в стороннем SaaS для MVP не нужна.
|
||||
|
||||
## План спринтов MVP
|
||||
|
||||
### Спринт 0 — фундамент, 1 неделя
|
||||
|
||||
- создать `frontend/`;
|
||||
- настроить Next.js, TypeScript, lint и сборку;
|
||||
- выбрать до трёх референсов в Refero Styles и утвердить одно визуальное
|
||||
направление;
|
||||
- создать `frontend/DESIGN.md` с правилами выбранного направления;
|
||||
- установить полный набор `jakubkrehel/skills` для проектных design review;
|
||||
- определить маршруты и типы API;
|
||||
- создать дизайн-токены;
|
||||
- реализовать базовые компоненты: кнопка, поле, селект, статус, карточка,
|
||||
пагинация;
|
||||
- создать общий layout и двуязычную навигацию;
|
||||
- добавить footer с версиями frontend и backend;
|
||||
- подготовить макеты поиска, результатов и документа;
|
||||
- провести первый `better-interface` review макетов;
|
||||
- настроить CI.
|
||||
|
||||
Результат: интерфейсный каркас работает на mock-ответах API.
|
||||
|
||||
### Спринт 1 — быстрый поиск, 2 недели
|
||||
|
||||
- главная страница с поиском;
|
||||
- интеграция с `/search`;
|
||||
- список результатов;
|
||||
- подсветка совпадений;
|
||||
- URL, которым можно поделиться;
|
||||
- переключение RU/KY;
|
||||
- состояния загрузки, отсутствия результатов и ошибки API;
|
||||
- базовая мобильная версия.
|
||||
|
||||
Результат: пользователь может найти документ и открыть результат.
|
||||
|
||||
### Спринт 2 — точный отбор, 2 недели
|
||||
|
||||
- фильтры по реквизитам;
|
||||
- сортировка;
|
||||
- пагинация;
|
||||
- отображение числа результатов;
|
||||
- сброс отдельных и всех фильтров;
|
||||
- сохранение состояния в URL;
|
||||
- доступное управление с клавиатуры;
|
||||
- адаптивная панель фильтров.
|
||||
|
||||
Результат: поддерживается быстрый и реквизитный поиск.
|
||||
|
||||
### Спринт 3 — просмотр документа, 2 недели
|
||||
|
||||
- заголовок, реквизиты, статус и дата актуальности;
|
||||
- безопасное отображение очищенного HTML;
|
||||
- переключение языка;
|
||||
- поиск внутри документа;
|
||||
- навигация по найденным фрагментам;
|
||||
- список редакций;
|
||||
- открытие предыдущей редакции;
|
||||
- ссылка на ЦБД Минюста;
|
||||
- печать средствами браузера.
|
||||
|
||||
Результат: пользователь может проверить текст и его происхождение.
|
||||
|
||||
### Спринт 4 — стабилизация и выпуск, 2 недели
|
||||
|
||||
- сквозные тесты поиска и просмотра;
|
||||
- проверка русских, кыргызских и одноязычных документов;
|
||||
- соответствие WCAG 2.2 AA;
|
||||
- защита от внедрения небезопасного HTML;
|
||||
- проверка производительности;
|
||||
- корректные метаданные страниц;
|
||||
- обработка недоступности API;
|
||||
- production-сборка и развёртывание;
|
||||
- пользовательское тестирование на 10–15 реальных юридических задачах.
|
||||
|
||||
Результат: публичный MVP.
|
||||
|
||||
Оценка frontend-части после готовности API: **9 недель**.
|
||||
|
||||
## Спринты после MVP
|
||||
|
||||
### Спринт 5 — персональный кабинет
|
||||
|
||||
Авторизация, закладки, заметки, подборки и сохранённые фильтры.
|
||||
|
||||
### Спринт 6 — контроль изменений
|
||||
|
||||
Документы на контроле, подписки на редакции и уведомления.
|
||||
|
||||
### Спринт 7 — юридические связи
|
||||
|
||||
Сравнение редакций, прямые и обратные ссылки, утратившие силу фрагменты.
|
||||
|
||||
### Спринт 8 — практические материалы
|
||||
|
||||
Формы, образцы, инструкции, чек-листы, календари и справочные данные.
|
||||
|
||||
### Спринт 9 — расширенный анализ
|
||||
|
||||
Судебная практика, экспертные комментарии, дерево связей и RAG с обязательными
|
||||
ссылками на источники.
|
||||
|
||||
### Спринт 10 — корпоративные функции
|
||||
|
||||
Роли, журналирование, API, интеграция с СЭД, расширенный экспорт и
|
||||
персонализация.
|
||||
|
||||
---
|
||||
|
||||
Акылдаш · Telegram-бот v0.2.2 · Backend v0.2.1 · Frontend — не создан
|
||||
217
docs/product/minjust-document-normalization-agent-task.md
Normal file
217
docs/product/minjust-document-normalization-agent-task.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# Задание агенту: нормализация документов ЦБД Минюста КР
|
||||
|
||||
## Цель
|
||||
|
||||
Реализовать первую рабочую версию воспроизводимого нормализатора локального
|
||||
архива `data/minjust-cbd`. Нормализованные данные должны быть пригодны для
|
||||
последующей загрузки в OpenSearch, backend API и RAG, но подключение этих
|
||||
сервисов в текущую задачу не входит.
|
||||
|
||||
## Текущее состояние
|
||||
|
||||
- загрузчик находится в `backend/ingestion/minjust_cbd.py`;
|
||||
- сырой архив хранится в `data/minjust-cbd` и исключён из Git;
|
||||
- в манифесте 209 811 успешно загруженных документов;
|
||||
- 13 кодов остаются в таблице `errors` и отсутствуют в таблице `documents`;
|
||||
- документ содержит `metadata.json` и каталог `editions`;
|
||||
- редакция содержит `metadata.json`, `ru.html` и/или `ky.html`, иногда
|
||||
изображения;
|
||||
- HTML создан Microsoft Word, может содержать некорректный
|
||||
`<meta charset=unicode>`, служебные стили и неполную разметку;
|
||||
- файлы архива записаны загрузчиком в UTF-8;
|
||||
- часть документов одноязычная, а часть не содержит HTML-текста.
|
||||
|
||||
## Обязательные ограничения
|
||||
|
||||
1. Не изменять и не перезаписывать `data/minjust-cbd`.
|
||||
2. Не запускать полный проход по архиву во время автоматических тестов.
|
||||
3. Не подключать PostgreSQL, OpenSearch, OCR, embeddings, машинный перевод и
|
||||
сетевые API.
|
||||
4. Сначала использовать стандартную библиотеку. Новая зависимость допустима
|
||||
только если на реальных образцах доказано, что стандартный HTML-парсер не
|
||||
обеспечивает корректность или безопасность.
|
||||
5. Все записи выполнять атомарно.
|
||||
6. Ошибка одного документа не должна останавливать длительный прогон.
|
||||
7. Повторный запуск должен пропускать неизменившиеся документы.
|
||||
8. Не изменять пользовательские файлы `logs/`, исходный DOCX и несвязанные
|
||||
незакоммиченные изменения.
|
||||
|
||||
## Размещение
|
||||
|
||||
Использовать существующую backend-структуру:
|
||||
|
||||
```text
|
||||
backend/
|
||||
normalization/
|
||||
minjust_cbd.py
|
||||
```
|
||||
|
||||
Результат по умолчанию:
|
||||
|
||||
```text
|
||||
data/minjust-normalized/
|
||||
manifest.sqlite3
|
||||
documents/<document_code>/document.json
|
||||
documents/<document_code>/editions/<edition_code>/edition.json
|
||||
documents/<document_code>/editions/<edition_code>/<lang>/content.html
|
||||
documents/<document_code>/editions/<edition_code>/<lang>/content.txt
|
||||
documents/<document_code>/editions/<edition_code>/<lang>/fragments.json
|
||||
```
|
||||
|
||||
Каталог уже покрывается правилом игнорирования `data/`.
|
||||
|
||||
## Канонические данные
|
||||
|
||||
### `document.json`
|
||||
|
||||
Сохранить как минимум:
|
||||
|
||||
- `schema_version`;
|
||||
- `source_code`;
|
||||
- двуязычные `class`, `type`, `title`, `name`, `status`;
|
||||
- номера и даты без юридически неподтверждённых выводов;
|
||||
- флаги публичности;
|
||||
- органы, публикации, ключевые слова и классификаторы с сохранением дерева;
|
||||
- пути листьев иерархий для будущих фильтров;
|
||||
- ссылки из `References` без выдумывания связей;
|
||||
- `available_languages`;
|
||||
- список редакций;
|
||||
- путь к источнику и SHA-256 исходных файлов;
|
||||
- версию нормализатора и время обработки.
|
||||
|
||||
Пустые строки привести к `null`, но не переводить значения и не заменять
|
||||
официальные формулировки собственными.
|
||||
|
||||
### `edition.json`
|
||||
|
||||
Сохранить:
|
||||
|
||||
- исходный код редакции;
|
||||
- двуязычное название;
|
||||
- исходный тип;
|
||||
- доступные языки;
|
||||
- изображения без бинарных данных;
|
||||
- контрольные суммы источников;
|
||||
- признаки качества.
|
||||
|
||||
Не считать дату из `Name` датой вступления редакции в силу и не назначать
|
||||
актуальную редакцию без подтверждённого правила источника.
|
||||
|
||||
### Языковой вариант
|
||||
|
||||
Для каждого имеющегося `ru.html` или `ky.html` сформировать:
|
||||
|
||||
- `content.html` — безопасный HTML для frontend;
|
||||
- `content.txt` — извлечённый текст с сохранением смысловых переносов;
|
||||
- `fragments.json` — упорядоченные адресуемые блоки.
|
||||
|
||||
Сырой HTML всегда читать как UTF-8, не доверяя его meta charset.
|
||||
|
||||
## Очистка HTML
|
||||
|
||||
- удалить `script`, `style`, `meta`, `link`, комментарии и служебные элементы;
|
||||
- удалить обработчики событий, inline-стили и опасные URL;
|
||||
- разрешить минимальный набор структурных тегов: заголовки, абзацы, `pre`,
|
||||
списки, таблицы, безопасные ссылки, изображения и базовое текстовое
|
||||
выделение;
|
||||
- нормализовать Unicode в NFC;
|
||||
- преобразовать неразрывные пробелы и избыточные пробелы только в
|
||||
`content.txt`, не искажая отображаемый юридический текст;
|
||||
- не загружать внешние ресурсы;
|
||||
- относительные изображения связывать только с файлами внутри редакции;
|
||||
- неизвестную или сломанную разметку сохранять как текст, а не терять молча.
|
||||
|
||||
## Фрагменты
|
||||
|
||||
Минимальная версия должна создавать фрагмент для каждого содержательного
|
||||
блочного элемента. Распознавание статей и пунктов допускается только простыми
|
||||
проверяемыми правилами RU/KY; обычный абзац является fallback.
|
||||
|
||||
Каждый фрагмент содержит:
|
||||
|
||||
- стабильный `id`;
|
||||
- `document_code`, `edition_code`, `language`;
|
||||
- порядковую позицию;
|
||||
- тип блока;
|
||||
- чистый текст;
|
||||
- SHA-256 текста.
|
||||
|
||||
Идентификатор должен быть детерминированным и включать документ, редакцию,
|
||||
язык и позицию. Не добавлять сложное сопоставление фрагментов между
|
||||
редакциями — это отдельная будущая задача.
|
||||
|
||||
## Манифест и возобновление
|
||||
|
||||
SQLite-манифест должен хранить:
|
||||
|
||||
- код документа;
|
||||
- SHA-256 набора исходных файлов;
|
||||
- версию схемы и нормализатора;
|
||||
- время успешной обработки;
|
||||
- состояние и текст последней ошибки.
|
||||
|
||||
Если checksum и версия нормализатора не изменились, документ пропускается.
|
||||
После успешной повторной обработки ошибка удаляется. Добавить `--limit` и
|
||||
понятный терминальный прогресс, пригодный для долгого запуска.
|
||||
|
||||
## CLI и импорт из будущего backend
|
||||
|
||||
CLI запускается из корня репозитория:
|
||||
|
||||
```bash
|
||||
python3 backend/normalization/minjust_cbd.py
|
||||
```
|
||||
|
||||
Предусмотреть параметры:
|
||||
|
||||
- `--input`;
|
||||
- `--output`;
|
||||
- `--limit`;
|
||||
- `--refresh`;
|
||||
- `--log-level`.
|
||||
|
||||
Основную функцию можно импортировать без запуска CLI. Не создавать
|
||||
планировщик, очередь задач или framework-интеграцию.
|
||||
|
||||
## Проверки
|
||||
|
||||
Добавить один компактный тестовый модуль, который проверяет:
|
||||
|
||||
1. русскую редакцию;
|
||||
2. кыргызскую редакцию;
|
||||
3. двуязычную редакцию;
|
||||
4. Word HTML с опасным `script`, inline-стилем и `javascript:` URL;
|
||||
5. документ без HTML;
|
||||
6. повторный запуск и пропуск неизменившегося документа;
|
||||
7. продолжение после ошибки одного документа;
|
||||
8. детерминированные fragment ID и checksums.
|
||||
|
||||
Провести пилотный read-only запуск на небольшой реальной выборке через
|
||||
`--limit`, не нормализовать весь архив в рамках разработки.
|
||||
|
||||
## Документация и версия
|
||||
|
||||
- описать запуск, структуру результата и ограничения в `backend/README.md`;
|
||||
- отметить реализацию в `docs/operations/project-status.md`;
|
||||
- это новая обратно совместимая backend-функция: увеличить minor-версию
|
||||
backend по SemVer;
|
||||
- обновить все отображаемые backend-версии и footer, не меняя версию
|
||||
Telegram-бота;
|
||||
- frontend по-прежнему помечать как не созданный.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- сырой архив не изменён;
|
||||
- тесты проходят;
|
||||
- `git diff --check` проходит;
|
||||
- пилотный запуск завершается без остановки на отдельных ошибках;
|
||||
- повторный пилотный запуск пропускает неизменившиеся документы;
|
||||
- unsafe HTML не попадает в `content.html`;
|
||||
- каждый фрагмент прослеживается до документа, редакции, языка и исходного
|
||||
файла;
|
||||
- отсутствуют молча потерянные HTML или ошибки;
|
||||
- реализация не содержит PostgreSQL/OpenSearch/RAG-кода «на будущее».
|
||||
|
||||
---
|
||||
|
||||
Акылдаш · Telegram-бот v0.2.2 · Backend v0.2.1 · Frontend — не создан
|
||||
@@ -44,4 +44,4 @@
|
||||
|
||||
---
|
||||
|
||||
Акылдаш · Telegram-бот v0.2.2 · Backend v0.1.2 · Frontend — не создан
|
||||
Акылдаш · Telegram-бот v0.2.2 · Backend v0.2.1 · Frontend — не создан
|
||||
|
||||
Reference in New Issue
Block a user