# Architecture ## Goal Sync gameplay saves across Linux desktop, Linux laptop, and Android phone/tablet without Steam Cloud (missing Seamless Coop) and without continuous bidirectional sync of live save files. ## Components ``` ┌─────────────┐ ┌─────────────┐ ┌──────────────────┐ │ Linux PC │ │ Laptop │ │ Android app │ │ syncgames │ │ syncgames │ │ Compose UI │ │ Python CLI │ │ Python CLI │ │ S3 SDK │ └──────┬──────┘ └──────┬──────┘ └────────┬─────────┘ │ HTTPS WAN │ │ └────────────────┼──────────────────┘ ▼ Cloudflare DNS + Tunnel (+ optional Access) ▼ NGINX (NAS) ▼ MinIO bucket: syncgames ``` ## Data flow 1. **Idle** — no lease; `live/` is SSOT. 2. **Start** — device acquires lease in `meta.json`, downloads `live/` into native save path(s), stores parent hash locally. 3. **Play** — only native files change; SSOT untouched. 4. **End** — snapshot native files → `history///` → atomically update `live/` + `meta.json` → release lease → prune old history for that device. ## Trust boundaries - MinIO credentials authenticate API calls. - Optional Cloudflare Access gates the hostname before MinIO sees traffic. - Lease + hash gate prevent two devices from inventing conflicting “live” states without an explicit restore. ## What is not synced - Entire Proton prefixes - Game installs / shaders - Continuous file watchers writing straight into SSOT ## Local state (per device) Under `~/.local/state/syncgames/` (Linux) or app private storage (Android): - `sessions/.json` — active lease parent hash, started_at - `wip//` — optional staging copies during push See [protocol.md](protocol.md) for exact wire format.