[{"data":1,"prerenderedAt":455},["ShallowReactive",2],{"navigation_docs_en":3,"-en-docs-getting-started-project-structure":62,"-en-docs-getting-started-project-structure-surround":450},[4,9,26,37,51],{"title":5,"path":6,"stem":7,"icon":8},"Introduction","\u002Fen\u002Fdocs\u002Fintroduction","en\u002Fdocs\u002F1.introduction","i-heroicons-book-open",{"title":10,"icon":11,"path":12,"stem":13,"children":14,"page":25},"Getting Started","i-heroicons-bolt","\u002Fen\u002Fdocs\u002Fgetting-started","en\u002Fdocs\u002F2.getting-started",[15,20],{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fen\u002Fdocs\u002Fgetting-started\u002Finstallation","en\u002Fdocs\u002F2.getting-started\u002Finstallation","i-heroicons-cloud-arrow-down",{"title":21,"path":22,"stem":23,"icon":24},"Project Structure","\u002Fen\u002Fdocs\u002Fgetting-started\u002Fproject-structure","en\u002Fdocs\u002F2.getting-started\u002Fproject-structure","i-heroicons-folder",false,{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":25},"Architecture","i-heroicons-square-3-stack-3d","\u002Fen\u002Fdocs\u002Farchitecture","en\u002Fdocs\u002F3.architecture",[32],{"title":33,"path":34,"stem":35,"icon":36},"Architecture: Nuxt Layers","\u002Fen\u002Fdocs\u002Farchitecture\u002Foverview","en\u002Fdocs\u002F3.architecture\u002Foverview","i-heroicons-cpu-chip",{"title":38,"icon":39,"path":40,"stem":41,"children":42,"page":25},"Plugin System","i-heroicons-puzzle-piece","\u002Fen\u002Fdocs\u002Fplugin-system","en\u002Fdocs\u002F4.plugin-system",[43,46],{"title":38,"path":44,"stem":45,"icon":39},"\u002Fen\u002Fdocs\u002Fplugin-system\u002Fbasics","en\u002Fdocs\u002F4.plugin-system\u002Fbasics",{"title":47,"path":48,"stem":49,"icon":50},"Override System","\u002Fen\u002Fdocs\u002Fplugin-system\u002Foverride-modes","en\u002Fdocs\u002F4.plugin-system\u002Foverride-modes","i-heroicons-arrow-path",{"title":52,"icon":53,"path":54,"stem":55,"children":56,"page":25},"Guides","i-heroicons-academic-cap","\u002Fen\u002Fdocs\u002Fguides","en\u002Fdocs\u002F5.guides",[57],{"title":58,"path":59,"stem":60,"icon":61},"Plugin Creation Guide","\u002Fen\u002Fdocs\u002Fguides\u002Fcreate-plugin","en\u002Fdocs\u002F5.guides\u002Fcreate-plugin","i-heroicons-command-line",{"id":63,"title":21,"body":64,"description":443,"extension":444,"links":445,"meta":446,"navigation":447,"path":22,"seo":448,"stem":23,"__hash__":449},"docs_en\u002Fen\u002Fdocs\u002F2.getting-started\u002Fproject-structure.md",{"type":65,"value":66,"toc":438},"minimark",[67,71,89,99,104,107,161,167,353,357,368,394,397,403,407,423,426,434],[68,69,21],"h1",{"id":70},"project-structure",[72,73,74,75,79,80,84,85,88],"p",{},"Alkademi LMS Open Source uses a Nuxt Layers based ",[76,77,78],"strong",{},"modular monolith"," structure. The application is still one codebase and one build, but features are separated into ",[81,82,83],"code",{},"cores\u002F"," and ",[81,86,87],{},"plugins\u002F",".",[90,91,97],"pre",{"className":92,"code":94,"language":95,"meta":96},[93],"language-text","lms-opensource\u002F\n|-- app\u002F                    # Global components, layouts, composables, and Nuxt plugins\n|   |-- components\u002F          # AppHeader, AppSidebar, and other global components\n|   |-- composables\u002F         # App composables, including the sidebar generator\n|   |-- layouts\u002F             # Default and landing layouts\n|   `-- plugins\u002F             # App-level Nuxt plugins, including the plugin registry\n|-- cores\u002F                  # Built-in LMS features\n|   |-- kelas\u002F\n|   |   |-- components\u002F\n|   |   |-- pages\u002F\n|   |   |-- server\u002Fapi\u002F\n|   |   |-- stores\u002F\n|   |   |-- types\u002F\n|   |   |-- core.config.ts\n|   |   `-- nuxt.config.ts\n|   |-- assignment\u002F\n|   |-- form\u002F\n|   |-- program\u002F\n|   |-- pustaka\u002F\n|   |-- studio\u002F\n|   `-- uikit\u002F\n|-- plugins\u002F                # Custom plugins or extensions\n|   `-- custom-class\u002F\n|       |-- components\u002F\n|       |-- pages\u002F\n|       |-- server\u002Fapi\u002F\n|       |-- plugin.config.ts\n|       |-- sidebar.ts\n|       `-- nuxt.config.ts\n|-- shared\u002F                 # Shared types and utilities\n|   |-- types\u002F\n|   `-- utils\u002Flayers.ts\n|-- web\u002F                    # Landing\u002Fpublic site layer\n|-- public\u002F                 # Static assets\n|-- nuxt.config.ts          # Main layer composition\n`-- package.json\n","text","",[81,98,94],{"__ignoreMap":96},[100,101,103],"h2",{"id":102},"core-folders","Core Folders",[72,105,106],{},"Each core feature is an independent Nuxt Layer. An active core should have:",[108,109,110,121,135,144],"ul",{},[111,112,113,116,117,120],"li",{},[81,114,115],{},"nuxt.config.ts",": allows the folder to be included in the ",[81,118,119],{},"extends"," array.",[111,122,123,126,127,130,131,134],{},[81,124,125],{},"core.config.ts",": defines ",[81,128,129],{},"enabled"," and the ",[81,132,133],{},"routes"," used by the sidebar.",[111,136,137,140,141,88],{},[81,138,139],{},"pages\u002F",": feature pages. For example ",[81,142,143],{},"cores\u002Fkelas\u002Fpages\u002Fdashboard\u002Fkelas\u002Findex.vue",[111,145,146,149,150,149,153,156,157,160],{},[81,147,148],{},"components\u002F",", ",[81,151,152],{},"stores\u002F",[81,154,155],{},"server\u002Fapi\u002F",", and ",[81,158,159],{},"types\u002F",": used as needed by the feature.",[72,162,163,164,166],{},"Example ",[81,165,125],{},":",[90,168,172],{"className":169,"code":170,"language":171,"meta":96,"style":96},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import type { FeatureConfig } from '..\u002F..\u002Fshared\u002Ftypes\u002Ffeature'\n\nexport default {\n  enabled: true,\n  routes: [\n    {\n      key: 'kelas',\n      path: '\u002Fdashboard\u002Fkelas',\n      icon: 'i-heroicons-academic-cap',\n      label: 'Kelas'\n    }\n  ]\n} satisfies FeatureConfig\n","typescript",[81,173,174,210,217,229,245,256,262,280,297,313,328,334,340],{"__ignoreMap":96},[175,176,179,183,186,190,194,197,200,203,207],"span",{"class":177,"line":178},"line",1,[175,180,182],{"class":181},"s7zQu","import",[175,184,185],{"class":181}," type",[175,187,189],{"class":188},"sMK4o"," {",[175,191,193],{"class":192},"sTEyZ"," FeatureConfig",[175,195,196],{"class":188}," }",[175,198,199],{"class":181}," from",[175,201,202],{"class":188}," '",[175,204,206],{"class":205},"sfazB","..\u002F..\u002Fshared\u002Ftypes\u002Ffeature",[175,208,209],{"class":188},"'\n",[175,211,213],{"class":177,"line":212},2,[175,214,216],{"emptyLinePlaceholder":215},true,"\n",[175,218,220,223,226],{"class":177,"line":219},3,[175,221,222],{"class":181},"export",[175,224,225],{"class":181}," default",[175,227,228],{"class":188}," {\n",[175,230,232,236,238,242],{"class":177,"line":231},4,[175,233,235],{"class":234},"swJcz","  enabled",[175,237,166],{"class":188},[175,239,241],{"class":240},"sfNiH"," true",[175,243,244],{"class":188},",\n",[175,246,248,251,253],{"class":177,"line":247},5,[175,249,250],{"class":234},"  routes",[175,252,166],{"class":188},[175,254,255],{"class":192}," [\n",[175,257,259],{"class":177,"line":258},6,[175,260,261],{"class":188},"    {\n",[175,263,265,268,270,272,275,278],{"class":177,"line":264},7,[175,266,267],{"class":234},"      key",[175,269,166],{"class":188},[175,271,202],{"class":188},[175,273,274],{"class":205},"kelas",[175,276,277],{"class":188},"'",[175,279,244],{"class":188},[175,281,283,286,288,290,293,295],{"class":177,"line":282},8,[175,284,285],{"class":234},"      path",[175,287,166],{"class":188},[175,289,202],{"class":188},[175,291,292],{"class":205},"\u002Fdashboard\u002Fkelas",[175,294,277],{"class":188},[175,296,244],{"class":188},[175,298,300,303,305,307,309,311],{"class":177,"line":299},9,[175,301,302],{"class":234},"      icon",[175,304,166],{"class":188},[175,306,202],{"class":188},[175,308,53],{"class":205},[175,310,277],{"class":188},[175,312,244],{"class":188},[175,314,316,319,321,323,326],{"class":177,"line":315},10,[175,317,318],{"class":234},"      label",[175,320,166],{"class":188},[175,322,202],{"class":188},[175,324,325],{"class":205},"Kelas",[175,327,209],{"class":188},[175,329,331],{"class":177,"line":330},11,[175,332,333],{"class":188},"    }\n",[175,335,337],{"class":177,"line":336},12,[175,338,339],{"class":192},"  ]\n",[175,341,343,346,349],{"class":177,"line":342},13,[175,344,345],{"class":188},"}",[175,347,348],{"class":181}," satisfies",[175,350,352],{"class":351},"sBMFI"," FeatureConfig\n",[100,354,356],{"id":355},"plugin-folders","Plugin Folders",[72,358,359,360,363,364,367],{},"Plugins are also Nuxt Layers, but they use ",[81,361,362],{},"plugin.config.ts",". When ",[81,365,366],{},"enabled: true",", a plugin will:",[108,369,370,373,376,382,388],{},[111,371,372],{},"be included in the Nuxt Layer composition;",[111,374,375],{},"be registered in the runtime plugin registry;",[111,377,378,379,381],{},"add sidebar routes from the ",[81,380,133],{}," field;",[111,383,384,385,381],{},"replace selected cores through the ",[81,386,387],{},"replaces",[111,389,390,391,88],{},"optionally enrich the sidebar through ",[81,392,393],{},"sidebar.ts",[72,395,396],{},"Minimal plugin structure:",[90,398,401],{"className":399,"code":400,"language":95,"meta":96},[93],"plugins\u002Fmy-plugin\u002F\n|-- pages\u002F\n|   `-- dashboard\u002Fmy-plugin\u002Findex.vue\n|-- plugin.config.ts\n`-- nuxt.config.ts\n",[81,402,400],{"__ignoreMap":96},[100,404,406],{"id":405},"shared-types-and-discovery","Shared Types and Discovery",[72,408,409,410,413,414,417,418,84,420,422],{},"The contracts for cores, plugins, and sidebars live in ",[81,411,412],{},"shared\u002Ftypes\u002F",". Layer auto-discovery lives in ",[81,415,416],{},"shared\u002Futils\u002Flayers.ts","; it reads ",[81,419,125],{},[81,421,362],{}," to decide which layers are active.",[424,425],"hr",{},[72,427,428,429,88],{},"Next, let's dive deeper into the ",[430,431,433],"a",{"href":432},"\u002Farchitecture\u002Foverview","Layer Architecture",[435,436,437],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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);}",{"title":96,"searchDepth":212,"depth":212,"links":439},[440,441,442],{"id":102,"depth":212,"text":103},{"id":355,"depth":212,"text":356},{"id":405,"depth":212,"text":406},"Alkademi LMS Open Source uses a Nuxt Layers based modular monolith structure. The application is still one codebase and one build, but features are separated into cores\u002F and plugins\u002F.","md",null,{},{"icon":24},{"title":21,"description":443},"-UpoybixMS7e1tUcDBZLOvupvJrWae_5NfGE29Ht4pY",[451,453],{"title":16,"path":17,"stem":18,"description":452,"icon":19,"children":-1},"Follow the steps below to install Alkademi LMS Open Source in your local environment.",{"title":33,"path":34,"stem":35,"description":454,"icon":36,"children":-1},"Alkademi LMS Open Source is built as a modular monolith. Every feature still runs inside one Nuxt application, but each domain feature is isolated as a Nuxt Layer so it can be maintained, replaced, or extended more easily.",1780026930465]