Platform administration
What platform staff see across every workspace: recurring revenue and its export, organizations with suspend and reactivate, users and their restore, staff, platform roles and platform settings, and what Platform admin and Support may do.
For the Full Stack package
Who uses it
- Platform administration is for the people who run the product, not for a workspace's members. An account is platform staff when it holds a platform role; workspace roles have nothing to do with it.
- It opens in the same dashboard, in its own sidebar column. An account with a platform permission and a workspace sees Platform admin at the foot of the workspace sidebar and Return to workspace in the platform one. Staff with no workspace land on the platform overview after signing in.
- Every platform route checks the account's platform permissions on the server, whatever the screen shows. A page opened without them says "Platform administration is open to platform staff only."
Pages
| Sidebar item | Path | Permission | What it does |
|---|---|---|---|
| Overview | /en/admin | platform.view | Recurring revenue, the plan mix, the revenue trend and the latest organizations, with Export report. |
| Organizations | /en/admin/organizations | organizations.view | Every workspace on the platform with its plan, seats and status; each one's detail; suspend and reactivate. |
| Users | /en/dashboard/users/all | users.view | Every account and the workspaces it belongs to, with the deleted accounts under Deleted. |
| Staff | /en/dashboard/admins-management | admins.view | The accounts that hold a platform role, and their roles. |
| Roles | /en/dashboard/admins-roles | roles.view | What each platform role may do. |
| Settings | /en/admin/settings | settings.view | Platform-wide settings. |
Search in the top bar finds organizations here.
Platform admin and Support
| Role | Seeded account | Permissions |
|---|---|---|
| Platform admin | platform@northstack.example (Riley Brooks) | All 21: every page and every action below |
| Support | support@northstack.example (Dana Quinn) | platform.view, reports.export, organizations.view, users.view, admins.view, roles.view, settings.view: every platform page read only, and the report export |
Neither account belongs to a workspace. yarn seed sets both roles back to exactly these lists each time it runs, so a change you made to them on the Roles page is undone by the next seed; roles you create yourself are left alone. The installation guide lists the sign-in details.
The platform overview
- Monthly recurring revenue: every paid workspace (active, past due or ending) at its plan's monthly price, with the number of paid workspaces, trials, and the accounts past due with a link to them.
- Plan distribution: how many paid workspaces are on Starter, Pro and Scale.
- MRR trend: one point per month. The Report range (Last 30 days, Last 90 days, Last 6 months or Last 12 months, 6 months by default) sets how many months it shows. Past months come from the
mrr_snapshotstable, and the current month is worked out from the workspaces as they are now. Only the seed writes past months: nothing records a month's figure as it closes, so on a live install the trend grows only if your own job stores one row per month. - Organizations: the latest ones, with plan and status filters and the same actions as the Organizations page.
- Export report (
reports.export) downloadsnorthstack-organizations.csv: every organization withorganization,id,plan,status,seats,mrr_usdandcreated.
The seed creates 732 organizations so the figures add up: 690 paid (480 on Starter, 120 on Pro and 90 on Scale), 6 of them past due, and 42 trials, with five past months of revenue, so the trend shows at most six points on a fresh seed.
Organizations
- The list searches names and addresses and filters by Plan and Status (Trial, Active, Past due, Ending, Canceled, Suspended), ten a page, most recently updated first.
- An organization's page shows its owner, plan, status, seats, region, address, billing email and renewal date, its API requests and storage, its members with their roles, its latest twelve invoices, its subscription history and its platform events.
- Suspend (
organizations.manage) asks for a reason and is written to the organization's platform events. A suspended workspace keeps every read: its members still sign in and see their data, and every change they try is refused withworkspace_suspended. - Reactivate returns it to Active, or to Past due when it had an unpaid invoice, and the reason is cleared.
Users
- All users lists every account with its workspaces and roles, its platform role and when it joined, ten a page. Role filters by Workspace owner, Workspace admin, Workspace member, Billing, Platform staff or No workspace.
- Create user (
users.create) makes an account with a name, an email and a password of at least 8 characters; nothing is mailed, so share the details safely. The account has no workspace until it creates one or accepts an invitation. - Edit and Change password need
users.update. A new password or email for an account that holds a platform permission the caller lacks is refused with a 403, "This account holds platform permissions you do not have, so only a Platform admin can change its password or email." A Platform admin may change any account, and the email is guarded because a password reset is sent to it. - Delete (
users.delete) moves the account to Deleted: it can no longer sign in. An account that owns a workspace cannot be deleted until another member is made that workspace's owner. - Restore (
users.restore) brings a deleted account back with its old memberships. The seed includes one deleted account to try it on.
Staff
- Add staff (
admins.create) creates an account with a name, an email, a password typed twice and its platform roles. - Edit changes the details (
admins.edit), with the same guard on another account's password and email as on Users. Platform roles changes the roles (admins.assign_roles); with none left, the person leaves the staff list and keeps their account. A role that holds a platform permission the caller lacks can be neither granted nor taken away: "This role holds platform permissions you do not have, so you cannot grant it or take it away." - Remove (
admins.delete) deletes the account and its platform access; it can be restored from Users, Deleted. - A staff member's page lists the permissions their roles grant.
Platform roles and their permissions
/en/dashboard/admins-roles shows each platform role as a column and each permission as a row, in six groups. Create role (roles.create) adds a role with no permissions; Rename (roles.edit) and Delete (roles.delete) are in each column's menu; ticking cells and Save changes needs roles.assign_permissions, and the API saves only permissions the caller holds itself, on a role that holds none the caller lacks: "You can only give a role permissions you hold yourself, and only change a role that holds no permission you lack." So nobody raises their own role, or one above them. The API refuses to delete a role somebody still holds. The dashboard keeps the Platform admin column locked with every permission, so the platform always has someone who can manage it.
| Group | Permissions |
|---|---|
| Overview and reports | platform.view, reports.export |
| Organizations | organizations.view, organizations.manage |
| Users | users.view, users.create, users.update, users.delete, users.restore |
| Staff | admins.view, admins.create, admins.edit, admins.delete, admins.assign_roles |
| Roles | roles.view, roles.create, roles.edit, roles.delete, roles.assign_permissions |
| Settings | settings.view, settings.edit |
The list is defined in back-end/src/database/seeders/platform-access.seeder.ts; the seed adds new names and removes the ones it no longer lists. A change to a role's permissions, or to someone's platform roles, reaches a signed-in staff member at once with the notice "Your permissions have been updated".
Platform settings
/en/admin/settings lists the platform's settings by category, with a search. Each value is edited in place, or the setting deleted, with settings.edit; settings.view reads them.
| Setting | Key | Seeded value |
|---|---|---|
| Product name | site_name | Northstack |
| Tagline | site_tagline | B2B SaaS starter |
| Support address | support_email | an example address |
| Notification sender | notification_email | an example address |
| Maintenance mode | maintenance_mode | off |
| New sign-ups | signups_enabled | on |
| Trial length (days) | trial_days | 14 |
- New sign-ups off refuses the dashboard's sign-up and the creation of a new workspace in onboarding with a 403, "New sign-ups are closed on this platform right now." Existing accounts still sign in and accept invitations, and staff can still create accounts on the Users page.
- Trial length (days) is how long each new workspace trials, from the next one created. A value that is not a whole number of days above zero counts as 14.
- Maintenance mode on closes the product to everyone but platform staff (accounts holding
platform.view, Platform admin and Support as seeded). Everyone else sees the dashboard's maintenance screen, "Closed for maintenance.", which checks again on its own, and the API answers their requests with a 503. Staff sign in as usual and see "Maintenance mode is on" with a link to these settings. The website's contact form and licence checkout, the Stripe webhook and the health check stay open. - The AI assistant reads the product name, the support address and maintenance mode for its answers. The tagline and the notification sender are stored and shown here for your own code to read: the API sends no mail from them.
- Each change applies to the next request.
yarn seedsets these seven back to their seeded values, so a change made here is undone by the next seed, and removes any other setting.
The routes behind these pages
| Route | Permission |
|---|---|
GET /api/platform/overview?range=30d|90d|6m|12m | platform.view |
GET /api/platform/overview/export | reports.export |
GET /api/platform/organizations (search, plan, status, page, limit up to 100), GET /api/platform/organizations/:id | organizations.view |
POST /api/platform/organizations/:id/suspend (reason), POST /api/platform/organizations/:id/reactivate | organizations.manage |
GET /api/users, GET /api/users/deleted, GET /api/users/:username | users.view |
POST /api/users; PATCH /api/users/:username, PATCH /api/users/:username/change-password; DELETE /api/users/:username; POST /api/users/deleted/:username/restore | users.create; users.update; users.delete; users.restore |
/api/admins/* | admins.* |
/api/roles/* | roles.* |
GET /api/settings; PATCH and DELETE /api/settings/:key | settings.view; settings.edit |
How a change reaches signed-in staff
Included with your purchase. Sign in to read, or open it in your download.
The live connection that pushes a platform role change to staff who are signed in.