Super Admin Console
The super-admin console is the operator’s view of a SaaS cluster. It is the only place where you see across every tenant at once — listing them, suspending them, watching system health, reading billing, and triggering migrations. Tenants never see it. It lives at the apex domain (https://saas.proxrad.com/admin/), not at any tenant subdomain, and authenticates against a separate user table with a separate JWT signing key.
This page covers how the console is structured, what each section does, and the deliberate separation between the super-admin realm and the per-tenant realm.
Authentication realm
Section titled “Authentication realm”The super-admin console runs in its own authentication world:
| Aspect | Tenant admin | Super-admin |
|---|---|---|
| URL | <slug>.saas.proxrad.com/login | saas.proxrad.com/admin/login |
| User table | tenant_<slug>.users | public.super_admins |
| JWT signing key | SAAS_TENANT_JWT_SECRET (shared across tenants, scoped by tenant_id claim) | SAAS_SUPERADMIN_JWT_SECRET (separate env var, separate signing key) |
| JWT claim shape | {user_id, tenant_id, user_type, exp} | {super_admin_id, role, exp} |
| Brute-force lockout | 5 fails → 15 min, 10 → 1 hour, 20 → 24 hour | Same progression, separate counter, never shares state with tenant counters |
| MFA | Optional per tenant | Required — TOTP enrolment is mandatory at first login |
Even if a tenant’s database is compromised and an attacker pulls every JWT secret known to the tenant code path, the super-admin secret is not reachable from any tenant-scoped query. The keys live in the cluster’s .env and only the super-admin handler reads them.
A super-admin cannot log in to a tenant panel by using their super-admin credentials. They can only impersonate a tenant admin from the console — and impersonation creates a new short-lived JWT for that specific tenant, leaving an audit trail.
Layout
Section titled “Layout”| Section | What it shows | Permission |
|---|---|---|
| Dashboard | Cluster-wide counters: active tenants, total subscribers, today’s signups, today’s revenue, today’s churn, host CPU/memory/disk | saas.dashboard.view |
| Tenants | Searchable table of every tenant — slug, plan, status, subscriber count, last login, MRR | saas.tenants.view |
| Billing | Per-tenant subscription state, invoices, failed-payment list, upcoming renewals | saas.billing.view |
| System Health | Postgres connection-pool utilisation, Redis memory, backup-queue depth, RADIUS auth rate, WireGuard peer count | saas.system.view |
| Audit Log | Every super-admin action: tenant created, suspended, restored, JWT key rotated, etc. | saas.audit.view |
| Settings | Cluster config — JWT secrets, SaaS email relay credentials, default plans, signup toggle | saas.settings.edit |
Tenants section in depth
Section titled “Tenants section in depth”The Tenants table is the centre of the console. Each row is one tenant.
Tenant CRUD
Section titled “Tenant CRUD”| Action | Effect | Reversible? |
|---|---|---|
| Create | Runs the onboarding pipeline (Tenant Onboarding) — schema, tables, seed permissions, first admin user | Yes — delete the tenant |
| Edit | Change plan, quota, status, billing email. Does not touch tenant data | Yes |
| Suspend | Sets tenants.status = 'suspended'. Tenant cannot log in; resolver returns 403. Subscribers stay online — RADIUS continues serving them. | Yes — Activate |
| Activate | Reverse of suspend | Yes |
| Impersonate | Issues a 1-hour JWT scoped to that tenant with user_type = admin. Used for support. | n/a — token expires |
| Delete | Drops the tenant row, drops tenant_<slug> schema, deletes uploads, deletes cloud backups | No — coordinate with the tenant first |
Plan changes
Section titled “Plan changes”Plans determine quotas (subscriber count, cloud backup size, scheduled-backup frequency, custom domains allowed). Changing a tenant’s plan is immediate:
- Subscriber-count quota tightens — the tenant cannot add new subscribers but existing ones keep working.
- Subscriber-count quota loosens — the tenant can immediately add subscribers up to the new ceiling.
- Cloud-backup quota tightens — existing backups stay; new ones are rejected if they push over.
- Custom-domain allowance revoked — existing custom domains keep working; new ones can’t be added.
Billing-wise, the proration is handled by the billing integration (Stripe by default). The console writes a plan_changed_at timestamp on the tenant for proration calculations.
Impersonation audit trail
Section titled “Impersonation audit trail”Every impersonation is logged with:
- Super-admin user ID
- Target tenant ID
- Target user inside the tenant (always the first admin)
- Timestamp + duration of the impersonation session
- IP address
The impersonated session also writes into the tenant’s own audit log so the tenant can see when support staff accessed their panel. The super-admin console cannot suppress this — it is a non-negotiable transparency feature.
Billing section
Section titled “Billing section”The Billing page integrates with the payment provider (Stripe by default; the integration is pluggable). It surfaces:
- Active subscriptions — count by plan.
- MRR / ARR — monthly and annualised recurring revenue.
- Churn this month — tenants who cancelled or downgraded.
- Failed payments — tenants whose last invoice failed and are now in a 7-day dunning window.
- Upcoming renewals — tenants whose next invoice is in the next 14 days.
Each tenant row is clickable, showing their invoice history, payment method on file, and a “trigger manual charge” button for support cases (e.g. a customer who paid out-of-band and wants their invoice marked paid).
The billing data lives in the public.saas_billing and public.saas_invoices tables. It is replicated from Stripe webhooks; if Stripe is the source of truth, the console is the read-side projection.
System Health section
Section titled “System Health section”The system-health panel is the operator’s “is the cluster OK?” view:
| Metric | What healthy looks like | What to do otherwise |
|---|---|---|
| Postgres pool | Below 70% utilisation under normal load | Above 90% sustained → bump max_connections or split the cluster |
| Redis memory | Below 60% of allocated | Above 80% → bump Redis memory or shorten cache TTLs |
| Backup queue depth | Drains within 5 minutes | Sustained >50 jobs → license-server upload bottleneck; investigate |
| RADIUS auth rate | Stable per tenant | Sustained spikes → a tenant’s NAS is flapping |
| Cluster CPU | Below 70% | Above 85% → split tenants across clusters |
| WireGuard peer count | Matches sum(tenant.peers) | Mismatch → wg state out of sync; restart wg0 |
The page polls every 10 seconds and shows trend lines for the last hour. Click-through to a more detailed Grafana dashboard if the cluster has the LGTM observability stack deployed (optional).
Settings section
Section titled “Settings section”Cluster-level settings the super-admin can change:
| Setting | Effect | Restart required |
|---|---|---|
| Disable public signup | Hides the /signup page on the apex domain | No |
| Default plan | Plan assigned to self-service signups | No |
| SaaS email relay credentials | SMTP for outgoing welcome / invoice emails | No |
| License key | The cluster’s license, registered with the license server | API restart |
| Cloudflare API token | Used for DNS-01 cert renewals | No |
| Rotate super-admin JWT secret | Invalidates every super-admin session immediately | No, but every super-admin must re-login |
| Rotate tenant JWT secret | Invalidates every tenant session immediately | No, but every tenant user must re-login |
JWT-secret rotation is the nuclear option for credential compromise. Use it if a super-admin laptop is stolen or if .env is exposed.
What super-admins cannot do
Section titled “What super-admins cannot do”The console is powerful but deliberately limited:
- Cannot read tenant data without impersonating. There is no “show me subscriber
alice@acmefrom tenant Acme” query at the super-admin level. To see that, you impersonate (logged), and then look it up inside Acme’s panel. - Cannot edit tenant data directly. Same reason. Every data change is attributable to a real user inside a real tenant — even if that user is “support impersonating the admin”.
- Cannot bypass MFA. TOTP is enforced; “I forgot my TOTP” requires a second super-admin to reset, with full audit trail.
- Cannot decrypt a tenant’s backups without the cluster license key. Same encryption rules apply to super-admins as to tenants.
These constraints make audit easier: the worst-case bad-actor super-admin must impersonate to do damage, and every impersonation leaves a trail in both the cluster audit log and the tenant’s own audit log.
Super-admin user management
Section titled “Super-admin user management”The first super-admin is created during cluster install. Subsequent super-admins are invited from Settings → Super Admins:
- Existing super-admin clicks Invite Super-Admin.
- Enters the new admin’s email.
- The new admin gets an invitation email with a magic-link signup.
- They set password + enrol TOTP at first login.
- Their role (
owner,admin,support) is set by the inviter and can be changed later.
| Role | Permissions |
|---|---|
| owner | Everything, including super-admin user CRUD and JWT rotation |
| admin | Tenant CRUD, billing, system health. Cannot manage other super-admins. |
| support | Read-only across tenants, can impersonate, cannot suspend/delete |
Permissions
Section titled “Permissions”Super-admin permissions are flat (assigned per super-admin role, not via a permission-group system like the tenant side). The permissions checked by the API are:
| Permission | What it gates |
|---|---|
saas.dashboard.view | The cluster Dashboard page |
saas.tenants.view | The tenant list |
saas.tenants.create / saas.tenants.edit / saas.tenants.delete | Tenant CRUD |
saas.tenants.impersonate | The Impersonate button |
saas.billing.view / saas.billing.edit | Billing page + manual-charge button |
saas.system.view | System health page |
saas.audit.view | Super-admin audit log |
saas.settings.edit | Cluster settings, JWT rotation |
saas.super_admins.manage | Invite / remove other super-admins. Owner-only. |
Related pages
Section titled “Related pages”- SaaS Overview — the multi-tenant model the console manages.
- Tenant Onboarding — what the “New Tenant” button triggers.
- Schema-Per-Tenant Isolation — the boundary super-admins do not cross.
- Tenant Backups — cluster-wide backup health visible in System Health.
- Wildcard Subdomain Routing — DNS / TLS state the console depends on.