{
  "version": 1,
  "note": "Hand-committed page manifest — the authoritative source of pages (feature-registry tries /api/features/list first, then falls back here; that live scan endpoint is deferred — see docs/architecture/webui-architecture.md). 'module' is the feature's self-registering index.js; the kernel loads these from here so they no longer need <script> tags in index.html. 'handler' names the LibrePortalSPAClean method kept as the fallback during the strangler migration; 'navId' is the topbar element id for active-state highlighting.",
  "features": [
    {
      "id": "dashboard",
      "routes": [
        "/",
        "/dashboard"
      ],
      "module": "/components/dashboard/index.js",
      "handler": "handleDashboard",
      "navId": "nav-dashboard",
      "nav": {
        "label": "Dashboard",
        "order": 10
      },
      "order": 10
    },
    {
      "id": "apps",
      "routes": [
        "/apps",
        "/apps*",
        "/app",
        "/app*"
      ],
      "module": "/components/apps/index.js",
      "handler": "handleApps",
      "navId": "nav-app-center",
      "nav": {
        "label": "App Center",
        "order": 20
      },
      "order": 20
    },
    {
      "id": "admin",
      "routes": [
        "/admin",
        "/admin*"
      ],
      "module": "/components/admin/index.js",
      "handler": "handleAdmin",
      "navId": "nav-config",
      "nav": {
        "label": "Admin",
        "order": 40
      },
      "order": 40
    },
    {
      "id": "tasks",
      "routes": [
        "/tasks",
        "/tasks*"
      ],
      "module": "/components/tasks/index.js",
      "handler": "handleTasks",
      "navId": "nav-tasks",
      "nav": {
        "label": "Tasks",
        "order": 60
      },
      "order": 60
    },
    {
      "id": "updater",
      "routes": [
        "/updater",
        "/updater*"
      ],
      "module": "/components/updater/index.js",
      "navId": "nav-updater",
      "order": 30
    }
  ]
}
