Admin System¶
Mozaiks has one visible admin route family:
/admin
/admin/users
/admin/billing
/admin/usage
/admin/activity
/admin/settings
/admin/integrations
/admin/support
These routes are rendered by the framework-owned AdminPortal component. The shell is fixed and semantic. Studio, Build, and other builder surfaces are separate product routes, not admin sections.
Ownership¶
| Source | Owner | Declared In | Data/API |
|---|---|---|---|
| Runtime/operator panels | platform host | app/config/admin.json | same-host /api/admin/* |
| Feature panels | module contract | modules/{module}/admin.yaml | module actions and optional backend/admin.py hooks |
| App-business panels | optional connected app backend | app_backend_url/api/admin/config | app_backend_url/api/admin/* |
The platform host owns the shell and access model. Modules own feature admin panels. An app backend may add app-business panels, but it does not replace the host-owned /admin shell.
Host Config¶
app/config/admin.json is host-owned. It controls:
- whether admin is enabled
- admin email allowlist
- section visibility and ordering
- runtime/operator panel visibility
It does not declare feature panels.
Example:
{
"schema_version": "mozaiks.admin.host.v1",
"enabled": true,
"admin_emails": ["builder@example.com"],
"sections": {
"overview": { "label": "Overview", "enabled": true, "order": 999 },
"users": { "label": "Users", "enabled": true, "order": 1000 },
"billing": { "label": "Billing", "enabled": false, "order": 1001 },
"usage": { "label": "Usage", "enabled": true, "order": 1002 },
"activity": { "label": "Activity", "enabled": true, "order": 1003 },
"settings": { "label": "Settings", "enabled": true, "order": 1004 },
"integrations": { "label": "Integrations", "enabled": true, "order": 1005 },
"support": { "label": "Support", "enabled": true, "order": 1006 }
},
"runtime_panels": [
{ "id": "stats", "label": "Usage Stats", "section": "usage" },
{ "id": "runs", "label": "Active Runs", "section": "usage" },
{ "id": "sessions", "label": "Recent Sessions", "section": "activity" }
]
}
When this file exists and enabled is true, the platform shell injects the /admin route family with the AdminPortal component. Generators must not create a separate admin page, /app-admin route, page schema, or admin React shell.
Feature Admin Contract¶
Feature-owned admin UI lives in modules/{module}/admin.yaml.
Each panel must declare one semantic section:
The canonical module admin schema is mozaiks.admin.v2.
Example:
schema_version: mozaiks.admin.v2
panels:
- id: campaigns.overview
label: Campaigns
description: Review and manage campaign activity.
section: usage
order: 20
renderer: schema
layout: full-width
sections:
- id: campaigns-table
primitive: DataTable
config:
api_endpoint: /api/modules/campaigns/list_campaigns
columns:
- key: name
label: Campaign
- key: status
label: Status
type: badge
permissions: [campaigns.write]
hooks: []
Use renderer: schema for the normal path. Schema panels reuse the same primitive section system as ui/pages/*.yaml, but they render inside the host-owned /admin shell rather than becoming standalone routes.
Use renderer: custom_component only when the shipped primitive system cannot express the panel cleanly. In that case:
admin.yamldeclaresrenderer: custom_componentand a stablecomponentregistry keymodule_contract.js_stubsdeclares the required React stub file- the app-level
ui/index.jsregistration barrel registers that component
Optional Python support for complex panel data belongs in modules/{module}/backend/admin.py.
App-Backend Panels¶
A connected app backend may contribute app-business admin panels through GET {app_backend_url}/api/admin/config.
Those panels must declare:
schema_version: mozaiks.admin.app_backend.v1panels[]renderer: builtin | schema | custom_componentbuiltin_panelfor builtin panelslayout + sections[]for schema panelscomponentfor bounded custom components
Recommended generated file ownership for split backends:
backend/admin_config.pyreturns the canonical payloadbackend/routes/admin.pyexposes it throughmozaiksai.core.admin.build_app_backend_admin_router(...)- AppGenerator should treat
ControllerOutput.app_backend_admin_configas the typed source of truth and may regenerate those two files from it during assembly/download validation.
This keeps admin rendering deterministic across module-owned and app-backend surfaces.
The detailed connected app-backend panel contract remains repo-internal planning material for now. Keep the public contract anchored on this page plus the host-owned /admin shell behavior described here.
Generator Rules¶
- Generate
app/config/admin.jsonfor admin access and runtime/operator panel visibility only. - Generate
modules/{module}/admin.yamlfor feature-owned admin panels. - Every generated admin panel must set
sectionto one of the semantic admin sections listed above. - Prefer
renderer: schemawithlayout + sections[]. - Use
renderer: custom_componentonly when the shipped primitive system cannot express the panel cleanly. - Mark admin-only module actions in
module.yaml.actions[]with admin permissions. - Do not generate admin page schemas,
/app-admin, standalone admin servers, or frontend admin shells.
Access¶
Admin access follows the platform auth rules:
- JWT role includes
admin - user email matches
admin_emailsinapp/config/admin.json - local dev auth mode allows admin access
The unified UI does not collapse authority:
- runtime/operator panels use same-host admin APIs
- feature panels use module contracts
- app-business panels may use a connected app backend