Keep using Photos.app like you always do. Attic quietly backs up your originals and edits to an S3 bucket you control. One-way, append-only.
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update architecture docs for S3 manifest

+16 -9
+16 -9
docs/architecture.md
··· 14 14 15 15 ├─→ S3 upload (original + metadata JSON) 16 16 17 - └─→ manifest.json (local progress tracker) 17 + └─→ manifest.json (on S3, shared across machines) 18 18 ``` 19 19 20 20 Attic never modifies Photos.sqlite. The database is opened read-only. ··· 106 106 107 107 ### 4. Manifest 108 108 109 - The manifest is a JSON file at `~/.attic/manifest.json` mapping UUID to 110 - `{ s3Key, checksum, backedUpAt }`. It's saved periodically during backup (every 111 - 50 assets by default) and always at the end. Writes are atomic: write to `.tmp`, 112 - then rename. 109 + The manifest is stored on S3 at `manifest.json` in the bucket root, mapping UUID 110 + to `{ s3Key, checksum, backedUpAt }`. S3 is the single source of truth — there 111 + is no local manifest file. This enables cross-machine and cross-app (CLI ↔ menu 112 + bar app) continuity. 113 + 114 + On backup start, the manifest is downloaded from S3. It's saved back to S3 115 + periodically (every 50 assets by default) for crash resilience, and always at 116 + the end of a run. 117 + 118 + **Migration**: existing local manifests at `~/.attic/manifest.json` are 119 + automatically uploaded to S3 on first run via `loadManifestWithMigration()`. 113 120 114 121 The manifest can be reconstructed from S3 via `verify --rebuild-manifest`, which 115 122 reads every `metadata/assets/*.json` file and validates UUID format, S3 key ··· 132 139 specifies the S3 endpoint, region, bucket, path-style preference, and Keychain 133 140 service names. It's created by `attic init` or manually. 134 141 135 - `scan` and `status` work without config (they only read Photos.sqlite). `backup` 136 - and `verify` require config and fail fast with a clear message if it's missing 137 - or invalid. 142 + `scan` works without config (it only reads Photos.sqlite). All other commands 143 + (`status`, `backup`, `verify`, `refresh-metadata`) require config and S3 144 + credentials since the manifest is stored on S3. 138 145 139 146 ## Credentials 140 147 ··· 151 158 | ---------------- | --------------------------------------------- | ------------------------------------------ | 152 159 | `S3Provider` | AWS SDK client for any S3-compatible endpoint | In-memory `Map<string, Uint8Array>` | 153 160 | `Exporter` | Ladder subprocess | Returns pre-configured assets from a `Map` | 154 - | `ManifestStore` | File-based JSON with atomic writes | Same implementation, pointed at a temp dir | 161 + | `ManifestStore` | S3-backed JSON (`manifest.json` in bucket) | Same S3 mock used for uploads | 155 162 | `PhotosDbReader` | SQLite reader for Photos.sqlite | In-memory SQLite with test fixtures | 156 163 157 164 Tests never hit external services, credentials, or the real Photos library.