[{"data":1,"prerenderedAt":487},["ShallowReactive",2],{"page-\u002Fv1\u002Fadapters\u002Flaravel\u002Fcross-module":3},{"id":4,"title":5,"body":6,"description":480,"extension":481,"meta":482,"navigation":187,"path":483,"seo":484,"stem":485,"__hash__":486},"content\u002Fv1\u002Fadapters\u002Flaravel\u002Fcross-module.md","Laravel cross-module bridges",{"type":7,"value":8,"toc":470},"minimark",[9,13,31,36,81,101,105,146,219,229,233,324,331,336,353,357,366,370,403,406,410,466],[10,11,5],"h1",{"id":12},"laravel-cross-module-bridges",[14,15,16,17,21,22,26,27,30],"p",{},"Core rules for ACL and Events are unchanged. This page shows ",[18,19,20],"strong",{},"Laravel wiring"," only, using greenfield ",[23,24,25],"code",{},"Ordering"," \u002F ",[23,28,29],{},"Warehouse"," names.",[32,33,35],"h2",{"id":34},"golden-rules-host-reminder","Golden rules (host reminder)",[37,38,39,43,54,65,68],"ol",{},[40,41,42],"li",{},"Application\u002FDomain of module A never import Application\u002FDomain of module B.",[40,44,45,46,49,50,53],{},"Need peer answer ",[18,47,48],{},"now"," → local port + Infrastructure ACL adapter → thin peer ",[23,51,52],{},"*ModuleInterface",".",[40,55,56,57,60,61,64],{},"Need peer side effect ",[18,58,59],{},"later"," → Domain Event → consumer Infrastructure ",[18,62,63],{},"translation listener"," → inbound Use Case.",[40,66,67],{},"Bind ports in the module ServiceProvider (composition root).",[40,69,70,71,74,75,80],{},"Prefer ACL ",[18,72,73],{},"validate before"," local DB commit; never one transaction across two modules’ tables (",[76,77,79],"a",{"href":78},"\u002Fv1\u002Fcore\u002Ftransactions-and-failures","transactions",").",[14,82,83,84,88,89,88,93,88,97,53],{},"Full Core diagrams: ",[76,85,87],{"href":86},"\u002Fv1\u002Fcore\u002Fcross-module-acl","ACL"," · ",[76,90,92],{"href":91},"\u002Fv1\u002Fcore\u002Fcross-module-events","Events",[76,94,96],{"href":95},"\u002Fv1\u002Fcore\u002Fcross-module-contracts","Contracts",[76,98,100],{"href":99},"\u002Fv1\u002Fcore\u002Fevent-delivery","Event delivery",[32,102,104],{"id":103},"sync-acl-bind-example","Sync ACL — bind example",[106,107,112],"pre",{"className":108,"code":109,"language":110,"meta":111,"style":111},"language-php shiki shiki-themes github-light github-dark","\u002F\u002F Ordering Application\u002FProviders\n$this->app->bind(\n    WarehouseAvailabilityPortInterface::class,\n    WarehouseAvailabilityAclAdapter::class,\n);\n","php","",[23,113,114,122,128,134,140],{"__ignoreMap":111},[115,116,119],"span",{"class":117,"line":118},"line",1,[115,120,121],{},"\u002F\u002F Ordering Application\u002FProviders\n",[115,123,125],{"class":117,"line":124},2,[115,126,127],{},"$this->app->bind(\n",[115,129,131],{"class":117,"line":130},3,[115,132,133],{},"    WarehouseAvailabilityPortInterface::class,\n",[115,135,137],{"class":117,"line":136},4,[115,138,139],{},"    WarehouseAvailabilityAclAdapter::class,\n",[115,141,143],{"class":117,"line":142},5,[115,144,145],{},");\n",[106,147,149],{"className":108,"code":148,"language":110,"meta":111,"style":111},"\u002F\u002F Ordering Infrastructure — only layer that may import Warehouse façade\nfinal class WarehouseAvailabilityAclAdapter implements WarehouseAvailabilityPortInterface\n{\n    public function __construct(\n        private WarehouseAvailabilityModuleInterface $warehouse,\n    ) {}\n\n    public function isAvailable(string $itemCode, int $quantity): bool\n    {\n        return $this->warehouse->isStockAvailable($itemCode, $quantity);\n    }\n}\n",[23,150,151,156,161,166,171,176,182,189,195,201,207,213],{"__ignoreMap":111},[115,152,153],{"class":117,"line":118},[115,154,155],{},"\u002F\u002F Ordering Infrastructure — only layer that may import Warehouse façade\n",[115,157,158],{"class":117,"line":124},[115,159,160],{},"final class WarehouseAvailabilityAclAdapter implements WarehouseAvailabilityPortInterface\n",[115,162,163],{"class":117,"line":130},[115,164,165],{},"{\n",[115,167,168],{"class":117,"line":136},[115,169,170],{},"    public function __construct(\n",[115,172,173],{"class":117,"line":142},[115,174,175],{},"        private WarehouseAvailabilityModuleInterface $warehouse,\n",[115,177,179],{"class":117,"line":178},6,[115,180,181],{},"    ) {}\n",[115,183,185],{"class":117,"line":184},7,[115,186,188],{"emptyLinePlaceholder":187},true,"\n",[115,190,192],{"class":117,"line":191},8,[115,193,194],{},"    public function isAvailable(string $itemCode, int $quantity): bool\n",[115,196,198],{"class":117,"line":197},9,[115,199,200],{},"    {\n",[115,202,204],{"class":117,"line":203},10,[115,205,206],{},"        return $this->warehouse->isStockAvailable($itemCode, $quantity);\n",[115,208,210],{"class":117,"line":209},11,[115,211,212],{},"    }\n",[115,214,216],{"class":117,"line":215},12,[115,217,218],{},"}\n",[14,220,221,222,225,226,80],{},"Use Cases inject ",[23,223,224],{},"WarehouseAvailabilityPortInterface"," only. Keep the Warehouse façade thin (",[76,227,228],{"href":95},"contracts",[32,230,232],{"id":231},"async-events-listener-placement","Async Events — listener placement",[234,235,236,249],"table",{},[237,238,239],"thead",{},[240,241,242,246],"tr",{},[243,244,245],"th",{},"Piece",[243,247,248],{},"Laravel place",[250,251,252,264,280,290,300,312],"tbody",{},[240,253,254,258],{},[255,256,257],"td",{},"Domain Event class",[255,259,260,263],{},[23,261,262],{},"Ordering\u002FDomain\u002FEvents\u002FOrderFulfilled.php"," (pure PHP)",[240,265,266,269],{},[255,267,268],{},"Dispatch",[255,270,271,272,275,276,279],{},"Via Shared ",[23,273,274],{},"EventDispatcherInterface"," adapter (not ",[23,277,278],{},"Event"," facade in Use Cases)",[240,281,282,285],{},[255,283,284],{},"Translation listener",[255,286,287],{},[23,288,289],{},"Warehouse\u002FInfrastructure\u002F...\u002FOrderingOrderFulfilledTranslationListener.php",[240,291,292,295],{},[255,293,294],{},"Inbound Use Case",[255,296,297],{},[23,298,299],{},"Warehouse\u002FApplication\u002FUseCases\u002F...\u002FDeductStockForFulfilledOrderUseCase.php",[240,301,302,305],{},[255,303,304],{},"Idempotency",[255,306,307,308,311],{},"Consumer Infra store of processed ",[23,309,310],{},"eventId"," (same DB transaction as side effect when possible)",[240,313,314,317],{},[255,315,316],{},"Registration",[255,318,319,320,323],{},"Module provider \u002F ",[23,321,322],{},"EventServiceProvider"," discovery — wiring only",[14,325,326,327,330],{},"Prefer ",[18,328,329],{},"queued"," listeners for side effects so Ordering’s request does not wait on Warehouse.",[332,333,335],"h3",{"id":334},"payload-contract","Payload contract",[14,337,338,339,342,343,345,346,345,349,352],{},"Published events are a ",[18,340,341],{},"public contract",". Include ",[23,344,310],{},", ",[23,347,348],{},"occurredAt",[23,350,351],{},"schemaVersion",", and a rich happy-path payload. Prefer additive evolution.",[332,354,356],{"id":355},"outbox-recommended-on-laravel","Outbox (recommended on Laravel)",[14,358,359,360,363,364,53],{},"Persist the Ordering write and an ",[18,361,362],{},"outbox"," row in one DB transaction; a scheduled\u002Fqueued job publishes to the Laravel event bus \u002F queue afterward. Prevents “committed without dispatch.” Table shape is host-specific; the Core rule is in ",[76,365,100],{"href":99},[32,367,369],{"id":368},"replaceability-on-laravel","Replaceability on Laravel",[234,371,372,382],{},[237,373,374],{},[240,375,376,379],{},[243,377,378],{},"Today",[243,380,381],{},"Tomorrow",[250,383,384,392],{},[240,385,386,389],{},[255,387,388],{},"In-process thin Warehouse façade",[255,390,391],{},"HTTP client inside the same ACL adapter class (or sibling)",[240,393,394,400],{},[255,395,396,397],{},"Queue translation listener on ",[23,398,399],{},"OrderFulfilled",[255,401,402],{},"Webhook controller in Warehouse Infrastructure calling the same inbound Use Case",[14,404,405],{},"Ordering \u002F Warehouse Application + Domain stay untouched.",[32,407,409],{"id":408},"forbidden-on-laravel-hosts","Forbidden on Laravel hosts",[234,411,412,422],{},[237,413,414],{},[240,415,416,419],{},[243,417,418],{},"Smell",[243,420,421],{},"Fix",[250,423,424,435,446,458],{},[240,425,426,432],{},[255,427,428,431],{},[23,429,430],{},"use App\\Modules\\Warehouse\\Application\\..."," in Ordering Use Case",[255,433,434],{},"Local ACL port",[240,436,437,443],{},[255,438,439,442],{},[23,440,441],{},"Event::dispatch"," inside Domain",[255,444,445],{},"Shared dispatcher port",[240,447,448,455],{},[255,449,450,451,454],{},"Domain Event using ",[23,452,453],{},"SerializesModels"," with Eloquent",[255,456,457],{},"Primitives \u002F Domain DTOs",[240,459,460,463],{},[255,461,462],{},"Filament Resource importing peer Models for policy",[255,464,465],{},"Own Use Case + ACL",[467,468,469],"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":111,"searchDepth":124,"depth":124,"links":471},[472,473,474,478,479],{"id":34,"depth":124,"text":35},{"id":103,"depth":124,"text":104},{"id":231,"depth":124,"text":232,"children":475},[476,477],{"id":334,"depth":130,"text":335},{"id":355,"depth":130,"text":356},{"id":368,"depth":124,"text":369},{"id":408,"depth":124,"text":409},"Laravel-host ACL and Domain Event wiring — ServiceProvider binds, listeners, queues — without breaking Core replaceability.","md",{},"\u002Fv1\u002Fadapters\u002Flaravel\u002Fcross-module",{"title":5,"description":480},"v1\u002Fadapters\u002Flaravel\u002Fcross-module","1O5kayqFrh4nHItUptv7fvXDhqR23yaC_IckE5wfCmg",1786241413849]