Platform admin — Tenantx kernel
Platform admin is the operator console for the whole product: all organizations, plans, billing operations, cross-tenant support tools, and global content (e.g. help center). It is not a tenant inside a customer org.
Identity and permission
- Permission: global
subscription.admin(stored as a permission withorganization_id = NULL; assigned to the user with Spatie’s team context matching the platform team UUID used in your app — see middleware below). - Middleware:
platform.admin→EnsurePlatformAdmin(backend/app/Http/Middleware/EnsurePlatformAdmin.php). - Flow: clear stray team id, then set team id to the platform org UUID
00000000-0000-0000-0000-000000000000, thenhasPermissionTo('subscription.admin'). On success the request getsis_platform_adminmerged for downstream use.
Platform admins may still have a profile linked to a demo org (e.g. admin@tenantx.dev) so they can use both /platform and the tenant app; the important part is that platform routes never use tenant organization middleware the same way tenant data routes do.
Frontend
- Routes:
/platform/*wrapped inPlatformAdminRoute(checks platform permission client-side; server must still enforce). - Layout:
PlatformAdminLayout— separate nav, no tenantSmartSidebar. - API client:
platformApi— calls/api/platform/...only; must not send tenantworkspace_idquery params (tenantApiClientattaches workspace for non-platform requests). - Permissions hook:
usePlatformAdminPermissions— notuseHasPermission(org-scoped).
Backend API prefix
All routes in Route::middleware(['auth:sanctum', 'platform.admin'])->prefix('platform') in backend/routes/api.php, including (non-exhaustive):
| Area | Examples |
|---|---|
| Dashboard / analytics | GET /api/platform/dashboard, limits overview |
| Plans & subscriptions | Plans CRUD, subscriptions list, org subscription detail, renewals, payments confirm/reject |
| Organizations | List/create/update/delete any org (storePlatformAdmin, destroyPlatformAdmin, etc.) |
| Per-org subscription ops | Activate, suspend, limit overrides, feature add-ons, usage snapshots, recalculate usage |
| Files | Platform file storage listing/upload |
| Discount codes | Operator discount-code management via platform subscription endpoints |
| Maintenance / license fees | Operator views and confirm flows |
| Users | Platform user list CRUD, password resets |
| Login audit | /api/platform/login-audit/... |
| Help center | /api/platform/help-center/categories and .../articles (full CRUD) |
| Maintenance mode | Enable/disable/status for the app |
Tenant-scoped POST/DELETE /api/organizations are disabled for normal tenant users in the kernel; creating orgs as an operator uses POST /api/platform/organizations (storePlatformAdmin).
Mental model: three shells
flowchart TB
subgraph tenant [Tenant app same origin]
WS[Workspace tenant UI SmartSidebar]
OA[Org admin OrganizationAdminSidebar /org-admin]
end
subgraph platform [Platform /platform]
PA[PlatformAdminLayout + platformApi]
end
U[User session Sanctum]
U --> WS
U --> OA
U --> PA
- Workspace UI: one org, usually one workspace context for data.
- Org admin: one org, many workspaces, org-wide admin screens.
- Platform: many orgs, global configuration and support.
Promoting an operator
php artisan platform:assign-admin you@example.com --organization=acme-corp
--organization is optional (slug); use it when the user should also have a normal tenant profile in that org.
Security checklist
- Never reuse tenant
PermissionRouteoruseHasPermissionalone to guard/platformroutes. - Never trust client org or workspace ids for authorization on platform endpoints — use path/query ids with server-side validation.
- Keep
subscription.adminoff bulk customer roles; it is super-operator level in the kernel.
Related docs
- PERMISSIONS.md — global vs org permissions.
- ORG_ADMIN.md — customer org-wide admin vs platform.
- HELP_CENTER.md — tenant read vs platform CRUD for articles.