feat: Docker volume backup, Tier 2 restore, restore dropdown fixes (v0.33.0)

- Add Docker named volume backup to Tier 1 (dump to tar, include in restic)
  and Tier 2 (copy tars to rsync mirror _volumes/ dir)
- Fix volume name resolution: use project-prefixed names (mealie_mealie_data)
- Fix double Tier 1 in restore dropdown: filter snapshots by app's home drive
- Add Tier 2 restore: RestoreAppFromTier2() restores from rsync mirror
- Show Tier 2 entry in restore dropdown when cross-drive backup succeeded
- Add .fab import link in restore section
- Volume-aware restore type banners and backup content labels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-27 21:43:02 +01:00
parent 5bf13ca19d
commit c929948f27
12 changed files with 655 additions and 45 deletions
+11 -6
View File
@@ -198,6 +198,7 @@ func main() {
// Wire cross-drive → backup manager for pre-backup DB dumps
if backupMgr != nil {
crossDriveRunner.SetDBDumper(backupMgr)
crossDriveRunner.SetVolumeDumper(backupMgr)
}
// --- Initialize alert manager ---
@@ -891,6 +892,7 @@ func (a *stackAdapter) ListDeployedStacks() []backup.StackSummary {
DisplayName: s.Meta.DisplayName,
ComposePath: s.ComposePath,
NeedsHDD: s.Meta.Resources.NeedsHDD,
HasVolumes: len(backup.ParseComposeNamedVolumes(s.ComposePath)) > 0,
})
}
return result
@@ -932,6 +934,14 @@ func (a *stackAdapter) GetStackHDDMounts(name string) []string {
return allMounts
}
func (a *stackAdapter) GetDockerVolumes(name string) []string {
s, ok := a.mgr.GetStack(name)
if !ok {
return nil
}
return backup.ResolveDockerVolumeNames(s.ComposePath)
}
func (a *stackAdapter) GetStackHDDPath(name string) string {
s, ok := a.mgr.GetStack(name)
if !ok {
@@ -1163,12 +1173,7 @@ func (a *exportAdapter) GetDockerVolumes(name string) []string {
if !ok {
return nil
}
vols := backup.ParseComposeNamedVolumes(s.ComposePath)
var names []string
for _, v := range vols {
names = append(names, v.Name)
}
return names
return backup.ResolveDockerVolumeNames(s.ComposePath)
}
func (a *exportAdapter) IsStackDeployed(name string) bool {