# Aurisar Ledger — Data Retention & Deletion Policy

| Field | Value |
| --- | --- |
| Document Owner | Aurisar Ledger (operator / data controller) |
| Effective Date | 2026-04-25 |
| Last Reviewed | 2026-04-25 |
| Next Review | 2026-10-25 (semi-annual) |
| Version | 1.0 |

---

## 1. Purpose

This policy defines how long Aurisar Ledger retains each category of
data, when and how it is deleted, and how the operator handles
data-subject deletion requests. It is enforced through a combination of
in-app controls, scheduled database maintenance, and platform-level
backup retention at Supabase.

## 2. Data categories & retention periods

| # | Category | Storage | Retention | Deletion mechanism |
| --- | --- | --- | --- | --- |
| D1 | User passwords (bcrypt hash) | `users.password_hash` | Until user deleted | `DELETE FROM users WHERE id = ...` (cascades to refresh_tokens / webauthn_credentials) |
| D2 | TOTP secrets (AES-256-GCM) | `settings.totp_secret` | Until 2FA disabled | `Settings → Disable 2FA` |
| D3 | WebAuthn credentials | `webauthn_credentials` | Until removed by user | `Settings → Security → Remove passkey` |
| D4 | JWT access tokens | Client localStorage | 15 minutes | Auto-expiry |
| D5 | Refresh tokens | `refresh_tokens` | 7 days | Auto-expiry; logout marks `revoked = true`. Hard-deleted by retention job after expiry. |
| D6 | Plaid access tokens (AES-256-GCM) | `plaid_items.access_token` | Until institution removed or local wipe | Institution removal revokes each Item at Plaid before local deletion; a wipe erases the locally stored encrypted tokens |
| D7 | Account & balance metadata | `accounts` | Until deleted | Per-account delete or wipe |
| D8 | Transaction history | `transactions` | Until deleted | Per-transaction delete, per-account delete, or wipe |
| D9 | Budgets, goals, rules, tags, merchants, recurring series | corresponding tables | Until deleted | Per-record delete or wipe |
| D10 | Settings | `settings` | Until deleted | Wipe |
| D11 | Security events (audit log) | `security_events` | 90 days | Daily retention job |
| D12 | WebAuthn challenges | `webauthn_challenges` | 5 minutes | Auto-expiry; cleared on consume |
| D13 | Application logs at Render | Render platform | 30 days (Render policy) | Render-managed |
| D14 | Database backups at Supabase | Supabase platform | 7 days rolling (Supabase policy) | Supabase-managed |
| D15 | Source code & CI logs at GitHub | GitHub | 90 days for action logs | GitHub-managed |

## 3. User-initiated deletion

The operator can delete data at any time through these in-app controls:

- **Settings → Data → Delete All Data** — wipes the contents of every
  user-data table in a single transaction. This calls
  [`POST /api/settings/wipe`](../server/routes/settings.js).
- **Accounts / Settings → Institutions → Remove** — shows server-computed
  account, hidden-account, transaction, and provider-item counts; revokes every
  Plaid Item for that institution; then deletes the related accounts and
  transactions in one local database transaction. A provider revocation
  failure stops local deletion so the application never reports an unrevoked
  connection as removed.
- **Per-record deletion** — accounts, transactions, budgets, goals,
  rules, tags, and merchants each have a delete control in the UI.

Deletion is immediate and final at the application layer. Backups at
Supabase persist for up to 7 days per Supabase's platform policy and
will be aged out automatically.

## 4. Scheduled retention jobs

Two background jobs implement time-based retention:

| Job | Frequency | Action |
| --- | --- | --- |
| Refresh-token sweeper | Daily (00:15 UTC) | `DELETE FROM refresh_tokens WHERE expires_at < NOW() - INTERVAL '1 day'` |
| Security-event sweeper | Daily (00:30 UTC) | `DELETE FROM security_events WHERE created_at < NOW() - INTERVAL '90 days'` |
| WebAuthn-challenge sweeper | Hourly | `DELETE FROM webauthn_challenges WHERE expires_at < NOW()` |

These jobs are invoked from `server/scheduler.js`. Failures are logged
to the Render application log. The operator reviews the sweeper output
during the semi-annual policy review.

## 5. Data-subject requests (GDPR / UK GDPR / CCPA / CPRA)

Because Aurisar Ledger is a single-owner application, the operator
typically *is* the data subject. If the operator chooses to honour a
request from a third party (e.g., a household member who shared the
deployment):

| Request type | SLA | Mechanism |
| --- | --- | --- |
| Access (export) | 30 days | CSV export in app + on-request SQL dump from Supabase |
| Rectification | 30 days | In-app edit |
| Erasure | 30 days | "Delete All Data" control |
| Restriction | 30 days | Disable account / pause syncs |
| Portability | 30 days | CSV / JSON export |
| Object to processing | 30 days | Remove sub-processor or stop syncs |

Requests received at `security@aurisar-ledger.com` are logged in
`docs/DSR_LOG.md` (created on first request) with: request date,
requester identity verification, action taken, completion date.

## 6. Backup retention & recovery

- Supabase performs continuous WAL-based backups with **7 days of
  point-in-time recovery** on the operator's plan.
- Render's filesystem is ephemeral; the application itself persists no
  data outside Supabase.
- Recovery procedure: restore Supabase to the desired point in time and
  redeploy the Render service. Documented in
  `docs/DISASTER_RECOVERY.md` (created on first DR drill).
- Backups inherit the same encryption and access controls as the
  primary database.

## 7. Deletion of decommissioned deployments

When a deployment is permanently decommissioned the operator MUST:

1. Run **Delete All Data** in the app.
2. Pause / delete the Render service.
3. Delete the Supabase project (this purges backups within Supabase's
   contractual SLA).
4. Revoke Plaid items at the Plaid Dashboard.
5. Rotate / revoke shared secrets (`JWT_SECRET`, `ENCRYPTION_KEY`,
   Plaid keys).
6. Record the decommission date in `docs/DECOMMISSION_LOG.md`.

## 8. Verification

Compliance with this policy is verified by:

- The CI security audit job (`.github/workflows/security-audit.yml`),
  which fails the build on any new Plaid-data column not flagged in
  this document. (Future enhancement.)
- The semi-annual policy review (Section 9).

## 9. Review

This policy is reviewed at least every 6 months and after any change
to the data model, the sub-processor list, or applicable privacy law.
Reviews update the *Last Reviewed* and *Next Review* fields above.

## 10. Related documents

- [Privacy Policy](./PRIVACY_POLICY.md)
- [Information Security Policy](./SECURITY_POLICY.md)
- [Vulnerability Management Policy](./VULNERABILITY_MANAGEMENT.md)
- [Security Controls reference](./SECURITY_CONTROLS.md)
