# План внутреннего интерфейса оценки поисковой выдачи ## Цель Создать закрытую лабораторию релевантности: юрист оценивает фактическую выдачу нашего OpenSearch по практическим запросам. Цель — улучшать собственное ранжирование, а не воспроизводить алгоритм сайта Минюста КР. ЦБД Минюста используется как официальный источник текста, реквизитов, статуса и редакции акта. Порядок результатов и оценка их полезности определяются в нашем сервисе. Это внутренний рабочий инструмент, а не публичный frontend MVP. Он не включает регистрацию, личные кабинеты, публичный дизайн, сложные фильтры или сравнение редакций. ## Сценарий юриста 1. Указать поисковый запрос и язык. 2. Получить первые 10–20 результатов в точном порядке OpenSearch. 3. Увидеть позицию каждого результата: `#1`, `#2` и далее. 4. Открыть выбранный документ по клику на название в правой панели страницы. 5. Поставить каждому просмотренному результату оценку и комментарий. 6. Сохранить снимок выдачи и оценок. 7. Передать накопленные записи на анализ ранжирования. ## Оценка результата | Балл | Значение | | ---: | --- | | 0 | Нерелевантен: совпали слова, но акт не отвечает на вопрос. | | 1 | Косвенно полезен: относится к теме, но прямого ответа нет. | | 2 | Частично полезен: отвечает не полностью или требует другого акта. | | 3 | Прямо и достаточно отвечает на запрос. | Оценка относится к отдельному документу, а не ко всей выдаче. Результат без оценки считается непросмотренным, а не нерелевантным. ## Интерфейс Рекомендуемый экран — две панели. - Вверху: поле запроса, переключатель RU/KY, выбор числа результатов и кнопка «Найти». - Слева: карточки результатов в порядке выдачи. Карточка содержит позицию, название, тип, статус, дату, номер и фрагмент текста. - Справа: заголовок, реквизиты, очищенный HTML выбранной редакции и ссылка на официальный источник. - В карточке: кнопки оценки `0`, `1`, `2`, `3` и раскрываемое поле комментария. - Внизу: имя или псевдоним проверяющего, общий комментарий и кнопка «Сохранить оценку». Правая панель предпочтительнее popup: она не блокируется браузером, сохраняет контекст выдачи и работает на одном экране с оценкой. ### Доступность оценки и документа Оценка реализуется нативной группой `radio` внутри `fieldset` с `legend` «Оценка результата». У каждого значения есть видимая подпись: «0 — нерелевантен», «1 — косвенно полезен», «2 — частично полезен», «3 — прямо отвечает». Нельзя передавать смысл оценки только цветом. Все элементы управления доступны с клавиатуры, имеют видимый `:focus-visible`; выбранный результат обозначается текстом и визуальным состоянием. На узком экране список результатов занимает всю страницу. Кнопка «Открыть документ» открывает полноэкранный нативный `` с явной кнопкой «Закрыть». При закрытии фокус возвращается на исходную кнопку «Открыть документ». ### Состояния - Во время поиска и сохранения показывается состояние загрузки; повторная отправка на это время недоступна. Стабильная пустая область `role="status"` в DOM объявляет начало поиска, число результатов и успешное сохранение. - Пустая выдача сообщает: «По запросу „…“ ничего не найдено» и предлагает «Изменить запрос». - Ошибка поиска сообщает причину и предлагает «Повторить поиск»; текст ошибки выводится в `role="alert"`. - Ошибка сохранения сообщает: «Не удалось сохранить. Проверьте подключение и повторите». Черновик остаётся в браузере, текст ошибки выводится в `role="alert"`. - После сохранения выводится: «Оценка сохранена · № … · дата и время» в указанной стабильной области `role="status"`. До сохранения черновик хранится в `localStorage`. После успешного сохранения интерфейс показывает ID записи и время сохранения. ## Backend и хранение Использовать существующие endpoint: - `GET /search` — получить ранжированный список результатов; - `GET /documents/{code}/editions/{edition}` — получить текст выбранной редакции. Добавить два endpoint: - `POST /search-reviews` — валидирует и сохраняет оценку; - `GET /search-reviews/export` — отдаёт накопленные записи в JSON. Для первой версии достаточно отдельной SQLite-базы. Это стандартная библиотека Python, данные переживают перезапуск и легко выгружаются для анализа. Доступ к интерфейсу и всем endpoint `search-reviews`, включая экспорт, должен быть ограничен локальной сетью/VPN или аутентификацией reverse proxy. Одна запись представляет один сохранённый поисковый сеанс: | Поле | Назначение | | --- | --- | | `id`, `created_at` | Идентификатор и время сохранения. | | `reviewer` | Имя или псевдоним проверяющего. | | `query`, `language` | Исходный запрос и язык поиска. | | `index_name`, `algorithm_version` | Версия индекса и алгоритма на момент оценки. | | `top_result_code` | Код документа в позиции `#1`. | | `results_json` | Снимок результатов в исходном порядке с оценками и комментариями. | | `overall_comment` | Общий комментарий к выдаче. | В `results_json` для каждого результата сохраняются: `rank`, `document_code`, `edition_code`, название, реквизиты, фрагмент, оценка и комментарий. Снимок выдачи обязателен: после изменения алгоритма можно будет восстановить именно тот результат, который видел юрист. ## Правила сохранения - Запрос не пустой, не длиннее 500 символов. - Оценка может быть только целым числом от 0 до 3 либо отсутствовать у непросмотренного результата. - Комментарии имеют ограничение длины; пользовательские значения не вставляются в HTML. - `GET /search` возвращает краткоживущий HMAC-подписанный снимок выдачи: запрос, язык, индекс, результаты и их позиции. `POST /search-reviews` принимает этот снимок и только оценки с комментариями. Сервер проверяет подпись и срок, самостоятельно формирует `results_json` и отклоняет оценки для отсутствующих либо подменённых позиций и документов. - Нельзя передавать персональные данные или закрытые материалы в комментариях. - Кнопка «Сохранить оценку» остаётся доступной до отправки: отсутствующие обязательные поля проверяются после нажатия, ошибка показана рядом с полем и фокус переводится на первое некорректное поле. ## Анализ данных Экспорт должен содержать исходный JSON-снимок, чтобы его можно было обработать скриптом или открыть в табличном инструменте. Первый отчёт строит: - среднюю оценку для каждой позиции выдачи; - долю результатов с оценкой `3` в top-1, top-3 и top-10; - запросы, где нет результатов с оценкой `2` или `3`; - документы, которые часто получают низкую оценку в первых позициях; - комментарии для ручного разбора ошибок. Сырые оценки не должны автоматически менять веса поиска. Сначала команда разбирает причины: анализатор, синонимы, статус, отсутствие документа, неправильная формулировка запроса или юридическая неоднозначность. ## Этапы реализации 1. Утвердить шкалу 0–3, обязательность имени проверяющего и правила доступа. 2. Добавить SQLite-хранилище, валидацию, сохранение и JSON-экспорт. 3. Добавить статическую внутреннюю страницу в существующий Python-сервер, без Next.js и отдельного публичного приложения. 4. Подключить поиск, правую панель документа, черновик, адаптивный режим и сохранение в закреплённой панели действий на широком экране. 5. Добавить минимальные backend-проверки сохранения, повторного запуска, экспорта и недопустимых оценок. 6. Провести ручный прогон на десяти русскоязычных практических запросах с двумя юристами. 7. На собранных записях настроить OpenSearch и повторить тот же набор запросов. ## Критерий готовности Юрист вводит запрос, видит порядок выдачи, открывает документ, выставляет оценки и комментарии, сохраняет их. Экспорт содержит запрос, язык, документ на позиции `#1`, полный порядок результатов, оценки, комментарии и версию индекса. Данные можно сравнить до и после изменения алгоритма. --- Акылдаш · Telegram-бот v0.2.2 · Backend v0.7.1 · Frontend — не создан