···6677```bash
88deno task check # Type check
99-deno task test # Run tests (42 tests)
99+deno task test # Run tests (44 tests)
1010deno task lint # Lint
1111deno task fmt # Format
1212deno task fmt:check # Check formatting
···2323 src/export/ # Exporter interface + ladder subprocess integration
2424```
25252626-## Architecture
2626+## Reference Docs
27272828-- **Interface-driven**: `S3Provider`, `ManifestStore`, `Exporter` — all injected for testability
2929-- **Mocks for testing**: `createMockS3Provider()`, `createMockExporter()` — tests never hit real services
3030-- **Runtime validation at trust boundaries**: Photos.sqlite schema, manifest JSON, ladder subprocess output, S3 metadata during rebuild
3131-- **Atomic manifest writes**: temp file + rename pattern in `ManifestStore.save()`
3232-- **Credentials**: macOS Keychain via `security find-generic-password` — never in env vars or config files
3333-- **Streaming uploads**: `putObject` accepts `ReadableStream<Uint8Array>` to avoid loading large files into memory
3434-3535-## S3 Bucket Structure
3636-3737-```
3838-originals/{year}/{month}/{uuid}.{ext} # Original photo/video files
3939-metadata/assets/{uuid}.json # Per-asset metadata JSON
4040-```
2828+- [Architecture](docs/architecture.md) — pipeline, reader, ladder protocol, manifest, interfaces, design boundaries
2929+- [Asset Metadata](docs/metadata.md) — per-asset JSON schema uploaded to S3
41304231## Conventions
4332
+6-64
README.md
···9292| `--rebuild-manifest` | Reconstruct the local manifest from S3 metadata files |
9393| `--bucket NAME` | S3 bucket name (default: `photo-cloud-storage`) |
94949595-## S3 Bucket Structure
9696-9797-```
9898-photo-cloud-storage/
9999- originals/
100100- 2024/
101101- 01/
102102- <uuid>.heic
103103- <uuid>.mov
104104- 02/
105105- ...
106106- metadata/
107107- assets/
108108- <uuid>.json
109109-```
110110-111111-- **originals/** -- Organized by year and month (UTC) from the asset's creation date. Each file is named by its Photos library UUID with the appropriate extension.
112112-- **metadata/** -- One JSON file per asset containing original filename, dimensions, GPS coordinates, file size, UTI type, favorite status, S3 key, SHA-256 checksum, and backup timestamp.
113113-114114-## Local State
115115-116116-Attic stores its state in `~/.attic/`:
117117-118118-- `manifest.json` -- Tracks which assets have been backed up (UUID, S3 key, checksum, timestamp). The manifest is saved periodically during backup and can be rebuilt from S3 metadata via `verify --rebuild-manifest`.
119119-- `staging/` -- Temporary directory where ladder exports files before upload. Files are cleaned up after each successful upload.
120120-12195## Testing
1229612397```bash
···126100127101Tests use dependency injection with mock implementations for the S3 client and exporter, so no external services or credentials are needed.
128102129129-## Future Plans
103103+## Documentation
130104131131-- **Scheduled backups via launchd** -- A LaunchAgent plist to run backups daily on a dedicated Mac. Includes an `--auto` flag (no prompts, file-based logging to `~/.attic/logs/`), macOS notifications on completion/failure, and `deno task install-schedule` / `deno task uninstall-schedule` commands.
105105+- [Architecture](docs/architecture.md) -- How attic works: the backup pipeline, Photos.sqlite reader, ladder protocol, manifest lifecycle, and design boundaries
106106+- [Asset Metadata](docs/metadata.md) -- Schema reference for the per-asset JSON uploaded to S3
132107133133-## Project Structure
108108+## Future Plans
134109135135-```
136136-attic/
137137- deno.json # Workspace config and task definitions
138138- shared/ # Shared types and utilities
139139- types.ts # PhotoAsset, AssetKind, CloudLocalState
140140- s3-paths.ts # S3 key generation (originalKey, metadataKey)
141141- s3-paths.test.ts
142142- cli/ # CLI application
143143- mod.ts # Entry point and argument parsing
144144- src/
145145- format.ts # Byte formatting utility
146146- photos-db/
147147- reader.ts # SQLite reader for Photos.sqlite
148148- reader.test.ts
149149- storage/
150150- s3-client.ts # Scaleway S3 client (AWS SDK)
151151- s3-client.mock.ts
152152- s3-client.test.ts
153153- export/
154154- exporter.ts # Ladder binary wrapper
155155- exporter.mock.ts
156156- exporter.test.ts
157157- manifest/
158158- manifest.ts # Local backup manifest (JSON)
159159- manifest.test.ts
160160- commands/
161161- scan.ts # Library scan report
162162- status.ts # Backup status report
163163- backup.ts # Backup pipeline
164164- backup.test.ts
165165- verify.ts # Integrity verification
166166- verify.test.ts
167167- rebuild.ts # Manifest reconstruction from S3
168168- rebuild.test.ts
169169-```
110110+- **Scheduled backups via launchd** -- A LaunchAgent plist to run backups daily on a dedicated Mac
111111+- **Rendered edit backup** -- Detect and upload edited versions alongside originals (see `docs/plans/`)