Delivery — operator runbook
Операционное руководство для P2c DeliveryRule aggregate (см. ADR-0038).
Feature flags
Engine + admin HTTP + readiness probe — always on. P1 stub retired в commit c028439. Master flags нет.
Env vars
| Var | Default | Tuning |
|---|---|---|
DELIVERY_SNAPSHOT_POLL_INTERVAL | 10s | Incremental fetch cadence. |
DELIVERY_SNAPSHOT_FULL_RELOAD_INTERVAL | 5m | Полный rebuild snapshot — safety net. |
JWT admin role: delivery_admin (отдельная permission boundary от pricing_admin / stock_admin).
Readiness
delivery.snapshot health.Checker fails until PollingLoader.Bootstrap completes.
Метрики (counters)
| Metric | Labels | Source |
|---|---|---|
delivery_snapshot_reload_total | mode ∈ {incremental, full} × result ∈ {ok, failed} | PollingLoader.tick / fullReload |
delivery_outbox_emit_total | event_kind × result | CrudService.runInTxAndEmit |
delivery_overlap_conflicts_total | — | OverlapValidator.Check |
delivery_rule_mutations_total | event_kind × result | CrudService post-commit |
Rule kinds
4 transformation типа:
| Kind | Что делает |
|---|---|
carrier_filter | Allowlist OR blocklist по carrier name. Mismatch → outcome.Status=rejected, reason=carrier_blocked. |
lead_time_override | Mode: absolute (Min+Max) / add_days (signed) / multiply (>0). Применяется к baseline lead_time. |
logistics_markup | Cost compute: flat (FlatAmount) / per_warehouse (× warehouse count). per_kg отложен до Phase 5+ (нет weight ingestion). |
free_delivery_threshold | Когда order_value (Price.Base × qty) ≥ MinOrderValue → Cost = 0. |
Engine применяет в canonical порядке: carrier_filter → lead_time_override → logistics_markup → free_delivery_threshold.
Triage
| Симптом | Шаг |
|---|---|
/readyz красный, причина delivery.snapshot | Проверить PG. Если PG жив — глянуть delivery.snapshot.bootstrap slog event. |
Шквал delivery.metrics.overlap_conflict | Operators ставят пересекающиеся правила. Глянуть DeliveryRuleConflictDetected outbox events. |
| Operator: «cost не считается» | Проверить что logistics_markup rule active в snapshot. Cost nil без markup — by design (downstream interpret как “carrier handles”). |
free_delivery_threshold not applied при large order | Currency mismatch: MinOrderValue.Currency() != Price.Base.Currency(). ExchangeRate не выполняется в P2c (defer to P6a). |
per_kg mode rejected при Validate | By design в P2c — нет upstream weight data. Phase 5+ unblock. |