feat: expand platform APIs, sources, and test coverage
Some checks failed
CI/CD Pipeline / Run Tests (pull_request) Successful in 1m53s
CI/CD Pipeline / Telegram Notify Success (push) Has been cancelled
CI/CD Pipeline / Run Tests (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (pull_request) Failing after 2m54s
CI/CD Pipeline / Telegram Notify Success (pull_request) Has been skipped

This commit is contained in:
2026-03-17 12:56:48 +01:00
parent b505c67968
commit 3d298ce352
101 changed files with 8387 additions and 292 deletions

View File

@@ -0,0 +1,47 @@
# ADR-001: Platform Version Policy
## Status
Accepted
## Context
Проект разрабатывается и эксплуатируется в ограниченном (регулируемом) технологическом контуре.
Доступные версии ПО определяются:
- внутренними репозиториями и зеркалами
- требованиями безопасности
- сертификацией
- инфраструктурными ограничениями
Использование последних upstream-версий не является возможным или допустимым.
## Decision
Проект использует фиксированный (approved) стек версий:
- Python 3.11.x
- Django 3.2.x
- PostgreSQL 15.x
- Redis 7.x
- Celery 5.3.x
Политика обновлений:
- PATCH-обновления внутри approved ветки — разрешены
- MINOR/MAJOR — только после отдельного согласования
- Источник правды — lock-файлы и Docker-образы
## Consequences
### Positive
- стабильность среды
- воспроизводимость окружения
- соответствие требованиям контура
### Negative
- невозможность использовать новые фичи
- потенциальный техдолг (осознанный)
## Alternatives
- Использование latest upstream — отклонено (несовместимо с контуром)

View File

@@ -0,0 +1,39 @@
# ADR-002: Technology Stack Selection
## Status
Accepted
## Context
Необходим backend для:
- ETL обработки
- интеграции с внешними источниками
- фоновых задач
- администрирования данных
## Decision
Выбран стек:
- Django — основной framework
- Django REST Framework — API
- Celery — асинхронные задачи
- PostgreSQL — основное хранилище
- Redis — брокер и кеш
- Docker Compose — оркестрация
## Consequences
### Positive
- зрелый стек
- высокая предсказуемость
- большой опыт эксплуатации
### Negative
- монолитная архитектура
- ограниченная гибкость по сравнению с microservices
## Alternatives
- FastAPI — отклонён (меньше зрелости в админке и ORM экосистеме)
- Kubernetes — избыточен для текущего контура

View File

@@ -0,0 +1,38 @@
# ADR-003: Background Processing Architecture
## Status
Accepted
## Context
Обработка данных требует:
- асинхронности
- планирования задач
- устойчивости к сбоям
## Decision
Используется Celery:
- worker — выполнение задач
- beat — планировщик
- Redis — broker/backend
Типы задач:
- парсинг источников
- синхронизация данных
- обработка файлов
## Consequences
### Positive
- горизонтальное масштабирование
- разделение runtime и фоновых задач
### Negative
- сложность дебага
- необходимость контроля idempotency
## Alternatives
- RQ / Dramatiq — отклонены (меньше зрелости)

View File

@@ -0,0 +1,34 @@
# ADR-004: Data Ingestion and ETL Strategy
## Status
Accepted
## Context
Система интегрируется с нестабильными внешними источниками:
- гос API
- HTML/JS порталы
- файлы (Excel/XML)
## Decision
Используется ETL-подход:
- Extract — парсеры
- Transform — сервисный слой
- Load — PostgreSQL
Особенности:
- инкрементальная загрузка
- потоковый парсинг больших файлов
- обработка ошибок
## Consequences
### Positive
- контроль над данными
- устойчивость к изменениям источников
### Negative
- сложность поддержки парсеров
- необходимость ручного восстановления

View File

@@ -0,0 +1,30 @@
# ADR-005: External Integrations Strategy
## Status
Accepted
## Context
Внешние источники:
- proverki.gov.ru
- zakupki.gov.ru
- ФНС
- Минпромторг
## Decision
Подход:
- каждый источник — отдельный parser module
- Playwright используется для JS-порталов
- SOAP/API — через клиентов
## Consequences
### Positive
- изоляция интеграций
- возможность независимого развития
### Negative
- высокая хрупкость
- зависимость от изменений внешних систем

View File

@@ -0,0 +1,25 @@
# ADR-006: Configuration and Environment Strategy
## Status
Accepted
## Context
Необходимо разделение окружений:
- dev
- prod
## Decision
- .env.dev / .env.prod
- DJANGO_SETTINGS_MODULE
- startup checks (fail-fast)
## Consequences
### Positive
- предсказуемость запуска
- контроль конфигурации
### Negative
- риск рассинхронизации env

View File

@@ -0,0 +1,24 @@
# ADR-007: Deployment Model
## Status
Accepted
## Context
Ограниченный контур без Kubernetes.
## Decision
Используется Docker Compose:
- dev — полный стек
- prod — только сервисы (без DB/Redis)
## Consequences
### Positive
- простота деплоя
- воспроизводимость
### Negative
- ограниченная масштабируемость

View File

@@ -0,0 +1,27 @@
# ADR-008: Testing Strategy
## Status
Accepted
## Context
Нужно тестировать:
- бизнес-логику
- парсеры
- фоновые задачи
## Decision
- тесты вне src
- pytest
- отдельные скрипты запуска
- режим "production-like"
## Consequences
### Positive
- изоляция тестов
- удобство CI
### Negative
- сложность настройки среды

View File

@@ -0,0 +1,24 @@
# ADR-009: Observability and Health Checks
## Status
Accepted
## Context
Необходим контроль состояния системы.
## Decision
- /health
- /health/live
- /health/ready
- логирование через Docker
## Consequences
### Positive
- готовность к оркестрации
- диагностика проблем
### Negative
- ограниченная глубина мониторинга

View File

@@ -0,0 +1,30 @@
# ADR-010: Project Structure and Modularity
## Status
Accepted
## Context
Проект должен быть:
- расширяемым
- читаемым
## Decision
Структура:
- apps/
- core
- user
- parsers
- core/
- settings/
## Consequences
### Positive
- модульность
- понятная навигация
### Negative
- возможная связность между модулями

View File

@@ -0,0 +1,128 @@
# ADR-011: Idempotency and Retry Strategy for Background Tasks
## Status
Accepted
## Context
Система активно использует фоновые задачи Celery для:
- загрузки данных из внешних источников
- инкрементальной синхронизации
- обработки файлов
- периодических сканирований и парсинга
Внешние источники и фоновые очереди не гарантируют:
- exactly-once delivery
- стабильность сети
- неизменность ответа источника
- отсутствие повторных запусков задач
- отсутствие ручных перезапусков оператором
Также возможны следующие сценарии:
- worker завершился после частичной записи данных
- задача была запущена повторно по retry
- beat и ручной запуск вызвали одинаковую задачу почти одновременно
- внешняя система ответила ошибкой после того, как часть данных уже была получена
- оператор повторно инициировал синхронизацию за тот же период
Для такого класса системы идемпотентность является не оптимизацией, а обязательным архитектурным требованием.
## Decision
Все фоновые задачи, изменяющие данные или взаимодействующие с нестабильными внешними источниками, должны проектироваться как idempotent-first.
### Основные правила
1. Повторный запуск одной и той же задачи не должен приводить к неконтролируемому дублированию данных.
2. Результат повторного выполнения должен быть либо:
- идентичен первому успешному выполнению,
- либо безопасно приводить систему к тому же целевому состоянию.
3. Retry рассматривается как нормальный сценарий эксплуатации, а не как исключение.
### Идемпотентность обеспечивается за счет
- уникальных ограничений на уровне БД для естественных бизнес-ключей
- upsert/update-or-create подходов там, где это возможно
- явной привязки загружаемых данных к периоду, источнику, типу выгрузки или внешнему идентификатору
- дедупликации на уровне сервисного слоя перед записью
- разделения этапов extract / transform / load
- фиксации статуса фоновой задачи и контекста её выполнения
- запрета на "append-only" запись без проверки уникальности для синхронизируемых сущностей
### Retry policy
Retry допускается только для временных ошибок:
- сетевые сбои
- временная недоступность внешнего источника
- rate limiting
- временные ошибки брокера или инфраструктуры
- временные проблемы с файловой системой или внешним сервисом
Retry не должен безусловно выполняться для:
- ошибок валидации входных данных
- ошибок схемы/контракта источника
- систематических ошибок парсинга
- нарушений инвариантов модели
- ошибок конфигурации
Для retry необходимо:
- использовать ограниченное число повторов
- использовать backoff
- логировать причину повтора
- сохранять контекст периода/источника/операции
### Concurrency policy
Для задач, работающих по одному и тому же периоду или источнику, должна применяться логическая защита от параллельного конкурентного запуска.
Предпочтительный порядок контроля:
1. блокировка на уровне бизнес-контракта задачи
2. проверка существующего job-run статуса
3. защита уникальными ограничениями БД
4. безопасное повторное выполнение как fallback
### Operational policy
Задача считается корректной, если после:
- retry
- повторного ручного запуска
- запуска за уже обработанный период
- частичного падения и повторного восстановления
данные остаются консистентными и не требуют ручной чистки в обычном сценарии эксплуатации.
## Consequences
### Positive
- система устойчива к повторным запускам и временным отказам
- снижается риск дублирования данных
- упрощается эксплуатация и ручной re-run задач
- Celery retry становится безопасным штатным механизмом
- упрощается восстановление после сбоев worker-процессов
### Negative
- усложняется реализация сервисного слоя и моделей
- требуется дисциплина в проектировании бизнес-ключей
- часть задач становится медленнее из-за дополнительных проверок
- нужны дополнительные ограничения и индексы в БД
- необходимо явно проектировать поведение при partial success
## Alternatives considered
### 1. At-most-once execution
Отклонено, так как не соответствует реальной природе фоновой обработки и нестабильных внешних интеграций.
### 2. Полагаться только на Celery retry без идемпотентности на уровне домена
Отклонено, так как это приводит к дублированию данных и хрупкому поведению при сбоях.
### 3. Полная ручная очистка данных перед каждым повторным запуском
Отклонено, так как не масштабируется и опасно в эксплуатации.
## Notes
Следующими связанными решениями должны быть:
- политика дедупликации данных
- модель частичной загрузки и фиксации прогресса
- политика конкурентного запуска задач

View File

@@ -0,0 +1,133 @@
# ADR-012: Data Consistency and Partial Load Model
## Status
Accepted
## Context
Система загружает данные из внешних государственных и смежных источников, которые могут:
- быть нестабильны
- отдавать большие объёмы данных
- завершаться по таймауту
- менять формат ответа
- содержать частично поврежденные записи
- быть доступны только частично на момент синхронизации
Загрузка может выполняться:
- по периоду
- по файлам
- по внешним реестрам
- в инкрементальном режиме
На практике возможно частичное успешное выполнение:
- часть записей уже сохранена, часть ещё нет
- файл обработан наполовину
- один источник за период обработался, второй — нет
- FZ-248 успешно загружен, а FZ-294 завершился ошибкой
- часть данных валидна, часть — нет
Без явной модели частичной загрузки система становится трудно восстанавливаемой и операционно непрозрачной.
## Decision
Проект принимает модель controlled partial progress.
Это означает:
- частично выполненная загрузка допустима
- частичный прогресс должен быть наблюдаем и восстанавливаем
- повторный запуск должен быть безопасен
- состояние загрузки должно быть определимо без ручного анализа базы
### Основные правила
1. Единицей согласованности является не "вся система целиком", а отдельная операция загрузки:
- период
- файл
- тип источника
- подтип данных
- конкретная синхронизационная задача
2. Частичная загрузка допустима только если:
- данные записываются идемпотентно
- можно безопасно повторить обработку
- есть способ определить статус операции
3. Полный rollback всей загрузки не является обязательным требованием.
Вместо этого используется повторяемая и безопасная модель дозагрузки/перезапуска.
### Модель фиксации состояния
Для каждой операции загрузки система должна уметь определить:
- что именно загружалось
- за какой период или из какого файла
- когда началась обработка
- завершилась ли она успешно
- была ли частичная ошибка
- можно ли безопасно повторить запуск
Предпочтительная гранулярность статусов:
- pending
- running
- partial
- failed
- completed
### Правила работы с частичными данными
- уже сохраненные валидные данные не удаляются автоматически только из-за того, что операция завершилась частично
- повторный запуск обязан корректно переиспользовать уже записанные сущности
- повреждённые или невалидные записи должны логироваться отдельно
- ошибка части набора данных не должна молча скрываться как общий успех
### Периодическая синхронизация
Для периодических источников (например, месячные загрузки):
- период считается завершённым только после явной успешной фиксации
- отсутствие новых записей само по себе не всегда считается ошибкой
- для "пустых" периодов допустима отдельная бизнес-логика подтверждения отсутствия данных
### Работа с файлами
Для file-based ingestion:
- файл должен иметь трассируемый жизненный цикл
- необходимо различать:
- файл получен
- файл распознан
- файл обработан успешно
- файл обработан частично
- файл отклонён
- перемещение файла в processed или failed является частью операционного контракта
## Consequences
### Positive
- система сохраняет управляемость при partial failures
- упрощается восстановление после ошибок
- уменьшается потребность в ручной чистке данных
- повышается наблюдаемость загрузок и синхронизаций
- упрощается повторный запуск задач по периоду или файлу
### Negative
- модель состояний усложняется
- требуется более аккуратный job tracking
- появляется необходимость различать "partial" и "failed"
- возрастает ответственность сервисного слоя за корректную фиксацию статусов
## Alternatives considered
### 1. Полная транзакционность всей синхронизации
Отклонено, так как для больших и внешних ETL-процессов это дорого, хрупко и часто нереализуемо.
### 2. Игнорировать частичный прогресс и считать любую ошибку полным провалом
Отклонено, так как приводит к потере уже обработанного полезного результата и затрудняет recovery.
### 3. Append-only ingestion без статусов операции
Отклонено, так как делает систему непрозрачной и плохо сопровождаемой.
## Notes
Это решение напрямую зависит от:
- ADR-011 Idempotency and Retry Strategy
- ADR-013 Parser Stability and Source Change Detection

View File

@@ -0,0 +1,118 @@
# ADR-013: Parser Stability and Source Change Detection for External Sources
## Status
Accepted
## Context
Система зависит от внешних источников данных, которые находятся вне зоны контроля команды:
- государственные порталы
- HTML-страницы
- JS-heavy интерфейсы
- файловые выгрузки
- SOAP/API интеграции
- Excel/XML источники
Эти источники подвержены изменениям:
- меняется DOM-структура
- меняются URL и маршруты
- меняются названия полей
- меняется формат выгрузки
- появляются новые обязательные поля
- меняются ограничения доступа
- изменяется поведение клиентского JavaScript
Для системы такого типа изменение внешнего источника является не исключением, а ожидаемым операционным событием.
## Decision
Проект принимает стратегию parser instability as expected.
Это означает:
- каждый внешний источник считается потенциально нестабильным
- отказ парсера по причине изменения источника рассматривается как ожидаемый класс инцидента
- архитектура должна облегчать локализацию, диагностику и восстановление интеграции
### Архитектурные правила
1. Каждый источник должен быть изолирован в собственном parser/client/service слое.
2. Логика получения данных из источника не должна быть размазана по нескольким доменам без явной границы.
3. Изменение одного источника не должно ломать остальные интеграции.
4. Парсер должен быть максимально отделён от логики сохранения данных.
5. Нормализация и запись в БД не должны зависеть от деталей DOM/HTML/XML конкретного источника.
### Change detection policy
Система должна позволять определить, что проблема вызвана именно изменением внешнего источника, а не внутренней ошибкой приложения.
Минимально необходимы:
- явное логирование этапа сбоя
- логирование URL, периода, типа выгрузки или источника
- различение сетевых ошибок, ошибок структуры ответа и ошибок сохранения
- сохранение диагностического контекста для повторного анализа
### Playwright policy
Playwright допускается для источников, где:
- критическая логика формируется на клиенте
- прямой HTTP scraping недостаточен
- требуется JS rendering или пользовательская навигация
При этом Playwright считается более хрупкой интеграционной точкой по сравнению с HTTP/API клиентами.
Для Playwright-based интеграций принимаются дополнительные ограничения:
- сценарий навигации должен быть максимально коротким
- DOM-селекторы должны быть минимально хрупкими
- логика парсинга должна быть отделена от логики браузерной навигации
- fallback или быстрая диагностика деградации обязательны
### Resilience policy
При изменении внешнего источника система должна:
- завершать конкретную задачу контролируемой ошибкой
- не повреждать уже сохранённые данные
- не маскировать сбой как успешную синхронизацию
- сохранять возможность повторного запуска после исправления
### Ownership policy
Каждая интеграция с внешним источником должна иметь:
- понятную точку входа
- понятный набор задач
- понятный формат выходных данных
- наблюдаемый статус выполнения
## Consequences
### Positive
- уменьшается связность между интеграциями
- упрощается ремонт конкретного источника
- проще локализовать причину отказа
- снижается риск каскадного повреждения всей системы
- повышается операционная предсказуемость
### Negative
- возрастает количество прикладного кода и адаптеров
- приходится поддерживать отдельные контракты на источник
- растут требования к логированию и smoke-проверкам
- интеграции невозможно считать "написал один раз и забыл"
## Alternatives considered
### 1. Общий универсальный парсер для разных источников
Отклонено, так как источники сильно отличаются по протоколу, структуре и стабильности.
### 2. Встраивание логики источников прямо в задачи или view-слой
Отклонено, так как это увеличивает связность и ухудшает сопровождаемость.
### 3. Опора только на "ручное замечание", что парсер сломался
Отклонено, так как это не соответствует требованиям эксплуатационной зрелости.
## Notes
Следующим развитием данного решения должны быть:
- smoke checks для критичных источников
- классификация типов ошибок интеграции
- runbook для восстановления парсеров после изменения внешних порталов

View File

@@ -0,0 +1,81 @@
# ADR-014: API Versioning and Backward Compatibility Policy
## Status
Accepted
## Context
Система предоставляет API для:
- внутренних сервисов
- админ-панели
- потенциальных внешних интеграций
API развивается со временем:
- добавляются новые поля
- меняется структура ответов
- появляются новые эндпоинты
- изменяется бизнес-логика
Без политики версионирования возможны:
- поломка клиентов
- неявные регрессии
- невозможность безопасного развития API
## Decision
Используется versioned API через URL:
- /api/v1/
Версия API фиксируется в URL и не изменяется неявно.
### Правила изменения API
#### Разрешено (без изменения версии)
- добавление новых эндпоинтов
- добавление новых необязательных полей
- расширение enum-значений (если не ломает клиентов)
- улучшение производительности без изменения контракта
#### Запрещено без новой версии
- удаление полей
- изменение типа поля
- изменение обязательности поля
- изменение структуры ответа
- изменение семантики существующего поля
### Deprecation policy
- устаревшие эндпоинты помечаются как deprecated
- поддерживаются ограниченное время
- удаляются только после явного перехода клиентов
### Backward compatibility
Система гарантирует:
- сохранение контракта внутри одной версии API
- предсказуемое поведение для существующих клиентов
## Consequences
### Positive
- безопасное развитие API
- предсказуемость для клиентов
- снижение риска регрессий
### Negative
- необходимость поддержки старых версий
- усложнение документации
- возможный рост технического долга
## Alternatives considered
### 1. Версионирование через заголовки
Отклонено — сложнее отлаживать и документировать.
### 2. Отсутствие версионирования
Отклонено — высокий риск поломки клиентов.

View File

@@ -0,0 +1,87 @@
# ADR-015: Configuration Source of Truth and Secret Management
## Status
Accepted
## Context
Система использует множество конфигураций:
- база данных
- Redis
- Celery
- внешние API (FNS, закупки и т.д.)
- Django settings
Ошибки конфигурации приводят к:
- невозможности запуска
- некорректной работе
- утечкам секретов
Также важно:
- разделение dev/prod
- воспроизводимость окружения
- безопасность секретов
## Decision
Используется environment-based configuration.
### Источники конфигурации
1. `.env.dev` — локальная разработка
2. `.env.prod` — production
3. `.env.prod.example` — контракт обязательных переменных
4. Docker Compose — точка применения конфигурации
5. `settings.*` — логика конфигурации
### Source of Truth
- обязательные переменные определяются через `.env.*`
- структура и использование переменных — в `settings`
- значения по умолчанию должны быть минимальны
### Secret policy
- секреты НЕ хранятся в репозитории
- `.env.*` файлы не коммитятся (кроме example)
- реальные значения задаются через:
- env-файлы
- секреты инфраструктуры
- CI/CD переменные
### Fail-fast policy
При старте приложения:
- проверяется доступность DB
- проверяется Redis
- проверяются критические переменные
При ошибке:
- приложение не стартует
### Configuration constraints
- запрещено хардкодить значения в коде
- запрещено использовать разные имена переменных для одного и того же
- запрещено использовать устаревшие пути (например config.settings.*)
## Consequences
### Positive
- воспроизводимость окружения
- безопасность
- предсказуемость запуска
### Negative
- необходимость поддерживать env-файлы
- риск рассинхронизации example и реальных env
## Alternatives considered
### 1. Конфигурация через код
Отклонено — небезопасно и негибко.
### 2. Хранение секретов в репозитории
Отклонено — нарушает требования безопасности.

View File

@@ -0,0 +1,104 @@
# ADR-016: Background Job Tracking and Operational Recovery Model
## Status
Accepted
## Context
Система использует фоновые задачи для:
- парсинга данных
- синхронизации источников
- обработки файлов
Возможны сценарии:
- задача упала
- задача зависла
- задача выполнилась частично
- задача была запущена повторно
- оператору нужно вручную перезапустить процесс
Без модели трекинга задач:
- невозможно понять состояние системы
- невозможно безопасно повторить операцию
- сложно диагностировать ошибки
## Decision
Вводится явная модель отслеживания фоновых задач (BackgroundJob).
### Основные свойства задачи
Каждая задача должна иметь:
- тип (parser / sync / file processing)
- источник данных
- период или файл
- статус
- время запуска
- время завершения
- результат (успех / ошибка / частично)
- контекст выполнения
### Статусы задач
Минимальный набор:
- pending
- running
- completed
- failed
- partial
### Правила выполнения
1. Каждая бизнес-операция должна быть трассируема через job.
2. Повторный запуск не должен создавать конфликтов (см. ADR-011).
3. Статус задачи должен отражать реальное состояние, а не "успешно/не успешно".
4. Частичный успех должен фиксироваться явно.
### Recovery model
Система должна позволять:
- повторный запуск задачи за тот же период
- повторную обработку файла
- безопасный re-run без очистки БД
- диагностику причины ошибки через лог и статус
### Manual operations
Администратор должен иметь возможность:
- увидеть список задач
- понять их состояние
- повторно запустить задачу
- увидеть ошибки
### Integration with Celery
- Celery отвечает за выполнение
- BackgroundJob — за бизнес-трекинг
- ID задачи Celery связывается с доменной задачей
## Consequences
### Positive
- прозрачность фоновых процессов
- управляемость ETL
- возможность безопасного восстановления
- упрощение эксплуатации
### Negative
- дополнительный слой логики
- необходимость синхронизации статусов
- увеличение количества записей в БД
## Alternatives considered
### 1. Полагаться только на Celery task state
Отклонено — недостаточно для бизнес-анализа и recovery.
### 2. Отсутствие трекинга задач
Отклонено — делает систему неуправляемой.

20
docs/adr/ADR-INDEX.md Normal file
View File

@@ -0,0 +1,20 @@
# Architecture Decision Records (ADR)
## Index
- ADR-001: Platform Version Policy
- ADR-002: Technology Stack Selection
- ADR-003: Background Processing Architecture (Celery)
- ADR-004: Data Ingestion and ETL Strategy
- ADR-005: External Integrations Strategy
- ADR-006: Configuration and Environment Management
- ADR-007: Deployment Model (Docker Compose)
- ADR-008: Testing Strategy
- ADR-009: Observability and Health Checks
- ADR-010: Project Structure and Modularity
## Future ADRs (Proposed)
- ADR-011: Idempotency and Retry Strategy
- ADR-012: Data Deduplication and Consistency Model
- ADR-013: Parser Stability and Change Detection