feat(snapshots): capture app data-volume snapshots
Build / build (push) Successful in 10m59s

Add per-workload capture of host-bind data volumes as downloadable tar.gz archives: a new internal/volsnap engine (enumerate host-bind volumes via the computeMounts merge, archive with archive/tar+gzip skipping symlinks/special files, per-workload retention + startup orphan cleanup), a volume_snapshots table + store CRUD, admin-gated API (list/snapshotable/create/download/delete), and a Snapshots panel on /apps/[id] that shows coverage and which volumes are skipped (and why). Scope: image-source apps, host-bind scopes (absolute/stage/project); Docker named volumes, tmpfs, and instance scope are surfaced as not-yet-supported. Restore is a separate later phase. Download/FilePath are containment-checked; create returns a typed no-data error (400) vs generic 500. Covered by archiver unit tests + full API e2e.
This commit is contained in:
2026-06-02 14:56:10 +03:00
parent 2ba49b9bb6
commit 6b45ed62bb
16 changed files with 1565 additions and 4 deletions
+6
View File
@@ -31,6 +31,7 @@
import ContainerStats from '$lib/components/ContainerStats.svelte';
import ToggleSwitch from '$lib/components/ToggleSwitch.svelte';
import WorkloadNotificationsPanel from '$lib/components/WorkloadNotificationsPanel.svelte';
import WorkloadSnapshotsPanel from '$lib/components/WorkloadSnapshotsPanel.svelte';
import TriggerKindForm, {
createTriggerKindFormState,
isTriggerFormValid,
@@ -2765,6 +2766,11 @@
<WorkloadNotificationsPanel workloadId={id} />
{/if}
<!-- ── Data-volume snapshots (capture) ────────────── -->
{#if !editing}
<WorkloadSnapshotsPanel workloadId={id} />
{/if}
<!-- ── Log scan rules (effective set) ─────────────── -->
{#if !editing}
<section class="panel" aria-labelledby="log-rules-heading">