---
description: Staff passwords — setup link only; never set another user’s password
globs: backend/src/modules/staff/**,frontend/src/components/ui/staff/**,frontend/src/app/**/accept-invite/**,frontend/src/lib/api/staff.ts
alwaysApply: false
---

# Staff passwords

- Owner / `TAB_STAFF_EDIT` may **clear** a password, never set one for someone else.
- `POST /staff/members/:membershipId/clear-password`: `passwordHash: null`, delete sessions, revoke unused invites on that membership, mint a 7-day `/accept-invite` URL. Refuse owner, self, pending, disabled (`STAFF_CANNOT_CLEAR_OWN_PASSWORD`, `STAFF_PASSWORD_CLEAR_ACTIVE_ONLY`).
- List DTO: `hasPassword` boolean only (never the hash). `previewInvite` `mode`: `join` | `password_setup` from `membership.isActive`.
- Login page unchanged — null hash is invalid credentials until they set a password on the setup link.
- `/accept-invite` `password_setup`: password fields only; then `login()` + `navigateIntoAppIfOrgSelected` (no enter-app hook).
