[{"data":1,"prerenderedAt":384},["ShallowReactive",2],{"page-\u002Fv1\u002Fcookbook\u002Fordering-warehouse":3},{"id":4,"title":5,"body":6,"description":377,"extension":378,"meta":379,"navigation":131,"path":380,"seo":381,"stem":382,"__hash__":383},"content\u002Fv1\u002Fcookbook\u002Fordering-warehouse.md","Ordering ↔ Warehouse",{"type":7,"value":8,"toc":369},"minimark",[9,14,18,23,56,60,71,75,181,191,195,262,268,272,322,326,341,365],[10,11,13],"h1",{"id":12},"cookbook-ordering-warehouse","Cookbook — Ordering ↔ Warehouse",[15,16,17],"p",{},"Two collaborating modules, zero Application\u002FDomain imports across the boundary.",[19,20,22],"h2",{"id":21},"story","Story",[24,25,26,42],"ol",{},[27,28,29,33,34,37,38,41],"li",{},[30,31,32],"strong",{},"Place order"," — Ordering must know stock is available ",[30,35,36],{},"now"," → sync ",[30,39,40],{},"ACL"," (validate before commit).",[27,43,44,47,48,51,52,55],{},[30,45,46],{},"Fulfill order"," — Warehouse must deduct reserved stock ",[30,49,50],{},"after"," success → async ",[30,53,54],{},"Domain Event"," (idempotent consumer).",[19,57,59],{"id":58},"module-sketches","Module sketches",[61,62,68],"pre",{"className":63,"code":65,"language":66,"meta":67},[64],"language-text","Ordering\u002F\n├── Application\u002F\n│   ├── DTO\u002FOrder\u002FPlaceOrderDTO.php\n│   └── UseCases\u002FOrder\u002FPlaceOrderUseCase.php\n│                    MarkOrderFulfilledUseCase.php\n├── Domain\u002F\n│   ├── Entities\u002FOrderEntity.php\n│   ├── Events\u002FOrderFulfilled.php          # eventId, schemaVersion, rich payload\n│   └── Ports\u002F\n│       ├── Order\u002FOrderRepositoryInterface.php\n│       └── Acl\u002FWarehouseAvailabilityPortInterface.php\n└── Infrastructure\u002F\n    └── ExternalServices\u002FWarehouseAvailabilityAclAdapter.php\n\nWarehouse\u002F\n├── Application\u002F\n│   ├── DTO\u002F...\u002FDeductStockForFulfilledOrderDTO.php\n│   └── UseCases\u002F...\u002FDeductStockForFulfilledOrderUseCase.php\n├── Domain\u002F\n│   └── Ports\u002FModule\u002FWarehouseAvailabilityModuleInterface.php   # thin façade\n└── Infrastructure\u002F\n    ├── Messaging\u002FOrderFulfilledTranslationListener.php\n    └── Persistence\u002F…\u002FProcessedEventStore (eventId idempotency)\n","text","",[69,70,65],"code",{"__ignoreMap":67},[19,72,74],{"id":73},"flow-a-place-order-acl","Flow A — place order (ACL)",[61,76,80],{"className":77,"code":78,"language":79,"meta":67,"style":67},"language-mermaid shiki shiki-themes github-light github-dark","sequenceDiagram\n    autonumber\n    participant UI as Ordering UI\n    participant UC as PlaceOrderUseCase\n    participant WP as WarehouseAvailabilityPortInterface\n    participant ACL as WarehouseAvailabilityAclAdapter\n    participant WM as WarehouseAvailabilityModuleInterface\n\n    UI->>UC: PlaceOrderDTO\n    UC->>WP: isAvailable(lines)\n    WP->>ACL: bound adapter\n    ACL->>WM: isStockAvailable(…)\n    WM-->>ACL: result\n    ACL-->>UC: local result\n    UC->>UC: persist order \u002F fail\n    UC-->>UI: OrderEntity\n","mermaid",[69,81,82,90,96,102,108,114,120,126,133,139,145,151,157,163,169,175],{"__ignoreMap":67},[83,84,87],"span",{"class":85,"line":86},"line",1,[83,88,89],{},"sequenceDiagram\n",[83,91,93],{"class":85,"line":92},2,[83,94,95],{},"    autonumber\n",[83,97,99],{"class":85,"line":98},3,[83,100,101],{},"    participant UI as Ordering UI\n",[83,103,105],{"class":85,"line":104},4,[83,106,107],{},"    participant UC as PlaceOrderUseCase\n",[83,109,111],{"class":85,"line":110},5,[83,112,113],{},"    participant WP as WarehouseAvailabilityPortInterface\n",[83,115,117],{"class":85,"line":116},6,[83,118,119],{},"    participant ACL as WarehouseAvailabilityAclAdapter\n",[83,121,123],{"class":85,"line":122},7,[83,124,125],{},"    participant WM as WarehouseAvailabilityModuleInterface\n",[83,127,129],{"class":85,"line":128},8,[83,130,132],{"emptyLinePlaceholder":131},true,"\n",[83,134,136],{"class":85,"line":135},9,[83,137,138],{},"    UI->>UC: PlaceOrderDTO\n",[83,140,142],{"class":85,"line":141},10,[83,143,144],{},"    UC->>WP: isAvailable(lines)\n",[83,146,148],{"class":85,"line":147},11,[83,149,150],{},"    WP->>ACL: bound adapter\n",[83,152,154],{"class":85,"line":153},12,[83,155,156],{},"    ACL->>WM: isStockAvailable(…)\n",[83,158,160],{"class":85,"line":159},13,[83,161,162],{},"    WM-->>ACL: result\n",[83,164,166],{"class":85,"line":165},14,[83,167,168],{},"    ACL-->>UC: local result\n",[83,170,172],{"class":85,"line":171},15,[83,173,174],{},"    UC->>UC: persist order \u002F fail\n",[83,176,178],{"class":85,"line":177},16,[83,179,180],{},"    UC-->>UI: OrderEntity\n",[15,182,183,186,187,190],{},[30,184,185],{},"Port names only:"," Ordering Use Cases never see the Warehouse ",[69,188,189],{},"*ModuleInterface",".",[19,192,194],{"id":193},"flow-b-fulfill-event","Flow B — fulfill (Event)",[61,196,198],{"className":77,"code":197,"language":79,"meta":67,"style":67},"sequenceDiagram\n    autonumber\n    participant UC as MarkOrderFulfilledUseCase\n    participant D as EventDispatcherInterface\n    participant L as OrderFulfilledTranslationListener\n    participant IU as DeductStockForFulfilledOrderUseCase\n\n    UC->>UC: mark fulfilled + persist\n    UC->>D: OrderFulfilled (eventId + rich payload)\n    D->>L: deliver (at-least-once)\n    L->>L: skip if eventId seen; else map DTO\n    L->>IU: __invoke(DTO)\n    IU-->>L: done\n",[69,199,200,204,208,213,218,223,228,232,237,242,247,252,257],{"__ignoreMap":67},[83,201,202],{"class":85,"line":86},[83,203,89],{},[83,205,206],{"class":85,"line":92},[83,207,95],{},[83,209,210],{"class":85,"line":98},[83,211,212],{},"    participant UC as MarkOrderFulfilledUseCase\n",[83,214,215],{"class":85,"line":104},[83,216,217],{},"    participant D as EventDispatcherInterface\n",[83,219,220],{"class":85,"line":110},[83,221,222],{},"    participant L as OrderFulfilledTranslationListener\n",[83,224,225],{"class":85,"line":116},[83,226,227],{},"    participant IU as DeductStockForFulfilledOrderUseCase\n",[83,229,230],{"class":85,"line":122},[83,231,132],{"emptyLinePlaceholder":131},[83,233,234],{"class":85,"line":128},[83,235,236],{},"    UC->>UC: mark fulfilled + persist\n",[83,238,239],{"class":85,"line":135},[83,240,241],{},"    UC->>D: OrderFulfilled (eventId + rich payload)\n",[83,243,244],{"class":85,"line":141},[83,245,246],{},"    D->>L: deliver (at-least-once)\n",[83,248,249],{"class":85,"line":147},[83,250,251],{},"    L->>L: skip if eventId seen; else map DTO\n",[83,253,254],{"class":85,"line":153},[83,255,256],{},"    L->>IU: __invoke(DTO)\n",[83,258,259],{"class":85,"line":159},[83,260,261],{},"    IU-->>L: done\n",[15,263,264,267],{},[30,265,266],{},"Payload:"," lines, quantities, item codes, order reference — enough that Warehouse does not call back into Ordering Domain on the happy path.",[19,269,271],{"id":270},"replaceability-checkpoints","Replaceability checkpoints",[273,274,275,291],"table",{},[276,277,278],"thead",{},[279,280,281,285,288],"tr",{},[282,283,284],"th",{},"Change",[282,286,287],{},"What you rewrite",[282,289,290],{},"What stays",[292,293,294,309],"tbody",{},[279,295,296,300,306],{},[297,298,299],"td",{},"Warehouse becomes HTTP",[297,301,302,305],{},[69,303,304],{},"WarehouseAvailabilityAclAdapter"," (+ listener ingress)",[297,307,308],{},"Ordering Use Cases, local port, Warehouse inbound Use Case",[279,310,311,314,317],{},[297,312,313],{},"Ordering becomes external publisher",[297,315,316],{},"Warehouse listener becomes webhook\u002Fmessage consumer",[297,318,319],{},[69,320,321],{},"DeductStockForFulfilledOrderUseCase",[19,323,325],{"id":324},"do-not","Do not",[327,328,329,332,335,338],"ul",{},[27,330,331],{},"Import Catalog\u002FSales\u002FInventory (or any product-app) trees into this story",[27,333,334],{},"Treat another repository’s class dump as the architecture standard",[27,336,337],{},"Put stock enums into Shared “for convenience”",[27,339,340],{},"Span one DB transaction across Ordering + Warehouse tables",[15,342,343,344,348,349,348,353,348,357,348,361,190],{},"Related Core: ",[345,346,40],"a",{"href":347},"\u002Fv1\u002Fcore\u002Fcross-module-acl"," · ",[345,350,352],{"href":351},"\u002Fv1\u002Fcore\u002Fcross-module-events","Events",[345,354,356],{"href":355},"\u002Fv1\u002Fcore\u002Fcross-module-contracts","Contracts",[345,358,360],{"href":359},"\u002Fv1\u002Fcore\u002Fevent-delivery","Event delivery",[345,362,364],{"href":363},"\u002Fv1\u002Fcore\u002Fdecision-tree","Decision tree",[366,367,368],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":67,"searchDepth":92,"depth":92,"links":370},[371,372,373,374,375,376],{"id":21,"depth":92,"text":22},{"id":58,"depth":92,"text":59},{"id":73,"depth":92,"text":74},{"id":193,"depth":92,"text":194},{"id":270,"depth":92,"text":271},{"id":324,"depth":92,"text":325},"Place order with ACL stock check; fulfill with Domain Event that deducts reserved stock.","md",{},"\u002Fv1\u002Fcookbook\u002Fordering-warehouse",{"title":5,"description":377},"v1\u002Fcookbook\u002Fordering-warehouse","-6JV7FPh3T8vTezQgouHP_kRJoelKORpQ2Cw1T7tJ24",1786241412946]