Admin System¶
Mozaiks Studio does not expose a separate customer-facing /admin page in the first-party Studio. The Admin Portal entry for Studio routes to /apps, which is the workspace app-management surface.
App Studio keeps these pages visible instead:
Generated app AdminPortal routes use /admin and /admin/<page> paths. The /apps/:appId/... route family is reserved for first-party Studio and hosted product app operations.
Framework-owned admin composition remains internal and host-owned. Build, Usage, app access, and support are product surfaces; they are not admin sections. Deep diagnostic routes such as /apps/:appId/health, /apps/:appId/activity, and /apps/:appId/integrations may remain routable but hidden from primary navigation when they are needed for support, build history, or setup detail. Hosted deployments may provide billing or hosting surfaces through their own workspace routes or capability packs; the OSS factory Studio does not hardcode those hosted product routes.
Terminology note:
- use
Operational healthinside Overview for runtime posture, workflow reliability, validation, hosting, and integration setup signals - keep
operationsas an internal admin taxonomy when framework-owned admin panels need a bounded section for incidents, logs, or runtime state
Ownership¶
| Source | Owner | Declared In | Data/API |
|---|---|---|---|
| Runtime/operator panels | platform host | framework admin contract plus app/app.json admins for access | same-host /api/admin/* |
| Feature panels | module contract | modules/{module}/contracts/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 framework-owned admin shell.
Canonical Model¶
The admin system has four distinct layers. Keep them separate:
app/app.jsonadminsis the admin bootstrap/access allowlist for the app.- The built-in admin section registry is framework-owned and defines the semantic section ids, default labels, route paths, and default ordering for the app admin route family.
modules/{module}/contracts/admin.yamlcontributes feature-owned panels into those semantic sections.- An optional connected app backend may contribute app-business panels through
GET {app_backend_url}/api/admin/config.
AdminPortal should resolve section rendering from those contracts. Studio workspace/app navigation is a separate WorkspaceLayout concern and must not be mutated by module admin panels.
Admin Bootstrap¶
There is no app-level admin.json contract anymore.
Admin bootstrap and access are owned by app/app.json admins plus the normal auth role model.
Runtime/operator panels are framework-owned defaults surfaced by same-host /api/admin/* endpoints. Feature panels and app-business panels use their own contracts described above. The same-host /api/admin/* endpoints are internal framework APIs; Studio pages may consume their data, but customer-facing copy should not expose "Admin" as a product section.
That means:
- generated apps should set
app/app.jsonadminsfor bootstrap access - generators should not emit
app/config/admin.json - runtime/operator panels remain framework-owned
- the workflow-owned build sequence and other product routes remain separate product concerns, not admin sections
Example:
Generated app hosts may still mount framework-owned admin panels through AdminPortal, but generators must not create a separate app-admin page, route family, page schema, or admin React shell for Studio.
Built-In Section Registry¶
The built-in admin sections are framework-owned. They provide the semantic taxonomy for:
- internal admin shell route injection
- sidebar and drawer navigation
- section-level rendering inside
AdminPortal - placement of runtime, module, and app-backend panels
The canonical built-in ids are:
The taxonomy is fixed by the framework today. If a future product genuinely needs bounded app-level section overrides, add a new explicit contract rather than reintroducing app/config/admin.json.
Implementation rule:
- runtime/platform code owns the canonical section metadata
- frontend admin rendering must derive section routing from that canonical metadata or from a payload resolved from it
- Studio navigation stays deterministic and product-scoped; admin panels do not add, rename, or reorder Studio nav items
First-party Studio routes must be declared in factory_app/app/ui/route_manifest.json. The first-party factory_app/app/admin/admin_registry.yaml is reserved for AdminPortal extension pages and should not duplicate Studio product routes. Generated app admin registries normally omit surfaces and are mounted by the platform host.
Feature Admin Contract¶
Feature-owned admin UI lives in modules/{module}/contracts/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 generated-app 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.
Custom Admin UI vs Custom Admin Routes¶
Mozaiks must allow agent-generated custom admin UI, but the default path is to generate panels inside the host-owned generated-app admin shell, not to generate a second admin shell.
Use this order of preference:
renderer: schemafor panels that can be expressed through the shipped primitive systemrenderer: custom_componentfor bounded React customization when schema is not sufficient- only introduce standalone generated admin route families through a future, explicit contract if the product truly needs them
Do not overload app/app.json, modules/{module}/contracts/admin.yaml, or any other existing contract into a general admin-page generator. If Mozaiks later supports agent-generated standalone admin subroutes, that must be a new contract with explicit ownership, registration, and validation rules.
Componentization Rule¶
"Fully componentized" in the admin system means:
- the shell is presentation-first and consumes a resolved navigation model
- built-in section ids and routes come from one canonical registry
- module and app-backend panels plug into those sections through explicit contracts
- custom React is a bounded extension point declared by contract, not an ad hoc frontend escape hatch
It does not mean that agents may emit arbitrary admin React pages or bypass the host-owned generated-app admin shell by default.
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:
app/services/admin_config.pyreturns the canonical payloadapp/services/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 generated-app admin shell behavior described here.
Generator Rules¶
- Populate
app/app.jsonadminsfor admin bootstrap access. - Generate
modules/{module}/contracts/admin.yamlonly when the module needs 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, frontend admin shells, or ad hoc admin route families.
Access¶
Admin access follows the platform auth rules:
- JWT role includes
admin - user email matches an entry in
app/app.jsonadmins - 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