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:
tenantshostshost_servicesalert_rulesnotification_channelsdashboardscollectorsmonitoring_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_servicesof the host too — samedeletion_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:
- Find all
deleted_at < NOW() - 30 days - Delete hypertables for the entry
- Remove item from the table
- 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
Wiki articles with service link¶
If a service is deleted that has linked wiki articles: junction entries persist, restore brings links back.
Next¶
- Audit log
- Users & tenants — delete behavior