Перейти к содержанию

Контракт: warehouse/inventory

Метаданные

  • Namespace: warehouse
  • Name: inventory
  • Version: 1.2.0
  • Owner: warehouse-team
  • Email: warehouse-data@company.ru
  • Mattermost: #warehouse-alerts

Описание

Актуальные остатки товаров на складах. Данные обновляются в реальном времени при каждом движении товара (приход, расход, перемещение, списание).

Используется для:

  • Проверки доступности при оформлении заказов
  • Планирования закупок
  • Аналитики по движению товаров
  • Алертов о низких остатках

Kafka Topics

Topic Описание Retention
warehouse.inventory.raw Сырые данные из WMS 7 дней
warehouse.inventory.prod Провалидированные данные 30 дней
warehouse.inventory.dlq Проблемные записи 90 дней

Schema (Avro)

schema.avsc
{
  "type": "record",
  "name": "Inventory",
  "namespace": "warehouse.inventory",
  "doc": "Складские остатки товаров",
  "fields": [
    {
      "name": "snapshot_id",
      "type": "string",
      "doc": "Уникальный ID снэпшота (формат: snap_XXXXXXXXXXXXXXXX)"
    },
    {
      "name": "sku",
      "type": "string",
      "doc": "Артикул товара (Stock Keeping Unit)"
    },
    {
      "name": "warehouse_id",
      "type": "string",
      "doc": "ID склада (формат: wh_XXXXXX)"
    },
    {
      "name": "warehouse_name",
      "type": "string",
      "doc": "Название склада"
    },
    {
      "name": "quantity_available",
      "type": "int",
      "doc": "Доступное количество товара"
    },
    {
      "name": "quantity_reserved",
      "type": "int",
      "doc": "Зарезервированное количество"
    },
    {
      "name": "quantity_total",
      "type": "int",
      "doc": "Общее количество на складе"
    },
    {
      "name": "unit",
      "type": {"type": "enum", "name": "Unit", "symbols": ["pcs","kg","l","m","m2","m3"]},
      "doc": "Единица измерения"
    },
    {
      "name": "last_movement_type",
      "type": ["null", {"type": "enum", "name": "MovementType", "symbols": ["receipt","shipment","transfer_in","transfer_out","adjustment","write_off"]}],
      "doc": "Тип последнего движения товара"
    },
    {
      "name": "last_movement_at",
      "type": ["null", {"type": "long", "logicalType": "timestamp-millis"}],
      "doc": "Время последнего движения"
    },
    {
      "name": "snapshot_at",
      "type": {"type": "long", "logicalType": "timestamp-millis"},
      "doc": "Время создания снэпшота"
    },
    {
      "name": "cost_price",
      "type": ["null", {"type": "bytes", "logicalType": "decimal", "precision": 10, "scale": 2}],
      "doc": "Себестоимость единицы (RUB)"
    },
    {
      "name": "location_zone",
      "type": ["null", "string"],
      "doc": "Зона хранения на складе"
    },
    {
      "name": "location_row",
      "type": ["null", "string"],
      "doc": "Ряд хранения"
    },
    {
      "name": "location_shelf",
      "type": ["null", "string"],
      "doc": "Полка хранения"
    }
  ]
}

Quality Rules

Critical (error)

  • snapshot_id — не null
  • sku — не null
  • warehouse_id — не null
  • quantity_available — не null, >= 0
  • quantity_reserved — >= 0
  • quantity_total — >= 0
  • snapshot_at — не null, не старше 5 минут (freshness)
  • snapshot_id — уникальный в батче
  • quantity_total == quantity_available + quantity_reserved (consistency)
  • quantity_reserved <= quantity_total (consistency)

Warnings

  • quantity_total — предупреждение если > 1 000 000 (аномально большое количество)
  • quantity_available — предупреждение если = 0

Уникальность consistency checks

В отличие от sales/orders, контракт warehouse/inventory имеет custom-выражения для проверки согласованности количеств:

- name: "total_equals_sum"
  type: "custom"
  expression: "quantity_total == quantity_available + quantity_reserved"
  severity: "error"

SLA

Availability

  • Target: 99.9%
  • Schedule: 24/7
  • Maintenance: Воскресенье 03:00-04:00 MSK

Freshness

Критически важная свежесть

Данные об остатках критичны для операций — максимальный возраст 5 минут.

  • Max age: 5 минут
  • Alert threshold: 10 минут
  • Critical threshold: 30 минут

Response Time

Priority Response Recovery
Critical 15 мин 2 часа
High 1 час 4 часа
Medium 4 часа
Low 1 день

Retention

Layer Duration Storage
Kafka raw 7 дней Kafka
Kafka prod 30 дней Kafka
Kafka DLQ 90 дней Kafka
DWH hot 1 год SSD
DWH warm 3 года HDD
DWH cold 7 лет S3 Glacier

Physical Layout (Iceberg)

Partitioning

strategy: "iceberg_hidden"
spec:
  - source_column: "snapshot_at"
    transform: "day"         # Партиция по дню

  - source_column: "warehouse_id"
    transform: "identity"    # По складу

Sort Order

columns:
  - column: "sku"
    direction: "asc"

  - column: "snapshot_at"
    direction: "desc"

Parquet Settings

  • Compression: ZSTD level 3 (~4.5x)
  • Row group size: 128 MB
  • Dictionary encoding: warehouse_id, warehouse_name, unit, last_movement_type, location_zone
  • Bloom filters: snapshot_id (1%), sku (1%), warehouse_id (5%)

Типичные запросы

SELECT sku, warehouse_id, quantity_available, snapshot_at
FROM warehouse.inventory
WHERE sku = 'SKU123'
  AND snapshot_at >= CURRENT_DATE
ORDER BY snapshot_at DESC
LIMIT 1
SELECT 
  warehouse_id, warehouse_name,
  SUM(quantity_available) as total_available,
  SUM(quantity_reserved) as total_reserved,
  MAX(snapshot_at) as last_update
FROM warehouse.inventory
WHERE snapshot_at >= CURRENT_TIMESTAMP - INTERVAL 1 HOUR
GROUP BY warehouse_id, warehouse_name
SELECT sku, warehouse_id, quantity_available
FROM warehouse.inventory
WHERE quantity_available < 10
  AND snapshot_at >= CURRENT_DATE

Consumers

System Team Usage Criticality
Order Service sales-team Проверка доступности critical
Purchasing System purchasing-team Планирование закупок high
Analytics Dashboard analytics Аналитика остатков medium

Lineage

graph LR
    A[WMS<br/>PostgreSQL] -->|CDC| B[API Gateway<br/>mTLS + Avro]
    B --> C[warehouse.inventory.raw]
    C --> D[Quality<br/>Validator]
    D --> E[warehouse.inventory.prod]
    D --> F[warehouse.inventory.dlq]
    E --> G[Order Service]
    E --> H[Clickhouse DWH]
    E --> I[S3 Data Lake]

    style D fill:#FF9800
    style F fill:#F44336

История версий

v1.2.0 (2026-01-24)

  • Добавлены поля location_zone, location_row, location_shelf
  • Добавлено поле cost_price
  • Breaking: Нет

v1.1.0 (2025-12-15)

  • Добавлено поле last_movement_type
  • Добавлено поле last_movement_at
  • Breaking: Нет

v1.0.0 (2025-08-01)

  • Первая версия контракта

Ссылки