Files
mostovik-backend/docs/source-records-public-runtime-contract.md
Aleksandr Meshchryakov 18971d33ec
All checks were successful
Mostovik Backend CI/CD / Tests and lint (push) Successful in 3m55s
Mostovik Backend CI/CD / Build linux/amd64 release images (push) Successful in 3m43s
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 1m45s
feat: complete published registry contracts and gated SRO ingestion
2026-09-14 17:01:02 +02:00

9.2 KiB
Raw Blame History

Карточки, задачи, история и готовые выгрузки — 14.09.2026

Этот документ уточняет общий runtime-контракт по новому source-records-backend-improvements.md. Для выгрузок он заменяет разделы SME/SRO source-first спецификаций, в которых описан preparing / HTTP 202. Действующий frontend использует готовый ticket HTTP 201 и native form POST со скачиванием HTTP 200; этот flow сохранён.

Источник Card slug Parser source Export group
Бюджет budget-process-registry budget_ubpandnubp budget_process_registry
МСП sme-support-recipients-registry fns_sme_support_recipients government_support
СРО sro-membership-check sro_membership_check sro_membership

Карточки и история

GET /api/v1/sources/ и /api/v1/sources/{slug}/ возвращают одинаковую полную форму карточки, включая source_items, active_tasks, latest_load и latest_success_load. Для трёх источников records_count — все опубликованные записи, organizations_count — уникальные организации опубликованного набора. ОПК остаётся отдельным показателем dashboard registry_data_coverage и registry_enrichment_analytics. Scope остальных карточек сохранён.

Последняя неуспешная попытка видна в latest_load; она не заменяет latest_success_load и не сдвигает last_updated_at. Данные snapshot в карточках, dashboard и логах содержат artifact_id, snapshot_date, version, checksum_sha256, published_at. Неизвестная дата/отсутствующая публикация — null; пустая версия/checksum не подменяется выдуманным значением.

В /api/v1/system/logs/, detail и CSV для новых источников source — канонический parser source из таблицы, source_label — человекочитаемое название. CSV добавляет код источника, дату/версию/SHA256 снимка. records_count отражает опубликованный итог. У incremental СРО текущий итог и изменённая часть разделены в artifact metadata (snapshot_records_count, snapshot_organizations_count, batch_published_records_count, updated_records_count).

Запуск и polling

Оба admin entrypoint — POST /api/v1/sources/{slug}/refresh/ и /api/v1/parsers/run/{source}/ — принимают {} или {"params": {}}. Внешние URL, file paths и параметры loader не принимаются для трёх источников. Только SRO parser-run дополнительно принимает mode: incremental|full, по умолчанию incremental; неверное значение — HTTP 400 invalid_mode.

Card refresh возвращает plain HTTP 202 {task_id, task_ids, status: "queued"}; parser-run возвращает эти поля плюс source и task_name внутри стандартного {success, data, errors, meta}. Активный запуск исключает второй запуск через любой entrypoint: HTTP 409 refresh_already_running. До согласования upstream доступа СРО возвращает HTTP 409 upstream_access_not_approved, без постановки задачи в очередь. Worker повторно проверяет доступ.

GET /api/v1/jobs/{task_id}/ для этих трёх источников различает queued, running, retrying, success, failed, cancelled, skipped; progress остаётся целым числом, message отражает ход работы. source — канонический код. result успешной публикации содержит batch/load/artifact IDs, счётчики и метаданные снимка (SnapshotJobResult). meta для новых задач типизирован как SnapshotRunMetadata: режим СРО, число кандидатов/запрошенных организаций/найденных членств, публикация и карантин, счётчики HTTP/parse ошибок и nullable дата реестра. В публичный meta входят только разрешённые счётчики, без конфигурации loader или raw responses. Те же счётчики доступны в log meta; terminal result имеет aliases records_count / organizations_count. Legacy jobs сохраняют прежние значения статуса и прежний result. Общая схема допускает legacy error, deprecated raw aliases pending|started|retry|failure|revoked и дополнительные поля result. Generic parser results list имеет уникальный operationId api_v1_parsers_results_list; detail сохраняет прежний api_v1_parsers_results_read. Dashboard сохраняет operationId api_v1_parsers_dashboard_list и tag api, чтобы generated client оставался в прежнем модуле.

Выгрузка

POST /api/v2/organization-source-records/export-ticket/ с sources и format возвращает HTTP 201 {ticket, file_name, expires_in}. Ticket одноразовый, TTL по умолчанию 300 секунд. POST /export-download/ с form field ticket возвращает ZIP HTTP 200; истёкший, неизвестный или использованный ticket — HTTP 410 {detail, code: "ticket_expired"}. Capability позволяет native form без передачи JWT в URL. Для выпуска ticket нужны прежние admin permissions.

Публикация любого из трёх снимков запрашивает существующую фоновую сборку экспорта после commit. Если подготовленное поколение относится к предыдущей публикации, новый ticket получает HTTP 503 source_export_not_ready до готовности новой сборки. Ошибка импорта не делает успешное поколение устаревшим. При занятой блокировке запрос сборки повторяется через 30 секунд; бюджет покрывает TTL блокировки плюс два повтора. Исчерпание бюджета — ошибка Celery с явной записью в журнале, а не успешный пропуск. Ночной запуск остаётся восстановительным путём.

Сборка читает записи и идентификаторы публикаций из одного PostgreSQL REPEATABLE READ snapshot; спулирование завершается до рендеринга CSV/JSON/XLSX. Вложенный transaction защищён дополнительной проверкой неизменности идентичности публикаций. Ticket закрепляет immutable generation: новая публикация не меняет его содержимое. Удаление старых поколений выдерживает TTL после retirement; уже начавшийся stream держит открытые файлы и не ломается при последующей уборке поколения.

Все три группы экспортируют полную опубликованную историю; ИНН, ОГРН и ОКПО остаются строками во всех форматах. После обновления схемы/нормализации старого payload требуется запустить существующую команду build_source_record_exports: появление СРО меняет матрицу с 40 на 43 артефакта, а нормализация payload сама по себе не создаёт новый artifact ID. Она атомарно увеличивает content revision затронутых опубликованных артефактов; новая выдача ticket проверяет и эту ревизию. До пересборки возвращается 503, ранее выданные tickets сохраняют свою generation.

Локальные контрактные тесты не подтверждают живой upstream СРО или принятие frontend UI. Доступ к upstream по умолчанию выключен; включение требует отдельного согласованного основания. Настоящие адреса/секреты стендов в эти проверки не входят.