Platform admin
Managing organizations
Cross-tenant org lifecycle — suspend, reactivate, soft-delete, transfer ownership.
/admin/organizations lists every org. Click an org name to open the detail page (members, invitations, API keys, subscription summary, danger zone).
Actions
| Action | Route | Audit | Notes |
|---|---|---|---|
| Suspend | POST /api/v1/platform/organizations/{id}/suspend | platform.org.suspended | Sets isActive=false. Members hit rejectIfOrgSuspended on org-scoped routes. |
| Reactivate | POST /api/v1/platform/organizations/{id}/reactivate | platform.org.reactivated | Refuses on soft-deleted orgs. |
| Soft-delete | DELETE /api/v1/platform/organizations/{id} | platform.org.soft_deleted | Sets deletedAt. Idempotent. |
| Transfer ownership | POST /api/v1/platform/organizations/{id}/transfer-ownership | platform.org.ownership_transferred | Reassigns the system "owner" role on OrganizationMember. |
How transfer ownership works
The boilerplate uses role-based ownership — there is no Organization.ownerUserId column. The "owner" is whichever member's roleId matches the org's system Role(name='owner', isSystem=true). Transfer:
- Resolves the current owner automatically (the platform admin doesn't have to know who they are).
- Validates the target user exists, is active, not soft-deleted, and is a current member of the org.
- Atomically re-assigns the owner role to the target and demotes the previous owner to
'admin'(or whateverdemotedRoleNameis passed). - Audits
platform.org.ownership_transferredwith{ previousOwnerId, newOwnerId }.
If the boilerplate ever migrates to an Organization.ownerUserId column, only apps/server/src/modules/tenancy/application/use-cases/admin/transfer-organization-ownership.ts and the underlying TransferOwnershipUseCase need to change.
What soft-delete does NOT do
- Cancel subscriptions. The boilerplate's
Subscription.customerInternalIdis the user id, not the org id (a user can own multiple orgs). Cancelling on soft-delete would clobber the wrong tenant. Cancel separately via the Billing admin page. - Hard-delete data. All FKs use
onDelete: Cascadefor hard deletes only. Soft-delete just flipsdeletedAt; members, invitations, API keys, and subscriptions stay queryable for incident investigation. - Sign members out. A soft-deleted org's members keep their existing sessions but immediately hit
rejectIfOrgSuspendedif they try to act on the org's resources. They can still access other orgs they belong to.