Skip to content
Select themeSelect language

The owner console

The owner console at /admin is the instance-wide administration surface. It is one shell with a tab rail; every tab is a query parameter on the same route (/admin/?tab=<key>), which the console echoes as a locator chip under its title. In the sidebar it is labelled Owner, and it sits in an admin-gated section together with the separate Operator console. Nothing on this page is workspace-scoped except where a tab is explicitly called out as such — an edit here changes the deployment for every organization on it.

The owner console at /admin with its tab rail — users, features, plans, templates, customers, queues, audit and the marketplace review surfaces.The owner console at /admin with its tab rail — users, features, plans, templates, customers, queues, audit and the marketplace review surfaces.

These three surfaces are routinely confused. They are distinct routes with distinct authorization.

Surface Route Scope Who may open it
Owner console /admin The whole instance — users, billing plans, entitlements, marketplace governance An instance admin only
Operator console /operator The whole instance — cross-tenant operability plus the global kill-switch An instance admin session, or a headless deployment operator token
Operations report /reports/operations One workspace — that workspace’s dispatch, routing and circuit breakers That workspace’s owner or admin

/reports/operations is a tab of the Reports hub, not a console: it is the read-only, tenant-scoped view of the same operability data, and a workspace owner reaches it without any instance privilege. See Reports. The cross-tenant reads and the global global_dispatch switch live on /operator only — see Operate the delivery engine.

A user is an instance admin when their user_profiles.is_admin column is true or they hold the system_admin row in user_roles. That flag is set at profile creation and only then: an email that case-insensitively matches SUPACLOUD_INITIAL_ADMIN_EMAILS is created both approved and admin; every other signup is created neither. The console offers no control to promote a user, so promoting one is a database or bootstrap-configuration act, not a UI act.

Authorization is enforced in two independent places. The whole /api/admin/* sub-router is wrapped in a require_system_admin middleware layer, and each handler additionally calls require_admin_user — which first requires an approved account, then the admin flag. The page itself redirects a non-admin to /settings after its profile load resolves, and the sidebar entry is hidden without the flag; neither of those is the security boundary.

Tab Route What it governs Most consequential change
Users ?tab=users Approval of every account on the instance Reject — it deletes the pending account row outright
Features ?tab=features Nothing — it reports which optional features are wired Read-only
SEO ?tab=seo Nothing — it reports the marketing site’s metadata health Read-only
Plans ?tab=plans Every billing plan’s price, interval, included seats and visibility Editing amount_cents rotates the plan’s Stripe Price
Templates ?tab=templates The transactional email the instance sends Saving overwrites the live subject and body for all recipients
Customers ?tab=customers Nothing — it lists every workspace with its plan and subscription status Read-only
Overrides ?tab=overrides Entitlement grants that sit above the plan A global (unscoped) grant changes entitlements for every tenant
Queues ?tab=queues Nothing — it reports the Stripe event backlog and reconciliation status Read-only
Audit ?tab=audit Nothing — it is the append-only record of admin and billing changes Read-only
Marketplace Payouts ?tab=payouts Seller payouts and the platform fee percentages Submit — it sends a SEPA batch to the bank; there is no un-submit
Error page ?tab=error-page The instance-default App error page Saving replaces the whole JSON bag; there is no merge
Marketplace review ?tab=marketplace-review The install gate on catalog items Approve — it flips an item to verified and thus installable
Marketplace sources ?tab=marketplace-sources Source registry of the active workspace, not the instance Deleting a source (refused while it has published items)

An unknown or absent tab parameter falls back to Users.

Backed by GET /api/admin/users/pending and GET /api/admin/users, with POST /api/admin/users/{user_id}/approve and DELETE /api/admin/users/{user_id}/reject.

The tab has two blocks: Pending Users — a warning-edged action list with Approve / Reject per row — above All Users, the full roster with an admin badge and an Approved / Pending status badge per account.

Reject is irreversible. It is not a status change: the server hard-deletes the user_profiles row (WHERE approved = false). There is no undo and no rejected-user list; the person must register again. Approve, by contrast, is a one-way UPDATE ... SET approved = true and is safe to re-issue.

This tab shows the admin flag but never sets it.

Backed by GET /api/admin/feature-availability. Read-only.

The feature-availability report answers one question: which optional, secret-backed features does this running process actually have configured. A KPI strip carries the resolved Secret backend (env or openbao), an available-of-total count, a Boot-critical health badge, the deployment Edition (Community or Enterprise) and the unavailable count. Below it, one row per feature — category, name, the env-var name chips, and an Available / Unavailable badge — with a drawer per row.

Nothing on this tab writes anything. To change what it reports, set the named variable in the environment or in the supacloud/app vault map and redeploy — see Environment variables, the SECRET_BACKEND matrix and Secret provisioning. The reported edition comes from the license token, not from this tab; see Apply an edition license.

Backed by GET /api/admin/seo. Read-only.

A diagnostic of the public marketing site’s metadata: a score, the number of indexed routes, the locales served, the count of public plans, then the search and social assets — canonical base URL, Open Graph image with its dimensions and a live preview, and the Twitter card type — and finally one row per check with its status. Changing any of it is a marketing-site configuration or build change; the tab has no controls.

Backed by GET /api/admin/plans, PUT /api/admin/plans/{plan_id} and POST /api/admin/plans/{plan_id}/stripe-sync.

Every billing plan on the instance, including inactive and non-public ones. Each row is an editable draft — display name, amount in cents, Included seats, interval (month, year, one_time, custom) and currency (EUR, USD, GBP) — committed per row with Save, plus Active and Public toggles and a per-plan Stripe sync.

  • A plan is a shared instance object. Editing one changes it for every organization subscribed to it, immediately.
  • An amount_cents change rotates the plan’s Stripe Price. The Stripe sync action is a preview of that reconciliation, not the money movement itself.
  • Included seats is the plan’s users.max entitlement: a non-negative whole number, or the literal unlimited. Anything else is rejected. For how the pool and the overage bill, see Manage seats and billing — this page does not restate it.
  • Every save writes an audit entry with before/after, visible on the Audit tab.

Backed by GET /api/admin/templates and PUT /api/admin/templates/{key}.

The transactional-email templates the instance sends, stored in the database rather than in the image. Three columns: the list of template keys, an editor (Subject, Body, optional Change reason) and a live preview rendering the body against a sample context. Detected {{variable}} placeholders are listed as chips under the editor, and the row header shows whether the draft is unsaved.

Saving replaces the stored subject and body for the whole instance — the next email of that kind uses the new text. The change reason is written to the audit log, but the tab offers no revert and no version list; recovering an earlier wording means reading it back out of the audit entry.

Backed by GET /api/admin/customers. Read-only.

Every workspace on the instance grouped under its owning organization: an organization header (name, a Personal / Organization kind badge, workspace count) over one row per workspace showing its plan id and a subscription-status badge. A workspace whose organization the payload does not carry falls into a single ungrouped bucket rather than disappearing. There are no controls.

Backed by GET /api/admin/overrides/board (server-paginated, with feature, scope and status facets plus free-text search), POST /api/admin/overrides and POST /api/admin/overrides/{override_id}/revoke.

An entitlement override grants a feature entitlement outside the plan. The grant form takes a feature key, a JSON value (a number, a string such as "unlimited", or an object), a reason, an optional workspace and/or user scope, and an optional expiry. The table lists Feature, Scope, Value, Expires and Status; an unscoped row shows scope Global.

Revoke is a stamp, not a delete: the row stays in the table with status revoked, which is what makes the grant history auditable. Granting and revoking both write audit entries.

Backed by GET /api/admin/queues. Read-only.

Three figures on one card: Stripe events (total received), Pending (received but not yet processed) and a Reconciliation status badge. It answers whether the Stripe webhook backlog is draining. There is no requeue or replay control here.

Backed by GET /api/admin/audit/board.

The admin and billing audit log — plan edits, override grants and revokes, template changes — each entry carrying before/after snapshots. The board is server-paginated with facet filters on action and target kind, free-text search and header sort on action and target.

This log is append-only from the console: there is no delete, no edit and no retention control on this tab.

Backed by GET /api/admin/marketplace/payouts/queue, GET|POST /api/admin/marketplace/payouts/batches, the per-batch actions approve, submit, tan, cancel, reconcile and sepa_xml, and GET|PUT /api/admin/marketplace/fee-settings. Three sub-tabs, routed on a second query parameter (&subtab=):

Sub-tab Route Contents
Queue &subtab=queue Sellers with a payable ledger balance; creating a batch from them
Batches &subtab=batches The batch lifecycle — approve, submit, TAN, cancel, reconcile, SEPA XML
Fee Settings &subtab=fees The platform package and runner fee percentages

Fee Settings are a singleton, instance-wide row. package_fee_percent and runner_fee_percent must each be between 0 and 100; the server rejects anything outside that range. A change applies to future settlements — it does not retroactively re-price a batch already in the queue.

Backed by GET /api/admin/error-page and PUT /api/admin/error-page.

A raw JSON editor for the singleton instance-default error page (error_page_config) — the fallback rendered for a deployed App when neither the per-App nor the per-workspace error page is set. The configuration is an opaque bag, so the tab is a textarea rather than a form; invalid JSON is refused in the browser before the request is sent.

Saving replaces the whole bag rather than merging into it, so an edit that drops a key drops that key. The value is the last fallback for every hosted App on the instance; see Separate-origin App hosting.

Backed by POST /api/admin/marketplace/items/{id}/review/approve and .../review/reject, each taking an optional reason.

The review gate for catalog items. Each row shows the item name, its slug, its current verdict pill and a reason field, with Approve and Reject.

  • Approve flips marketplace_items.verified — the install gate — so a paid or central item becomes installable across the instance. That is the consequential act on this tab.
  • Reject records the rejection and leaves verified false, so the item stays uninstallable for the paid/central path.
  • A decided item drops out of the queue; the tab lists only undecided ones.

For what publishing looks like from the other side, see Publish a marketplace bundle.

Backed by GET|POST /api/marketplace/sources, PATCH|DELETE /api/marketplace/sources/{id} and POST /api/marketplace/sources/{id}/sync.

The source registry: list, create, edit, delete and per-source Sync, with a kind (Git or Workspace) and an Enabled / Disabled / Sync error status badge per row.

Two server-side guards apply regardless of role:

  • The curated official source (kind official, owned by no workspace) is read-only: it shows its status and a Sync button, and the server refuses an edit or a delete.
  • Delete is refused with 409 while the source still has published items, so removing a source can never silently cascade its catalog away. Retire the items first.

To install from a source once it is synced, see Install a marketplace connector.


See also: Reports (the tenant-scoped operability view), Operate the delivery engine (the /operator console), Manage seats and billing, Editions and entitlements, Environment variables, and Navigation and hubs.