Phase 2: M1 closed - re-auth on account delete + storage teardown
DELETE /user/account is now properly destructive and properly gated.
Re-authentication:
- Credentials users (password_hash present) must supply `password`
in the JSON body. Missing returns 401 with code password_required;
wrong returns 401 with detail "Incorrect password" (timing-safe
via bcrypt.compare).
- Entra-only users (no password_hash) must supply `confirm_text`
matching their lowercase email. Missing or wrong returns 401 with
code email_confirmation_required and the expected email in the
detail so the UI can echo it back. Defeats casual misuse of a
still-valid session via browser extension, stolen Bearer, or
shared device.
Storage teardown:
- Before deleting the row, enumerate every storage_path and
pdf_storage_path across the user's document_versions (joined to
documents). Set of unique paths is best-effort deleted after the
cascade commits. Failures are logged but do not block the user
delete; orphaned storage objects are easier to detect later than
missing data is to recover.
Audit:
- audit_events row written inside the same transaction as
DELETE FROM users so the actor identity survives the cascade
(audit_events.user_id is ON DELETE SET NULL).
- Metadata captures storage_objects count, had_password,
had_entra so an admin scrolling the log can see the deletion's
scope without joining to the now-missing user row.
Frontend:
- Account > Delete Account panel grew password + email-confirm
inputs. Validates locally that at least one is non-empty before
enabling the destructive button. On 401 the server's detail is
surfaced inline (with the expected email for Entra-only users).
- mikeApi.deleteAccount now takes an options object
{ password?, confirmText? }.
End-to-end verified against Postgres 16:
- Credentials: missing pw 401, wrong pw 401, correct pw 204 with
full cascade (project/document/version all removed) and audit
row with metadata { storage_objects: 2, had_password: true,
had_entra: false }.
- Entra-only: missing confirm 401, wrong email 401, correct email
204. Two audit rows recorded across both deletions.
Closes audit finding M1.
| Repository | cpatpa/PIP |
|---|---|
| Author | Claude <noreply@anthropic.com> |
| Authored | |
| Parents | e114baf9 |
| Stats | 4 files changed , +239 , -33 |
| Part of | Phase 2 - Supabase JS → plain pg cutover across the backend |
Capture this commit into my fork
Download a Markdown prompt that tells Claude how to port this
exact commit into your working tree. Run it via
claude -p < capture-commit-ed34140e.md
from inside the repo you want the change in.