diff --git a/README.md b/README.md index 7da1fc1..34b1f5f 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,110 @@ # TapeHoard -A robust, index-driven Tape Backup Manager designed for single-tape drive users and scalable to tape libraries. +> Physical media archival for people who don't trust the cloud alone. -For full architectural details, see [PLAN.md](PLAN.md). +TapeHoard is a self-hosted backup manager designed for offline-capable storage: LTO tapes, USB hard drives, and S3-compatible cloud. It indexes your source filesystems, tracks what has been archived to which medium, and gives you a searchable catalog—even when the media itself is sitting in a vault across town. -## Docker Deployment +![Dashboard](docs/screenshots/dashboard.png) -TapeHoard is designed to run as a Docker container with native hardware access. +## Features -### Permissions (PUID/PGID) -The container supports `PUID` and `PGID` environment variables to ensure files written to volumes match your host user's identity. +- **Index-First Design** — All browsing, searching, and discrepancy checks run against the database. The live filesystem is only touched during scans. +- **LTO Tape Native** — Barcode discovery via MAM, hardware compression control, and direct SCSI streaming. No intermediary disk staging required for sequential writes. +- **Multi-Media Fleet** — Manage tapes, HDDs, and cloud buckets in one inventory. Priority-based auto-archival fills media in your preferred order. +- **Redundancy-Aware** *(planned)* — Target N copies across active media. TapeHoard will distribute files until every byte has the redundancy you specify. +- **Restore Queue** — Stage files for recovery from any combination of media. Get a minimum-media manifest so you only mount what you need. +- **Discrepancy Detection** — Find files that have gone missing, changed without a new backup, or been excluded by policy. +- **Encrypted at Rest** — Per-media encryption secrets managed through a built-in keystore. Compatible with LTO hardware encryption (`stenc`) and client-side cloud encryption. -**Critical:** To ensure fast startup times, TapeHoard **does not** perform a recursive `chown` on your data. You must ensure your host directories are owned by the same PUID/PGID you provide to the container: +## Screenshots -```bash -# Example: If PUID=1000 and PGID=1000 -sudo chown -R 1000:1000 ./db ./staging ./source_data ./restores -``` +| Dashboard | Media Inventory | +|---|---| +| ![Dashboard](docs/screenshots/dashboard.png) | ![Inventory](docs/screenshots/inventory.png) | -### Example `docker-compose.yml` +| Live Filesystem | System Settings | +|---|---| +| ![Filesystem](docs/screenshots/filesystem.png) | ![Settings](docs/screenshots/settings.png) | + +## Quick Start (Docker Compose) + +The recommended deployment is a single container with persistent volumes for the database, staging area, and source/restore mounts. ```yaml services: tapehoard: - image: tapehoard:latest + image: ghcr.io/tapehoard/tapehoard:latest container_name: tapehoard - environment: - - PUID=1000 - - PGID=1000 - - TZ=UTC - volumes: - - ./db:/database - - ./staging:/staging - - /mnt/my_data:/source_data:ro - - /mnt/restores:/restores - # LTO Tape Drive Passthrough - - /dev/nst0:/dev/nst0 - - /dev/sgX:/dev/sgX + cap_add: + - SYS_RAWIO devices: - /dev/nst0:/dev/nst0 - - /dev/sgX:/dev/sgX + environment: + - TZ=UTC + - DATABASE_URL=sqlite:////database/tapehoard.db + - STAGING_DIRECTORY=/staging ports: - - "8000:8000" - restart: unless-stopped + - '30265:8000' + volumes: + - ./database:/database + - ./staging:/staging + - /mnt/archive:/source_data:ro + - /mnt/restores:/restores ``` -## Project Structure +### Requirements -* `backend/`: Python/FastAPI application handling the heavy lifting (hashing, streaming, db indexing). -* `frontend/`: Svelte 5 application providing the Web UI. -* `docker/`: Files required for building the multi-stage Docker container. -* `docs/`: Additional documentation. +- **Linux host** (LTO tape support requires `mt`, `sg_read_attr`, and optionally `stenc` on the host or in the container) +- **SYS_RAWIO capability** — Required for direct SCSI access to tape drives +- **Device passthrough** — Map `/dev/nst0` (or your tape device) into the container +- **Persistent volumes** — Database and staging must survive container restarts -## Quickstart +### Hardware-Specific Notes -(Coming soon) +**LTO Tape:** +- The container must run as root or have access to the SCSI device node +- Set `TAPEHOARD_TEST_MODE=true` to enable a mock LTO provider for development without hardware + +**USB / SATA HDDs:** +- Mount the drive filesystem into the container at `/source_data` or a restore destination +- The HDD provider reads a `.tapehoard_id` file on the drive root to identify media + +### First Run + +1. Start the container: `docker compose up -d` +2. Open `http://host:30265` +3. Go to **Settings → Drives** and configure your tape drive path and source roots +4. Trigger an initial scan from the dashboard +5. Register media under **Physical Inventory** +6. Run your first backup + +## Development + +TapeHoard uses [`just`](https://github.com/casey/just) as its command runner. Install it (`brew install just` or `cargo install just`), then run `just` to see all available commands. + +### Common Tasks + +```bash +just dev # Start backend + frontend with hot reload +just backend # Start only the backend +just frontend # Start only the frontend +just test # Run linting, backend tests, and E2E tests +just lint # Run Ruff, ty, and Svelte checks +just format # Auto-format Python code +just generate-client # Regenerate TypeScript SDK from OpenAPI spec +``` + +### Database Migrations + +```bash +just db-upgrade # Apply pending migrations +just db-migrate "add user table" # Autogenerate a new migration +``` + +## Why TapeHoard? + +Most backup tools treat tape as a liability. TapeHoard treats it as a first-class citizen: + +- **Air-gappable** — Pull the tape, store it offline. Your index stays searchable even when the media is in a vault. +- **Auditability** — Every file's SHA-256, every version's offset on every medium, tracked in SQLite. +- **No vendor lock-in** — Standard tar archives on tape, standard files on disk. If TapeHoard disappears, your data doesn't. diff --git a/docs/screenshots/dashboard.png b/docs/screenshots/dashboard.png new file mode 100644 index 0000000..e2d0ef4 Binary files /dev/null and b/docs/screenshots/dashboard.png differ diff --git a/docs/screenshots/filesystem.png b/docs/screenshots/filesystem.png new file mode 100644 index 0000000..1265668 Binary files /dev/null and b/docs/screenshots/filesystem.png differ diff --git a/docs/screenshots/inventory.png b/docs/screenshots/inventory.png new file mode 100644 index 0000000..0f0d372 Binary files /dev/null and b/docs/screenshots/inventory.png differ diff --git a/docs/screenshots/settings.png b/docs/screenshots/settings.png new file mode 100644 index 0000000..86316b7 Binary files /dev/null and b/docs/screenshots/settings.png differ