Files
KArtSell.Aegis/docs/Design/kbx-foundation-v60-status-canonical-contract-hardening/docs/operations-projection-example-v6.md
T
kjh2064 3f293d8aa8
deploy / deploy (push) Successful in 1m52s
deploy / notify (push) Successful in 1s
V13-FE-006: consolidate approved UI and contract hardening
2026-08-13 02:41:00 +09:00

1.6 KiB

Source module → Operations Projection example

A source module does not call an arbitrary Exception Center REST endpoint from its domain transaction. Prefer an Outbox event and an idempotent consumer that updates the operational projection.

Example flow:

OMS AllocationFailed
  ↓ same OMS transaction
Outbox
  ↓
Operations projection consumer
  ↓
OperationsProjectionWriter.UpsertAsync
  ↓
COMMON-OPS-001

When the source condition becomes normal:

OMS AllocationSucceeded
  ↓
Outbox
  ↓
OperationsProjectionWriter.ResolveBySourceAsync

Suggested mapping:

await writer.UpsertAsync(new UpsertWorkItem(
    tenantId,
    "OMS",
    "order",
    orderId.ToString(),
    orderNo,
    "OMS-ORD-001",
    orderVersion,
    "STOCK_SHORTAGE",
    $"재고 부족 · {orderNo}",
    "출고 가능한 재고가 부족합니다.",
    "warning",
    occurredAt,
    dueAt: shipmentCutoff,
    context: new { orderNo, shortageSkuCount }), ct);

Recovery:

await writer.ResolveBySourceAsync(
    tenantId,
    "OMS",
    "order",
    orderId.ToString(),
    "STOCK_SHORTAGE",
    "재고 할당 성공",
    orderVersion,
    ct);

This keeps the source module authoritative and makes the exception center disposable/rebuildable as a projection.

Out-of-order event protection

source_version is part of the projection contract. An older or duplicate failure event must not reopen an exception after a newer recovery event has resolved it. Producers should therefore publish a monotonically increasing aggregate/source version whenever possible.