DBENGINE / app /admin /templates /backups.html
triflix's picture
Upload 21 files
0c1a3e2 verified
{% extends "base.html" %}
{% block title %}Backups - SQLite DBaaS{% endblock %}
{% block content %}
<div class="page-header">
<div>
<h1 class="page-title">Backups</h1>
<p class="page-subtitle">Manage database snapshots and remote storage</p>
</div>
<a href="/admin/dashboard" class="m3-button m3-button--text">
<span class="material-symbols-outlined">arrow_back</span>
Dashboard
</a>
</div>
<!-- HF Diagnostics -->
<div class="m3-card">
<div class="m3-card-header">
<div class="m3-card-icon">
<span class="material-symbols-outlined">cloud_sync</span>
</div>
<div>
<div class="m3-card-title">HuggingFace Setup</div>
<div class="m3-card-subtitle">Remote backup configuration</div>
</div>
</div>
<div class="diag-list">
{% for check in hf_diagnosis.checks %}
<div class="diag-item">
<div class="diag-status {% if '✅' in check.status %}success{% elif '❌' in check.status %}error{% endif %}">
<span class="material-symbols-outlined">
{% if '✅' in check.status %}check{% elif '❌' in check.status %}close{% else %}info{% endif %}
</span>
</div>
<div class="diag-content">
<div class="diag-name">{{ check.name }}</div>
<div class="diag-value">{{ check.value }}</div>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- Create Backup -->
<div class="m3-card">
<div class="m3-card-header">
<div class="m3-card-icon">
<span class="material-symbols-outlined">add_circle</span>
</div>
<div>
<div class="m3-card-title">Create Backup</div>
<div class="m3-card-subtitle">Local snapshot or remote upload</div>
</div>
</div>
<div class="m3-button-group">
<form method="POST" action="/admin/backups/create" style="display: inline;">
<input type="hidden" name="backup_type" value="snapshot">
<button type="submit" class="m3-button m3-button--outlined">
<span class="material-symbols-outlined">photo_camera</span>
Snapshot
</button>
</form>
<form method="POST" action="/admin/backups/create" style="display: inline;">
<input type="hidden" name="backup_type" value="compressed">
<button type="submit" class="m3-button m3-button--outlined">
<span class="material-symbols-outlined">compress</span>
Compressed
</button>
</form>
<form method="POST" action="/admin/backups/create" style="display: inline;">
<input type="hidden" name="backup_type" value="vacuum">
<button type="submit" class="m3-button m3-button--outlined">
<span class="material-symbols-outlined">cleaning_services</span>
VACUUM
</button>
</form>
<form method="POST" action="/admin/backups/create" style="display: inline;">
<input type="hidden" name="backup_type" value="hf_upload">
<button type="submit" class="m3-button m3-button--filled">
<span class="material-symbols-outlined">cloud_upload</span>
Upload to HF
</button>
</form>
</div>
</div>
<!-- Local Snapshots -->
<div class="m3-card">
<div class="m3-card-header">
<div class="m3-card-icon">
<span class="material-symbols-outlined">folder</span>
</div>
<div>
<div class="m3-card-title">Local Snapshots</div>
<div class="m3-card-subtitle">{{ backups.snapshot_dir }}</div>
</div>
</div>
{% if backups.local_snapshots %}
<div class="m3-table-container">
<table class="m3-table">
<thead>
<tr>
<th>Filename</th>
<th>Size</th>
<th>Modified</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for snapshot in backups.local_snapshots %}
<tr>
<td class="mono">{{ snapshot.name }}</td>
<td>{{ snapshot.size_mb }} MB</td>
<td>{{ snapshot.modified }}</td>
<td>
<a href="/admin/backups/download/{{ snapshot.name }}" class="m3-button m3-button--text">
<span class="material-symbols-outlined">download</span>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty-state">
<span class="material-symbols-outlined empty-icon">folder_off</span>
<div class="empty-title">No snapshots yet</div>
<div class="empty-description">Create your first snapshot above</div>
</div>
{% endif %}
</div>
<!-- Backup Strategy -->
<div class="m3-card">
<div class="m3-card-header">
<div class="m3-card-icon">
<span class="material-symbols-outlined">layers</span>
</div>
<div>
<div class="m3-card-title">3-Layer Backup Strategy</div>
</div>
</div>
<div class="strategy-layers">
<div class="strategy-layer">
<div class="layer-number">1</div>
<div class="layer-content">
<h4>Litestream — Real-time</h4>
<p>Automatic replication every second. Max 1s data loss. Local file replica.</p>
</div>
</div>
<div class="strategy-layer">
<div class="layer-number">2</div>
<div class="layer-content">
<h4>Python Backup — On-demand</h4>
<p>Atomic snapshots using sqlite3.backup(). Gzip compressed. Consistent while DB is in use.</p>
</div>
</div>
<div class="strategy-layer">
<div class="layer-number">3</div>
<div class="layer-content">
<h4>HF Bucket — Persistent</h4>
<p>Remote storage on HuggingFace. 100GB free. Survives container restarts.</p>
</div>
</div>
</div>
</div>
<!-- Quick API Test -->
<div class="m3-card">
<div class="m3-card-header">
<div class="m3-card-icon">
<span class="material-symbols-outlined">api</span>
</div>
<div>
<div class="m3-card-title">API Endpoints</div>
<div class="m3-card-subtitle">For programmatic access</div>
</div>
</div>
<div class="m3-code-block">GET /admin/api/diagnostics - Check HF setup
POST /admin/api/backup/test - Test backup creation
POST /admin/api/backup/upload - Upload to HF Bucket</div>
</div>
{% endblock %}