{% extends "base.html" %} {% block title %}Backups{% endblock %} {% block content %} {# Item-10 scheduled-status page: is there a recent backup, did the last attempt succeed, and is the receipt chain intact. #}

Backups

Target: {{ backups.status.target_label }}

{% if notice %}
{{ notice }}
{% endif %} {% if error %}
{{ error }}
{% endif %} {% set state = backups.status.status %}
Status: {{ state }} {% if state == 'ok' %} Last successful backup {{ backups.status.last_success_at }} ({{ backups.status.age_hours }}h ago). {% elif state == 'stale' %} Last successful backup was {{ backups.status.age_hours }}h ago, older than the configured {{ backups.status.cadence.expected_interval_hours }}h cadence. {% elif state == 'failing' %} The most recent backup attempt failed ({{ backups.status.last_attempt_at }}). {% else %} No successful backup has ever been recorded for this target. {% endif %}
{% if not backups.status.cadence.configured %}

No cadence is configured, so this target is never reported as stale. Set backup.expected_interval_hours to enable staleness reporting.

{% else %}

Next backup due: {{ backups.status.cadence.next_due_at }}

{% endif %} {% if not backups.status.receipt_chain.ok %}
Receipt chain is broken. The audit trail for this target has been altered or truncated:
{% endif %} {% if backups.damaged %}
{{ backups.damaged|length }} backup(s) have an unreadable manifest and are not listed below: {{ backups.damaged|join(", ") }}
{% endif %}

Create a backup

Reads the database only; nothing is modified.

{# Without this the GUI has no way through a drift refusal: the button fails permanently and the runbook's remedy ("re-run with --allow-drift") is CLI-only, while the docs list Create on all three surfaces. #}

Backups ({{ backups.count }})

Storage: {{ backups.storage.uri }}

{% if not backups.backups %}

No backups have been taken for this target.

{% else %} {% for entry in backups.backups %} {% endfor %}
BackupClassCreatedRows SizeActions
{{ entry.backup_id }} {{ entry.backup_class }} {{ entry.created_at or "-" }} {{ entry.row_totals if entry.row_totals is not none else "-" }} {{ entry.bytes }}
Stage restore
{% endif %}

Recent activity

{% if not backups.status.recent_receipts %}

No lifecycle operations have been recorded.

{% else %} {% for receipt in backups.status.recent_receipts %} {# An explicit column, not a link hidden on the operation name. The first person shown this page could not find the evidence at all, because nothing indicated the name was clickable. Naming the check count also says *why* the link is worth following. #} {% endfor %}
WhenOperationStatusBackupBy Evidence
{{ receipt.created_at }} {{ receipt.operation }} {{ receipt.status }} {{ receipt.backup_id or "-" }} {{ receipt.actor.username or receipt.actor.surface }} {% set checks = receipt.detail.get("checks") or [] %} {% if checks %}View {{ checks|length }} checks{% else %}View{% endif %}
{% endif %}
{% endblock %}