Skip to content

Soft delete & trash

Instead of hard-deleting, Vesana sets a deleted_at flag. Items land in trash, vanish from normal views, and can be restored within 30 days.

Which tables

8 tables are soft-delete capable:

  • tenants
  • hosts
  • host_services
  • alert_rules
  • notification_channels
  • dashboards
  • collectors
  • monitoring_scripts

Plus wiki_articles (separate, migration 063+064).

Not soft-delete: users (have active flag), profiles and profile_checks (global, builtins from seed).

Columns

Per table:

Field Meaning
deleted_at timestamp (NULL = active)
deleted_by user UUID
deletion_batch_id groups cascading deletes

apply_filters() in auth.py automatically filters deleted_at IS NULL — normal endpoints see nothing deleted.

Cascade

When a host is deleted:

  • Host gets deleted_at
  • All host_services of the host too — same deletion_batch_id

When a tenant is deleted:

  • Tenant + all children (hosts, services, alert rules, channels, dashboards) get the same deletion_batch_id

On restore the whole family is reactivated.

Trash UI

/trash shows all deleted items with:

  • Tabs by type (hosts, services, alert rules, …)
  • Badge with count
  • Time of deletion
  • Author
  • Time until auto-purge (countdown)
  • Restore and Purge buttons

Restore

Prerequisite: parent exists (or is restored alongside).

Example: a host was deleted, including its tenant. To restore only the host — doesn't work because its tenant is missing. Restore the tenant first (or both at once, which the bulk function handles).

flowchart LR
    P[Tenant deleted] --> R{Restore hosts?}
    R -->|Tenant missing| FAIL[Error — restore tenant first]
    R -->|Tenant ok| OK[Host + all deletion_batch_id children back]

Permanent delete

Before 30-day auto-purge, explicit „Purge" removes the item from the DB. Hypertable data (check_results, logs) for the service isn't co-deleted, but they reference a non-existent service and are gone from normal views — auto cleanup eventually removes them via retention.

Auto purge

Background job runs daily at 04:00 UTC:

  1. Find all deleted_at < NOW() - 30 days
  2. Delete hypertables for the entry
  3. Remove item from the table
  4. Write audit entry

Order matters: hypertables first, since cascade delete doesn't auto-clean them.

Agent / collector / token

Item Soft delete Token behavior
Host (with agent token) Token disabled (active=false) Reactivated on restore
Collector (with API key) Key disabled Reactivated on restore

So an accidental soft delete is reversible even for tokens. Hard delete (manual or after 30 d) removes the token hash forever — agent gets 401.

Permissions

Permission Effect
trash.view View trash
trash.restore Restore items
trash.purge Permanently delete

trash.purge should only be for admin roles — protection from oversight is the trash's main purpose.

Audit

Soft deletes and restores appear in audit log with action = <kind>.delete / restore.

Edge cases

Existing alerts on soft delete

If a service with active hard-CRIT is soft-deleted:

  • Notifications stop immediately (service no longer evaluated)
  • Existing alerts aren't „deleted" — they remain in history
  • Restore: service back, status re-evaluated on next incoming result

If a service is deleted that has linked wiki articles: junction entries persist, restore brings links back.

Next