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

145 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Мостовик: интеграция frontend с backend, 13.09.2026
Передача Глебу. Проверен свежий frontend `origin/dev`
`c6f2ec787efef5617d6624ff83050589c3941f0d` после успешного SSH fetch через
штатный jump host. Рабочее дерево frontend не переключалось и не изменялось.
Backend-контракт: текущая поставка поверх
`c863563851642727045f58f16336aa96fb28308a`; основной контракт новых источников
описан в [registry-sources-ru.md](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-режима.