diff --git a/CHANGELOG.md b/CHANGELOG.md index ed4b1e6..88961e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.0] - 2026-05-19 + +### Added + +- Vault deletion — owners can delete a vault from the vault picker; all items inside are permanently purged immediately + +### Fixed + +- Filter row consolidated into a single layout component; `isMobile` prop removed from `VaultSheet` and `ItemCard`; `ListPanelAnimator` and `SyncStatusBar` polished; flaky e2e specs for folders, sync, and type-filter corrected + ## [0.8.0] - 2026-05-18 ### Added diff --git a/CONTEXT.md b/CONTEXT.md index 904277b..f59a029 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -46,7 +46,8 @@ The unlocked, in-memory set `{MasterKey, VaultKey(s), private signing key}` held ### Vault domain **Vault**: -A named container of **VaultItems** owned by one user, optionally shared. +A named container of **VaultItems** owned by one user, optionally shared. Deleting a vault permanently purges all its items immediately — no trash, no recovery. A user must always retain at least one vault; deletion is blocked (422) when only one remains. +_Invariant_: every account holds at least one vault at all times. **VaultItem**: One stored credential, fully decrypted. Type-discriminated payload: login, note, card, identity, TOTP, crypto wallet, dev credential. Lives in the browser only — the server never sees this shape. Defined in `packages/vault/src/item/schema.ts`. @@ -184,7 +185,7 @@ Composes access check + quota + repo for each write ceremony: `createItem`, `bat Vault-table queries: `createInitial`, `createVault`, `listOwnedByUser`, `listSharedWithUser`, `findOwnedById`, `updateMetadata`, `listIdsByOwner`. **VaultsService** (`vaults/service.ts`): -`createVault` ceremony — checks owner quota, then inserts. Other vault ops (update, list) skip service. +`createVault` — checks owner quota, then inserts. `deleteVault` — enforces the last-vault guard (rejects if only one vault remains), then deletes the vault and permanently purges all its items. Other vault ops (update, list) skip service. **SharesRepository** + **SharesService** (`vaults/shares/`): Repo: `listForVault`, `create`, `findByIdForUser`, `deleteById`. Service: `createShare` (self-share check + receiver lookup + insert), `deleteShare` (caller must be owner or receiver). diff --git a/apps/server/package.json b/apps/server/package.json index 797e4c6..d1fb837 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -1,6 +1,6 @@ { "name": "@blindpass/server", - "version": "0.8.0", + "version": "0.9.0", "private": true, "type": "module", "scripts": { diff --git a/apps/web/package.json b/apps/web/package.json index 6a4e60f..f0ccd55 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@blindpass/web", - "version": "0.8.0", + "version": "0.9.0", "private": true, "type": "module", "scripts": { diff --git a/docs/adr/0008-vault-deletion-name-confirmation-not-totp.md b/docs/adr/0008-vault-deletion-name-confirmation-not-totp.md new file mode 100644 index 0000000..95b0a76 --- /dev/null +++ b/docs/adr/0008-vault-deletion-name-confirmation-not-totp.md @@ -0,0 +1,10 @@ +# Vault deletion uses name-typed confirmation, not TOTP + +Deleting a vault permanently purges all its items with no recovery path. Despite that severity, the confirmation gate is a name-typed dialog ("type the vault name to confirm"), not a TOTP re-entry as account deletion requires. + +The asymmetry is deliberate. Account deletion erases the entire account — keys, vaults, items, auth state — and is truly irreversible. Vault deletion is scoped to one container; the last-vault guard (delete blocked when only one vault remains) removes the scenario where vault deletion approximates account destruction. The session is already authenticated and the vault already unlocked, so a TOTP gate would add friction — requiring the authenticator app to be in hand — without a meaningful security benefit over the typed-name ceremony, which already forces deliberate user intent. A TOTP gate would also fail for users temporarily without their authenticator device, blocking a legitimate destructive action they own. + +## Considered alternatives + +- **TOTP gate (matching account deletion).** Rejected: disproportionate friction for a scoped, owner-initiated action; the last-vault guard eliminates the worst-case scenario; session auth + vault unlock already establish trust. +- **Soft-delete / grace period.** Rejected: vault deletion should be immediate and deliberate; a grace period would persist UI deliberation as server state (the same reasoning as ADR-0001 for account deletion). diff --git a/package.json b/package.json index 6ad6144..50caf7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blindpass", - "version": "0.8.0", + "version": "0.9.0", "private": true, "type": "module", "packageManager": "pnpm@10.33.0", diff --git a/packages/api-schema/package.json b/packages/api-schema/package.json index c690453..4d4df20 100644 --- a/packages/api-schema/package.json +++ b/packages/api-schema/package.json @@ -1,6 +1,6 @@ { "name": "@blindpass/api-schema", - "version": "0.8.0", + "version": "0.9.0", "private": true, "type": "module", "exports": { diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 7472250..2f14993 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -1,6 +1,6 @@ { "name": "@blindpass/crypto", - "version": "0.8.0", + "version": "0.9.0", "private": true, "type": "module", "exports": { diff --git a/packages/types/package.json b/packages/types/package.json index ace3a30..de15e45 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@blindpass/types", - "version": "0.8.0", + "version": "0.9.0", "private": true, "type": "module", "exports": { diff --git a/packages/vault/package.json b/packages/vault/package.json index f14f419..3c25d89 100644 --- a/packages/vault/package.json +++ b/packages/vault/package.json @@ -1,6 +1,6 @@ { "name": "@blindpass/vault", - "version": "0.8.0", + "version": "0.9.0", "private": true, "type": "module", "exports": {