Session-gated MinIO save sync with AppImage GUI, CLI edit/session flow, and Gitea release helper. Co-authored-by: Cursor <[email protected]>
2.2 KiB
2.2 KiB
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
- Idle — no lease;
live/is SSOT. - Start — device acquires lease in
meta.json, downloadslive/into native save path(s), stores parent hash locally. - Play — only native files change; SSOT untouched.
- End — snapshot native files →
history/<device>/<ts>/→ atomically updatelive/+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_atwip/<game-id>/— optional staging copies during push
See protocol.md for exact wire format.