Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

10 KiB

Scratchpad — Collaborative Editor Document Integration

Key Discoveries

Current architecture

  • Documents are edited in a drawer (Documents.tsx), not a dedicated page
  • Drawer uses TextEditor (BlockNote) for editing, RichTextViewer for viewing
  • CollaborativeEditor uses Tiptap (not BlockNote) — different editor, different JSON schema
  • DocumentEditor (also Tiptap) exists but is NOT actively used anywhere in the app
  • Content stored in document_block_content.block_data as JSONB

Content format mismatch (CRITICAL)

  • BlockNote JSON: [{ type: "paragraph", props: {...}, content: [{ type: "text", text: "...", styles: {} }] }]
  • Tiptap/ProseMirror JSON: { type: "doc", content: [{ type: "paragraph", content: [{ type: "text", text: "..." }] }] }
  • Existing documents created via TextEditor are in BlockNote format
  • CollaborativeEditor reads/writes ProseMirror format
  • Need a conversion layer or format detection on load

Hocuspocus infrastructure

  • Server: hocuspocus/server.js on port 1234
  • Room naming: document:<tenantId>:<documentId>
  • Tenant validation in tenantValidation.js
  • createYjsProvider in packages/ui/src/editor/yjs-config.ts
  • Env vars: HOCUSPOCUS_URL (default http://localhost), HOCUSPOCUS_PORT (default 1234)

Snapshot/persistence

  • syncCollabSnapshot() in collaborativeEditingActions.ts already works
  • Converts Y.js XML fragment → ProseMirror JSON → document_block_content.block_data
  • Hocuspocus Database extension also persists to its own tables

Key file paths

  • packages/documents/src/components/Documents.tsx — main documents page with drawer
  • packages/documents/src/components/CollaborativeEditor.tsx — collab editor
  • packages/documents/src/components/DocumentEditor.tsx — unused single-user Tiptap editor
  • packages/documents/src/actions/documentBlockContentActions.ts — CRUD actions
  • packages/documents/src/actions/collaborativeEditingActions.ts — snapshot sync
  • packages/ui/src/editor/TextEditor.tsx — BlockNote editor (used in drawer today)
  • packages/ui/src/editor/yjs-config.ts — Y.js provider factory
  • hocuspocus/server.js — Hocuspocus WebSocket server

Decisions

  1. Keep drawer UX — replace TextEditor inside drawer with CollaborativeEditor
  2. Graceful fallback — detect Hocuspocus availability, fall back to current editor
  3. Keep Save button — auto-sync via Y.js, but keep explicit Save/Snapshot for confidence
  4. Content format: need to handle both BlockNote and ProseMirror JSON in DB

Open Questions

  • How many existing documents are in BlockNote format vs ProseMirror format?
  • Should we convert existing documents eagerly (migration) or lazily (on first open)?

Progress

  • Replaced drawer edit mode for existing in-app documents to render CollaborativeEditor (kept BlockNote editor only for new-document flow for now). Placeholder tenant/user display info used until F02 wiring.
  • Wired current user lookup in Documents.tsx to supply tenant/user identity to CollaborativeEditor for proper Hocuspocus room naming.
  • Added blockContentFormat helper with JSON parsing + format detection (BlockNote vs ProseMirror vs empty/unknown).
  • Implemented initial BlockNote-to-ProseMirror conversion for paragraph blocks in blockContentFormat.
  • Added heading block conversion with level mapping to ProseMirror heading nodes.
  • Added BlockNote list item conversion to ProseMirror bullet/ordered list nodes.
  • Expanded inline conversion to map text styles, links, and mentions to ProseMirror marks/text.
  • Added conversion support for checklists, code blocks, blockquotes, and table fallbacks.
  • Collaborative editor now initializes Y.js state from existing block_data with BlockNote conversion when needed.
  • Save button in drawer now triggers collaborative snapshot sync when using the collab editor.
  • Added best-effort snapshot on drawer close for collaborative sessions.
  • Added 3s Hocuspocus timeout handling to switch drawer editor into fallback mode.
  • Fallback editor now uses DocumentEditor with drawer-level save via updateBlockContent and shared toolbar/styling.
  • Added fallback status banner: "Offline — manual save mode".
  • Presence bar and collaboration cursors are available via CollaborativeEditor in the drawer context.
  • New document creation now pre-creates document + block_content and opens the collaborative editor in the new room.
  • Added read-only DocumentViewer (Tiptap) for drawer view mode to render BlockNote or ProseMirror content.
  • Document name input remains editable and wired to update document name on save in both collab and fallback modes.
  • Unsaved changes warning now accounts for fallback editor changes before closing the drawer.
  • BlockNote-to-ProseMirror conversion now persists converted JSON back to document_block_content.
  • Added drawer test coverage to ensure CollaborativeEditor renders on edit of in-app documents.
  • Synced entity-mode drawer rendering with collaborative/fallback editor logic (avoids legacy BlockNote path).
  • Added test ensuring CollaborativeEditor uses document:<tenantId>:<documentId> room naming.
  • Added format detection test for BlockNote JSON.
  • Added format detection test for ProseMirror JSON.
  • Added empty/null format detection test.
  • Added paragraph conversion test for BlockNote → ProseMirror.
  • Added styled text conversion test for bold/italic/underline marks.

2026-02-24 Updates

  • Added heading conversion test for BlockNote -> ProseMirror (levels 1-3) in packages/documents/src/lib/blockContentFormat.test.ts and marked T08 complete.
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts.
  • Added bullet list item conversion test in packages/documents/src/lib/blockContentFormat.test.ts and marked T09 complete.
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts.
  • Added numbered list item conversion test in packages/documents/src/lib/blockContentFormat.test.ts and marked T10 complete.
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts.
  • Added link inline conversion test in packages/documents/src/lib/blockContentFormat.test.ts and marked T11 complete.
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts.
  • Added mention inline conversion test in packages/documents/src/lib/blockContentFormat.test.ts and marked T12 complete.
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts (tests passed but the command hit the 10s timeout after printing results).
  • Added code block conversion test in packages/documents/src/lib/blockContentFormat.test.ts and marked T13 complete.
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts.
  • Added blockquote conversion test in packages/documents/src/lib/blockContentFormat.test.ts and marked T14 complete.
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts.
  • Added empty block conversion test in packages/documents/src/lib/blockContentFormat.test.ts and marked T15 complete.
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts.
  • Added recursive conversion to flatten children blocks in packages/documents/src/lib/blockContentFormat.ts plus a nested children test in packages/documents/src/lib/blockContentFormat.test.ts (T16).
  • Ran npx vitest run ../packages/documents/src/lib/blockContentFormat.test.ts.
  • Added CollaborativeEditor.init.test.tsx to cover ProseMirror load (no conversion) and BlockNote load (conversion + persistence), marking T17/T18 complete.
  • Mocked EditorToolbar in the new test file to avoid editor API dependencies.
  • Ran npx vitest run ../packages/documents/src/components/CollaborativeEditor.init.test.tsx.
  • Extended Documents.drawer.test.tsx to assert Save triggers syncCollabSnapshot in collaborative mode (T19) and adjusted mock to set connection status via useEffect.
  • Ran npx vitest run ../packages/documents/src/components/Documents.drawer.test.tsx.
  • Added drawer close snapshot test in Documents.drawer.test.tsx and marked T20 complete.
  • Ran npx vitest run ../packages/documents/src/components/Documents.drawer.test.tsx.

Updates

  • Fixed fallback mode timing loop by separating isEditingDocument from isCollaborativeEdit so the timeout can set fallback without immediately clearing it. Files: packages/documents/src/components/Documents.tsx.
  • Test T21 now passes by waiting for the 3s timeout to switch to the fallback editor. Test: packages/documents/src/components/Documents.drawer.test.tsx.
  • Added fallback mode save test (T22) asserting updateBlockContent runs when manual save is enabled. Enhanced DocumentEditor mock to drive unsaved state and content for fallback save. File: packages/documents/src/components/Documents.drawer.test.tsx.
  • Added T23 test to confirm offline indicator appears in fallback mode (Offline — manual save mode). File: packages/documents/src/components/Documents.drawer.test.tsx.
  • Added collaborative presence/caret tests in packages/documents/src/components/CollaborativeEditor.init.test.tsx:
    • Presence bar renders connected users from awareness state.
    • Collaboration caret render callback produces labeled cursor.
    • Collaboration extension configured with Yjs document for real-time sync.
  • Added T27 test to ensure folder-mode new document creation calls createBlockDocument and opens the collab editor. Test: packages/documents/src/components/Documents.drawer.test.tsx.
  • Added T28 test to ensure non-editable docs render the read-only viewer in the drawer. File: packages/documents/src/components/Documents.drawer.test.tsx.
  • Added T29 test confirming document name input in drawer is editable. File: packages/documents/src/components/Documents.drawer.test.tsx.
  • Added T30 test verifying unsaved changes confirmation appears when closing in fallback mode. Updated ConfirmationDialog mock to render when open. File: packages/documents/src/components/Documents.drawer.test.tsx.
  • Marked T31 complete based on existing conversion persistence assertion in packages/documents/src/components/CollaborativeEditor.init.test.tsx.
  • Added T32-T35 coverage in packages/documents/src/components/CollaborativeEditor.init.test.tsx:
    • Reopens content saved as ProseMirror JSON string.
    • Editor toolbar renders when editor is ready.
    • Emoticon extension included in editor configuration.
    • Link extension configured with autolink + linkOnPaste.