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

Soft-delete-capable tables include:

  • Tenants
  • Hosts
  • Host services (checks)
  • Sites
  • Aggregates
  • Alert rules
  • Notification channels
  • Dashboards
  • Collectors
  • Monitoring scripts
  • Wiki articles (own trash branch)
  • Users (the username is released immediately on deletion; the trash entry carries the deletion date in its name)
  • Device profiles, policies and icons — each with its own tab

Profile checks belong to their profile. The former "Service definitions" and "Templates" tabs no longer exist.

Deleted hosts, collectors and checks no longer count against the licence quota (from v1.9.437) — whoever deletes has room again immediately.

Columns

Per table:

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

A central filter automatically hides deleted rows — normal endpoints and views see nothing deleted, without every single query having to account for it.

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

Admin → Logs & Support → 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

Restoring is creating. The same limits apply as when creating something new:

  • On top of trash.restore you need the right to create that type (for a host, hosts.create).
  • The licensed host count and the tenant quota are checked — including the checks attached to a restored tenant. If the budget is not enough, the message names the free slots and nothing half-restored is left behind.
  • A restored check starts on "waiting for data" instead of its frozen old status.
  • A restored device never hangs on a collector that has since been deleted; its checks run again over the active checker right away.

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

Trash has three visibility levels instead of just yes/no, plus two action permissions:

Permission Effect
trash.view_own see only items you deleted yourself
trash.view_tenant see all deleted items within your own tenant
trash.view_global cross-tenant view (super-admin-only)
trash.restore restore items
trash.purge permanently delete

Instance-wide objects without a tenant (users, device profiles, tenants themselves) are only visible and deletable with trash.view_globaltrash.view_tenant is not enough for those.

trash.purge should only be for admin roles — protection from oversight is the trash's main purpose. trash.view_global deliberately stays super-admin-only, since it crosses tenant boundaries.

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