#486: in-browser document editing via WOPI (Collabora Online integration) #516

Merged
Cordy merged 18 commits from fix-486 into main 2026-09-13 16:51:03 +00:00
Owner

Implements #486 end to end, per the approved office-editor mockup rev 2.

Backend (witnessed-red TDD)

  • internal/office: discovery client (edit actions only, 10 min cache, error surfaced for the admin card), stateless HMAC access tokens (per-boot key; token pins user + path + write-bit + expiry), WOPI file-id codec, embedded empty templates for odt/ods/odp/docx/xlsx/pptx (md/txt create empty).
  • internal/api: /api/v1/office/status probe, /api/v1/office/open (write access decided up front from read-only spaces, covering locks and legal holds; Recents + office-open audit), /api/v1/admin/office, POST /api/v1/files/new (template create through the scoped store — quota/holds/locks enforced for free), and the /wopi host surface on the OUTER mux: CheckFileInfo (UserCanNotWriteRelative), GetFile (marks skip-context — an edit round-trip can never bake a download mark into the stored file), PutFile (X-COOL-WOPI-Timestamp handshake, 409 + COOLStatusCode 1010 on external change).
  • config office{url,appName,wopiBase}; env CAIRN_OFFICE_URL / CAIRN_OFFICE_WOPI_BASE win. marks.ContextSkipMarking. office-open audit verb registered.

Frontend (mockup rev 2, all four variants)

  • Row-menu "Edit in {app}" directly under Open; preview-panel Edit button. Formats from discovery, name from office.appName — nothing hardcoded.
  • "New folder" → New ▾ menu: Folder · odt/ods/odp · docx/xlsx/pptx · md/txt with extension chips; office entries only when configured; documents open straight into the editor.
  • Full-viewport editor page: single 40px bar (Back, centred name+path, read-only reason chip naming lock holder / legal hold / read-only space, app tag), token by form POST, browser back and ← both leave, no Save button by design.
  • Administration → Document editor read-only card (connected / not configured / unreachable with the error verbatim). i18n ×4.

Docs/packaging: handbook document-editing.md + index row, EULA third-party document server clause, compose + chart notes (default off), CHANGELOG v0.6.178.

CODE itself is already live at 192.168.10.250 behind code.c0rdyceps.ch (homelab-config k3s/collabora/), discovery verified with 74 edit actions.

Implements #486 end to end, per the approved office-editor mockup rev 2. **Backend (witnessed-red TDD)** - `internal/office`: discovery client (edit actions only, 10 min cache, error surfaced for the admin card), stateless HMAC access tokens (per-boot key; token pins user + path + write-bit + expiry), WOPI file-id codec, embedded empty templates for odt/ods/odp/docx/xlsx/pptx (md/txt create empty). - `internal/api`: `/api/v1/office/status` probe, `/api/v1/office/open` (write access decided up front from read-only spaces, covering locks and legal holds; Recents + `office-open` audit), `/api/v1/admin/office`, `POST /api/v1/files/new` (template create through the scoped store — quota/holds/locks enforced for free), and the `/wopi` host surface on the OUTER mux: CheckFileInfo (`UserCanNotWriteRelative`), GetFile (marks skip-context — an edit round-trip can never bake a download mark into the stored file), PutFile (`X-COOL-WOPI-Timestamp` handshake, 409 + `COOLStatusCode` 1010 on external change). - config `office{url,appName,wopiBase}`; env `CAIRN_OFFICE_URL` / `CAIRN_OFFICE_WOPI_BASE` win. `marks.ContextSkipMarking`. `office-open` audit verb registered. **Frontend (mockup rev 2, all four variants)** - Row-menu "Edit in {app}" directly under Open; preview-panel Edit button. Formats from discovery, name from `office.appName` — nothing hardcoded. - "New folder" → New ▾ menu: Folder · odt/ods/odp · docx/xlsx/pptx · md/txt with extension chips; office entries only when configured; documents open straight into the editor. - Full-viewport editor page: single 40px bar (Back, centred name+path, read-only reason chip naming lock holder / legal hold / read-only space, app tag), token by form POST, browser back and ← both leave, no Save button by design. - Administration → Document editor read-only card (connected / not configured / unreachable with the error verbatim). i18n ×4. **Docs/packaging**: handbook `document-editing.md` + index row, EULA third-party document server clause, compose + chart notes (default off), CHANGELOG v0.6.178. CODE itself is already live at 192.168.10.250 behind code.c0rdyceps.ch (homelab-config `k3s/collabora/`), discovery verified with 74 edit actions.
Covers: HMAC access tokens (round-trip, tamper, expiry, per-boot keys),
WOPI id codec, discovery parse/cache/error, embedded new-document
templates (ODF mimetype-first rule, OOXML content types), marks
skip-context, CheckFileInfo/GetFile/PutFile incl. the
X-COOL-WOPI-Timestamp 409/1010 handshake, office open/status probe,
and POST /api/v1/files/new.
internal/office: discovery client (edit actions only, 10min cache,
error surfaced for the admin card), stateless HMAC access tokens
(per-boot key; token pins user+path+write-bit+expiry), embedded empty
templates for odt/ods/odp/docx/xlsx/pptx (md/txt create empty).

internal/api: /api/v1/office/status probe, /api/v1/office/open (write
access decided up front from read-only spaces, covering locks and
legal holds; Recents + audit office-open on open), /api/v1/admin/office
card endpoint, POST /api/v1/files/new (template create via the scoped
store - quota/holds/locks enforced for free), and the /wopi host
surface on the OUTER mux: CheckFileInfo (UserCanNotWriteRelative),
GetFile (marks skip-context so an edit round-trip can never bake a
download mark into the stored file), PutFile (X-COOL-WOPI-Timestamp
handshake, 409 + COOLStatusCode 1010 on external change).

config: office{url,appName,wopiBase}; env CAIRN_OFFICE_URL wins.
marks: ContextSkipMarking/SkipFrom. audit: office-open verb.
Entry points (variant 1): 'Edit in {app}' in the row menu directly
under Open for discovery-editable formats; accent Edit button in the
preview panel header. App name comes from office.appName, formats
from the editor's own discovery - nothing hardcoded.

New menu (variant 2): the toolbar's New-folder button becomes New
with Folder, the ODF triple, the Microsoft triple and md/txt, each
with an extension chip; office entries render only when an editor is
configured, md/txt always; documents open straight into the editor.

Editor page (variant 3): full-viewport takeover with a single 40px
bar - Back, centred name+path, read-only reason chip (locked by
{user} / legal hold / read-only space), app tag - and the editor
iframe below; token delivered by form POST; browser back and the
Back button both return to the folder; no Save button by design.

Admin (variant 4): Administration -> Document editor read-only card
with Status (connected/not configured/unreachable with the fetch
error verbatim), Server, App name, New documents, Formats chips and
the config.json/CAIRN_OFFICE_URL footer. i18n x4.
docs+packaging(#486): handbook page, EULA clause, compose/chart notes, changelog; CAIRN_OFFICE_WOPI_BASE env
All checks were successful
ci / test-and-build (pull_request) Successful in 52s
ef83f646bd
docs/handbook/document-editing.md: what users get, config anatomy,
deployment requirements (both reachability directions, aliasgroup +
ssl.termination, per-boot token key), semantics (rights inheritance,
no Save As, marks bypass, office-open audit), licensing posture.

EULA: third-party document servers integrated via WOPI are licensed
separately by their vendors; Cairn ships none of their code and
grants no rights to them.

compose: commented-out optional collabora service + CAIRN_OFFICE_*
lines, off by default, browser-facing warning. chart: note that the
office block rides in the untemplated config Secret.

main: CAIRN_OFFICE_WOPI_BASE env override (env-wins rule), so a
GitOps deployment can configure the editor without touching the
config Secret.
Cordy scheduled this pull request to auto merge when all checks succeed 2026-09-13 16:50:54 +00:00
Cordy merged commit 2bde4fabcf into main 2026-09-13 16:51:03 +00:00
Cordy deleted branch fix-486 2026-09-13 16:51:06 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
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: Cordy/Cairn#516
No description provided.