Alkademi Logo
Architecture

Arsitektur: Nuxt Layers

Alkademi LMS Open Source dibangun sebagai modular monolith. Semua fitur tetap berjalan sebagai satu aplikasi Nuxt, tetapi setiap domain fitur dipisah menjadi Nuxt Layer agar lebih mudah dirawat, diganti, atau diperluas.

Arsitektur: Nuxt Layers

Alkademi LMS Open Source dibangun sebagai modular monolith. Semua fitur tetap berjalan sebagai satu aplikasi Nuxt, tetapi setiap domain fitur dipisah menjadi Nuxt Layer agar lebih mudah dirawat, diganti, atau diperluas.

Komposisi Layer

Komposisi layer utama berada di nuxt.config.ts root:

import { resolve } from 'path'
import { getLayerDirs } from './shared/utils/layers'

const rootDir = resolve(__dirname)

export default defineNuxtConfig({
  extends: [
    './web',
    ...getLayerDirs(rootDir, 'plugins'),
    ...getLayerDirs(rootDir, 'cores')
  ],
  modules: ['@pinia/nuxt', '@nuxt/ui']
})

Urutan aktual project adalah:

  1. ./web untuk landing/public site.
  2. Plugin aktif dari folder plugins/.
  3. Core aktif dari folder cores/.

Layer tidak ditulis manual satu per satu. Fungsi getLayerDirs(rootDir, baseDir) memindai folder plugins/ dan cores/, lalu hanya memasukkan folder yang memiliki nuxt.config.ts dan config aktif.

Auto-Discovery Core

Core dianggap aktif jika:

  • foldernya berada di cores/{core-id};
  • memiliki nuxt.config.ts;
  • memiliki core.config.ts;
  • core.config.ts berisi enabled: true;
  • core tersebut tidak sedang diganti oleh plugin aktif melalui replaces.

Jika core tidak memiliki core.config.ts, tidak memiliki flag enabled, atau enabled: false, layer tersebut dilewati.

Auto-Discovery Plugin

Plugin dianggap aktif jika:

  • foldernya berada di plugins/{plugin-id};
  • memiliki nuxt.config.ts;
  • memiliki plugin.config.ts;
  • plugin.config.ts berisi enabled: true.

Plugin aktif juga dibaca untuk menentukan core yang diganti. Jika sebuah plugin memiliki replaces: ['program'], core program tidak dimasukkan ke komposisi layer.

Replacement Core

Mekanisme replacement saat ini berbasis field replaces, bukan overrideMode atau targetCore.

export default {
  enabled: true,
  replaces: ['program'],
  routes: [
    {
      key: 'custom-class',
      path: '/dashboard/custom-class',
      icon: 'i-heroicons-sparkles',
      label: 'Custom Class'
    }
  ]
}

Saat plugin di atas aktif, discovery akan melewati core program. Dengan cara ini plugin dapat mengambil alih fitur core tanpa mengubah source di cores/program.

Runtime Registry

Selain discovery build-time di shared/utils/layers.ts, aplikasi juga punya runtime registry di app/plugins/plugin-registry.ts.

Registry ini:

  • membaca semua plugins/*/plugin.config.ts dengan import.meta.glob;
  • memvalidasi field enabled, replaces, dan routes;
  • hanya mendaftarkan plugin yang aktif;
  • menyediakan usePluginRegistry() untuk composable lain seperti sidebar.

Sidebar tidak ditulis statis di komponen. app/composables/useSidebarMenu.ts membangun menu dari:

  • core.config.ts untuk menu core;
  • plugin.config.ts untuk menu plugin;
  • optional sidebar.ts dari core/plugin untuk menu dinamis;
  • daftar core yang diganti oleh plugin aktif.

Ini membuat route, plugin registry, dan navigasi dashboard tetap mengikuti konfigurasi feature.


Pelajari lebih lanjut tentang Sistem Plugin untuk melihat bagaimana kustomisasi dilakukan.

Copyright © 2026