13 KiB
Мостовик: интеграция frontend с backend, 13.09.2026
Передача Глебу. Проверен свежий frontend origin/dev
c6f2ec787efef5617d6624ff83050589c3941f0d после успешного SSH fetch через
штатный jump host. Рабочее дерево frontend не переключалось и не изменялось.
Backend-контракт: текущая поставка поверх
c863563851642727045f58f16336aa96fb28308a; основной контракт новых источников
описан в registry-sources-ru.md.
Документ не подтверждает публикацию backend/frontend на dev-стенде.
Все frontend-пути ниже начинаются с src/pages/main/.
Уже подключено в свежем frontend dev: оба новых view, таблицы и настройки
запуска, оба источника в фильтре истории и обе группы общей выгрузки. Это
подтверждено чтением resolveSourceDetailView.ts, useScrapingCollectionCards.ts,
ReferenceDataSourcesExportCard.vue, updateHistoryLogs.ts и исполнением resolver.
Старое заключение об отсутствии этих подключений к свежему dev не относится.
| Источник | Slug | Source | Source group | Record type |
|---|---|---|---|---|
| Поддержка МСП | sme-support-recipients-registry |
fns_sme_support_recipients |
government_support |
sme_support_measure |
| Бюджетный процесс | budget-process-registry |
budget_ubpandnubp |
budget_process_registry |
budget_registry_organization |
MV-1. Привести DTO и детали к фактическому MVP payload.
Backend src/apps/parsers/budget_registry.py:55 отдаёт нормализованные
registry, classification, budget, address и полный исходный upstream
в детали. Он не обещает нормализованные legal, heads, contacts, activities,
authorities, successions, contracts, attachments, summary,
is_separate_division. Однако frontend
ui/SourceRecordDetail/BudgetProcessRegistryRecordDetail.vue:98 обращается к
payload.legal.firm_name, а
model/source-record-detail/sourceRecordDetail.ts:400,414 — к
payload.legal.legal_form и .heads.length. На payload фактического normalizer
исполнение mapper завершилось TypeError reading 'legal_form'.
Backend src/apps/parsers/sme_support.py:78 отдаёт recipient_type и
sme_category строковыми кодами, support_form/support_kind словарями,
provider с name/inn, support_sizes со значением и единицей. violations и
regulatory_documents сохраняют оригинальные XML-атрибуты. provenance и
нормализованного региона в payload нет. Frontend
model/source-detail/smeSupportRecipients.ts:61,195 ожидает словарь категории
и теряет существующий код при выводе; detail mapper
model/source-record-detail/sourceRecordDetail.ts:525 падает на
payload.provenance.dataset_url (TypeError воспроизведён).
Исправить перечисленные DTO, мапперы и detail renderer под этот контракт:
не читать несуществующие обязательные блоки; не заменять неизвестные признаки
значением «нет»; выводить подтверждённые код/значение/единицу, а не вымышленные
названия. Для бюджета полный исходный документ доступен в payload.upstream
детали/выгрузки. Для МСП читать реальные имена XML-атрибутов документов и
нарушений. Отдельно проверить экспорт полной карточки, использующий тот же mapper.
Список GET /api/v2/organization-source-records/ возвращает data и
meta.pagination, detail GET /{uid}/ — объект записи. Краткий payload
намеренно исключает source_document_id, violations, regulatory_documents,
upstream: за ними нужен detail-запрос. Отсутствие массива в списке не означает
отсутствие данных. Полный контракт: docs/registry-sources-ru.md.
MV-2. Оставить только поддержанные сортировки и фильтры.
Backend уже исправлен для составного ordering из существующего allowlist:
начальный запрос МСП ordering=-record_date,-external_id теперь проходит.
Каждый компонент отдельно валидируется; неизвестные поля остаются 400.
Дополнительные JSON-sort и специальные фильтры в MVP не добавлялись.
model/source-detail/useSmeSupportRecipientsSourceTable.ts:76–135 посылает
неподдержанные sort по support_form, support_kind, support_until, provider,
region, sme_category, has_violation.
model/source-detail/useBudgetProcessRegistrySourceTable.ts:93–129 — по
organization_type, establishment_kind, budget.level, address.region,
is_separate_division. Убрать sortable/orderingKey с этих заголовков до отдельного
согласования backend-расширения. Не подменять сортировку смыслово другим полем.
Допустимые простые поля для соответствующих колонок: record_date, updated_at,
status, external_id, extension__organization__name (также alias
organization__name), ИНН/ОГРН/ОКПО организации. Полный текущий allowlist находится
в src/organizations/views.py:104. Рекомендуемые defaults:
МСП -record_date,-external_id, бюджет extension__organization__name.
Бюджетная таблица на строках 252–259 отправляет budget_level,
establishment_kind, has_procurement_permission, is_branch,
organization_type, region_code: текущий backend эти шесть параметров
игнорирует. Скрыть/отключить соответствующие фильтры. Поддержаны общие
source/source_group/record_type, status, organization, search и период record_date.
Колонка бюджета «Обновлено» показывает updated_at, но её dateFilterKey —
record_date (строки 120–122): согласовать подпись/значение колонки с полем
фильтра. Это разные даты.
MV-3. Завершать polling по статусу и считать всю группу задач.
model/sources/useSourceCardRefreshTracking.ts:128–153 по-прежнему считает
progress=100 завершением и успехом даже для status=running или status=error
с пустым error. Оба результата воспроизведены. Статус jobs API —
running, success, error; 100% не доказывает завершение. Terminal и success
определять по статусу; ошибка должна оставаться ошибкой.
Строки 180–203 делят сумму только на уже полученные числовые ответы. Если из
двух task_ids первая задача ответила 100, а вторая временно недоступна,
расчёт показывает 100; после ответа второй с 0 даёт 50. Свежий
ui/SourceDetailPage/components/useSourceDetailRefresh.ts:107–128 уже удерживает
показанный максимум: пользователь теперь может видеть преждевременные 100,
а не снижение до 50. Исправить знаменатель на фиксированный полный task_ids,
сохранять последние значения при временной ошибке polling. После перезагрузки,
если полный набор неизвестен, использовать агрегированный backend progress:
текущий приоритет среднего только activeTasks на строках 73–102 исключает
завершённые части группы. Строки 87–88 и 130–133 показывают success/«Обновлено»
для любого неактивного состояния: отдельно отображать error и idle.
202 с task_ids уже поддерживается (queued вместо accepted не мешает).
При 409 source_refresh_running показать сообщение и перечитать карточку/
статусы; не включать фиктивный polling без IDs. Общий error envelope совместим,
отдельного восстановления карточки на 409 в hook пока нет.
История и общая выгрузка уже согласованы по исходникам.
model/update-history/useUpdateHistoryTable.ts:55,67,148 теперь отправляет
date_from/date_to и в список, и в экспорт, включает период в query key и
сбрасывает страницу. lib/update-history/updateHistoryLogs.ts:46 корректно
передаёт один день как одинаковые границы. Старый локальный date filter удалён.
Это регрессия для приёмки, не новая задача реализации. Проверить >100 строк,
совпадение периода/количества CSV и список, границу суток: backend фильтрует
updated_at в UTC, browser formatter использует локальную зону.
Обе новые группы уже есть в ReferenceDataSourcesExportCard.vue:86–93.
Общий ticket 201 / native POST download совместим. В
model/source-detail/exportSourceDetailTable.ts:111 новые таблицы остаются
на локальном CSV fallback. Если кнопка обещает полный реестр, подключить
серверную выгрузку; если только текущую страницу — явно обозначить объём.
Карточки/списки относятся к ОПК, полная выгрузка — ко всем сопоставленным
организациям справочника; эти счётчики могут отличаться по контракту.
Проверки и критерии готовности
Составной allowlisted ordering уже исправлен на backend: 29 API-тестов прошли,
Ruff и git diff --check прошли. Несуществующие payload-sort поля дают 400.
Node probes свежих frontend-функций воспроизвели ошибки деталей (legal_form,
dataset_url), потерю кода категории и ошибки определения terminal/progress.
Payload для деталей получен фактическими backend normalizers без сети и БД;
это не полный Vue/browser тест. Frontend build/Vitest/E2E здесь не запускались.
Готовность после MV-1–MV-3: оба реальных API списка и детали открываются без TypeError; отсутствующие поля не подменяются утверждением «нет»; доступны только работающие filters/sorts; running100 продолжает polling, error100 остаётся ошибкой; две задачи с задержанным ответом не показывают преждевременные 100%; после reload сохраняется прогресс всей группы. Проверить 409/refetch, экспорт карточки, серверный период истории и настоящий ZIP общей выгрузки. Использовать fixtures реального backend и стенд без frontend mock-режима.