Platform admin
Users (incl. delete)
/admin/users lists every user account on the platform —
super-admins, customers, and members invited into any workspace. The
page supports search by name/email, role promotion, BYOK per-user
overrides, edit, impersonate, change plan, and (since
v1.1) delete.
Change a customer's plan
Click Change plan on the user's row (or on Admin → Workspaces → the workspace). Plans belong to workspaces, so a user who owns more than one workspace picks the workspace first. Every plan is listed, inactive and hidden ones too, so a hand-made deal plan can be given to one customer.
- No payment, right away. The workspace switches to the plan immediately and keeps it until you change it again or the customer buys a plan on their Billing page (that purchase takes over).
- Trials. A trial that ran out (the upgrade wall) is lifted. Choosing a trial plan starts a fresh trial of that plan's length.
- Paying customers are refused. A workspace that Stripe, PayPal or Razorpay bills keeps its plan — change it in that gateway, or cancel the subscription first, so the customer is never charged for one plan while using another.
- The change is recorded in the audit log
(
billing.plan.changed_by_admin). Under the hood the workspace'splan_subscriptionsrow gets gatewayadmin.
Delete
Super-admin only. Click the Delete button on any user row (the button is hidden on your own row). A confirm dialog spells out the consequence — they lose access to every workspace and the row is soft-deleted for audit.
Safety rails
The controller refuses four cases:
- Self-delete — you cannot delete the account you are signed into. Would lock you out of admin.
- Last super-admin — defence-in-depth check; the controller refuses if the target is a super-admin and no other live super-admin exists.
-
Workspace owner — if the user still owns one or
more workspaces, the delete returns an error toast naming the
count. Transfer ownership at
/admin/workspaces/{id}first (or via the workspace's own Members & roles page) and retry. -
Non-super-admin actor — the route is in the
platform-admin group; a customer hitting
DELETE /admin/users/{id}directly returns 404 to hide the endpoint's existence.
What soft-delete touches
-
users.deleted_atis set to the current timestamp. Subsequent reads via Eloquent's default scope exclude the row. -
All
workspace_userspivot rows for the user are deleted so a re-invited account doesn't collide on the unique composite key. -
Foreign-key references in
conversations,leads,audit_logs, and other tables with auser_idcolumn are left intact — soft-delete preserves the row, so those joins keep working. -
An
AuditLogentry withaction=platform_user.deletedis written under the acting admin's default workspace, including the deleted email + role for forensic recovery.
Customer-initiated deletion (different code path)
When a customer deletes their own account from
/settings/profile, the row is
hard-deleted via forceDelete() — a
customer-initiated deletion is treated as a GDPR right-to-erasure
request, so the data goes away for real. Only the platform-admin
delete is soft.
Restoring a soft-deleted user
There is no admin UI for restore yet. To bring back a soft-deleted account run:
php artisan tinker --execute 'App\Models\User::withTrashed()->where("email","x@y.com")->first()->restore();'
The user's workspace memberships are NOT restored — they need a
fresh invitation. If the original workspace is gone too,
default_workspace_id will be stale and the next visit
redirects them through the standard onboarding flow.
Invitation-only installs (disable public sign-ups)
Settings → System → Sign-ups → "Allow public sign-ups" (on by default). Switch it off to run the installation invitation-only — the right mode when the platform serves internal departments rather than the public:
- The register page redirects to login, and the "create account" links disappear from the auth screens.
- Team invitations keep working: an email that holds a pending invitation can still create its account — the accept-invitation page links straight to a prefilled register form. Nobody else can.
- Existing accounts are unaffected either way, and the toggle can be flipped back at any time.