B Blengi docs

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, and (since v1.1) delete.

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 (its text says "Transfer ownership first"). There is no ownership transfer anywhere in the app: neither /admin/workspaces/{id} nor the workspace's own Team page can change the owner. The only way through is to delete those workspaces first (from /admin/workspaces) 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_at is set to the current timestamp. Subsequent reads via Eloquent's default scope exclude the row.
  • All workspace_users pivot 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 a user_id column are left intact — soft-delete preserves the row, so those joins keep working.
  • An AuditLog entry with action=platform_user.deleted is 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.