Clear the reused dry-run rsync log before each dry-run so run details
only show output from the current execution.
Populate new Django global configs with the existing safe rsync and
exclude defaults, including archive mode and standard pseudo-filesystem
exclusions.
Add a host check that fails when effective rsync args do not include
archive or recursive transfer, preventing real backups that only report
"skipping directory .".
Add a host detail action that scans the target SSH host key with
ssh-keyscan and stores it on the selected SSH credential.
Merge scanned known_hosts entries without duplicates and let the
existing runtime config pass them through as UserKnownHostsFile for
unattended rsync over SSH.
Extend host checks to warn when the selected credential has no known_hosts
entries, making host key verification failures actionable from Django.
Add filesystem-backed SSH credentials for the native systemd deployment
path. Generated keys are stored below POBSYNC_HOME with 0600
permissions, while Django keeps the public key, fingerprint, path, and
selection metadata.
Add a Django SSH key generation view, delete action for unused generated
keys, and a management command used by the installer to ensure a default
backup key exists.
Update runtime config to use generated key paths directly as IdentityFile,
extend host checks to verify key readability, and keep legacy uploaded
keys available for compatibility.
Update the native installer so the pobsync service user gets journal
read access when the host exposes systemd-journal or adm groups.
Apply ownership and private directory modes to the configured backup
root, and reuse the existing environment backup root on reinstall so
production updates do not fall back to /backups.
Add a self-check for journal access and a host detail action that can
prepare missing backup directories for existing host configurations.
Add host-level checks for address, enabled state, SSH credential
selection, and backup directory readiness, and show them on the host
detail page.
Create host backup directories during host creation and prefill new
hosts from the default global config.
Add a staff-only logs view backed by journalctl with filtering by
pobsync unit, priority, and message text.
Improve runtime checks for gunicorn in virtualenv installs and ensure
the native installer grants the service user access to the backup root.
Allow SSH credentials to be created from an uploaded private key file
as an alternative to pasting the key into a textarea.
Use multipart form handling in the credential views so server-side
keys can be imported without copy/paste wrapping or formatting damage.
Cover the upload path with a view test while keeping existing pasted
key validation behavior intact.
Expand the systemd installer so it can perform a complete native
installation with sensible defaults: copy the checkout into the target
app directory, create runtime directories, write the environment file,
install dependencies, configure systemd units, and optionally configure
nginx.
Add a staff-only Django self-check page that verifies runtime settings,
required binaries, writable paths, database connectivity, global config
state, and systemd service status when available.
Document installer overrides and expose the self-check from the main
navigation.
Validate uploaded SSH private keys with ssh-keygen before saving them so
invalid, malformed, or unsupported key material is rejected in the
control panel instead of failing later during rsync.
Auto-populate the public key when it is omitted, add an edit flow for
existing SSH credentials, and cover create, update, and invalid-key
paths with view tests.
Add SSH credentials as first-class Django data so backup keys can be
uploaded through the control panel instead of mounted into containers.
Credentials can be selected globally or overridden per host. At runtime
the selected key is materialized inside the container with restrictive
file permissions and injected into the rsync SSH command via IdentityFile.
Known hosts entries are handled the same way when configured.
Add control panel views for creating and listing SSH keys, expose the
fields in config forms and admin, document the workflow, and cover global
and host credential selection with tests.
Turn the host detail page into a more useful operator surface for
starting greenfield backups from Django.
Add quick actions for dry-run and real backup runs, keep the advanced
manual options available, and show whether a host is ready, disabled, or
blocked by missing global config. Surface queued and running counts plus
a direct link to the active run.
Expose requested backup options on the run detail page and cover the new
control flow with view tests.
Expose retention apply from the host retention plan page so planned
snapshot deletions can be executed from the Django UI.
The form requires explicit host confirmation, carries through the
selected retention kind and base-protection setting, and uses max_delete
as a deletion guard. The view delegates to the SQL retention apply
service and reports predictable pobsync errors back through Django
messages instead of surfacing a server error.
Add view coverage for confirmed deletion, invalid confirmation, and
POST-only enforcement.
Add latest snapshot context to each dashboard host row so imported legacy
snapshots are visible without opening every host page.
Link the latest snapshot directly to its detail page and show its kind
and status beside the host snapshot count.
Cover the dashboard latest-snapshot selection with a view test.
Add a discovery preflight that reports the configured backup root, host
root, and snapshot directory counts before importing anything.
Show discovery status on host detail pages so missing mounts or mismatched
host directories are visible from the UI.
Warn clearly when discovery scans zero snapshots, including whether the
host backup directory is missing or simply empty.
Remove backup_root from the normal Django global config form and display
the fixed container path /backups instead.
Always persist /backups from the setup form so Docker deployments do not
mix host paths with container paths.
Update tests and docs to clarify that the host backup directory is chosen
through the Docker mount, while Django always uses /backups internally.
Add a staff-only manual backup form to host detail pages with safe
dry-run defaults and optional retention settings.
Queue manual BackupRun records through the existing worker-backed runner
path instead of executing backups inside the web request.
Validate disabled hosts, missing global config, and invalid methods with
view tests covering the new UI flow.
Fix the global config edit view so default initial values are only used
when creating a new config, preventing saved backup_root values from
being hidden by form defaults.
Keep pobsync_home as an internal runtime setting instead of exposing it
in the normal Django setup form.
Mount a host backup directory into Docker at /backups and document
POBSYNC_BACKUP_ROOT so backup_root behaves predictably in containers.
Add staff-only run and snapshot detail pages so scheduler and command
output can be inspected from the Django UI.
Link dashboard and host detail tables to the new detail views, including
snapshot/base relationships and linked backup runs.
Render stored result and metadata JSON in readable form and cover the new
inspection views with tests.
Add staff-only UI routes for creating/editing the default GlobalConfig
and creating the first HostConfig from the dashboard.
Improve the empty dashboard state so a fresh database guides the user
towards the next useful setup action instead of only showing empty tables.
Cover the setup flow with view tests for empty state prompts, global
config creation, and host creation.
Add a staff-only Django form for editing operational host settings while keeping
host identity stable. Support address, enablement, SSH/source overrides,
include/exclude lists, rsync extra args, and retention settings using the same
SQL-backed HostConfig model consumed by backup and scheduler flows.
Parse newline-separated list fields into JSON lists, preserve nullable
excludes_replace semantics, and cover rendering plus update behavior with view
tests.
Add a staff-only Django form for creating and updating host schedules using the
SQL-backed ScheduleConfig model. Link the form from host detail pages, validate
cron expressions with the existing scheduler parser, and preserve scheduler/CLI
behavior by writing to the same source of truth.
Cover default rendering, schedule creation, updates, and invalid cron handling
with view tests.
Add a staff-only retention plan page for each host using the SQL-backed
retention service. Link it from the host detail page and show policy settings,
keep reasons, and snapshots that would be deleted for scheduled, manual, or all
snapshot kinds.
Keep the flow non-destructive for now, validate query parameters, and cover the
view with tests for rendering, base protection, and invalid kind handling.
Add a staff-only POST action on host detail pages to discover existing snapshots
for that host and record them into SQL. Show success or failure feedback through
Django messages, and keep the action non-destructive before adding heavier
backup or retention controls.
Cover the action with view tests for successful discovery, redirect behavior,
and method safety.
Add a small template-based UI for inspecting pobsync state through Django. The
dashboard shows host, schedule, snapshot, and backup run summaries, while host
detail pages show config, schedule, recent runs, and discovered snapshots.
Keep the views read-only and staff-protected, document the new dashboard URL,
and cover the routes with focused view tests.