Summary
Admin Users → Remove from portal appears to do nothing when the target principal still has chat activity. The mutation fails in the database, the React Query optimistic update rolls back, and no error toast is shown.
Measured root cause
removePortalUser in apps/web/src/lib/server/domains/users/user.service.ts does:
await db.delete(principal).where(eq(principal.id, principalId))
But live schema has ON DELETE RESTRICT on at least:
chat_messages.principal_id → principal
conversations.visitor_principal_id → principal
A portal user who only opened chat (0 posts / 0 comments / 0 votes) can still be undeleteable. Postgres raises a FK violation → wrapped as InternalError('DATABASE_ERROR', …) → client onError restores the list with no UI feedback.
Client gap
useRemovePortalUser (apps/web/src/lib/client/mutations/users.ts) has onError rollback only — no toast.
UsersContainer.handleRemoveUser only clears selection on onSuccess.
Suggested fix
- Before deleting the principal (or inside a transaction), detach/delete org-scoped chat residue in a product-safe way or refuse with a typed error the UI can show (e.g. “This user still has conversations”).
- Surface mutation failures with a toast / dialog error (don’t fail closed silently).
- Align the comment above
removePortalUser with actual FK direction (principal.user_id → user CASCADE does not delete the user when the principal is deleted — the newer comment in-tree is correct; the older inline comment next to the delete is misleading).
Repro shape
- Create/sign a portal
role=user principal.
- Start a widget chat so
conversations.visitor_principal_id + chat_messages.principal_id point at that principal.
- Admin → Users → select user → Remove from portal → confirm.
- Observe: modal/selection behavior looks like a no-op; principal remains.
Observed on Quackback v0.13.2 (Rerolla tenant). Happy to share more schema detail if useful.
Summary
Admin Users → Remove from portal appears to do nothing when the target principal still has chat activity. The mutation fails in the database, the React Query optimistic update rolls back, and no error toast is shown.
Measured root cause
removePortalUserinapps/web/src/lib/server/domains/users/user.service.tsdoes:But live schema has ON DELETE RESTRICT on at least:
chat_messages.principal_id→principalconversations.visitor_principal_id→principalA portal user who only opened chat (0 posts / 0 comments / 0 votes) can still be undeleteable. Postgres raises a FK violation → wrapped as
InternalError('DATABASE_ERROR', …)→ clientonErrorrestores the list with no UI feedback.Client gap
useRemovePortalUser(apps/web/src/lib/client/mutations/users.ts) hasonErrorrollback only — no toast.UsersContainer.handleRemoveUseronly clears selection ononSuccess.Suggested fix
removePortalUserwith actual FK direction (principal.user_id → userCASCADE does not delete the user when the principal is deleted — the newer comment in-tree is correct; the older inline comment next to the delete is misleading).Repro shape
role=userprincipal.conversations.visitor_principal_id+chat_messages.principal_idpoint at that principal.Observed on Quackback
v0.13.2(Rerolla tenant). Happy to share more schema detail if useful.