معماری چندکسبوکاری، تجاری و تجارت الکترونیک · فصل ۷ — 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 مناسب طراحی کند.
خلاصهٔ درس
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 نیست.
سه خط قرمز:
provider status != canonical order truthprocessing time != event timeterminal != 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
| Field | Meaning | Critical |
|---|---|---|
order_id | Stable commerce order identity | yes |
state_model_version | Version governing state vocabulary/transitions | yes |
payment_state | Canonical payment axis | yes |
fulfillment_state | Canonical fulfillment axis | yes |
commercial_state | Commercial/cancellation/refund axis | no |
exception_state | Exception/dispute axis | no |
source_system | System that emitted observation | no |
source_status | Raw provider/vendor status | yes |
canonical_event | Internal mapped event | yes |
from_state | Expected source state on affected axis | yes |
to_state | Proposed target state on affected axis | yes |
transition_guard | Boolean/predicate result before mutation | yes |
invariant_set | Named invariants checked for transition | yes |
event_id | Source event identity | yes |
event_time | Business/source occurrence time | yes |
processing_time | Local handling time | no |
idempotency_key | Logical dedupe identity | yes |
late_event_policy | Policy for older/out-of-order event | yes |
terminal_state | Whether target/source is terminal under policy | no |
reopen_authority | Authority/evidence for leaving terminal state | no |
transition_result | Bounded transition decision | yes |
owner | Owner/reviewer for unresolved case | no |
evidence_ref | Traceable evidence reference | yes |
Example decisions
| Order | Event | From → To | Result |
|---|---|---|---|
| O-100 | PAYMENT_CAPTURED | AUTHORIZED → PAID | APPLY_TRANSITION |
| O-101 | FULFILLMENT_COMPLETED | PACKED → FULFILLED | HOLD_GUARD_FAILED |
| O-102 | FULFILLMENT_PACKED | PACKED → PACKED | NOOP_DUPLICATE |
| O-103 | FULFILLMENT_PARTIAL | UNFULFILLED → PARTIALLY_FULFILLED | APPLY_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
- کدام model version برای این order/event معتبر است؟
- event اجازه دارد کدام axis را تغییر دهد؟
- source status mapping صریح به canonical event دارد؟
- current state واقعی با
from_stateیکی است؟ to_stateاز آن source قانونی است؟- guard قبل از mutation پاس شده؟
- invariantها بعد از transition برقرار میمانند؟
- این event/idempotency key قبلاً پردازش شده؟
- event time و processing time هر دو ثبت شدهاند؟
- event میتواند state جدیدتر را regress کند؟
- target برای این axis terminal است؟
- اگر reopen است، authority صریح داریم؟
- axisهای غیرمرتبط ثابت ماندهاند؟
- نتیجه بدون 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
برای پایان درس باید بتوانی:
- مرز COM-030 را از COM-029 و COM-031 جدا کنی؛
- Canonical Order State Transition Ledger v1 بسازی؛
- transition با guard false را رد کنی؛
- event تکراری را idempotent کنی؛
- event قدیمی را بعد از transition جدیدتر reconcile کنی؛
- reopen authority را صریح نگه داری؛
- partial fulfillment را بدون تغییر payment transitionهای غیرمرتبط اضافه کنی؛
- توضیح بدهی چرا 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.
COM-030-S2 application
Build Canonical Order State Transition Ledger v1 from baseline fixture.
COM-030-S3 diagnosis
Diagnose guard-false, duplicate and late-event mutations without silently regressing state.
COM-030-S4 transfer
Add partial fulfillment while preserving unrelated payment transitions.
ملاکهای ارزیابی (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.
منابع و تازگی
مطالعهٔ موارد (case studies)
فایلهای آزمایشگاه
در همین پوشه python run_checks.py را اجرا کن. هشت fixture مصنوعی mapping isolation، guard/invariant، idempotency، late-event reconciliation، terminal reopen authority، missing evidence و transfer مربوط به partial fulfillment را میسنجند. شبکه یا credential لازم نیست.