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
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:
47
docs/adr/ADR-001: Platform Version Policy.md
Normal file
47
docs/adr/ADR-001: Platform Version Policy.md
Normal 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 — отклонено (несовместимо с контуром)
|
||||
39
docs/adr/ADR-002: Technology Stack Selection.md
Normal file
39
docs/adr/ADR-002: Technology Stack Selection.md
Normal 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 — избыточен для текущего контура
|
||||
38
docs/adr/ADR-003: Background Processing Architecture.md
Normal file
38
docs/adr/ADR-003: Background Processing Architecture.md
Normal 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 — отклонены (меньше зрелости)
|
||||
34
docs/adr/ADR-004: Data Ingestion and ETL Strategy.md
Normal file
34
docs/adr/ADR-004: Data Ingestion and ETL Strategy.md
Normal 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
|
||||
- сложность поддержки парсеров
|
||||
- необходимость ручного восстановления
|
||||
30
docs/adr/ADR-005: External Integrations Strategy.md
Normal file
30
docs/adr/ADR-005: External Integrations Strategy.md
Normal 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
|
||||
- высокая хрупкость
|
||||
- зависимость от изменений внешних систем
|
||||
25
docs/adr/ADR-006: Configuration Strategy.md
Normal file
25
docs/adr/ADR-006: Configuration Strategy.md
Normal 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
|
||||
24
docs/adr/ADR-007: Deployment Model.md
Normal file
24
docs/adr/ADR-007: Deployment Model.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# ADR-007: Deployment Model
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
Ограниченный контур без Kubernetes.
|
||||
|
||||
## Decision
|
||||
|
||||
Используется Docker Compose:
|
||||
|
||||
- dev — полный стек
|
||||
- prod — только сервисы (без DB/Redis)
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- простота деплоя
|
||||
- воспроизводимость
|
||||
|
||||
### Negative
|
||||
- ограниченная масштабируемость
|
||||
27
docs/adr/ADR-008: Testing Strategy.md
Normal file
27
docs/adr/ADR-008: Testing Strategy.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# ADR-008: Testing Strategy
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
Нужно тестировать:
|
||||
- бизнес-логику
|
||||
- парсеры
|
||||
- фоновые задачи
|
||||
|
||||
## Decision
|
||||
|
||||
- тесты вне src
|
||||
- pytest
|
||||
- отдельные скрипты запуска
|
||||
- режим "production-like"
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- изоляция тестов
|
||||
- удобство CI
|
||||
|
||||
### Negative
|
||||
- сложность настройки среды
|
||||
24
docs/adr/ADR-009: Observability.md
Normal file
24
docs/adr/ADR-009: Observability.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# ADR-009: Observability and Health Checks
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
Необходим контроль состояния системы.
|
||||
|
||||
## Decision
|
||||
|
||||
- /health
|
||||
- /health/live
|
||||
- /health/ready
|
||||
- логирование через Docker
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- готовность к оркестрации
|
||||
- диагностика проблем
|
||||
|
||||
### Negative
|
||||
- ограниченная глубина мониторинга
|
||||
30
docs/adr/ADR-010: Project Structure.md
Normal file
30
docs/adr/ADR-010: Project Structure.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# ADR-010: Project Structure and Modularity
|
||||
|
||||
## Status
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
Проект должен быть:
|
||||
- расширяемым
|
||||
- читаемым
|
||||
|
||||
## Decision
|
||||
|
||||
Структура:
|
||||
|
||||
- apps/
|
||||
- core
|
||||
- user
|
||||
- parsers
|
||||
- core/
|
||||
- settings/
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- модульность
|
||||
- понятная навигация
|
||||
|
||||
### Negative
|
||||
- возможная связность между модулями
|
||||
128
docs/adr/ADR-011: Idempotency and Retry Strategy.md
Normal file
128
docs/adr/ADR-011: Idempotency and Retry Strategy.md
Normal 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
|
||||
|
||||
Следующими связанными решениями должны быть:
|
||||
- политика дедупликации данных
|
||||
- модель частичной загрузки и фиксации прогресса
|
||||
- политика конкурентного запуска задач
|
||||
133
docs/adr/ADR-012: Data Consistency Model.md
Normal file
133
docs/adr/ADR-012: Data Consistency Model.md
Normal 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
|
||||
118
docs/adr/ADR-013: Parser Stability Strategy.md
Normal file
118
docs/adr/ADR-013: Parser Stability Strategy.md
Normal 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 для восстановления парсеров после изменения внешних порталов
|
||||
@@ -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. Отсутствие версионирования
|
||||
Отклонено — высокий риск поломки клиентов.
|
||||
@@ -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. Хранение секретов в репозитории
|
||||
Отклонено — нарушает требования безопасности.
|
||||
@@ -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
20
docs/adr/ADR-INDEX.md
Normal 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
|
||||
Reference in New Issue
Block a user