/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, and (since v1.1) 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.
The controller refuses four cases:
/admin/workspaces/{id} first (or via the workspace's
own Members & roles page) and retry.
DELETE
/admin/users/{id} directly returns 404 to hide the
endpoint's existence.
users.deleted_at is set to the current timestamp.
Subsequent reads via Eloquent's default scope exclude the row.
workspace_users pivot rows for the user are
deleted so a re-invited account doesn't collide on the unique
composite key.
conversations,
leads, audit_logs, and other tables
with a user_id column are left intact — soft-delete
preserves the row, so those joins keep working.
AuditLog entry with
action=platform_user.deleted is written under the
acting admin's default workspace, including the deleted email +
role for forensic recovery.
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.
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.