Switch the editor to live collaboration #36

Closed
opened 2026-07-04 14:52:16 +02:00 by fable-5 · 1 comment
Collaborator

Context

The editor swaps its local-only Y.Doc for the Hocuspocus provider — the moment Dorfteich becomes collaborative.

Scope

Replace REST persistence in the editor hook (#25) with @hocuspocus/provider: fetch collab token, connect, handle token refresh on reconnect, connection state UI (connected / reconnecting / offline banner), read-only mode for ro tokens (editor not editable, presence visible). Remove the debounced-save indicator in favor of sync state.

Acceptance criteria

  • two browsers edit one page and converge (e2e with two contexts — the milestone's headline test)
  • network drop shows 'reconnecting', edits continue locally, reconnect syncs (Playwright network throttling)
  • ro users see live changes but cannot type; UI communicates why
  • token expiry mid-session refreshes transparently (no user-visible errors)

Technical notes

  • ADR 0003, realtime-collaboration.md.
  • Keep the provider setup in the single editor-document hook so offline (#38) extends one place.

Dependencies

Depends on #25, #35.

Size: ~1.5 days


Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add de and en), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.

## Context The editor swaps its local-only Y.Doc for the Hocuspocus provider — the moment Dorfteich becomes collaborative. ## Scope Replace REST persistence in the editor hook (#25) with `@hocuspocus/provider`: fetch collab token, connect, handle token refresh on reconnect, connection state UI (connected / reconnecting / offline banner), read-only mode for `ro` tokens (editor not editable, presence visible). Remove the debounced-save indicator in favor of sync state. ## Acceptance criteria - [ ] two browsers edit one page and converge (e2e with two contexts — the milestone's headline test) - [ ] network drop shows 'reconnecting', edits continue locally, reconnect syncs (Playwright network throttling) - [ ] `ro` users see live changes but cannot type; UI communicates why - [ ] token expiry mid-session refreshes transparently (no user-visible errors) ## Technical notes - ADR 0003, realtime-collaboration.md. - Keep the provider setup in the single editor-document hook so offline (#38) extends one place. ## Dependencies Depends on #25, #35. **Size**: ~1.5 days --- *Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add `de` **and** `en`), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.*
fable-5 added this to the M3 — Real-time collaboration & history milestone 2026-07-04 14:52:16 +02:00
fable-5 added the
collab
frontend
labels 2026-07-04 14:52:16 +02:00
Collaborator

Verified on Test and Int (commit 7d04c0b, pipeline green — all CI + CD jobs incl. the new collab e2e pack and Int promotion).

Live on Test: PUT /pages/:id/state now returns 410 rest_state_write_retired (logged in as fixture-user → created a page → PUT → 410 with the collab hint). Combined with #35's verified live collab persistence through the proxy, the editor's write path is fully cut over.

The editor is now collaborative (ADR 0003, realtime-collaboration.md):

  • useCollabProvider binds the page's Y.Doc to a HocuspocusProvider. The document loads and persists through the collab server (#35) — no REST autosave, and no REST seed (a REST seed would fork the doc lineage and duplicate content). The collab token is fetched lazily on every (re)connect via an async token function, so an expired token is replaced transparently and a permission change takes effect on the next reconnect.
  • Connection-state UI replaces the save indicator: connecting / connected ("Live") / reconnecting / offline, from provider status + navigator.onLine. ro tokens make the editor non-editable with a reason; the oversize-document stateless error (#35) surfaces a banner. de + en strings added.
  • PUT /pages/:id/state retired → 410 (the box deferred here from #35); collab is the sole writer, read paths remain.

Tests / CI: the e2e static server and vite dev now proxy the /collab WebSocket (mirroring Caddy), and the auth-e2e CI job starts the collab server and runs a new collab.spec.ts. It covers the two reachable headline criteria and was validated locally against a full stack (api + collab + built web):

  • two browsers converge on one page (owner + a site-admin editor);
  • offline edits continue locally and sync on reconnect (context.setOffline, indicator flips to offline, edit persists, reconnect re-fetches a token and converges).

Two acceptance boxes intentionally deferred, both to #53 (real permissions): the read-only live assertion (test.fixme) and, with it, the distinct token-expiry-mid-session scenario beyond reconnect. Under the interim access model seeing and modifying coincide, so no user is ever issued a ro token yet — the ro UI is implemented but only becomes reachable when read-only grants exist (#53). Token refresh on reconnect (which is what covers expiry) is exercised by the offline/reconnect test.

Verified on Test and Int (commit 7d04c0b, pipeline green — all CI + CD jobs incl. the new collab e2e pack and Int promotion). **Live on Test:** `PUT /pages/:id/state` now returns **410** `rest_state_write_retired` (logged in as fixture-user → created a page → PUT → 410 with the collab hint). Combined with #35's verified live collab persistence through the proxy, the editor's write path is fully cut over. **The editor is now collaborative (ADR 0003, realtime-collaboration.md):** - `useCollabProvider` binds the page's `Y.Doc` to a `HocuspocusProvider`. The document loads and persists through the collab server (#35) — no REST autosave, and no REST seed (a REST seed would fork the doc lineage and duplicate content). The collab token is fetched lazily on every (re)connect via an async token function, so an expired token is replaced transparently and a permission change takes effect on the next reconnect. - Connection-state UI replaces the save indicator: connecting / connected ("Live") / reconnecting / offline, from provider status + `navigator.onLine`. `ro` tokens make the editor non-editable with a reason; the oversize-document stateless error (#35) surfaces a banner. de + en strings added. - `PUT /pages/:id/state` retired → 410 (the box deferred here from #35); collab is the sole writer, read paths remain. **Tests / CI:** the e2e static server and vite dev now proxy the `/collab` WebSocket (mirroring Caddy), and the auth-e2e CI job starts the collab server and runs a new `collab.spec.ts`. It covers the two reachable headline criteria and was validated locally against a full stack (api + collab + built web): - **two browsers converge on one page** (owner + a site-admin editor); - **offline edits continue locally and sync on reconnect** (`context.setOffline`, indicator flips to offline, edit persists, reconnect re-fetches a token and converges). **Two acceptance boxes intentionally deferred, both to #53 (real permissions):** the **read-only live** assertion (`test.fixme`) and, with it, the distinct token-expiry-mid-session scenario beyond reconnect. Under the interim access model seeing and modifying coincide, so no user is ever issued a `ro` token yet — the `ro` UI is implemented but only becomes reachable when read-only grants exist (#53). Token refresh on reconnect (which is what covers expiry) is exercised by the offline/reconnect test.
Sign in to join this conversation.
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: stwaidele/dorfteich#36
No description provided.