101 lines
4.3 KiB
Markdown
101 lines
4.3 KiB
Markdown
# ROADMAP — sync_relay_project (canonical phase tracker)
|
||
|
||
This is the durable source of truth for phases. Chat is ephemeral;
|
||
this file + `HANDOFF.md` (root) + `PROTOCOL.md` / `ARCHITECTURE.md`
|
||
carry state across sessions. Update this file when a phase changes
|
||
state. Proto bumps still require PROTOCOL.md same-commit.
|
||
|
||
Model: direct-serve (host opens ports, clients open nothing). The
|
||
brief's old WSS host-upload tunnel is obsolete unless a VPS tier
|
||
needs remote-host upload. Server = Relic, client WS =
|
||
web_socket_channel. Protocol still v4.
|
||
|
||
## Status legend
|
||
|
||
- DONE: exit criteria met, tests green at the time.
|
||
- PARTIAL: shipped + tested, exits still open.
|
||
- TODO: not started or explicitly deferred.
|
||
|
||
## Phase 0 — Scaffold (DONE)
|
||
|
||
Monorepo, path deps, CI (`dart analyze` + `dart test` on core/server),
|
||
logging/config/errors, Flutter-free enforcement tests, relay binary
|
||
binds/logs/exits, stub ARCHITECTURE.md.
|
||
|
||
## Phase 1 — mpv HTTP contract (DONE)
|
||
|
||
Relic `resolveMediaRequest` + `mountMediaRoute`, full Range table
|
||
(200 / 206×3 shapes / 416 / 401 / 403 / 410 / 503), byte-exact tests,
|
||
real mpv traces in `mpv-http-contract.md`, `tool/range_logger.dart`
|
||
+ `tool/shaper.dart` (KB/s cap, latency, --kill-after).
|
||
|
||
## Phase 2 — Sessions + media endpoint (DONE)
|
||
|
||
Secret → 128-bit token, 401/403/410 gates, kick kills WS+media,
|
||
byte counters, `tool/fake_viewer.dart` ALL PASS live. Proto v2→v3
|
||
for `kicked`/`kick`. Media: local-file relay SHIPPED
|
||
(`FileMediaSource` + token-gated Range route); links path SHIPPED
|
||
(server distributes shared URL, viewers stream direct);
|
||
`HttpSource` (server-side URL fetch) DEFERRED to Phase 8; WSS
|
||
upload tunnel NOT BUILT (spec reserved in ARCHITECTURE.md).
|
||
|
||
## Phase 3 — Sync engine + readiness (DONE)
|
||
|
||
`RoomEngine` (injectable clock): server-owned clock, reports never
|
||
move it, stale-eventId guard, free seeks, PLAYING/HELD gate, quorum
|
||
(in-set≥2 unless ≤1 fresh), swap reset, force with actor feed.
|
||
22+ engine tests, `tool/e2e_check.dart` 15/15 sim. Syncplay audit
|
||
done (conscious deviations documented in HANDOFF §2). Proto v4.
|
||
Follow-ups landed: NaN guards, name/chat caps, stale vs leave feed,
|
||
1 Hz feed flush, silent-drop (15 s stale / 30 s drop + close).
|
||
|
||
## Phase 4 — Desktop app (PARTIAL)
|
||
|
||
Shipped: SyncClient framing, RoomDiff (eventId diff, 0.95× latch),
|
||
media_kit wiring, Space=ready, avatars, toasts+sheet, health display,
|
||
reconnect loop. Counts at last green: core 42, server 40, desktop 17.
|
||
Late 09-12 session: internet test PASSED (WAN, port 6969, 2-client);
|
||
server logging wired into app (`initLogging` in `main.dart` + hello
|
||
join/reject logs in `room_hub.dart`); Cancel aborts a pending
|
||
connect (`SyncClient.disconnect` completes the welcome future);
|
||
first-join failure shows the dialog and stops (auto-reconnect only
|
||
after an established session drops).
|
||
Open exits (manual, user-driven): remove bisect flags in
|
||
`apps/desktop/lib/app.dart`; 2-client LAN soak; 1.4 GB real-file test
|
||
(user resupplies URL, never paste api_key into files);
|
||
cache-exhaustion long outage.
|
||
|
||
## Phase 5 — Resilience (PARTIAL)
|
||
|
||
Shipped: isClosed sweep, onError forget, stop() closes sockets,
|
||
silence-timeout + reconnect loop. Never run: shaper chaos suite
|
||
(host drop 5 s / 30 s, viewer stall, 20-seek storm), OOM / stuck-room
|
||
/ drift-recovery assertions, CI wiring.
|
||
|
||
## Phase 6 — Identity & social (PARTIAL)
|
||
|
||
Shipped: names (32 cap), avatars (64 KiB, picker + crop), kick nudge
|
||
+ reason, feed attribution. Open: real chat pane/history (schema
|
||
only), sounds swap-in (wiring + NoopSfxService ready; pick
|
||
flutter_soloud or equivalent, Kenney/ObsydianX/akx sources in
|
||
HANDOFF §7).
|
||
|
||
## Phase 7 — Deployment & updates (TODO, deferred)
|
||
|
||
Thin `bin/server.dart` compiles; systemd unit exists. Missing:
|
||
Windows zip, Linux tar/AppDir, TLS/Caddy doc, update manifest +
|
||
verifier. Needs explicit user go + code-signing decision.
|
||
|
||
## Phase 8 — Optional quality (TODO, deferred)
|
||
|
||
Playlist (`queue-add`/`queue-skip`, shape reserved in PROTOCOL.md),
|
||
sidecar subtitles, local-file fallback (viewer plays matching
|
||
size+duration file locally, still synced — saves host uplink),
|
||
`HttpSource` (host pastes a direct-stream URL, server fetches +
|
||
re-serves — makes Jellyfin usable through the whitelist today, no
|
||
native integration). No code until approved.
|
||
|
||
## Deferred backlog (needs explicit approval)
|
||
|
||
Jellyfin native, P2P/WebRTC, multi-session, transcode, Android.
|