Files
DawnsorrowandCursor 0d6b0b2f80 Initial SyncGames tree: agent, Android, deploy, docs.
Session-gated MinIO save sync with AppImage GUI, CLI edit/session flow, and Gitea release helper.

Co-authored-by: Cursor <[email protected]>
2026-07-14 22:06:36 -05:00

53 lines
2.2 KiB
Markdown

# 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/<device>/<ts>/` → 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/<game-id>.json` — active lease parent hash, started_at
- `wip/<game-id>/` — optional staging copies during push
See [protocol.md](protocol.md) for exact wire format.