# Agent notes for PVE Cloud Backup This project is a directly installed Proxmox backup web app. It runs from: ```text /opt/pve-cloud-backup/ backend/ FastAPI app, worker, SQLite migrations, tests frontend/ Vue 3 + TypeScript + Tailwind source static/ generated frontend build; ignored by git data/ runtime SQLite database; ignored by git logs/ runtime logs; ignored by git scripts/ install/update/uninstall/manual integration scripts systemd/ source copies of service units ``` The live services are: - `pve-cloud-backup-web.service` - `pve-cloud-backup-worker.service` The web app listens on `0.0.0.0:8080`. ## Core rules - Keep runtime configuration in SQLite only. Do not add `.env`, YAML, JSON, TOML, or other runtime config files. - Do not commit `/opt/pve-cloud-backup/data/`, `/logs/`, `/static/`, `.venv`, `node_modules`, caches, or generated artifacts. - Do not use Docker or add distributed-worker infrastructure. - Do not call `vzdump` directly. Use `pvesh` for backup operations. - Do not require a crypt remote. Plain OneDrive remotes and crypt remotes are both allowed. - Do not use `rclone sync`. - Use exact-object rclone operations: - upload with `copyto`; - verify with `lsjson`; - delete files with `deletefile`; - remove empty per-backup folders with `rmdir`. - Never delete a local archive unless upload completed and the remote object was verified. - Mock `pvesh` and `rclone` in automated tests. Manual integration testing is limited to `scripts/integration-test-adguard.sh`. ## Runtime data SQLite database: ```text /opt/pve-cloud-backup/data/app.db ``` Current important settings live in SQLite, not files. Common live values on this node have included: - Proxmox node: `astrid` - Proxmox storage: `hitachi` - local dump path: `/mnt/pve/hitachi/dump` - rclone remote: `onedrive` - remote path: `pve-cloud-backup` - timezone: `Europe/Berlin` - manual test guest: `adguard`, VMID `110`, type `lxc` Do not hardcode those into normal app behavior. They are local operational context. ## Backend map - `backend/app/main.py` - FastAPI app, API routes, setup/settings validation, static frontend serving. - `backend/app/backup_service.py` - Backup state machine, upload/delete/retention/recovery logic. - `backend/app/commands.py` - Shell wrappers for `pvesh` and `rclone`. - `backend/app/jobs.py` - Cron validation, timezone-aware next-run calculation, job CRUD helpers. - `backend/app/migrations.py` - SQLite schema and default settings. - `backend/app/settings_store.py` - SQLite settings serialization/parsing. - `backend/app/worker.py` - Scheduler/worker entrypoint. - `backend/tests/` - Unit tests. Keep external command usage mocked. ## Frontend map - `frontend/src/App.vue` - Single-file UI for setup, dashboard, guests, jobs, history, backup details, and settings. - `frontend/src/main.ts` - Vue mount entrypoint. - `frontend/src/style.css` - Tailwind/global styling. The built frontend goes to `/opt/pve-cloud-backup/static/` via `npm run build`; do not commit that directory. ## Backup workflow Expected states: - `queued` - `pve_running` - `local_ready` - `uploading` - `remote_ready` - `local_deleting` - `completed` - `failed` - `deleting` - `deleted` Important behavior: - The worker atomically claims queued backups before starting Proxmox work. - `pve_running` must have a real Proxmox UPID before polling task status. - Local archive discovery must ignore `.log` and `.notes`; only real archive suffixes count. - Remote path shape is: ```text :// ``` - Deleting a backup removes the exact remote file and then attempts to remove the empty `` folder. - Deleting a backup already in `deleted` state purges the SQLite metadata row. - Deleting a job deletes all known non-active backups for that job first, then removes the job. - Retention runs after backup completion and hourly from the worker. ## Applying updates after pulling changes After a `git pull`, apply the new code with: ```bash cd /opt/pve-cloud-backup ./scripts/apply-update.sh ``` The script: 1. backs up `data/app.db` to `data/update-backups/`; 2. stops web/worker services; 3. creates/updates `backend/.venv`; 4. installs backend requirements; 5. optionally runs backend tests if `RUN_TESTS=1`; 6. runs `npm ci` or `npm install`; 7. builds frontend assets into `static/`; 8. runs SQLite migrations; 9. installs systemd units from `systemd/`; 10. reloads systemd; 11. restarts and health-checks services. Use this stricter variant when practical: ```bash cd /opt/pve-cloud-backup git pull --ff-only RUN_TESTS=1 ./scripts/apply-update.sh ``` If the health check fails, inspect: ```bash journalctl -u pve-cloud-backup-web.service -u pve-cloud-backup-worker.service --no-pager -n 100 ``` ## Validation commands Backend tests: ```bash cd /opt/pve-cloud-backup/backend ./.venv/bin/pytest ``` Frontend typecheck/build: ```bash cd /opt/pve-cloud-backup/frontend npm run build ``` Service status: ```bash systemctl is-active pve-cloud-backup-web.service pve-cloud-backup-worker.service ``` API smoke checks: ```bash curl -fsS http://127.0.0.1:8080/api/setup/status curl -fsS http://127.0.0.1:8080/api/jobs | python3 -m json.tool curl -fsS http://127.0.0.1:8080/api/backups | python3 -m json.tool ``` Manual integration test: ```bash API_URL=http://127.0.0.1:8080 /opt/pve-cloud-backup/scripts/integration-test-adguard.sh ``` Only run the manual integration test when the user explicitly wants a real Proxmox/rclone backup test. ## Git workflow Remote: ```text origin ssh://gitea@gitea.reversed.dev:2222/space/pve-cloud-backups.git ``` Default branch: ```text main ``` Before committing, check: ```bash git status --short --ignored ``` Confirm ignored runtime files stay ignored: ```bash git check-ignore -v data/app.db logs/worker.log static/index.html frontend/node_modules/.package-lock.json backend/.venv/pyvenv.cfg ```