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

7.6 KiB

Scratchpad — Ticket Description Rich Text Cutover

  • Plan slug: ticket-description-rich-text-cutover
  • Created: 2026-03-09

What This Is

Working notes for converting ticket descriptions onto the same rich-text editor model used by ticket comments while simplifying duplicate ticket rich-text logic.

Decisions

  • (2026-03-09) Store rich descriptions in the existing ticket.attributes.description field as serialized BlockNote JSON; do not add a new schema field.
  • (2026-03-09) Use lazy upgrade for historical plain-text descriptions: keep them readable and only rewrite them when a description is edited and saved.
  • (2026-03-09) Description cancel behavior for pasted images should prompt keep/delete, matching the richer draft workflow rather than silently leaking uploads.
  • (2026-03-09) Use the simplification-cascade approach: treat ticket description, comment compose, and comment edit as the same ticket rich-text problem with different draft-tracking modes.
  • (2026-03-09) Scope the abstraction to the ticket module for this unit of work rather than attempting an app-wide editor refactor.
  • (2026-03-09) Keep the shared rich-text abstractions ticket-scoped in packages/tickets even though TextEditor already has its own parsing fallback, because the PRD explicitly wants ticket-only consolidation of description/comment behavior and draft image session rules.
  • (2026-03-09) Extract the description save-side effect from TicketDetailsContainer into a small helper (ticketDescriptionUpdate.ts) so the payload merge/auth/error path can be tested directly without pulling the full optimized ticket action graph into jsdom.
  • (2026-03-09) Count the plan test checklist as satisfied by a combination of new unit/hook/helper tests and existing ticket clipboard contract tests; no separate database harness was introduced for this cutover.

Discoveries / Constraints

  • (2026-03-09) TicketInfo.tsx already renders descriptions with RichTextViewer and uses TextEditor in edit mode, but it still carries its own JSON parsing fallback logic and does not wire the comment upload/mention helpers into the description editor.
  • (2026-03-09) TextEditor.tsx already owns markdown paste handling, HTML normalization behavior, mention insertion support, and uploadFile-based clipboard-image handling. Description work should reuse that path instead of adding description-specific paste code.
  • (2026-03-09) TicketConversation.tsx already contains the ticket clipboard-image upload, draft tracking, keep/delete prompt, and hard-delete flow for new comment drafts. That behavior is the direct precedent for description edit cancel semantics.
  • (2026-03-09) CommentItem.tsx already has separate JSON/plain-text fallback parsing for comments and uses clipboard upload without draft tracking during existing-comment edit. That is a good target for shared-helper consolidation.
  • (2026-03-09) TicketDetailsContainer.tsx and TicketDetails.tsx already save description changes through onUpdateDescription(content: string), which currently writes the string directly into ticket.attributes.description.
  • (2026-03-09) Existing code already supports rendering plain-text fallback by wrapping strings into paragraph blocks, so no migration is required to keep old tickets readable.
  • (2026-03-09) packages/tickets/vitest.config.ts does not alias several cross-package server-only modules (@alga-psa/documents, @alga-psa/event-bus, etc.), so meaningful unit tests had to avoid importing those graphs eagerly. Lazy-loading the default upload/delete actions inside useTicketRichTextUploadSession fixed that without changing runtime behavior.
  • (2026-03-09) The description editor needed the same document refresh callback that comments already use so cancel-delete can remove draft image documents and refresh the ticket document list immediately.
  • (2026-03-09) Existing clipboardImageDraftActions.contract.test.ts already covers the guard rails for “already referenced”, “has other associations”, and “permission denied”, so the new description cancel-delete coverage only needed to verify the description flow routes into that action correctly.

Completed Work

  • (2026-03-09) Completed F001-F018: description edit now uses the shared TextEditor affordances (mentions, markdown/html paste, clipboard image upload), persists serialized BlockNote JSON, shares a ticket-scoped parse helper plus upload/session helper with comment compose/edit, prompts keep/delete for draft description images, refreshes ticket documents after upload/delete, and preserves comment compose/edit behavior on the shared helper path.
  • (2026-03-09) Completed T001-T031: added ticketRichText.test.ts, useTicketRichTextUploadSession.test.tsx, TicketDetailsContainer.description.test.tsx, and TicketInfo.richText.contract.test.ts; updated the ticket clipboard/comment contract suites to assert the new shared-helper wiring; reused existing clipboardImageUtils.test.ts and clipboardImageDraftActions.contract.test.ts coverage for validation and delete guard rails.

Commands / Runbooks

  • (2026-03-09) Scaffolded the plan folder with:
    • python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/scaffold_plan.py "Ticket Description Rich Text Cutover" --slug ticket-description-rich-text-cutover
  • (2026-03-09) Validate the finished plan with:
    • python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py ee/docs/plans/2026-03-09-ticket-description-rich-text-cutover
  • (2026-03-09) Key exploration commands:
    • rg -n "onUpdateDescription|descriptionContent|TextEditor|RichTextViewer" packages/tickets/src/components/ticket
    • rg -n "uploadClipboardImage|handleClipboardImageUpload|deleteDraftClipboardImages" packages/tickets/src/components/ticket
    • sed -n '1,520p' packages/ui/src/editor/TextEditor.tsx
  • (2026-03-09) Verification commands:
    • npx vitest run --config vitest.config.ts src/actions/comment-actions/clipboardImageDraftActions.contract.test.ts src/lib/clipboardImageUtils.test.ts src/lib/ticketRichText.test.ts src/components/ticket/useTicketRichTextUploadSession.test.tsx src/components/ticket/__tests__/TicketDetailsContainer.description.test.tsx src/components/ticket/TicketInfo.richText.contract.test.ts src/components/ticket/TicketConversation.clipboard.contract.test.ts src/components/ticket/TicketClipboardFlow.e2e.contract.test.ts src/components/ticket/CommentItem.clipboardImage.contract.test.ts (run from packages/tickets/)
    • npx tsc -p packages/tickets/tsconfig.json --noEmit
  • Reference implementation plan: ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/
  • Ticket description read/edit implementation: packages/tickets/src/components/ticket/TicketInfo.tsx
  • Description save path: packages/tickets/src/components/ticket/TicketDetails.tsx
  • Container save action: packages/tickets/src/components/ticket/TicketDetailsContainer.tsx
  • Shared ticket description save helper: packages/tickets/src/components/ticket/ticketDescriptionUpdate.ts
  • Shared editor implementation: packages/ui/src/editor/TextEditor.tsx
  • Existing ticket clipboard-image draft flow: packages/tickets/src/components/ticket/TicketConversation.tsx
  • Existing ticket comment edit flow: packages/tickets/src/components/ticket/CommentItem.tsx
  • Shared ticket rich-text parse helper: packages/tickets/src/lib/ticketRichText.ts
  • Shared ticket upload/session helper: packages/tickets/src/components/ticket/useTicketRichTextUploadSession.ts

Open Questions

  • Confirm whether any downstream email/export path renders ticket descriptions in contexts that need additional regression coverage for rich image blocks beyond the ticket UI.