Back to docs
Guide 08

Administration

Operational guide for administrators: users, roles and RBAC, workspaces, audit, licenses, and administrative backups. Every operation requires authMiddleware plus specific permissions - see the API Reference for the full endpoint inventory.

4 min read

Operational guide for administrators: users, roles and RBAC, workspaces, audit, licenses, and administrative backups. Every operation requires authMiddleware plus specific permissions - see the API Reference for the full endpoint inventory.

Bootstrap admin

On first startup (when SEED_BOOTSTRAP_ADMIN=true), the server creates an admin account from env credentials (SEED_ADMIN_USERNAME=admin, SEED_ADMIN_PASSWORD=admin123, [email protected]). The account carries mustChangePassword=true → the first login forces a rotation. Setup wizard via GET /api/system/is-initialized → POST /api/system/initialize.

Security: change the bootstrap password immediately and set a strong JWT_SECRET
in production. The scryptSync(JWT_SECRET, ...) fallback for ENCRYPTION_KEY makes
JWT_SECRET cryptographic material - never expose it.

Users - /api/users

OperationEndpointPermission
Paginated listGET /usersrequireAdmin
DetailGET /users/:idself/admin
UpdatePUT/PATCH /users/:idself/admin (updateUserSchema)
DeleteDELETE /users/:idrequireAdmin
AvatarPOST/DELETE /users/:id/avatarJWT (multipart)

Delete: DELETE is a hard delete with relation cleanup (UserRole, ProjectAccess, WorkspaceAccess) and auth-cache invalidation; an admin cannot delete themselves. updateUserSchema validates username/email/password/firstName/lastName/customInstructions/textSize (custom instructions are prepended to the agent's system prompt); non-admins cannot change their own password through this endpoint.

Roles & RBAC - /api/roles

44 permissions defined in packages/shared/src/constants/permissions.ts (PERMISSION_NAMES). 15 menu sections (MENU_SECTIONS, includes uploads, skills, and plugins).

OperationEndpointPermission
Visible menu sectionsGET /roles/me/menu-sectionsJWT
List rolesGET /rolesrequireAdmin
DetailGET /roles/:roleIdrequireAdmin (UUID)
CreatePOST /rolesrequireAdmin (createRoleSchema, isDefault=false)
UpdatePUT /roles/:roleIdrequireAdmin (atomic permission replace)
Role menu sectionsPUT /roles/:roleId/menu-sectionsrequireAdmin
Per-role visibilityGET/PUT /roles/:roleId/visibilityrequireAdmin (per-section visibility matrix)
DeleteDELETE /roles/:roleIdrequireAdmin
Assign/RevokePOST /roles/assign /revokerequireAdmin

Default roles: admin (all 44 permissions) and user (16 permissions: the 9 base ones plus memory:read/memory:write for per-user memories, skill:create/skill:read/skill:write/skill:delete for custom user skills, and widget:manage; filters:manage is reserved for admin/superuser). "Superuser" coincides with admin. Permissions are enforced via requirePermission(name) or the requireAdmin shortcut. Assignment is many-to-many (UserRole).

Workspaces & Projects

Workspace (/api/workspaces): the isolation unit for chats, documents, and agent config.

  • Creation: workspace:create + license max_workspaces (Community 3, Enterprise ∞).
  • Access: requireWorkspaceAccess middleware (WorkspaceAccess join table).
  • Soft-delete + restore (PUT /:id/restore).
  • Chat folders: /:id/folders[/:folderId] + restore.

Project (/api/projects): groups related workspaces.

  • Creation: project:create + license max_projects.
  • Access: requireProjectAccess (ProjectAccess).
  • Archive export: GET /:projectId/export (stream).
  • Usage stats: GET /:projectId/usage.

Audit / Event Log - /api/event-logs

License audit_log_immutable (Enterprise). GET with filters entityType/entityId/userId plus limit/offset (pagination). eventLogService.logEvent delegates the write to the enterprise plugin (a no-op in Community) and dispatches fire-and-forget webhooks. Logged entities (EntityType, 24 types): user, role, workspace, project, chat, document, mcp_connection, mcp_catalog_entry, dlp, archive/archive_page/archive_import, ocr_job, synthesis_run, wiki_edit, skill, upload_draft, chat_connector, widget, quota, backup_destination/backup_job, provider, memory. When the immutable flag is active, records cannot be modified or deleted (app-level append-only).

Licenses

  • Community (default): limited flags (see 03 - Configuration).
  • Enterprise: licenses are RS256 (asymmetric) JWTs - the public key is embedded in the server source (packages/server/src/services/license-public-key.ts), so only LICENSE_KEY is needed (vendor-issued, no secret env: the v0.22-era HS256 LICENSE_SECRET died with the asymmetric rotation). Payload validated against licensePayloadSchema. Expired/invalid → Community fallback with a warning, graceful degradation at runtime (no restart).
  • Endpoint: GET /api/license/info (public) → { license, features }.
  • Runtime instance-license slot (Phase 221, no-.env): **Settings → Security → License** (admin, admin:settings) pastes the vendor-issued RS256 JWT. Verified probe-first (a rejected key is never stored), stored ONLY as AES-256-GCM ciphertext (SystemConfig INSTANCE_LICENSE - the plaintext and its ciphertext never ride any response), applied to the live instance by the same resolver the boot step runs. Source precedence (identical at boot and runtime): INSTANCE_LICENSE slot → verified plugin row (enterprise-tier license) → ENV LICENSE_KEY → Community.
  • Slot APIs: PUT /api/license/instance ({ licenseKey } → 200 { licenseStatus: "verified", tier, licensee, expiresAt }; rejects are 400 { error, reason } with the closed reason invalid/expired/plugin_bound/ community_tier), GET /api/license/instance (metadata-only status surface), DELETE /api/license/instance (clears the paste: the instance reverts to what the NEXT BOOT would derive, boot/runtime parity). A paste must be UNCLAIMED (plugin-bound keys act only as that plugin's license - the instance slot rejects them with plugin_bound) and only an ENTERPRISE-tier key can be stored (a community paste would silently downgrade a valid env key - rejected with community_tier). The bulk settings channel (PUT /api/system/settings) rejects the key - the paste route is its sole write path.
  • Gating: requireFeature(flag) → 402; requireFeatureLimit(flag, model) → 402 when count >= limit (Enterprise = Infinity).

Administrative backups

See 05 - Feature Guide § Backup. Admin endpoints:

  • Logs /api/system/backups (backup:log:read).
  • Destinations /api/backup-destinations (backup:destination:read/write, license max_backup_destinations).
  • Jobs /api/backup-jobs (backup:job:read/write), manual trigger POST /:id/run.
  • Restore /api/backups/restore/:logId[/dry-run] (backup:restore:write).
  • Test destination POST /backup-destinations/:id/test.

Settings - /api/system/settings

Bulk GET/PUT (returns { updated, rejected }). Groups: LLM, Embedding/Vector, ports/URL, Auth, Branding (gated white_label), Feature, OCR, Synthesis, Retention. ALWAYS_READONLY keys are rejected. Chat retention only via PUT /api/system/chat-retention (audited, confirmDataLoss: true). Details in 03 - Configuration.

SSO - /api/sso

License sso_enabled. GET/PUT /config, POST /test. Enterprise SAML/OIDC config.

v0.28.1 Provenance

StatementSource
44 permissions / 15 menu sections (+skills/plugins); admin = [...PERMISSION_NAMES] (all 44); user = 16 permissionspackages/shared/src/constants/permissions.ts (row-time source count, 35-02 probe) - F-RBAC-1/2/4
GET/PUT /roles/:roleId/visibility (per-section visibility matrix)packages/server/src/routes/roles.ts (row-time) - F-RBAC-4
RS256 license + embedded public key + runtime instance slot + the /api/license/instance routes (+closed reasons)docs/ADMIN.md (Enterprise License, Runtime license paste - Phase 221) - F-LIC-1
EntityType = 24 types (incl. skill, chat_connector, widget, quota)packages/shared/src/types/index.ts:250 (row-time) - F-AUDIT-1

Operational reference - Simmetric Chat v0.28.1 (docs updated 2026-10-02, census SHA `aca5b8ff`).