معماری چندکسب‌وکاری، تجاری و تجارت الکترونیک · فصل ۷ — Connector، Order، Packing، Barcode، Carrier و Notification · 271

Order State Machine

workflow تجاری را به UI یا integration منفرد تقلیل می‌دهد و state، rights، approval و measurement را یکپارچه نمی‌کند. موضوع جاری: «Order State Machine». می‌تواند «Order State Machine» را برای یک workflow محدود با state/contract/approval و verification مناسب طراحی کند.

Order State Machine — en-US

خلاصهٔ درس

workflow تجاری را به UI یا integration منفرد تقلیل می‌دهد و state، rights، approval و measurement را یکپارچه نمی‌کند. موضوع جاری: «Order State Machine».

می‌تواند «Order State Machine» را برای یک workflow محدود با state/contract/approval و verification مناسب طراحی کند.

خروجی این درس

می‌تواند «Order State Machine» را برای یک workflow محدود با state/contract/approval و verification مناسب طراحی کند.

پیش‌نیازها

وقتی یک status باید پنج حقیقت متفاوت را نمایندگی کند، سیستم می‌شکند

یک سفارش ساعت ۱۰ پرداخت می‌شود. ساعت ۱۰:۰۵ fulfillment شروع می‌شود. ساعت ۱۰:۱۱ یک webhook قدیمی می‌گوید payment failed و ساعت ۱۰:۱۲ همان رویداد packed دوباره retry می‌شود. اگر فقط یک order.status داشته باشیم، معلوم نیست این رشته دارد وضعیت پرداخت، fulfillment، لغو، refund یا exception را می‌گوید.

خروجی این درس Canonical Order State Transition Ledger v1 است. هر transition پذیرفته‌شده باید از روی identity سفارش، نسخه‌ی مدل، axisهای فعلی، source event، mapping، guard، invariant، زمان/شناسه‌ی event، idempotency، late-event policy، terminal/reopen rule و evidence قابل بازسازی باشد.

مرز مالکیت COM-030

COM-030 مالک canonical order lifecycle و transition evidence است. COM-029 معماری connector/adapter و transport را مالک است. COM-031 eligibility و priority صف packing را مالک است. این درس اجازه نمی‌دهد status یک provider بی‌صدا lifecycle داخلی را تعریف کند و state transition هم به‌تنهایی مجوز pack، ship، refund یا notify نیست.

سه خط قرمز:

  1. provider status != canonical order truth
  2. processing time != event time
  3. terminal != reopenable without authority

مدل ذهنی: External observation → Canonical event → Axis-local transition → Guard/invariants → Commit یا reconcile

مسیر قابل ممیزی:

source system/status → canonical event mapping → current axis snapshot → from/to candidate → guard → invariants → idempotency/temporal checks → transition result → evidence

سؤال اول نباید «order.status چه شود؟» باشد. اول بپرس این event اجازه دارد کدام axis را تغییر دهد؟ رویداد payment معمولاً payment axis را تغییر می‌دهد؛ رویداد fulfillment، fulfillment axis را. commercial cancellation و exception/dispute هم جدا هستند مگر policy صریح خلافش را بگوید.

FACT، INFERENCE و DESIGN را قاطی نکن

FACT: SCXML 1.0 یک W3C Recommendation پایدار برای محیط عمومی اجرای state machine است. state، initial configuration و transition دارد؛ اما e-commerce order state تعریف نمی‌کند.

FACT: مستندات جاری WooCommerce statusهایی مثل Pending payment، Processing، On hold، Completed، Cancelled، Refunded و Failed دارد. معنی این statusها عمداً بخشی از payment و fulfillment context را با هم حمل می‌کند چون مدل محصول WooCommerce این‌گونه است.

INFERENCE: وقتی eventها می‌توانند duplicate، late، partial یا out-of-order باشند، جداکردن payment، fulfillment، commercial و exception axisها باعث می‌شود regression غیرمجاز و mapping مبهم سریع‌تر دیده شود.

DESIGN: در MAKNOW از canonical event، transition محلی هر axis، guard، invariant، idempotency key، late-event policy و reopen authority استفاده می‌کنیم. این‌ها تصمیم طراحی محلی‌اند؛ الزام W3C یا WooCommerce نیستند.

قرارداد ۲۳بعدی Transition

FieldMeaningCritical
order_idStable commerce order identityyes
state_model_versionVersion governing state vocabulary/transitionsyes
payment_stateCanonical payment axisyes
fulfillment_stateCanonical fulfillment axisyes
commercial_stateCommercial/cancellation/refund axisno
exception_stateException/dispute axisno
source_systemSystem that emitted observationno
source_statusRaw provider/vendor statusyes
canonical_eventInternal mapped eventyes
from_stateExpected source state on affected axisyes
to_stateProposed target state on affected axisyes
transition_guardBoolean/predicate result before mutationyes
invariant_setNamed invariants checked for transitionyes
event_idSource event identityyes
event_timeBusiness/source occurrence timeyes
processing_timeLocal handling timeno
idempotency_keyLogical dedupe identityyes
late_event_policyPolicy for older/out-of-order eventyes
terminal_stateWhether target/source is terminal under policyno
reopen_authorityAuthority/evidence for leaving terminal stateno
transition_resultBounded transition decisionyes
ownerOwner/reviewer for unresolved caseno
evidence_refTraceable evidence referenceyes

Example decisions

OrderEventFrom → ToResult
O-100PAYMENT_CAPTUREDAUTHORIZED → PAIDAPPLY_TRANSITION
O-101FULFILLMENT_COMPLETEDPACKED → FULFILLEDHOLD_GUARD_FAILED
O-102FULFILLMENT_PACKEDPACKED → PACKEDNOOP_DUPLICATE
O-103FULFILLMENT_PARTIALUNFULFILLED → PARTIALLY_FULFILLEDAPPLY_TRANSITION

Gate 1 — قبل از تفسیر event، نسخه‌ی مدل را ثبت کن

state_model_version باید در evidence باشد. اگر vocabulary یا semantics تغییر کرد، event قدیمی باید با policy همان زمان تفسیر شود یا migration صریح و قابل ردیابی داشته باشد.

Gate 2 — Axisهای مستقل را حفظ کن

payment_state، fulfillment_state، commercial_state و exception_state سؤال‌های متفاوت‌اند. رشته‌ی completed provider نباید هر چهار را overwrite کند.

Gate 3 — اول provider status را به canonical event map کن

source_status مشاهده‌ی بیرونی است. canonical_event تفسیر داخلی توست. status ناشناخته، overloaded یا context-dependent باید وارد HOLD_PROVIDER_MAPPING شود تا mapping روشن شود.

Gate 4 — From/To را صریح کن

Transition یعنی proposal از from_state به to_state روی axis مشخص؛ نه «status=X». اگر current state واقعی با from_state یکی نیست، transition stale یا invalid است و نیاز به reconciliation دارد.

Gate 5 — Guard می‌گوید «الان مجاز است؟»

مثلاً ممکن است fulfillment completion نیازمند payment captured باشد یا cancellation بعد از یک milestone غیرقابل برگشت ممنوع باشد. retry شدن event، guard false را true نمی‌کند.

Gate 6 — Invariantها قواعدی هستند که همیشه باید درست بمانند

مثلاً captured amount منفی نشود، refund از capture بیشتر نشود، fulfilled quantity از quantity سفارش بیشتر نشود و commercial terminal state با event قدیمی silently regress نشود.

Gate 7 — Event ID و idempotency key جلوی side effect تکراری را می‌گیرند

Retry طبیعی است. اگر همان logical event دوباره پردازش شود، نتیجه باید NOOP_DUPLICATE یا state محدود مشابه باشد؛ دو بار دیده‌شدن، دو transition نیست.

Gate 8 — Event time با Processing time فرق دارد

Webhook ممکن است دیر برسد. event_time می‌گوید business event چه زمانی رخ داده و processing_time می‌گوید ما چه زمانی آن را پردازش کردیم. مرتب‌سازی فقط بر اساس arrival می‌تواند state را اشتباه عقب ببرد.

Gate 9 — Terminal state باید reopen rule صریح داشته باشد

Terminal بودن می‌تواند فقط برای یک axis باشد. اگر policy reopen دارد، reopen_authority باید مشخص کند چه actor/control و با چه evidence می‌تواند این کار را انجام دهد. نبود authority یعنی HOLD_REOPEN_AUTHORITY_REQUIRED.

Gate 10 — Partial fulfillment فقط fulfillment axis را توسعه می‌دهد

اگر provider جدید PARTIALLY_FULFILLED دارد، state vocabulary و transition fulfillment را توسعه بده؛ payment transitionها را فقط به‌خاطر تغییر overall provider status بازنویسی نکن.

Gate 11 — Late/out-of-order event را reconcile کن، نه اینکه خودکار rollback کنی

اگر event قدیمی بعد از transition جدیدتر/terminal رسید، آن را به‌عنوان evidence نگه دار و late_event_policy را اجرا کن. default امن HOLD_RECONCILE_LATE_EVENT است، نه regression خاموش.

Gate 12 — Missing decisive evidence باید fail-closed باشد

اگر mapping، guard، current state، idempotency identity، event time یا evidence ref مفقود است، HOLD_UNKNOWN_EVIDENCE یا state ضعیف‌تر بده. تمیزبودن dashboard ارزش جعل lifecycle را ندارد.

مثال‌های حل‌شده

1. PAYMENT_CAPTURED: AUTHORIZED → PAID → APPLY_TRANSITION

Event فقط payment axis را تغییر می‌دهد، guard/invariant پاس‌اند، idempotency key جدید است و evidence کامل است. بقیه axisها ثابت می‌مانند.

2. FULFILLMENT_COMPLETED با guard false → HOLD_GUARD_FAILED

ممکن است warehouse واقعاً کار کرده باشد، اما canonical transition تا reconciliation تحت policy جاری commit نمی‌شود.

3. Retry همان PACKED event → NOOP_DUPLICATE

Retry ثبت می‌شود ولی transition یا side effect دوم ایجاد نمی‌کند.

4. PAYMENT_FAILED قدیمی بعد از payment جدیدتر → HOLD_RECONCILE_LATE_EVENT

event time و processing time را هر دو حفظ کن؛ صرفاً به‌خاطر دیر رسیدن failure، state را عقب نبر.

5. Provider status=completed ولی axis نامشخص → HOLD_PROVIDER_MAPPING

بدون mapping نمی‌دانیم completed یعنی payment، fulfillment، commercial completion یا semantic خاص vendor.

6. Provider جدید partial fulfillment دارد → فقط fulfillment توسعه پیدا می‌کند

PARTIALLY_FULFILLED و transitionهایش را اضافه کن و payment/commercial/exception را دست‌نخورده نگه دار.

Failure modeهای رایج

  • یک order.status برای payment، fulfillment، refund و cancellation؛
  • کپی مستقیم status provider به state داخلی؛
  • transition بدون from_state/to_state؛
  • چک‌کردن guard بعد از mutation؛
  • نبود invariant؛
  • یکی‌گرفتن arrival order با event order؛
  • تبدیل retry به transition جدید؛
  • reopen terminal بدون authority؛
  • regression به‌خاطر late event؛
  • تغییر payment logic برای support کردن partial fulfillment؛
  • تبدیل mapping/evidence مفقود به success.

Alternatives و trade-offها

Single status enum: query و UI ساده‌تر است، ولی با رشد payment/fulfillment/returns/exceptions overloaded می‌شود.

Full event sourcing: audit/replay قدرتمند دارد، ولی commitment معماری بزرگ‌تری از scope این درس است. ما discipline شناسه و زمان event را می‌گیریم بدون اینکه storage architecture خاصی را تحمیل کنیم.

Workflow engine / SCXML: برای semantics اجرایی مفید است، اما runtime عمومی policy تجاری تو را تعریف نمی‌کند.

Vendor-native statuses: integration سریع‌تر، اما internal truth را به یک vendor قفل می‌کند و reconciliation چند provider را سخت می‌کند.

Multiple explicit axes + transition ledger: مدل‌سازی بیشتری می‌خواهد، ولی isolation، explainability و transfer بهتر می‌دهد؛ این الگوی bounded این درس است.

Experienced bridge: چهارده سؤال review

  1. کدام model version برای این order/event معتبر است؟
  2. event اجازه دارد کدام axis را تغییر دهد؟
  3. source status mapping صریح به canonical event دارد؟
  4. current state واقعی با from_state یکی است؟
  5. to_state از آن source قانونی است؟
  6. guard قبل از mutation پاس شده؟
  7. invariantها بعد از transition برقرار می‌مانند؟
  8. این event/idempotency key قبلاً پردازش شده؟
  9. event time و processing time هر دو ثبت شده‌اند؟
  10. event می‌تواند state جدیدتر را regress کند؟
  11. target برای این axis terminal است؟
  12. اگر reopen است، authority صریح داریم؟
  13. axisهای غیرمرتبط ثابت مانده‌اند؟
  14. نتیجه بدون hidden reasoning از evidence_ref قابل بازسازی است؟

تمرین هدایت‌شده و مستقل

Lab هشت fixture آفلاین دارد: transition معتبر payment، guard failure، duplicate retry، late event بعد از evidence جدیدتر/terminal، mapping مبهم provider، evidence مفقود، reopen بدون authority و transfer partial fulfillment.

تمرین مستقل: برای order با payment_state=PAID، provider status جدید partially_fulfilled را وارد کن. canonical event و fulfillment transition اضافه کن، بدون تغییر payment/commercial/exception. سپس همان event را دوباره بفرست و بعد یک FULFILLMENT_STARTED قدیمی‌تر وارد کن. طراحی درست باید بار اول apply، بار دوم deduplicate و event قدیمی را reconcile کند.

Verification evidence

خروجی قابل‌قبول باید هر ۲۳ dimension را مقداردهی کند یا یک typed non-success state صریح بدهد. mapping قبل از transition انجام شود؛ guard و invariant قبل از commit؛ duplicate bounded؛ event time حفظ؛ terminal/reopen صریح؛ و transfer فقط axis متاثر را تغییر دهد.

Lab کاملاً synthetic و offline است و به WooCommerce store، payment gateway، fulfillment provider، customer data یا credential واقعی نیاز ندارد.

Assessment و transfer

برای پایان درس باید بتوانی:

  1. مرز COM-030 را از COM-029 و COM-031 جدا کنی؛
  2. Canonical Order State Transition Ledger v1 بسازی؛
  3. transition با guard false را رد کنی؛
  4. event تکراری را idempotent کنی؛
  5. event قدیمی را بعد از transition جدیدتر reconcile کنی؛
  6. reopen authority را صریح نگه داری؛
  7. partial fulfillment را بدون تغییر payment transitionهای غیرمرتبط اضافه کنی؛
  8. توضیح بدهی چرا vendor status فقط mapping evidence است نه canonical authority.

منابع و freshness

  • W3C — State Chart XML (SCXML) 1.0؛ Recommendation مورخ 2015-09-01؛ rechecked در 2026-09-15. مرجع عمومی state-machine است، نه مرجع state تجاری.
  • WooCommerce — Order Statuses؛ rechecked در 2026-09-15؛ review due در 2026-10-18. معنی‌های جاری vendor برای Pending payment، Processing، On hold، Completed، Cancelled، Refunded و Failed.
  • Multi-axis model، guard/invariant، idempotency، late-event handling و reopen policy این درس DESIGN محلی MAKNOW هستند و به منابع بالا نسبت داده نمی‌شوند.

ارزیابی

پاسخ‌نامه‌ی این درس در بسته‌ی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار می‌فرستد.

COM-030-S1 retrieval

Explain the COM-030 boundary and one adjacent non-goal.

lesson ✗AI ✗notes ✗

COM-030-S2 application

Build Canonical Order State Transition Ledger v1 from baseline fixture.

lesson ✗AI ✗notes ✗

COM-030-S3 diagnosis

Diagnose guard-false, duplicate and late-event mutations without silently regressing state.

lesson ✗AI ✗notes ✗

COM-030-S4 transfer

Add partial fulfillment while preserving unrelated payment transitions.

lesson ✗AI ✗notes ✗
ملاک‌های ارزیابی (rubric)

A passing submission must preserve scope, bind external facts to their authority class, populate the 23-dimension ledger or explicit non-success states, reject guard/invariant failures, deduplicate retries, preserve event-time ordering, enforce terminal/reopen rules, and recompute the partial-fulfillment transfer without changing unrelated axes.

منابع و تازگی

W3C State Chart XML (SCXML) 1.0
·
WooCommerce Order Statuses
·
COM-030 Frozen Lesson Bible
·

مطالعهٔ موارد (case studies)

فایل‌های آزمایشگاه

در همین پوشه python run_checks.py را اجرا کن. هشت fixture مصنوعی mapping isolation، guard/invariant، idempotency، late-event reconciliation، terminal reopen authority، missing evidence و transfer مربوط به partial fulfillment را می‌سنجند. شبکه یا credential لازم نیست.