Files
finance/docs/operations/deletion-ledger.md
T
k1nq d582f15681 feat: add tests for import polling, login page, money utilities, and query keys
- Implemented tests for import polling functionality, ensuring correct behavior for active and terminal import statuses.
- Created tests for the login page, validating user interactions and error handling.
- Added unit tests for money utility functions, covering parsing, formatting, and summation of monetary values.
- Developed tests for query keys, ensuring proper scoping and invalidation roots.

chore: setup testing environment and configuration

- Added setup file for testing with Vitest and Testing Library.
- Configured TypeScript and Vite for the frontend project.
- Created Docker and Nginx configurations for local development and production environments.
- Established a PostgreSQL initialization script for setting up application roles.

docs: add README and environment configuration for infra

- Included README for the infra directory, detailing local development setup and service descriptions.
- Created an example environment configuration file for local development with placeholders for sensitive information.
2026-09-14 09:26:33 +05:00

2.0 KiB

Deletion Ledger

Status: contract definition. The hardening workstream (plan §9) implements this; nothing here is verified in code yet.

Purpose

Space deletion is final and must survive disaster restores. A backup restored after a purge would otherwise resurrect rows, objects and metadata of deleted spaces. The deletion ledger is an append-only record of completed deletions that any restore must replay before serving traffic.

Lifecycle

  1. Request — user requests space deletion. The space is locked immediately (no logins, writes or imports); a 30-day cancellation window starts.
  2. Cancel — within the window the owner may cancel; the lock is lifted, nothing is purged.
  3. Purge (after the window, via Celery worker):
    • hard-delete all space rows (financial tables, categories, payees, imports, memberships, users where applicable);
    • delete all S3 objects of the space and destroy the per-file DEK rows (crypto-shred, ADR 0004);
    • append one ledger entry only after all phases succeed.
  4. Ledger entry — append-only, minimal fields: space_id, requested_at, purged_at, executed_by (job id), phases_completed, integrity_hash (chain hash over prior entry). No financial payloads.

Replay after restore

On any disaster restore (see backup-and-restore.md step 6):

  1. Load ledger entries with purged_at later than the restored backup timestamp.
  2. For each: re-delete the space's rows (restored backups may contain them again), re-delete its objects, re-destroy DEK rows.
  3. Verify: no row with space_id in any financial table; bucket prefix absent; decryption of the space's files impossible.
  4. Record the replay in the drill log.

Implementation notes

  • The ledger table itself is never purged by space deletion and is included in backups.
  • A purge job must be idempotent and resumable: each phase is committed separately and the ledger entry is written last, in the same transaction as the final phase marker.
  • Ledger integrity is checked on startup after restore (chain hash mismatch = manual escalation).