{"id":47699191,"url":"https://github.com/egyan07/ghostbackup","last_synced_at":"2026-04-02T17:02:24.204Z","repository":{"id":344681671,"uuid":"1182699546","full_name":"Egyan07/GhostBackup","owner":"Egyan07","description":"Secure automated backup for Windows with AES-256-GCM streaming encryption, 3-2-1 redundancy, circuit breaker, 7-year compliance retention, and real-time file watching. Built with Electron + React + FastAPI.","archived":false,"fork":false,"pushed_at":"2026-03-26T22:00:49.000Z","size":3231,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-27T08:50:35.505Z","etag":null,"topics":["aes-256-gcm","automation","backup-tool","data-protection","desktop-app","electron","encryption","fastapi","file-sync","local-backup","python","react","sqlite","ssd-backup","vite","watchdog"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Egyan07.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-15T21:22:29.000Z","updated_at":"2026-03-26T22:00:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Egyan07/GhostBackup","commit_stats":null,"previous_names":["egyan07/ghostbackup"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/Egyan07/GhostBackup","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Egyan07%2FGhostBackup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Egyan07%2FGhostBackup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Egyan07%2FGhostBackup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Egyan07%2FGhostBackup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Egyan07","download_url":"https://codeload.github.com/Egyan07/GhostBackup/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Egyan07%2FGhostBackup/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31311027,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes-256-gcm","automation","backup-tool","data-protection","desktop-app","electron","encryption","fastapi","file-sync","local-backup","python","react","sqlite","ssd-backup","vite","watchdog"],"created_at":"2026-04-02T17:01:25.218Z","updated_at":"2026-04-02T17:02:24.194Z","avatar_url":"https://github.com/Egyan07.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 👻 GhostBackup\n\n\u003e ⚠️ **Windows Only** — macOS and Linux are not supported. The app may not install or run correctly on those platforms.\n\n### Local. Encrypted. Audited. Yours.\n\n![CI](https://img.shields.io/github/actions/workflow/status/Egyan07/GhostBackup/ci.yml?label=CI)\n![Backend Coverage](https://img.shields.io/badge/coverage-90%25-brightgreen)\n![Tests](https://img.shields.io/badge/tests-510%20passing-brightgreen)\n![GitHub issues](https://img.shields.io/github/issues/Egyan07/GhostBackup)\n![GitHub last commit](https://img.shields.io/github/last-commit/Egyan07/GhostBackup)\n![License](https://img.shields.io/github/license/Egyan07/GhostBackup)\n\n**Author: [Egyan07](https://github.com/Egyan07)**\n\n\u003e 💡 Most small businesses back up to Dropbox or OneDrive and call it a day. But when your files contain client financials, legal documents, or personal records — you don't want them on someone else's server. GhostBackup keeps your backups local, encrypted, and under your control. No monthly bill. No breach notification letters.\n\n---\n\nGhostBackup is a secure automated backup system built with **Electron, React, and Python FastAPI**. Originally built for and actively deployed at Red Parrot Accounting (UK) — open source and free for any small business with similar needs.\n\n---\n\n\u003e **In 30 seconds:** GhostBackup runs on a dedicated Windows machine, backs up your source folders to one or two local SSDs on a daily schedule, encrypts every file with AES-256-GCM, verifies integrity with xxhash, and emails you if anything fails. No cloud. No subscriptions. No IT staff required.\n\n---\n\n## ⚔️ How GhostBackup Compares\n\n| Feature | GhostBackup | Backblaze B2 | Veeam Free | IDrive |\n|---------|:-----------:|:------------:|:----------:|:------:|\n| AES-256-GCM encryption | ✅ | ✅ | ❌ | ✅ |\n| No cloud / no vendor dependency | ✅ | ❌ | ✅ | ❌ |\n| No subscription cost | ✅ | ❌ | ✅ | ❌ |\n| GUI dashboard + live run view | ✅ | ❌ | ✅ | ✅ |\n| Per-file integrity verification (xxhash) | ✅ | ❌ | ❌ | ❌ |\n| Email alerts on failure | ✅ | ✅ | ✅ | ✅ |\n| Dry-run restore preview | ✅ | ❌ | ❌ | ❌ |\n| Audit log with run history | ✅ | ❌ | ✅ | ✅ |\n| Key fingerprint rotation detection | ✅ | ❌ | ❌ | ❌ |\n| Open source | ✅ | ❌ | ❌ | ❌ |\n| Windows native | ✅ | ✅ | ✅ | ✅ |\n| Rate-limited REST API | ✅ | N/A | ❌ | ❌ |\n\n\u003e GhostBackup is purpose-built for small businesses that need real encryption, real audit trails, and zero recurring cost — without the complexity of enterprise backup suites.\n\n---\n\n## 📑 Table of Contents\n\n- [How GhostBackup Compares](#️-how-ghostbackup-compares)\n- [Screenshots](#-screenshots)\n- [Tech Stack](#-tech-stack)\n- [Features](#-features)\n- [Limitations](#-limitations)\n- [Quick Start](#-quick-start)\n- [Testing](#-testing)\n- [Architecture](#-architecture)\n- [API Endpoints](#-api-endpoints)\n- [Configuration](#-configuration)\n- [Environment Variables](#-environment-variables)\n- [Project Structure](#-project-structure)\n- [Security](#-security)\n- [Retention \u0026 Auditability](#-retention--auditability)\n- [Troubleshooting](#-troubleshooting)\n- [Disaster Recovery](#-disaster-recovery)\n- [Contributing](#-contributing)\n- [Use Cases](#-use-cases)\n- [License](#-license)\n- [Changelog](#-changelog)\n\n---\n\n## 📸 Screenshots\n\n| Dashboard | Live Run | Restore |\n|-----------|----------|---------|\n| ![Dashboard](screenshots/Dashboard.png) | ![Live Run](screenshots/Live%20Run.png) | ![Restore](screenshots/Restore.png) |\n| *Last run summary, SSD usage, and next scheduled backup* | *Live progress, per-library status, and file feed during an active run* | *Date and library selection with dry-run preview mode* |\n\n| Email Alert |\n|-------------|\n| ![Email Alert](screenshots/Email%20Alerts.png) |\n| *SMTP verification email confirming alerts are configured correctly* |\n\n---\n\n## 🧰 Tech Stack\n\n![Electron](https://img.shields.io/badge/Electron-191970?style=for-the-badge\u0026logo=electron\u0026logoColor=white)\n![React](https://img.shields.io/badge/React-20232A?style=for-the-badge\u0026logo=react\u0026logoColor=61DAFB)\n![FastAPI](https://img.shields.io/badge/FastAPI-009688?style=for-the-badge\u0026logo=fastapi\u0026logoColor=white)\n![Python](https://img.shields.io/badge/Python-3776AB?style=for-the-badge\u0026logo=python\u0026logoColor=white)\n![SQLite](https://img.shields.io/badge/SQLite-07405E?style=for-the-badge\u0026logo=sqlite\u0026logoColor=white)\n\n---\n\n## ✨ Core Features\n\n### 🛡️ Security \u0026 Privacy\n| Feature | Description |\n|---------|-------------|\n| 🔐 Encryption at Rest | AES-256-GCM streaming encryption via Python `cryptography` library. Constant memory usage regardless of file size. Per-file random nonce. Versioned encryption header for future key rotation. Per-installation HKDF salt for stronger key isolation. |\n| 🔐 Key Protection | Encryption keys stored in Windows Credential Manager (keyring). Automatic migration from `.env.local`. |\n| 🔒 API Security | Auto-generated session token per launch via `crypto.randomBytes(32)`. All endpoints authenticated via `X-API-Key` header with timing-safe comparison (`hmac.compare_digest`). Rate limiting on sensitive endpoints (slowapi). |\n| 🛡️ Immutable Window | Write-once-read-many (WORM) logic for the recent backup window (7 days). |\n| 💾 Dual-SSD Redundancy | Primary and secondary SSD support. Combined with the original source, this provides 3 copies across 2 drives. Manual offsite copy support via [OFFSITE.md](OFFSITE.md). |\n\n### 📊 Monitoring \u0026 Auditability\n| Feature | Description |\n|---------|-------------|\n| ✅ Integrity Verification | On-demand xxhash verification of all backups. Automatic spot-checks on startup. |\n| 🚀 Startup Self-Check | On launch, 5 random backup files are verified against the manifest. Critical alert on corruption. |\n| 🧪 Restore Drill Tracking | Every restore is logged as a drill. Escalating reminders if no drill in 30/37/44 days. Audit-ready history. |\n| 📧 Email Alerts | SMTP-based failure alerts and run summaries. Supports Gmail App Passwords and standard SMTP providers. |\n| 🔔 Desktop Notifications | Windows toast notification on backup completion for all outcomes — success, partial, and failed. |\n| 📝 Audit Logs | Detailed run history and alert logs persisted in a local SQLite database. |\n\n### ⚡ Performance \u0026 UX\n| Feature | Description |\n|---------|-------------|\n| ⏰ Scheduled Backups | Daily automated backups via APScheduler with configurable timezone support. |\n| 👁️ Real-Time Watching | Watchdog-based file system monitor for instant incremental sync. |\n| 🧪 Dry-Run Restore | Preview exactly which files will be restored before writing to disk. |\n| 🧹 Automated Pruning | Smart retention policy (daily/weekly/yearly) that automatically deletes old backups to free up SSD space while respecting the immutable window. |\n| 🌗 Dark/Light Theme | Toggle between dark (default) and light themes. Choice persists via localStorage. |\n\n### 🛠️ Developer \u0026 Admin Tools\n| Feature | Description |\n|---------|-------------|\n| 📋 SQLite Backend | Full backup history and per-file status stored in a local SQLite database. |\n| 📤 Audit Log Export | Export full run history as a downloadable CSV from the Logs page. |\n| 🏥 Deep Health Check | `GET /health/deep` returns comprehensive system status for monitors. |\n| 🔢 Structured Errors | API errors include codes (GB-Exxx) with actionable fix suggestions. |\n\n---\n\n## ⚠️ Limitations\n\nBefore adopting GhostBackup, understand what it **does not** do:\n\n| Limitation | Detail |\n|------------|--------|\n| **Windows only** | Requires Windows 10/11. No Linux or macOS support. |\n| **Local drives only** | Backs up to directly attached drives (internal/external SSDs). No cloud, NAS, or network share support. |\n| **No offsite copy** | GhostBackup handles local redundancy only. Offsite backup is your responsibility — see [OFFSITE.md](OFFSITE.md) for simple options using your existing tools. |\n| **No deduplication** | Changed files are copied in full on each backup run. No block-level or byte-level dedup. |\n| **Single machine** | No multi-user or networked deployment. If the machine is offline, no backup runs. |\n| **Files only** | Restores individual files/folders — not OS images. Pair with Macrium Reflect Free for full system recovery. |\n| **Locked files** | Files held open by other processes (e.g. open Excel) are retried but may be skipped. Check logs after each run. |\n| **Long paths** | Paths over 260 characters may fail unless Windows long path support is enabled (`HKLM\\SYSTEM\\CurrentControlSet\\Control\\FileSystem\\LongPathsEnabled = 1`). |\n| **Scale** | Tested up to ~50GB source data. Performance on 500GB+ datasets is untested. |\n| **No external security audit** | Encryption and authentication use industry-standard libraries but have not been reviewed by a third-party security firm. |\n| **Encryption key storage** | Key is stored in Windows Credential Manager (keyring) by default. Falls back to `.env.local` for CI environments. If the key is lost from all locations, all encrypted backups are permanently unrecoverable. |\n| **Not legal compliance** | GhostBackup provides tools that *support* compliance. It is not a compliance certification. |\n\n---\n\n## 🚀 Quick Start\n\n### Option A — Download Installer (Recommended)\n\n1. Download the latest `GhostBackup_Setup.exe` from the **[Releases](https://github.com/Egyan07/GhostBackup/releases)** page.\n2. Run the installer and follow the on-screen prompts.\n3. Launch GhostBackup from your desktop or start menu.\n\n### Option B — Manual Setup (~5 minutes)\n\nIf you prefer to install manually or use your existing Python/Node environments:\n\n### Prerequisites\n\n- Windows 10 or 11\n- [Python 3.10+](https://www.python.org/downloads/) — **must be added to PATH during installation**\n- [Node.js 18+](https://nodejs.org/)\n- At least one dedicated backup drive (SSD recommended)\n- ~200MB free disk space for dependencies\n- Internet connection required during install (for `pip install` and `npm install`)\n\n### Installation\n\n1. Clone the repository:\n   ```bash\n   git clone https://github.com/Egyan07/GhostBackup.git\n   cd GhostBackup\n   ```\n\n2. Run the guided installer:\n   ```\n   install.bat\n   ```\n   This will:\n   - Install Python and Node.js dependencies\n   - Prompt you to select backup source folders\n   - Prompt you to select primary (and optionally secondary) SSD drive\n   - Generate an AES-256 encryption key and per-installation HKDF salt, stored in Windows Credential Manager (falls back to `.env.local` in CI environments)\n   - Create `backend/config/config.yaml` from the template\n\n3. Launch GhostBackup:\n   ```\n   start.bat\n   ```\n\n\u003e **Note:** Admin privileges are not required. Expected install time: 2–5 minutes.\n\n\u003e Full step-by-step guide: **[SETUP.md](SETUP.md)**\n\n### If something goes wrong during install\n\n- **Python not found:** Reinstall Python and check \"Add to PATH\" during setup\n- **Permission errors:** Run `install.bat` as Administrator\n- **Port 8765 in use:** Another instance may be running in the tray. Right-click tray icon → Quit GhostBackup, then retry\n\n---\n\n## 🧪 Testing\n\n```bash\n# Backend — 368 tests, 90% line coverage\ncd backend\npython -m pytest tests/ -v --cov=. --cov-report=term-missing\n\n# Frontend — 142 tests\nnpm test\n\n# Frontend — with coverage\nnpm run test:coverage\n```\n\n| Suite | Tests | Coverage | Type | CI |\n|-------|-------|----------|------|----|\n| Backend | 368 | 90% line | Unit + integration | ✅ GitHub Actions |\n| Frontend | 142 | 63% stmt | Unit (Vitest + v8) | ✅ GitHub Actions |\n\n**What's tested:**\n- Backup engine (scan, encrypt, copy, verify, prune)\n- API endpoints (auth, config, runs, restore, alerts)\n- Configuration management and audit logging\n- Scheduler and file watcher lifecycle\n- Email alert formatting and delivery\n- Failure threshold behavior\n\n**What's not tested:**\n- End-to-end Electron → backend → disk pipeline (manual testing only)\n- Performance at scale beyond ~50GB\n- Multi-drive failure scenarios\n\n---\n\n## 🏗 Architecture\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│ ELECTRON (main.js)                                          │\n│ • Generates API token (crypto.randomBytes)                  │\n│ • Spawns Python backend as child process                    │\n│ • System tray integration                                   │\n│ • If Electron exits, Python process is terminated           │\n└──────────────────────────┬──────────────────────────────────┘\n                           │ token via environment\n                           ▼\n┌─────────────────────────────────────────────────────────────┐\n│ FASTAPI BACKEND (port 8765)                                 │\n│                                                             │\n│ 🔒 Auth Middleware (X-API-Key on all routes except /health) │\n│                                                             │\n│ ⏰ APScheduler          👁️ Watchdog File Watcher             │\n│ (daily cron job)        (15s debounce, 120s cooldown)       │\n│                                                             │\n│ Backup Engine (syncer.py)                                   │\n│  ├─ Scan source folders for new/changed files               │\n│  ├─ Encrypt each file (AES-256-GCM, per-file nonce, 4MB chunks) │\n│  ├─ Copy to primary SSD (and secondary if configured)       │\n│  ├─ Verify copy integrity (xxhash comparison)               │\n│  ├─ Abort library if failure rate exceeds threshold (5%)    │\n│  └─ Log every file result to SQLite                         │\n│                                                             │\n│ SQLite Database                                             │\n│  ├─ Backup runs with timestamps and status                  │\n│  ├─ Per-file records (hash, size, status, error)            │\n│  └─ Configuration audit trail                               │\n└─────────────────────────────────────────────────────────────┘\n                           ▲\n                           │ HTTP (localhost only, polling)\n┌──────────────────────────┴──────────────────────────────────┐\n│ REACT FRONTEND (Chromium sandbox enabled, CSP active)       │\n│ • Dashboard  • Live Run  • Logs                             │\n│ • Restore    • Settings  • Alert Bell                       │\n└─────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## 🔌 API Endpoints\n\nAll endpoints require the **X-API-Key header** except `/health`.\n\n**Core**\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | /health | Health check (no auth required) |\n| GET | /dashboard | Dashboard summary stats |\n\n**Backup Runs**\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| POST | /run/start | Start a backup run |\n| POST | /run/stop | Cancel the active run |\n| GET | /run/status | Active run state |\n| POST | /verify | Re-hash all backed-up files and return verified/corrupt/missing counts |\n| GET | /runs | Backup run history |\n| GET | /runs/:id | Single run detail |\n| GET | /runs/:id/logs | Per-file log entries for a run |\n\n**Restore**\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| POST | /restore | Restore files (path traversal validated) |\n\n**Configuration**\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | /config | Current configuration |\n| PATCH | /config | Update configuration |\n| GET | /config/audit | Configuration change audit trail |\n| POST | /config/sites | Add a backup source folder |\n| PATCH | /config/sites/:name | Update a source folder |\n| DELETE | /config/sites/:name | Remove a source folder |\n\n**Settings**\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| PATCH | /settings/smtp | Update SMTP email settings |\n| POST | /settings/smtp/test | Send a test email |\n| PATCH | /settings/retention | Update retention policy |\n| POST | /settings/prune | Manually trigger prune job |\n| POST | /settings/encryption/generate-key | Generate a new encryption key |\n| GET | /settings/drill-status | Restore drill status and history |\n\n**Monitoring**\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | /health/deep | Comprehensive health check for monitoring tools |\n| GET | /ssd/status | Disk usage and health for configured drives |\n| GET | /alerts | In-app alert list |\n| POST | /alerts/:id/dismiss | Dismiss a single alert |\n| POST | /alerts/dismiss-all | Dismiss all alerts |\n| GET | /watcher/status | File watcher running state |\n| POST | /watcher/start | Start file watcher |\n| POST | /watcher/stop | Stop file watcher |\n\n---\n\n## ⚙️ Configuration\n\nLocation: `backend/config/config.yaml`\nTemplate: `backend/config/config.yaml.example`\n\n```yaml\nssd_path: \"D:\\\\GhostBackup\"\nsecondary_ssd_path: \"E:\\\\GhostBackup2\"   # optional — leave blank to disable\n\nencryption:\n  enabled: true   # requires GHOSTBACKUP_ENCRYPTION_KEY in .env.local\n\nsources:\n  - label: \"Client Records\"\n    path: \"C:\\\\Users\\\\admin\\\\SharePoint\\\\Red Parrot\\\\Clients\"\n    enabled: true\n\nretention:\n  daily_days: 365         # keep daily backups for 1 year\n  weekly_days: 2555       # keep weekly backups for 7 years\n  compliance_years: 7     # minimum retention floor\n  guard_days: 7           # prevent accidental deletion of recent backups\n\nschedule:\n  time: \"08:00\"\n  timezone: \"Europe/London\"\n\ncircuit_breaker_threshold: 0.05   # abort library if \u003e5% of files fail\n\nwatcher:\n  debounce_seconds: 15    # wait this long after the last change before triggering a backup\n  cooldown_seconds: 120   # minimum gap between two watcher-triggered backup runs\n```\n\n---\n\n## 🔑 Environment Variables\n\nThe encryption key is stored in Windows Credential Manager by default. `.env.local` is used as a fallback for CI/headless environments and must never be committed (already in `.gitignore`).\n\n```bash\nGHOSTBACKUP_ENCRYPTION_KEY=your-base64-key-here\nGHOSTBACKUP_SMTP_PASSWORD=your-smtp-password\n# GHOSTBACKUP_API_PORT=8765\n```\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `GHOSTBACKUP_ENCRYPTION_KEY` | Yes (if encryption enabled) | Base64-encoded Fernet key — HKDF-derived to 256-bit AES. Generated by `install.bat` and stored in Windows Credential Manager by default. Set in `.env.local` for CI/headless environments. **If lost from all locations, all encrypted backups are unrecoverable.** |\n| `GHOSTBACKUP_HKDF_SALT` | No (recommended for new installs) | Per-installation salt for HKDF AES key derivation. Set on first install to strengthen key isolation. Falls back to a static default for backward compatibility with existing encrypted backups. |\n| `GHOSTBACKUP_SMTP_PASSWORD` | Yes (if email alerts enabled) | SMTP password. For Gmail, use an App Password. |\n| `GHOSTBACKUP_API_PORT` | No (default: 8765) | Port for the FastAPI backend. |\n| `GHOSTBACKUP_API_TOKEN` | Auto | Generated by Electron on each launch. Do not set manually. |\n| `GHOSTBACKUP_DB_PATH` | No (default: `backend/ghostbackup.db`) | Override the SQLite database path. Useful when running the backend standalone outside the project directory. |\n\n---\n\n## 📂 Project Structure\n\n```\nGhostBackup/\n│\n├── install.bat              ← guided first-time setup\n│\n├── backend/\n│   ├── config/\n│   │   ├── config.yaml.example\n│   │   └── config.yaml      ← your configuration (generated by install.bat)\n│   ├── api.py               ← FastAPI server\n│   ├── config.py            ← ConfigManager (load, validate, audit)\n│   ├── manifest.py          ← SQLite database (runs, files, audit trail)\n│   ├── reporter.py          ← AlertManager + SMTP email delivery\n│   ├── scheduler.py         ← APScheduler daily job\n│   ├── setup_helper.py      ← called by install.bat for guided setup\n│   ├── syncer.py            ← backup engine (scan, encrypt, copy, verify, prune)\n│   ├── utils.py             ← shared helpers (fmt_bytes, fmt_duration)\n│   ├── watcher.py           ← watchdog real-time file watcher\n│   └── tests/               ← 368 pytest tests (510 total with frontend)\n│\n├── electron/\n│   ├── main.js              ← Electron main process (spawns backend, tray)\n│   └── preload.js           ← contextBridge API surface\n│\n├── src/\n│   ├── GhostBackup.jsx      ← app shell + sidebar navigation\n│   ├── main.jsx             ← React entry point + backend health poller\n│   ├── api-client.js        ← authenticated fetch wrapper\n│   ├── styles.css           ← application styles\n│   ├── splash.css           ← splash/loading screen styles\n│   ├── components/          ← reusable UI components\n│   ├── pages/               ← full-page views (Dashboard, Restore, Settings, etc.)\n│   └── tests/               ← 142 vitest tests (510 total with backend)\n│\n├── screenshots/             ← README screenshots\n├── OFFSITE.md               ← offsite backup guide\n├── SETUP.md                 ← full setup guide\n├── RECOVERY.md              ← disaster recovery guide\n└── CHANGELOG.md             ← full version history\n```\n\n---\n\n## 🔐 Security\n\n| Layer | Implementation |\n|-------|----------------|\n| Encryption | AES-256-GCM via Python `cryptography` library. Streaming with constant memory. Per-file random nonce (`os.urandom`). Versioned header (v1) for key rotation support. Per-installation HKDF salt generated at setup for stronger key derivation isolation. **Fail-hard mode:** if encryption is enabled but key is missing or broken, the app refuses to start — no silent fallback to unencrypted backups. |\n| API Authentication | Session token via `crypto.randomBytes(32)` per launch. Validated with `hmac.compare_digest` (timing-safe). Rate limiting on sensitive endpoints (slowapi). |\n| Path Safety | Restore endpoint validates all paths against traversal attacks before any file operation. |\n| Electron Sandbox | Chromium sandbox enabled. CSP enforced in both dev and production builds. |\n| Credential Storage | Secrets in `.env.local` with input sanitization on writes. Excluded from version control. |\n| Database Integrity | SQLite with `PRAGMA synchronous=FULL`. File records committed every 100 inserts during a run — crash data loss limited to at most 100 files. WAL checkpoint after every run prevents unbounded WAL growth. Schema versioned with incremental delta migrations. Manifest DB backed up to SSD with 3-copy rotation after every run. |\n| Key Rotation Safety | Each backed-up file stores a SHA-256 fingerprint of the encryption key used. On restore, a fingerprint mismatch triggers a warning — detects silent restore failures after key rotation. |\n| Process Safety | Before killing a conflicting process on ports 8765 (API) and 8766 (notifications), GhostBackup verifies it's a Python/GhostBackup process. Will not kill unrelated processes. |\n| Data Integrity | xxhash checksum computed at source, verified after every copy to primary and secondary drives. |\n| Failure Protection | Configurable failure threshold (default 5%, min 3 files). If exceeded per library, that library aborts. |\n\n**What's NOT covered:**\n- No external penetration testing or third-party security audit\n- Encryption key stored in Windows Credential Manager by default;\n  `.env.local` fallback used in CI — protect with OS-level permissions\n- API is localhost-only with no TLS (acceptable for local Electron ↔ backend communication)\n\n**Vulnerability Reporting:**\nOpen a GitHub issue or contact the author directly. Do not include exploit details in public issues.\n\n---\n\n## 📜 Retention \u0026 Auditability\n\n\u003e **Disclaimer:** GhostBackup provides tools that *support* regulatory compliance — retention policies, audit trails, encryption at rest, and integrity verification. It is not a compliance certification. Consult a qualified legal or compliance professional for your jurisdiction (e.g. UK Companies Act 2006, GDPR, HMRC record-keeping).\n\n**Retention Settings**\n\n| Policy | Default | Purpose |\n|--------|---------|---------|\n| Daily retention | 365 days | Keep daily snapshots for 1 year |\n| Weekly retention | 2,555 days | Keep weekly snapshots for 7 years |\n| Compliance floor | 7 years | Minimum retention — cannot be reduced below this |\n| Guard days | 7 days | Prevents accidental pruning of the most recent backups |\n\n**Audit Capabilities**\n\n| Capability | Detail |\n|------------|--------|\n| Configuration audit trail | Every config change logged with timestamp, hostname, and previous value |\n| Backup run history | Every run recorded with start/end time, file count, success/failure counts |\n| Per-file records | Each file's hash, size, status, and any error message stored in SQLite |\n| Integrity verification | `/verify` endpoint re-hashes all backup files and returns verified/corrupt/missing counts to the UI |\n\n**Your Responsibilities**\n- **GDPR:** If backing up personal data, conduct your own data protection impact assessment. Consider how right-to-erasure requests interact with long-term retention.\n- **Key management:** Back up your encryption key securely. If lost, all encrypted backups are permanently unrecoverable.\n- **Restore testing:** Periodically verify you can actually restore from backups. GhostBackup provides the tools — you must verify they work for your data.\n- **Offsite copy:** GhostBackup handles local redundancy only. You are responsible for maintaining an offsite copy — see [OFFSITE.md](OFFSITE.md) for recommended approaches.\n\n---\n\n## 🛠 Troubleshooting\n\n**Q: I get \"port already in use\" every time I open the app.**\n\n**A:** Closing with the X button hides the app to tray — it was still running. Always quit via File → Exit or right-click tray icon → Quit GhostBackup. This fully exits and releases port 8765.\n\n---\n\n**Q: The splash screen shows \"backup service stopped unexpectedly (exit code 1)\".**\n\n**A:** Your Python dependencies are out of sync. Run:\n```\npip install -r backend/requirements.txt\n```\nThen relaunch via `start.bat`.\n\n---\n\n**Q: Email alerts aren't arriving.**\n\n**A:** If using Gmail, you need an App Password — not your regular password. Generate one at `https://myaccount.google.com/apppasswords`. In Settings configure: SMTP host `smtp.gmail.com`, port `587`, your Gmail in both From and Recipients. Save, then click Send Test Email.\n\n---\n\n**Q: The backup isn't running at the scheduled time.**\n\n**A:** Check the sidebar status dot — green means running, grey/red means stopped (restart the app). Also verify `schedule.time` and `schedule.timezone` in `config.yaml` match your intended schedule.\n\n---\n\n**Q: The dashboard shows \"No runs yet\" even after a backup completed.**\n\n**A:** The dashboard reads from `backend/ghostbackup.db`. If you moved or deleted this file, history is lost. Do not delete it — it contains your entire backup run history and audit trail.\n\n---\n\n**Q: A file was backed up but I can't find it on the SSD.**\n\n**A:** Encrypted backups are stored with a `.ghostenc` extension and are not human-readable. Restore them through GhostBackup's Restore page — do not try to open them directly.\n\n---\n\n**Q: Can I back up to a network share or NAS?**\n\n**A:** No. GhostBackup currently supports only directly attached drives. Network and cloud backup are not supported.\n\n---\n\n**Q: What happens if power is lost during a backup?**\n\n**A:** The current run is marked as failed. SQLite uses `PRAGMA synchronous=FULL` so the database will not corrupt. On next launch, run a new backup normally — partially written files will be re-copied.\n\n---\n\n**Q: How do I update GhostBackup?**\n\n**A:** Pull the latest changes and reinstall dependencies:\n```bash\ngit pull\npip install -r backend/requirements.txt\nnpm install --legacy-peer-deps\n```\nYour `config.yaml` and `.env.local` will not be overwritten.\n\n---\n\n**Q: Where are the log files for undiagnosed issues?**\n\n**A:** Logs are written to `backend/logs/` and also visible in the app under Logs \u0026 History. For backend errors not shown in the UI, check `backend/logs/ghostbackup.log`. You can filter by INFO, WARN, and ERROR levels in the Logs page.\n\n---\n\n## 🆘 Disaster Recovery\n\nWhen things go wrong, refer to **[RECOVERY.md](RECOVERY.md)** for step-by-step recovery procedures covering:\n\n- Lost encryption key\n- Corrupted manifest database\n- Deleted or corrupted `.env.local`\n- SSD failure mid-backup\n- Application won't start\n- Verification finds corrupted files\n- Prevention checklist\n\nKeep a printed copy alongside your offsite backup drive.\n\n---\n\n## 🤝 Contributing\n\nOriginally built for Red Parrot Accounting, now open-sourced under MIT. Contributions are welcome.\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b fix/your-fix`)\n3. Run tests before submitting:\n   ```bash\n   cd backend \u0026\u0026 python -m pytest tests/ -v\n   npm test\n   ```\n4. Open a pull request with a clear description of what changed and why\n\n**Code style:** Follow existing patterns in the codebase. Run `eslint src` for frontend and `flake8 backend/` for backend before submitting. No new dependencies without discussion.\n\n**Areas where contributions are especially welcome:**\n- Linux/macOS support\n- Network drive / NAS support\n- Additional test coverage (especially E2E and restore scenarios)\n- Documentation improvements\n\n---\n\n## 💼 Use Cases\n\n- **Accounting firms** — long-term retention supporting UK Companies Act 2006 and HMRC requirements\n- **Legal offices** — encrypted client file backups with full audit trail\n- **Financial services** — scheduled, verifiable backups with failure alerting\n- **Medical practices** — encrypted patient record backups (verify GDPR/NHS DSPT requirements separately)\n- **Any small business** — that needs encrypted, automated, auditable local backups without cloud dependency\n\n---\n\n## 📄 License\n\nMIT License — see [LICENSE](LICENSE) for full text.\n\n---\n\n## 📋 Changelog\n\nFull version history available in **[CHANGELOG.md](CHANGELOG.md)**.\n\n---\n\n*👻 GhostBackup — Silent. Secure. Auditable.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegyan07%2Fghostbackup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fegyan07%2Fghostbackup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegyan07%2Fghostbackup/lists"}