feat: drive migration & Tier 2 restic deprecation (v0.18.0)

Phase 1: Deprecate restic as Tier 2 method (rsync only), auto-migrate on startup
Phase 2: Enhanced per-app migration with backup awareness, DB dump copy, auto-cleanup
Phase 3: Full drive migration with decommissioned state, rollback support, wizard UI
Phase 4: Hub report includes decommissioned drive state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-19 21:49:14 +01:00
parent bdbe170a54
commit 99bf3ca7a8
22 changed files with 1725 additions and 402 deletions
+33 -10
View File
@@ -38,10 +38,19 @@
<ul style="margin:.5rem 0 0 1rem;padding:0">
<li>Az alkalmazás a mozgatás idejére leáll</li>
<li>Nagy adatmennyiségnél ez percekig tarthat</li>
<li>A régi adatok megmaradnak biztonsági másolatként</li>
<li>DB mentés fájlok is átkerülnek</li>
<li>A migráció után azonnal lefut egy biztonsági mentés az új meghajtón</li>
</ul>
</div>
<div style="margin-bottom:1.5rem">
<label style="display:flex;align-items:center;gap:.5rem;cursor:pointer">
<input type="checkbox" id="auto-delete" checked>
<span>Régi adatok törlése a forrás meghajtóról</span>
</label>
<span class="form-hint" style="margin-left:1.5rem">Ha bekapcsolva, a forrás meghajtóról az alkalmazás adatai és DB mentései automatikusan törlődnek a sikeres áthelyezés után.</span>
</div>
<div id="migrate-error" class="alert alert-error" style="display:none;margin-bottom:1rem"></div>
<div class="form-actions" style="gap:.75rem">
@@ -58,6 +67,8 @@
<div class="disk-step" id="mstep-copying"><span class="disk-step-icon"></span> Adatok másolása</div>
<div class="disk-step" id="mstep-updating"><span class="disk-step-icon"></span> Konfiguráció frissítése</div>
<div class="disk-step" id="mstep-starting"><span class="disk-step-icon"></span> Alkalmazás indítása</div>
<div class="disk-step" id="mstep-cleaning"><span class="disk-step-icon"></span> Régi adatok törlése</div>
<div class="disk-step" id="mstep-backing_up"><span class="disk-step-icon"></span> Biztonsági mentés</div>
<div class="disk-step" id="mstep-done"><span class="disk-step-icon"></span> Kész</div>
</div>
@@ -75,16 +86,18 @@
<div class="settings-card" id="migrate-done-card" style="display:none">
<h3>✅ Adatáthelyezés kész!</h3>
<p style="margin-top:.75rem;color:var(--text-secondary)">
Az alkalmazás az új tárolóról fut.<br>
A régi adatok a korábbi helyen megmaradtak biztonsági másolatként.
<p id="done-msg" style="margin-top:.75rem;color:var(--text-secondary)">
Az alkalmazás az új tárolóról fut.
</p>
<div class="alert alert-warning" style="margin-top:1rem">
<div id="done-tier2-warning" class="alert alert-warning" style="display:none;margin-top:1rem">
A 2. szintű mentés törlésre került, mert a cél meghajtó megegyezett a mentési céllal.
<a href="/stacks/{{.Meta.Slug}}/deploy">Újrakonfigurálás →</a>
</div>
<div id="done-manual-steps" class="alert alert-warning" style="margin-top:1rem">
<strong>Javasolt lépések:</strong>
<ol style="margin:.5rem 0 0 1rem;padding:0">
<li>Ellenőrizd, hogy az alkalmazás megfelelően működik</li>
<li>Győződj meg róla, hogy minden adat megtalálható</li>
<li>Ha minden rendben, törölheted a korábbi adatokat</li>
</ol>
</div>
<div style="margin-top:1.5rem;display:flex;gap:.75rem;flex-wrap:wrap">
@@ -111,10 +124,12 @@ function startMigrate() {
document.getElementById('migrate-form-card').style.display = 'none';
document.getElementById('migrate-progress-card').style.display = 'block';
var autoDelete = document.getElementById('auto-delete').checked;
fetch('/api/storage/migrate', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({stack_name: stackName, target_path: targetPath})
body: JSON.stringify({stack_name: stackName, target_path: targetPath, auto_delete_stale: autoDelete})
})
.then(function(r){ return r.json(); })
.then(function(data) {
@@ -129,7 +144,7 @@ function startMigrate() {
});
}
var migStepOrder = ['stopping','copying','updating','starting','done'];
var migStepOrder = ['stopping','copying','updating','starting','cleaning','backing_up','done'];
function pollMigProgress() {
fetch('/api/storage/migrate/status')
@@ -194,8 +209,16 @@ function showMigDone() {
document.getElementById('migrate-progress-card').style.display = 'none';
document.getElementById('migrate-done-card').style.display = 'block';
document.getElementById('migrate-done-card').scrollIntoView({behavior:'smooth'});
// Show the delete button (old data is at the source path)
document.getElementById('migrate-delete-old-btn').style.display = '';
var autoDeleteChecked = document.getElementById('auto-delete').checked;
if (autoDeleteChecked) {
document.getElementById('done-msg').textContent =
'Az alkalmazás az új tárolóról fut. A régi adatok automatikusan törölve lettek.';
} else {
document.getElementById('done-msg').innerHTML =
'Az alkalmazás az új tárolóról fut.<br>A régi adatok a korábbi helyen megmaradtak.';
document.getElementById('migrate-delete-old-btn').style.display = '';
}
}
function deleteOldMigrationData() {