feat: complete published registry contracts and gated SRO ingestion
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
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
This commit is contained in:
103
docs/source-records-public-runtime-contract.md
Normal file
103
docs/source-records-public-runtime-contract.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Карточки, задачи, история и готовые выгрузки — 14.09.2026
|
||||
|
||||
Этот документ уточняет общий runtime-контракт по новому
|
||||
[source-records-backend-improvements.md](source-integration/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 по умолчанию выключен; включение требует отдельного
|
||||
согласованного основания. Настоящие адреса/секреты стендов в эти проверки не входят.
|
||||
Reference in New Issue
Block a user