Модуль 10.4. Web/e-commerce/логистика
Темы: корзина, платежи, SLA доставки, трекинг, возвраты. Артефакты: 4 доменных мини-проекта с шаблонами. Практика: BPMN full-cycle заказа.
В e-commerce системный аналитик (SA) держит всю цепочку «от клика до склада и денег»: корзина → чекаут → платёж → фулфилмент → доставка/трекинг → возврат/рефанд → отчётность. В модуле — «производственные» шаблоны артефактов, контракты API/событий, модели данных, DMN-правила SLA, риски и чек-листы.
Доменная карта (минимум, который обязан знать SA)
Сущности:
Cart, CartItem, Offer/Price, Promotion, Order, OrderItem, Address, Payment, Shipment, Parcel, FulfillmentTask (pick/pack), Carrier, TrackingEvent, Return (RMA), Refund, Stock, Warehouse.
Главные статусы:
- Order: DRAFT → PLACED → PAID → FULFILLING → SHIPPED → DELIVERED → CLOSED (+ ветви CANCELLED/RETURN_REQUESTED/RETURNED/REFUNDED).
- Payment: NEW → AUTHORIZING → AUTHORIZED → CAPTURED/FAILED/REFUNDED.
- Shipment/Parcel: CREATED → IN_TRANSIT → OUT_FOR_DELIVERY → DELIVERED/FAILED.
- Return: REQUESTED → AWAITING_ITEM → RECEIVED → INSPECTED → APPROVED/REJECTED → REFUNDED.
Ключевые принципы:
идемпотентность (Idempotency-Key), корреляция (Correlation-Id), обещанная дата (Promised Delivery Date) ≠ фактическая (Actual), DMN для правил, CDC в DWH, наблюдаемость RED/USE.
NFR/качество (ориентиры)
- Корзина: GET/POST p95 < 200–350 мс, стабильность при 50–200 RPS; кэширование цен/акций.
- Чекаут/оплата: POST /orders p95 < 600–900 мс (без вызова PSP); при таймауте PSP — 202 и фоновый поток.
- Расчёт SLA: синхронный p95 < 200 мс (предрассчитанные матрицы/срезы).
- Трекинг: приём вебхуков 99.9%/кв., дедупликация по carrierRef+eventTime.
- Возвраты: рефанд ≤ 5 рабочих дней (конфигурируемо).
- Аудит/PII: маскирование, срок хранения логов ≥ 180 дней (или по политике).
Модели данных (фрагмент ER)
- Order(orderId PK, customerId, status, promisedDeliveryAt, placedAt, total, currency, …)
- OrderItem(orderItemId PK, orderId FK, sku, qty, unitPrice, discount, warehouseId, …)
- Payment(paymentId PK, orderId, status, method, amount, currency, pspRef, …)
- Shipment(shipmentId PK, orderId, status, carrierCode, serviceLevel, promisedDeliveryAt, …)
- Parcel(parcelId PK, shipmentId, trackingNumber, weight, dims, …)
- TrackingEvent(id PK, parcelId, carrierCode, status, eventTime, location, rawPayloadHash)
- Return(rmaId PK, orderId, status, reasonCode, method, labelUrl, …)
- Refund(refundId PK, rmaId/paymentId, amount, status, method, postedAt, …)
Контракты API (образцы)
Корзина/цены/акции
POST /v1/carts/{cartId}/items
Headers: Idempotency-Key
Body: { sku, qty, priceListId?, promoCodes?[] }
→ 200 { cartTotals, items[], promotionsApplied[] } | 409 DUPLICATE | 422 VALIDATION
- Правила рассчёта: промо-движок (DMN/decision tables), приоритеты, стоп-условия, стек скидок (stackable vs exclusive), налоги.
Чекаут/заказ
POST /v1/orders
Headers: Idempotency-Key, X-Correlation-Id
Body: { cartId, customer, shippingAddress, billingAddress, deliveryOptionId, paymentMethod, agreeToTerms }
→ 201 { orderId, status=PLACED, promisedDeliveryAt, amountToPay } | 422 | 409
- Резервы: мягкий (soft) при создании, жёсткий — перед отгрузкой.
- Антифрод: скоринг (ALLOW/CHALLENGE/DENY) — ветка CHALLENGE ⇒ 3DS/доп. проверка.
Платёж
POST /v1/payments
→ 201 AUTHORIZED | 202 Accepted (PSP timeout) | 4xx
POST /v1/payments/{id}/capture → 200 CAPTURED
POST /v1/payments/{id}/refund → 201 REFUND_REQUESTED/REFUNDED
- Идемпотентность: по ключу + уникальность в БД; событие payment.captured.v1.
Доставка/слоты/SLA
GET /v1/delivery/options?address&cartWeight&cartDims&cutoffAt
→ [{ optionId, carrierCode, serviceLevel, price, promisedDeliveryAt, sla: {min,max}, cutoffAt }]
- Слоты: интервал/квоты; DMN: регион × вес × склад × cutoff.
рекинг/вебхуки
POST /v1/tracking/webhook/{carrierCode}
Body: { trackingNumber, status, eventTime, location, ... }
→ 202 (обяз. дедуп по (carrierCode,trackingNumber,eventTime,rawHash))
Возвраты (RMA)
POST /v1/returns
Body: { orderId, items[{orderItemId, qty, reasonCode}], method: "COURIER_PICKUP"|"DROP_OFF", photos?[] }
→ 201 { rmaId, labelUrl?, pickupSlot? }
События (event-driven каталог, выдержки)
-
cart.updated.v1, order.placed.v1, order.paid.v1, fulfillment.started.v1,
shipment.created.v1, parcel.tracking.updated.v1, order.delivered.v1,
return.requested.v1, return.received.v1, refund.issued.v1.
Поля: eventId, occurredAt, correlationId, sourceSystem, ...payload…. Эволюция — additive-only, semver.
SLA доставки: логика и DMN
Факторы
- Cut-off (время закрытия сборки), регион/зона (S/D/EU), доступный склад, вес/габариты, уровень сервиса (Std/Exp/SameDay), праздники, квоты слотов.
Таблица решений (DMN, hit policy F)
|
zone |
service |
beforeCutoff? |
onStock? |
promisedMin |
promisedMax |
|---|---|---|---|---|---|
|
A |
SameDay |
true |
true |
today 20:00 |
today 22:00 |
|
A |
Exp |
true |
true |
+1d |
+1d |
|
B |
Std |
true |
true |
+2d |
+3d |
|
* |
* |
false |
* |
+1d к каждому |
+1d к каждому |
|
* |
* |
* |
false |
+N (перевоз со склада Y) |
+N+1 |
Пост-обработка: перенос с учётом праздников (календарь), округление до слотов.
Фулфилмент и логистика (потоки)
- Fulfilling: picklist → сборка → верификация → упаковка → ярлык/штрихкод → handover перевозчику.
- Split-shipment: если нет всего ассортимента — разбиваем заказ (несколько Shipment).
- Курьер/ПВЗ/почта: разные SLA, статусы и вебхуки.
- Трекинг: приводим статусы перевозчиков к собственному словарю (IN_TRANSIT, DELAYED, ADDRESS_ISSUE, …).
- Исключения: возврат на склад (RTS), потеря, частичная доставка.
Возвраты: политика и расчёт рефанда
- Методы: курьерский забор, ПВЗ, почта; предоплаченная этикетка.
- Проверки: состояние/комплектность; опционально — фото-верификация на входе.
- Правила денег: удержания (доставка не возвращается?), «restocking fee», частичный возврат.
- Рефанд: по исходному методу (card/original PSP) или на кошелёк/баланс.
- События: return.received.v1 → refund.issued.v1 → обновление order.balance.
Риски и контр-меры
|
Риск |
Проявление |
Меры |
|---|---|---|
|
Перепродажа (oversell) |
Заказ есть, товара нет |
Резервы/квоты, «серый» stock, алерты несоответствия |
|
Таймаут PSP |
«Висит» статус |
202 + ретраи, идемпотентность, события «pending» |
|
Неверный SLA |
Срывы доставки |
DMN + календари, измерение promise vs actual, компенсации |
|
Дубликаты трекинга |
Двойные события |
Дедуп по (carrierRef,eventTime,hash) |
|
Адресные ошибки |
Возвраты курьера |
Валидация адреса (сервис), интерактивные подсказки |
|
Фрод-возвраты |
«Пустые коробки» |
Фото до/после, выборочные вскрытия, blacklists |
|
PII в событиях |
Утечки |
Мин. атрибуты, маскирование, RLS/CLS |
|
Неучтённые разрезы цен |
Неверный чек |
Единый SoT прайс/промо, версионирование правил |
Артефакты: 4 мини-проекта (с шаблонами)
Mini-проект A. Корзина и прайсинг
Скоуп: добавление/удаление товара, цены/акции, пересчёт тоталов, доставка-квоты.
Артефакты:
- SRS-скелет: цели, словарь промо, AC к POST /carts/*.
- DMN: правила скидок (приоритеты/стоп).
- API: /carts/{id}/items, /pricing/quote.
- События: cart.updated.v1.
-
Тест-набор: 10 позитивов/10 негативов (несовместимые скидки, лимиты).
Риски: гонки (конкурентное изменение корзины) → ETag/версионность.
Mini-проект B. Чекаут и платежи
Скоуп: создание заказа, антифрод, авторизация/капчур, идемпотентность.
Артефакты:
- Sequence «POST /orders + POST /payments».
- OpenAPI платежей (идемпотентность, коды ошибок).
- NFR: p95/timeout, fallback 202.
-
События: order.placed.v1, order.paid.v1.
Риски: дубликаты/частичные ошибки → outbox, реестр идемпотентности.
Mini-проект C. Доставка и SLA/трекинг
Скоуп: опции доставки, формирование отгрузок, трекинг, SLA-метрики.
Артефакты:
- DMN «обещанная дата».
- API: /delivery/options, /tracking/webhook/*.
- Модели: Shipment/Parcel/TrackingEvent.
-
Дашборд: promise_vs_actual, on-time%, лаги трекинга.
Риски: рассинхрон с перевозчиками → маппинг статусов/перекодировка.
Mini-проект D. Возвраты и рефанды (RMA)
Скоуп: оформление RMA, этикетки, приёмка, инспекция, рефанд.
Артефакты:
- BPMN «Возврат (курьер/ПВЗ)».
- API: /returns, /refunds.
- Таблица правил удержаний (DMN).
-
События: return.requested.v1, refund.issued.v1.
Риски: «no-fault found» → политика частичного рефанда.
Чек-лист SA (коротко)
- Единый словарь статусов и маппинг перевозчиков.
- Idempotency/Correlation в каждом контракте.
- DMN для SLA и промо; версии и CHANGELOG.
- События по ключевым переходам; outbox; дедуп.
- Метрики: p95, error-rate, promise vs actual, % on-time, возвратность.
- DQ: валюта, суммы, штрихкоды, адреса; quarantine.
- Безопасность: PII-минимизация, RLS/CLS, аудит.
- DWH/BI: CDC платежей/заказов/треков, словарь метрик.
Практика: BPMN full-cycle заказа (90–150 мин)
Задание: нарисуйте BPMN от момента «Добавить в корзину» до «Рефанд завершён».
Пулы/лейны: Покупатель, Web/Checkout, Payments, Warehouse, Carrier, Returns, Accounting.
Ключевые элементы:
- Таймер cut-off перед задачей «Сборка».
- Пограничные события ошибок PSP/Carrier (timeout, decline).
- Подпроцесс «Split shipment» (мульти-инстанс).
- Сообщения/события: order.paid, shipment.created, tracking.updated, return.received, refund.issued.
-
Компенсации: отмена резерва/этикетки при CANCELLED.
Критерии зачёта: альтернативные ветви (decline, timeout, недоставка), точки SLA, точки метрик, финальные состояния.
Можно оформить как BPMN XML/диаграмму в Miro/FigJam/PlantUML-псевдо-BPMN, но обязательно показать таймеры, гейтвеи, ошибки и сообщения.
Вопрос–Ответ
В: Что хранить в событиях трекинга, чтобы не «убить» приватность?
О: Минимум: trackingNumber (токенизирован), status, eventTime, location (обобщённо), carrierCode, correlationId, hash raw. Не хранить персональные данные адресата.
В: Как обещать дату доставки честно?
О: Правила в DMN + календари + квоты слотов. Меряйте promise_vs_actual, вводите «компенсации» и контролируйте cut-off.
В: Что делать при таймауте PSP?
О: Возвращать 202, ставить задачу в очередь, публиковать payment.pending, делать ретраи (джиттер), показывать UX «Ожидаем подтверждение до N мин».
В: Как избежать дубликатов при вебхуках перевозчика?
О: Дедуп-реестр (carrier, trackingNumber, eventTime, hash), идемпотентная обработка, защита от re-delivery.
В: Возврат частичный: как считать рефанд?
О: По позициям (qty), пропорция скидок, удержания (доставка/фулфилмент, если политика позволяет), налоги. Правила — в DMN и в SRS.
В: Когда резервы делаем «жёсткими»?
О: Перед печатью этикетки/отгрузкой. До этого — soft-hold с таймером на освобождение.
Шпаргалка
- Вертикали: корзина → заказ → платёж → фулфилмент → доставка → возврат → деньги.
- Везде — идемпотентность, события, метрики.
- DMN: промо и SLA. BPMN: полный цикл + ошибки/компенсации.
- Promise vs Actual — главная логистическая метрика.
- Минимизируйте PII в логах/событиях, соблюдайте RLS/CLS.



