Files
mostovik-backend/docs/frontend-integration-2026-09-13.md
Aleksandr Meshchryakov 49cbfd265c
All checks were successful
Mostovik Backend CI/CD / Tests and lint (push) Successful in 9m37s
Mostovik Backend CI/CD / Build linux/amd64 release images (push) Successful in 4m18s
Mostovik Backend CI/CD / Deploy and verify internal main (push) Has been skipped
Mostovik Backend CI/CD / Deploy customer main (push) Has been skipped
Mostovik Backend CI/CD / Deploy dev (push) Successful in 1m48s
feat(registries): add SME and budget imports and fix source API workflows
2026-09-13 23:13:47 +02:00

13 KiB
Raw Blame History

Мостовик: интеграция 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:76135 посылает неподдержанные sort по support_form, support_kind, support_until, provider, region, sme_category, has_violation. model/source-detail/useBudgetProcessRegistrySourceTable.ts:93129 — по 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.

Бюджетная таблица на строках 252259 отправляет 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 (строки 120122): согласовать подпись/значение колонки с полем фильтра. Это разные даты.

MV-3. Завершать polling по статусу и считать всю группу задач. model/sources/useSourceCardRefreshTracking.ts:128153 по-прежнему считает progress=100 завершением и успехом даже для status=running или status=error с пустым error. Оба результата воспроизведены. Статус jobs API — running, success, error; 100% не доказывает завершение. Terminal и success определять по статусу; ошибка должна оставаться ошибкой.

Строки 180203 делят сумму только на уже полученные числовые ответы. Если из двух task_ids первая задача ответила 100, а вторая временно недоступна, расчёт показывает 100; после ответа второй с 0 даёт 50. Свежий ui/SourceDetailPage/components/useSourceDetailRefresh.ts:107128 уже удерживает показанный максимум: пользователь теперь может видеть преждевременные 100, а не снижение до 50. Исправить знаменатель на фиксированный полный task_ids, сохранять последние значения при временной ошибке polling. После перезагрузки, если полный набор неизвестен, использовать агрегированный backend progress: текущий приоритет среднего только activeTasks на строках 73102 исключает завершённые части группы. Строки 8788 и 130133 показывают 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:8693. Общий 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-1MV-3: оба реальных API списка и детали открываются без TypeError; отсутствующие поля не подменяются утверждением «нет»; доступны только работающие filters/sorts; running100 продолжает polling, error100 остаётся ошибкой; две задачи с задержанным ответом не показывают преждевременные 100%; после reload сохраняется прогресс всей группы. Проверить 409/refetch, экспорт карточки, серверный период истории и настоящий ZIP общей выгрузки. Использовать fixtures реального backend и стенд без frontend mock-режима.