Skip to main content
Проект: Интеллектуальная система управления логистикой маркетплейсов
Модуль: Logistic / Architecture
Версия: 2.0
Дата: Февраль 2026
Заменяет: adolf_logistic_1_architecture_v1_0.md

1.1 Обзор архитектуры

Принципы проектирования

ПринципОписание
МодульностьНезависимые компоненты с чёткими интерфейсами
ОтказоустойчивостьGraceful degradation при недоступности Ozon API или файла 1С
КэшированиеМинимизация запросов к API через Redis
АсинхронностьФоновая синхронизация через Celery
Dual-sourceДва независимых источника данных: Ozon API + файловый импорт 1С
РасширяемостьПодготовка к Wildberries / Yandex.Market в v2.0

Архитектурная диаграмма


1.2 Компоненты системы

Слой адаптеров

КомпонентНазначениеТехнология
OzonLogisticAdapterЕдиная точка интеграции с Ozon Seller APIaiohttp
FileImportAdapterПарсинг XLSX/XML файлов из 1Сopenpyxl / lxml
RateLimiterКонтроль частоты запросов к Ozon APIRedis + asyncio
RetryHandlerПовторные попытки при ошибкахtenacity

Слой сервисов

СервисНазначениеВходные данныеВыходные данные
StockServiceПолучение и кэширование остатков FBO по кластерамOzon APIClusterStock[]
AnalyticsServiceПолучение аналитики продаж и оборачиваемостиOzon APISalesData[], Turnover[]
WarehouseServiceУправление списком кластеров/складовOzon APIWarehouse[]
SupplyTaskServiceCRUD наряд-заданий, workflow статусовDomain modelsSupplyTask[]
AlertServiceГенерация и отправка алертовDomain eventsAlert[]
ImportServiceИмпорт и валидация файлов 1СFileImportAdapterWarehouseStock[]

Доменный слой

КомпонентНазначениеЛогика
StockMonitorОтслеживание уровня остатков по кластерамСравнение с порогами, расчёт дней до обнуления
DemandForecasterПрогноз спроса по кластерамWeighted moving average, тренды, сезонность
SupplyCalculatorРасчёт оптимального распределенияДефицит = Прогноз − Остаток FBO − В пути
TaskGeneratorФормирование наряд-заданийПриоритизация, проверка наличия на складе 1С

1.3 Потоки данных

Поток 1: Синхронизация остатков Ozon

Поток 2: Импорт остатков 1С

Поток 3: Формирование наряд-заданий

Поток 4: Workflow наряд-задания


1.4 Интеграция с ADOLF Core

Используемые компоненты Core

Middleware интеграция

MiddlewareИспользование
AuthMiddlewareВалидация JWT/API Key
RoleMiddlewareПроверка прав доступа
BrandFilterMiddlewareФильтрация данных по brand_id
PromptInjectionMiddlewareДобавление контекста для AI

Shared PostgreSQL схема

Модуль Logistic использует:
  • Собственные таблицы с префиксом logistic_*
  • Общие таблицы Core: users, brands, notifications
  • FK связи с другими модулями минимизированы

1.5 Структура кодовой базы

adolf/
├── modules/
│   └── logistic/
│       ├── __init__.py
│       ├── config.py                 # Конфигурация модуля
│       │
│       ├── adapters/                 # Слой адаптеров
│       │   ├── __init__.py
│       │   ├── ozon_adapter.py       # OzonLogisticAdapter
│       │   ├── file_import_adapter.py # FileImportAdapter (XLSX/XML)
│       │   ├── rate_limiter.py       # RateLimiter
│       │   └── retry_handler.py      # RetryHandler
│       │
│       ├── services/                 # Слой сервисов
│       │   ├── __init__.py
│       │   ├── stock_service.py      # StockService
│       │   ├── analytics_service.py  # AnalyticsService
│       │   ├── warehouse_service.py  # WarehouseService
│       │   ├── supply_task_service.py # SupplyTaskService
│       │   ├── alert_service.py      # AlertService
│       │   └── import_service.py     # ImportService (1С)
│       │
│       ├── domain/                   # Доменный слой
│       │   ├── __init__.py
│       │   ├── models.py             # Pydantic models
│       │   ├── stock_monitor.py      # StockMonitor
│       │   ├── demand_forecaster.py  # DemandForecaster
│       │   ├── supply_calculator.py  # SupplyCalculator
│       │   └── task_generator.py     # TaskGenerator
│       │
│       ├── api/                      # FastAPI endpoints
│       │   ├── __init__.py
│       │   ├── router.py             # Main router
│       │   ├── stocks.py             # /stocks endpoints
│       │   ├── supply_tasks.py       # /supply-tasks endpoints
│       │   ├── analytics.py          # /analytics endpoints
│       │   ├── imports.py            # /imports endpoints
│       │   ├── alerts.py             # /alerts endpoints
│       │   └── schemas.py            # Request/Response schemas
│       │
│       ├── tasks/                    # Celery tasks
│       │   ├── __init__.py
│       │   ├── sync_ozon_stocks.py   # Синхронизация остатков Ozon
│       │   ├── sync_ozon_analytics.py # Синхронизация аналитики
│       │   ├── import_1c_stocks.py   # Импорт файлов 1С
│       │   ├── generate_supply_tasks.py # Генерация наряд-заданий
│       │   └── generate_alerts.py    # Генерация алертов
│       │
│       ├── db/                       # Database
│       │   ├── __init__.py
│       │   ├── models.py             # SQLAlchemy models
│       │   └── repositories.py       # Data access
│       │
│       └── owui/                     # Open WebUI integration
│           ├── __init__.py
│           ├── pipeline.py           # Pipeline handler
│           └── tools.py              # Function tools

1.6 Конфигурация

Переменные окружения

# config.py
from pydantic_settings import BaseSettings
from pathlib import Path

class LogisticSettings(BaseSettings):
    """Настройки модуля Logistic."""
    
    # Ozon API
    ozon_client_id: str
    ozon_api_key: str
    ozon_api_url: str = "https://api-seller.ozon.ru"
    
    # 1С File Import
    import_1c_path: Path = Path("/data/imports/1c")
    import_1c_archive_path: Path = Path("/data/imports/1c/archive")
    import_1c_formats: list[str] = ["xlsx", "xml"]
    import_1c_schedule_cron: str = "0 8,14 * * *"  # 08:00 и 14:00
    
    # Rate limits (requests per second)
    ozon_rps: int = 5  # Ozon default
    
    # Sync intervals (minutes)
    sync_stocks_interval: int = 30
    sync_analytics_interval: int = 1440  # daily
    sync_warehouses_interval: int = 10080  # weekly
    
    # Alert thresholds
    critical_days_threshold: int = 3      # дней до обнуления
    warning_days_threshold: int = 7
    min_stock_threshold: int = 5          # минимальный остаток шт
    
    # Forecast settings
    forecast_window_days: int = 28        # окно анализа
    forecast_horizon_days: int = 14       # горизонт прогноза
    forecast_safety_factor: float = 1.2   # коэффициент запаса
    
    # Supply task settings
    task_generation_cron: str = "0 7 * * *"  # ежедневно в 07:00
    task_auto_cancel_hours: int = 48      # автоотмена неподтверждённых
    
    # Cache TTL (seconds)
    cache_stocks_ttl: int = 1500      # 25 min
    cache_analytics_ttl: int = 3600   # 1 hour
    cache_warehouses_ttl: int = 604800  # 7 days
    
    class Config:
        env_prefix = "LOGISTIC_"

Пример .env

# Ozon API
LOGISTIC_OZON_CLIENT_ID=your_client_id
LOGISTIC_OZON_API_KEY=your_api_key

# 1С Import
LOGISTIC_IMPORT_1C_PATH=/data/imports/1c
LOGISTIC_IMPORT_1C_SCHEDULE_CRON=0 8,14 * * *

# Thresholds
LOGISTIC_CRITICAL_DAYS_THRESHOLD=3
LOGISTIC_WARNING_DAYS_THRESHOLD=7
LOGISTIC_MIN_STOCK_THRESHOLD=5

# Forecast
LOGISTIC_FORECAST_WINDOW_DAYS=28
LOGISTIC_FORECAST_SAFETY_FACTOR=1.2

1.7 Кэширование

Стратегия кэширования

ДанныеХранилищеTTLКлюч Redis
Остатки FBO по кластерамRedis25 минlogistic:ozon:stocks:{date}
Аналитика продажRedis1 часlogistic:ozon:analytics:{date}
ОборачиваемостьRedis1 часlogistic:ozon:turnover:{date}
Список кластеровRedis7 днейlogistic:ozon:warehouses
Остатки 1СRedisдо след. импортаlogistic:1c:stocks:{import_id}

Структура кэша остатков по кластерам

# Redis key: logistic:ozon:stocks:2026-02-06
{
    "updated_at": "2026-02-06T10:30:00Z",
    "source": "ozon_api",
    "clusters": [
        {
            "cluster_name": "Москва, МО и Дальние регионы",
            "items": [
                {
                    "sku": 924771727,
                    "article": "51005/54",
                    "product_name": "Шорты Ohana market Стильно и модно",
                    "fbo_stock": 12,
                    "fbs_stock": 0,
                    "in_transit": 0,
                    "avg_daily_sales": 5.2,
                    "days_to_zero": 2
                }
            ]
        }
    ]
}

Структура кэша остатков 1С

# Redis key: logistic:1c:stocks:imp_20260206_0800
{
    "import_id": "imp_20260206_0800",
    "imported_at": "2026-02-06T08:00:00Z",
    "source_file": "stocks_20260206.xlsx",
    "items": [
        {
            "article": "51005/54",
            "product_name": "Шорты Стильно и модно",
            "warehouse_stock": 340,
            "unit": "шт"
        }
    ]
}

Cache-aside pattern


1.8 Обработка ошибок

Типы ошибок

ОшибкаИсточникКодОбработка
OzonAPIErrorOzon API500Retry с exponential backoff
OzonRateLimitErrorOzon API429Ожидание, затем retry
OzonAuthErrorOzon API401/403Алерт администратору
FileImportError1С файлЛогирование, алерт, пропуск файла
FileFormatError1С файлЛогирование, уведомление
SKUMappingErrorМаппингЛогирование, пропуск записи
DataValidationErrorЛюбой422Логирование, пропуск записи
CacheErrorRedisFallback на прямой запрос

Retry стратегия

from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=4, max=60),
    retry=retry_if_exception_type(OzonAPIError)
)
async def fetch_stocks(self) -> list[ClusterStock]:
    """Получение остатков с retry."""
    ...

Circuit Breaker

Обработка ошибок файлового импорта 1С


1.9 Мониторинг и логирование

Метрики (Prometheus)

МетрикаТипОписание
logistic_ozon_api_requests_totalCounterОбщее число запросов к Ozon API
logistic_ozon_api_errors_totalCounterОшибки Ozon API
logistic_ozon_api_latency_secondsHistogramЛатентность запросов
logistic_stocks_sync_duration_secondsHistogramВремя синхронизации остатков
logistic_1c_imports_totalCounterКоличество импортов 1С
logistic_1c_import_errors_totalCounterОшибки импорта 1С
logistic_supply_tasks_generated_totalCounterСгенерированные наряд-задания
logistic_supply_tasks_completed_totalCounterВыполненные наряд-задания
logistic_alerts_generated_totalCounterСгенерированные алерты
logistic_cluster_deficit_totalGaugeТекущий дефицит по кластерам

Структурированное логирование

import structlog

logger = structlog.get_logger("logistic")

# Пример: синхронизация остатков
logger.info(
    "ozon_stocks_synced",
    sku_count=2400,
    cluster_count=31,
    duration_ms=4200,
    cache_updated=True
)

# Пример: импорт 1С
logger.info(
    "1c_import_completed",
    file="stocks_20260206.xlsx",
    records_total=2400,
    records_imported=2380,
    records_skipped=20,
    duration_ms=1200
)

# Пример: наряд-задание
logger.info(
    "supply_tasks_generated",
    date="2026-02-06",
    tasks_total=20,
    priority_urgent=3,
    priority_planned=5,
    priority_recommended=12,
    total_quantity=847
)

1.10 Безопасность

API ключи Ozon

АспектРеализация
ХранениеПеременные окружения / Vault
ФорматClient-Id + Api-Key (два параметра)
ПередачаHTTP заголовки Client-Id, Api-Key
РотацияПоддержка hot-reload конфигурации
АудитЛогирование всех API-вызовов

Безопасность файлового импорта

АспектРеализация
Директория импортаОграниченные права доступа (0750)
Валидация файловПроверка расширения, размера, структуры
Максимальный размер50 МБ
КарантинНекорректные файлы перемещаются в /quarantine
АрхивированиеОбработанные файлы → /archive с timestamp

Доступ к данным


1.11 Масштабирование

Горизонтальное масштабирование

КомпонентСтратегия
APIStateless, несколько инстансов за LB
Celery WorkersУвеличение числа воркеров
RedisCluster mode (при необходимости)
PostgreSQLRead replicas (v2.0)
Файловый импортОдин обработчик, очередь файлов

Ограничения Ozon API

АспектЗначениеСтратегия
Rate limit~5 RPS (базовый)Регулируемый RateLimiter
Premium rate limitРасширенныйНастройка при наличии Premium
Пагинацияoffset/limit, cursorАвтоматическая обработка
Размер ответаДо 1000 записейПагинация с аккумуляцией

1.12 Диаграмма развёртывания


1.13 Зависимости

Python пакеты

# requirements-logistic.txt
aiohttp>=3.9.0
tenacity>=8.2.0
redis>=5.0.0
celery>=5.3.0
structlog>=24.1.0
pydantic>=2.5.0
sqlalchemy>=2.0.0
openpyxl>=3.1.0      # XLSX parsing (1С)
lxml>=5.0.0           # XML parsing (1С)
numpy>=1.26.0         # Demand forecasting

Внутренние зависимости

МодульЗависимостьТип
CoreMiddleware, PostgreSQL, Redis, Celery, NotificationsHard
CFOОтправка данных о логистических издержкахSoft (v2.0)
ScoutПолучение прогнозов продажSoft (v2.0)

1.14 Структура файлов модуля

/app/modules/logistic/
├── __init__.py
├── config.py
├── adapters/
│   ├── __init__.py
│   ├── ozon_adapter.py
│   ├── file_import_adapter.py
│   ├── rate_limiter.py
│   └── retry_handler.py
├── services/
│   ├── __init__.py
│   ├── stock_service.py
│   ├── analytics_service.py
│   ├── warehouse_service.py
│   ├── supply_task_service.py
│   ├── alert_service.py
│   └── import_service.py
├── domain/
│   ├── __init__.py
│   ├── models.py
│   ├── stock_monitor.py
│   ├── demand_forecaster.py
│   ├── supply_calculator.py
│   └── task_generator.py
├── api/
│   ├── __init__.py
│   ├── router.py
│   ├── stocks.py
│   ├── supply_tasks.py
│   ├── analytics.py
│   ├── imports.py
│   ├── alerts.py
│   └── schemas.py
├── tasks/
│   ├── __init__.py
│   ├── sync_ozon_stocks.py
│   ├── sync_ozon_analytics.py
│   ├── import_1c_stocks.py
│   ├── generate_supply_tasks.py
│   └── generate_alerts.py
├── db/
│   ├── __init__.py
│   ├── models.py
│   └── repositories.py
└── owui/
    ├── __init__.py
    ├── pipeline.py
    └── tools.py

Документ подготовлен: Февраль 2026
Версия: 2.0
Статус: Черновик
Заменяет: adolf_logistic_1_architecture_v1_0.md