[{"data":1,"prerenderedAt":922},["ShallowReactive",2],{"navigation":3,"\u002Fconcepts\u002Fboundaries":193,"\u002Fconcepts\u002Fboundaries-surround":917},[4,27,49,99,149,169,183],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":26},"Getting Started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,14,18,22],{"title":11,"path":12,"stem":13},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction",{"title":15,"path":16,"stem":17},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":19,"path":20,"stem":21},"Quick Start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start",{"title":23,"path":24,"stem":25},"Existing Application","\u002Fgetting-started\u002Fexisting-application","1.getting-started\u002F4.existing-application",false,{"title":28,"icon":29,"path":30,"stem":31,"children":32,"page":26},"Concepts","i-lucide-layers","\u002Fconcepts","2.concepts",[33,37,41,45],{"title":34,"path":35,"stem":36},"Layers","\u002Fconcepts\u002Flayers","2.concepts\u002F1.layers",{"title":38,"path":39,"stem":40},"Buckets","\u002Fconcepts\u002Fbuckets","2.concepts\u002F2.buckets",{"title":42,"path":43,"stem":44},"Boundaries","\u002Fconcepts\u002Fboundaries","2.concepts\u002F3.boundaries",{"title":46,"path":47,"stem":48},"Service Providers","\u002Fconcepts\u002Fservice-providers","2.concepts\u002F4.service-providers",{"title":50,"icon":51,"path":52,"stem":53,"children":54,"page":26},"Guides","i-lucide-book-marked","\u002Fguides","3.guides",[55,59,63,67,71,75,79,83,87,91,95],{"title":56,"path":57,"stem":58},"Add a Domain","\u002Fguides\u002Fadd-a-domain","3.guides\u002F01.add-a-domain",{"title":60,"path":61,"stem":62},"Share Code Between Layers","\u002Fguides\u002Fshare-code-between-layers","3.guides\u002F02.share-code-between-layers",{"title":64,"path":65,"stem":66},"Routes","\u002Fguides\u002Froutes","3.guides\u002F03.routes",{"title":68,"path":69,"stem":70},"Views and Components","\u002Fguides\u002Fviews-and-components","3.guides\u002F04.views-and-components",{"title":72,"path":73,"stem":74},"Seeders","\u002Fguides\u002Fseeders","3.guides\u002F05.seeders",{"title":76,"path":77,"stem":78},"Configuration","\u002Fguides\u002Fconfiguration","3.guides\u002F06.configuration",{"title":80,"path":81,"stem":82},"Events","\u002Fguides\u002Fevents","3.guides\u002F07.events",{"title":84,"path":85,"stem":86},"Tests and CI","\u002Fguides\u002Ftesting-and-ci","3.guides\u002F08.testing-and-ci",{"title":88,"path":89,"stem":90},"Production","\u002Fguides\u002Fproduction","3.guides\u002F09.production",{"title":92,"path":93,"stem":94},"Remove a Layer","\u002Fguides\u002Fremoving-a-layer","3.guides\u002F10.removing-a-layer",{"title":96,"path":97,"stem":98},"Multi-tenancy","\u002Fguides\u002Fmulti-tenancy","3.guides\u002F11.multi-tenancy",{"title":100,"icon":101,"path":102,"stem":103,"children":104,"page":26},"Commands","i-lucide-terminal","\u002Fcommands","4.commands",[105,109,113,117,121,125,129,133,137,141,145],{"title":106,"path":107,"stem":108},"Overview","\u002Fcommands\u002Foverview","4.commands\u002F01.overview",{"title":110,"path":111,"stem":112},"osdd:start","\u002Fcommands\u002Fosdd-start","4.commands\u002F02.osdd-start",{"title":114,"path":115,"stem":116},"osdd:layer","\u002Fcommands\u002Fosdd-layer","4.commands\u002F03.osdd-layer",{"title":118,"path":119,"stem":120},"osdd:list","\u002Fcommands\u002Fosdd-list","4.commands\u002F04.osdd-list",{"title":122,"path":123,"stem":124},"osdd:check","\u002Fcommands\u002Fosdd-check","4.commands\u002F05.osdd-check",{"title":126,"path":127,"stem":128},"osdd:graph","\u002Fcommands\u002Fosdd-graph","4.commands\u002F06.osdd-graph",{"title":130,"path":131,"stem":132},"osdd:seed","\u002Fcommands\u002Fosdd-seed","4.commands\u002F07.osdd-seed",{"title":134,"path":135,"stem":136},"osdd:phpunit","\u002Fcommands\u002Fosdd-phpunit","4.commands\u002F08.osdd-phpunit",{"title":138,"path":139,"stem":140},"osdd:remove","\u002Fcommands\u002Fosdd-remove","4.commands\u002F09.osdd-remove",{"title":142,"path":143,"stem":144},"osdd:cache","\u002Fcommands\u002Fosdd-cache","4.commands\u002F10.osdd-cache",{"title":146,"path":147,"stem":148},"Generators","\u002Fcommands\u002Fmake-commands","4.commands\u002F11.make-commands",{"title":150,"icon":151,"path":152,"stem":153,"children":154,"page":26},"API Reference","i-lucide-book-open","\u002Fapi-reference","5.api-reference",[155,159,162,166],{"title":156,"path":157,"stem":158},"LayerServiceProvider","\u002Fapi-reference\u002Flayer-service-provider","5.api-reference\u002F1.layer-service-provider",{"title":34,"path":160,"stem":161},"\u002Fapi-reference\u002Flayers","5.api-reference\u002F2.layers",{"title":163,"path":164,"stem":165},"SeederRegistry","\u002Fapi-reference\u002Fseeder-registry","5.api-reference\u002F3.seeder-registry",{"title":76,"path":167,"stem":168},"\u002Fapi-reference\u002Fconfiguration","5.api-reference\u002F4.configuration",{"title":170,"icon":171,"path":172,"stem":173,"children":174,"page":26},"Integrations","i-lucide-puzzle","\u002Fintegrations","6.integrations",[175,179],{"title":176,"path":177,"stem":178},"Laravel Boost","\u002Fintegrations\u002Flaravel-boost","6.integrations\u002F1.laravel-boost",{"title":180,"path":181,"stem":182},"Tinker and IDE Helper","\u002Fintegrations\u002Ftinker-and-ide-helper","6.integrations\u002F2.tinker-and-ide-helper",{"title":184,"icon":185,"path":186,"stem":187,"children":188,"page":26},"Upgrade","i-lucide-arrow-up-circle","\u002Fupgrade","7.upgrade",[189],{"title":190,"path":191,"stem":192},"Upgrade from 2.x","\u002Fupgrade\u002Ffrom-2x","7.upgrade\u002F1.from-2x",{"id":194,"title":42,"body":195,"description":909,"extension":910,"links":911,"meta":912,"navigation":913,"path":43,"seo":914,"sitemap":915,"stem":44,"__hash__":916},"docs\u002F2.concepts\u002F3.boundaries.md",{"type":196,"value":197,"toc":899},"minimark",[198,228,233,247,368,385,414,418,437,445,448,514,517,522,545,586,592,609,613,637,643,646,669,673,685,780,828,838,847,851,861,865,875,895],[199,200,201,202,206,207,210,211,214,215,218,219,221,222,227],"p",{},"Each layer lists the layers it depends on in the ",[203,204,205],"code",{},"require"," section of its ",[203,208,209],{},"composer.json",". All layers share one Composer autoloader, though, so PHP lets ",[203,212,213],{},"functional\u002Forders"," use a class of ",[203,216,217],{},"functional\u002Fbilling"," even when ",[203,220,213],{}," does not require it. ",[223,224,225],"a",{"href":123},[203,226,122],{}," closes that gap.",[229,230,232],"h2",{"id":231},"the-rule","The rule",[199,234,235,236,238,239,242,243,246],{},"A layer may only use the classes of the layers in its own ",[203,237,205],{},". Files under its ",[203,240,241],{},"tests\u002F"," folder may also use the layers in its ",[203,244,245],{},"require-dev",".",[248,249,255],"pre",{"className":250,"code":251,"filename":252,"language":253,"meta":254,"style":254},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\"require\": {\n    \"lomkit\u002Flaravel-osdd\": \"*\",\n    \"functional\u002Fusers\": \"*\"\n},\n\"require-dev\": {\n    \"technical\u002Ftesting\": \"*\"\n}\n","functional\u002Forders\u002Fcomposer.json","json","",[203,256,257,278,304,323,331,344,362],{"__ignoreMap":254},[258,259,262,266,269,271,275],"span",{"class":260,"line":261},"line",1,[258,263,265],{"class":264},"sMK4o","\"",[258,267,205],{"class":268},"sfazB",[258,270,265],{"class":264},[258,272,274],{"class":273},"sTEyZ",": ",[258,276,277],{"class":264},"{\n",[258,279,281,284,288,290,293,296,299,301],{"class":260,"line":280},2,[258,282,283],{"class":264},"    \"",[258,285,287],{"class":286},"spNyl","lomkit\u002Flaravel-osdd",[258,289,265],{"class":264},[258,291,292],{"class":264},":",[258,294,295],{"class":264}," \"",[258,297,298],{"class":268},"*",[258,300,265],{"class":264},[258,302,303],{"class":264},",\n",[258,305,307,309,312,314,316,318,320],{"class":260,"line":306},3,[258,308,283],{"class":264},[258,310,311],{"class":286},"functional\u002Fusers",[258,313,265],{"class":264},[258,315,292],{"class":264},[258,317,295],{"class":264},[258,319,298],{"class":268},[258,321,322],{"class":264},"\"\n",[258,324,326,329],{"class":260,"line":325},4,[258,327,328],{"class":264},"}",[258,330,303],{"class":273},[258,332,334,336,338,340,342],{"class":260,"line":333},5,[258,335,265],{"class":264},[258,337,245],{"class":268},[258,339,265],{"class":264},[258,341,274],{"class":273},[258,343,277],{"class":264},[258,345,347,349,352,354,356,358,360],{"class":260,"line":346},6,[258,348,283],{"class":264},[258,350,351],{"class":286},"technical\u002Ftesting",[258,353,265],{"class":264},[258,355,292],{"class":264},[258,357,295],{"class":264},[258,359,298],{"class":268},[258,361,322],{"class":264},[258,363,365],{"class":260,"line":364},7,[258,366,367],{"class":264},"}\n",[199,369,370,371,373,374,377,378,381,382,384],{},"With this file, ",[203,372,213],{}," may use ",[203,375,376],{},"Functional\\Users\\..."," anywhere, and ",[203,379,380],{},"Technical\\Testing\\..."," in its tests. A class of ",[203,383,217],{}," is a violation.",[199,386,387,388,390,391,394,395,397,398,400,401,403,404,406,407,413],{},"A layer reached through another requirement does not count: if ",[203,389,311],{}," requires ",[203,392,393],{},"technical\u002Fcore",", ",[203,396,213],{}," must still require ",[203,399,393],{}," to use it. Removing a requirement from ",[203,402,311],{}," then never breaks ",[203,405,213],{}," silently. Pass ",[223,408,410],{"href":409},"\u002Fcommands\u002Fosdd-check#options",[203,411,412],{},"--transitive"," to allow these layers too.",[229,415,417],{"id":416},"checking","Checking",[248,419,423],{"className":420,"code":421,"language":422,"meta":254,"style":254},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","php artisan osdd:check\n","bash",[203,424,425],{"__ignoreMap":254},[258,426,427,431,434],{"class":260,"line":261},[258,428,430],{"class":429},"sBMFI","php",[258,432,433],{"class":268}," artisan",[258,435,436],{"class":268}," osdd:check\n",[248,438,443],{"className":439,"code":441,"language":442},[440],"language-text","  ERROR  functional\u002Forders uses functional\u002Fbilling but does not require it.\n\n  functional\u002Forders\u002Fsrc\u002FCheckout.php:7 ........ Functional\\Billing\\Models\\Invoice\n  functional\u002Forders\u002Ftests\u002FCheckoutTest.php:5 .. Functional\\Billing\\Models\\Invoice\n\n   WARN  functional\u002Fbilling requires technical\u002Fcore but does not use it.\n\n  ERROR  1 boundary violation in 4 layers (1 unused requirement).\n","text",[203,444,441],{"__ignoreMap":254},[199,446,447],{},"The command reports:",[449,450,451,467],"table",{},[452,453,454],"thead",{},[455,456,457,461,464],"tr",{},[458,459,460],"th",{},"Finding",[458,462,463],{},"Level",[458,465,466],{},"Meaning",[468,469,470,482,497],"tbody",{},[455,471,472,476,479],{},[473,474,475],"td",{},"Undeclared dependency",[473,477,478],{},"Error",[473,480,481],{},"The layer uses a class of a layer it does not require. Each file and line is listed.",[455,483,484,487,489],{},[473,485,486],{},"Cycle",[473,488,478],{},[473,490,491,492,274,494,246],{},"Layers require each other through ",[203,493,205],{},[203,495,496],{},"functional\u002Forders -> functional\u002Fusers -> functional\u002Forders",[455,498,499,502,505],{},[473,500,501],{},"Unused requirement",[473,503,504],{},"Warning",[473,506,507,508,510,511,513],{},"A layer in ",[203,509,205],{}," or ",[203,512,245],{}," that the layer's code never references.",[199,515,516],{},"It exits with 1 when there is at least one error. Warnings do not fail the command.",[518,519,521],"h3",{"id":520},"what-is-read","What is read",[199,523,524,526,527,530,531,394,534,537,538,540,541,544],{},[203,525,122],{}," reads the ",[203,528,529],{},".php"," files of each layer's source directory, ",[203,532,533],{},"database\u002F",[203,535,536],{},"routes\u002F"," and ",[203,539,241],{}," folders, never ",[203,542,543],{},"vendor\u002F",". It parses them with the PHP tokenizer and never loads them. It collects:",[546,547,548,566,576],"ul",{},[549,550,551,554,555,558,559,537,562,565],"li",{},[203,552,553],{},"use"," imports, with groups (",[203,556,557],{},"use Functional\\Billing\\{Models\\Invoice, Models\\Payment};","), aliases, ",[203,560,561],{},"use function",[203,563,564],{},"use const",";",[549,567,568,569,394,572,575],{},"fully qualified names: ",[203,570,571],{},"\\Functional\\Billing\\Models\\Invoice::class",[203,573,574],{},"new \\...",", attributes, type hints;",[549,577,578,579,394,582,585],{},"qualified names, resolved through the imports and the current namespace (",[203,580,581],{},"Billing\\Models\\Invoice",[203,583,584],{},"namespace\\Foo",").",[199,587,588,589,591],{},"Comments, docblocks and strings are ignored, and an unqualified name only counts through its ",[203,590,553],{}," import.",[199,593,594,595,537,598,601,602,604,605,608],{},"Each name belongs to the layer with the longest matching prefix among the ",[203,596,597],{},"autoload.psr-4",[203,599,600],{},"autoload-dev.psr-4"," entries of every layer. Names of the same layer, of ",[203,603,543],{}," packages, of the framework or of ",[203,606,607],{},"App\\"," are never reported.",[229,610,612],{"id":611},"fixing-a-violation","Fixing a violation",[546,614,615,628,631],{},[549,616,617,618,620,621,623,624,627],{},"Add the used layer to the layer's ",[203,619,205],{},", or to ",[203,622,245],{}," when only its tests use it. Then run ",[203,625,626],{},"composer update"," for the layer.",[549,629,630],{},"Or move the shared code into a layer both may require.",[549,632,633,634,246],{},"Break a cycle by extracting the shared concept into a third layer, often under ",[203,635,636],{},"technical\u002F",[199,638,639,642],{},[223,640,641],{"href":61},"Share code between layers"," walks through each option.",[199,644,645],{},"For a new layer, declare its requirements when you create it:",[248,647,649],{"className":420,"code":648,"language":422,"meta":254,"style":254},"php artisan osdd:layer functional\u002Finvoices --requires=functional\u002Forders --requires=technical\u002Fcore\n",[203,650,651],{"__ignoreMap":254},[258,652,653,655,657,660,663,666],{"class":260,"line":261},[258,654,430],{"class":429},[258,656,433],{"class":268},[258,658,659],{"class":268}," osdd:layer",[258,661,662],{"class":268}," functional\u002Finvoices",[258,664,665],{"class":268}," --requires=functional\u002Forders",[258,667,668],{"class":268}," --requires=technical\u002Fcore\n",[229,670,672],{"id":671},"ignoring-a-dependency","Ignoring a dependency",[199,674,675,678,679,681,682,292],{},[203,676,677],{},"osdd.boundaries.ignore"," lists what ",[203,680,122],{}," does not report. Set it in ",[203,683,684],{},"technical\u002Fosdd\u002Fconfig\u002Fosdd.php",[248,686,689],{"className":687,"code":688,"filename":684,"language":430,"meta":254,"style":254},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","'boundaries' => [\n    'ignore' => [\n        'Technical\\\\Shared\\\\Contracts\\\\',\n        ['functional\u002Forders', 'technical\u002Fpayments'],\n    ],\n],\n",[203,690,691,707,721,746,771,776],{"__ignoreMap":254},[258,692,693,696,699,701,704],{"class":260,"line":261},[258,694,695],{"class":264},"'",[258,697,698],{"class":268},"boundaries",[258,700,695],{"class":264},[258,702,703],{"class":264}," =>",[258,705,706],{"class":264}," [\n",[258,708,709,712,715,717,719],{"class":260,"line":280},[258,710,711],{"class":264},"    '",[258,713,714],{"class":268},"ignore",[258,716,695],{"class":264},[258,718,703],{"class":264},[258,720,706],{"class":264},[258,722,723,726,729,732,735,737,740,742,744],{"class":260,"line":306},[258,724,725],{"class":264},"        '",[258,727,728],{"class":268},"Technical",[258,730,731],{"class":273},"\\\\",[258,733,734],{"class":268},"Shared",[258,736,731],{"class":273},[258,738,739],{"class":268},"Contracts",[258,741,731],{"class":273},[258,743,695],{"class":264},[258,745,303],{"class":264},[258,747,748,751,753,755,757,760,763,766,768],{"class":260,"line":325},[258,749,750],{"class":264},"        [",[258,752,695],{"class":264},[258,754,213],{"class":268},[258,756,695],{"class":264},[258,758,759],{"class":264},",",[258,761,762],{"class":264}," '",[258,764,765],{"class":268},"technical\u002Fpayments",[258,767,695],{"class":264},[258,769,770],{"class":264},"],\n",[258,772,773],{"class":260,"line":333},[258,774,775],{"class":264},"    ],\n",[258,777,778],{"class":260,"line":346},[258,779,770],{"class":264},[449,781,782,792],{},[452,783,784],{},[455,785,786,789],{},[458,787,788],{},"Entry",[458,790,791],{},"Effect",[468,793,794,813],{},[455,795,796,799],{},[473,797,798],{},"A string: class prefix",[473,800,801,802,805,806,809,810,246],{},"References to these classes are allowed from every layer. The prefix matches on namespace boundaries: ",[203,803,804],{},"Functional\\Billing"," covers ",[203,807,808],{},"Functional\\Billing\\..."," but not ",[203,811,812],{},"Functional\\BillingReports\\...",[455,814,815,818],{},[473,816,817],{},"A list of two layer names",[473,819,820,373,822,824,825,827],{},[203,821,213],{},[203,823,765],{}," without requiring it, its requirement on ",[203,826,765],{}," is never reported as unused, and the edge is left out of the cycle detection.",[199,829,830,831,833,834,837],{},"Any other entry fails ",[203,832,122],{}," with ",[203,835,836],{},"Invalid osdd.boundaries.ignore entry [...]",". Ignored references still count as uses for the \"unused requirement\" warning.",[839,840,841],"warning",{},[199,842,843,844,846],{},"Keep the list short. An ignored dependency is still a dependency: fix it in ",[203,845,209],{}," when it is a real one.",[229,848,850],{"id":849},"in-ci","In CI",[199,852,853,854,857,858,246],{},"Run ",[203,855,856],{},"php artisan osdd:check --format=github"," in your pipeline: each violation becomes an annotation on the pull request. See ",[223,859,84],{"href":860},"\u002Fguides\u002Ftesting-and-ci#check-the-boundaries-on-every-pull-request",[229,862,864],{"id":863},"seeing-the-graph","Seeing the graph",[199,866,867,871,872,874],{},[223,868,869],{"href":127},[203,870,126],{}," draws the ",[203,873,205],{}," edges between layers, in Mermaid, DOT or JSON:",[248,876,878],{"className":420,"code":877,"language":422,"meta":254,"style":254},"php artisan osdd:graph > docs\u002Flayers.mmd\n",[203,879,880],{"__ignoreMap":254},[258,881,882,884,886,889,892],{"class":260,"line":261},[258,883,430],{"class":429},[258,885,433],{"class":268},[258,887,888],{"class":268}," osdd:graph",[258,890,891],{"class":264}," >",[258,893,894],{"class":268}," docs\u002Flayers.mmd\n",[896,897,898],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":254,"searchDepth":261,"depth":280,"links":900},[901,902,905,906,907,908],{"id":231,"depth":280,"text":232},{"id":416,"depth":280,"text":417,"children":903},[904],{"id":520,"depth":306,"text":521},{"id":611,"depth":280,"text":612},{"id":671,"depth":280,"text":672},{"id":849,"depth":280,"text":850},{"id":863,"depth":280,"text":864},"The rule osdd:check enforces between layers, what it reads, and how to fix or ignore a violation.","md",null,{},true,{"title":42,"description":909},{"loc":43},"-7700xF75oiGslmjtKlHkgXNBiYjTwkHj9SJvddusqQ",[918,920],{"title":38,"path":39,"stem":40,"description":919,"children":-1},"The folders that hold the layers, what goes in each one, and how OSDD finds the layers inside them.",{"title":46,"path":47,"stem":48,"description":921,"children":-1},"How each layer wires its migrations, seeders, routes, views and config through a provider of its own.",1794437209293]