78 lines
2.7 KiB
Markdown
78 lines
2.7 KiB
Markdown
# DB Cleanup Audit
|
|
|
|
This document describes the non-destructive database cleanup audit for finding
|
|
orphan records, legacy schema leftovers, and soft-deleted row volume.
|
|
|
|
## Manual Audit
|
|
|
|
The cleanup audit is intentionally run as one-time read-only SQL on the target
|
|
database instead of a permanent application command. It should check the same
|
|
categories listed below and must not delete or update rows.
|
|
|
|
If rows are found, first capture affected-row details and a backup/export, then
|
|
apply cleanup through a reviewed migration or operations runbook.
|
|
|
|
## What It Checks
|
|
|
|
Orphan and broken-reference checks:
|
|
|
|
- active `asset_variants` with missing or soft-deleted `assets` parents
|
|
- active `pwa_caches` with missing or soft-deleted `projects` parents
|
|
- active `access_logs` with missing or soft-deleted `projects` or `users`
|
|
parents
|
|
- active `access_logs` with `NULL projectId` or `NULL userId` as warnings,
|
|
because admin/system or public/anonymous access may be valid
|
|
- active `production_presentation_access` grants with missing, soft-deleted, or
|
|
`NULL` `projectId`/`userId`
|
|
|
|
Legacy schema checks:
|
|
|
|
- old normalized constructor tables: `page_elements`, `page_links`,
|
|
`transitions`
|
|
- known removed columns: `assets.is_deleted`, `assets.deleted_at_time`,
|
|
`projects.is_deleted`, `projects.deleted_at_time`, `projects.phase`,
|
|
`projects.entry_page_slug`, `projects.transition_settings`
|
|
|
|
Soft-delete summary:
|
|
|
|
- every table with a `deletedAt` column is scanned for soft-deleted row count
|
|
- the report includes oldest and newest `deletedAt` timestamps per table
|
|
|
|
## Retention Policy
|
|
|
|
Keep soft-deleted rows indefinitely by default.
|
|
|
|
Reason: the project uses Sequelize paranoid models, deletion volume is expected
|
|
to be low, and restoring accidental deletes is more valuable than speculative
|
|
storage cleanup.
|
|
|
|
Any physical deletion must be a separate migration or operations runbook with:
|
|
|
|
- a fresh backup
|
|
- explicit affected-row query
|
|
- rollback or restore plan
|
|
- table-specific retention threshold
|
|
|
|
## Prevention
|
|
|
|
Asset deletion is handled in `AssetsService`. Because PostgreSQL foreign-key
|
|
`ON DELETE CASCADE` does not fire for Sequelize paranoid soft deletes,
|
|
`AssetsService.remove()` and `AssetsService.deleteByIds()` soft-delete active
|
|
`asset_variants` rows in the same transaction as the parent `assets` soft
|
|
delete. This prevents active variants from remaining attached to soft-deleted
|
|
assets after commit.
|
|
|
|
## Local Audit Result
|
|
|
|
Last local run: 2026-07-02.
|
|
|
|
Result:
|
|
|
|
- failed orphan checks: `0`
|
|
- warning orphan checks: `0`
|
|
- legacy schema candidates: `0`
|
|
- tables with soft-deleted rows: `4`
|
|
|
|
Soft-deleted rows were present in local `assets`, `projects`, `tour_pages`, and
|
|
`production_presentation_access`. No deletion was performed.
|