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

14 KiB

Scratchpad — Ticket Comment Clipboard Image Attachments

  • Plan slug: ticket-comment-clipboard-image-attachments
  • Created: 2026-03-01

What This Is

Working notes for implementing clipboard image paste support in ticket comments, with attachment-backed rendering and outbound email inline-image support.

Decisions

  • (2026-03-01) Paste behavior is immediate upload, not deferred-until-submit.
  • (2026-03-01) Uploaded clipboard images are persisted as ticket documents/files.
  • (2026-03-01) Render saved comment images from attachment-serving URLs, not embedded data:image payloads.
  • (2026-03-01) Outbound ticket-comment emails should render pasted images inline via CID attachments.
  • (2026-03-01) Cancel flow must offer keep/delete choice when pasted images were uploaded.
  • (2026-03-01) Delete choice on cancel is hard delete (remove metadata + stored object), not soft detach.

Discoveries / Constraints

  • (2026-03-01) Existing inbound email work already converts data:image/CID content into ticket document attachments; this plan should reuse those attachment rendering and storage patterns where possible.
  • (2026-03-01) Clipboard image flows are user-driven and must avoid storing raw base64 image strings in persisted comment payloads.
  • (2026-03-01) Cancel-delete safety must prevent removing artifacts that are already referenced by submitted comments.

Commands / Runbooks

  • (2026-03-01) Scaffolded plan folder with:
    • python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/scaffold_plan.py "Ticket Comment Clipboard Image Attachments" --slug ticket-comment-clipboard-image-attachments
  • Related plan: ee/docs/plans/2026-02-27-inbound-email-embedded-images-and-original-eml/
  • Related plan: ee/docs/plans/2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work/
  • Related plan: ee/docs/plans/2026-03-01-unified-inbound-email-pointer-queue/

Open Questions

  • Confirm final max size/count limits for clipboard image uploads, or reuse existing ticket attachment limits exactly.
  • Confirm whether cancel-delete prompt supports per-image selection or all-or-nothing delete in first version.
  • (2026-03-01) F001 implemented: ticket comment editor now supports clipboard image paste handling via BlockNote uploadFile wiring in TextEditor, enabled from TicketConversation when the new feature flag is on.
  • (2026-03-01) Implementation notes: introduced packages/tickets/src/lib/clipboardImageUtils.ts for MIME detection, deterministic naming, and pre-upload validation; this utility underpins paste-image handling.
  • (2026-03-01) Commands: npx vitest run src/lib/clipboardImageUtils.test.ts (packages/tickets), npx vitest run src/test/unit/notifications/ticketCommentInlineImageEmail.test.ts (server), npx vitest run src/blocknoteUtils.image.test.ts (packages/formatting), npx tsc -p packages/tickets/tsconfig.json --noEmit, npx tsc -p server/tsconfig.json --noEmit.
  • (2026-03-01) F002 implemented: ticket comment image uploads now start immediately on paste via TextEditor uploadFile wiring and TicketConversation.handleClipboardImageUpload, without waiting for comment submit.
  • (2026-03-01) F003 implemented: Persist pasted images through ticket document/file pipeline via uploadDocument and returned document/file ids in comment image URLs.
  • (2026-03-01) F004 implemented: Deterministic clipboard image naming added through createClipboardImageFilename and upload-time file renaming (clipboard-image-YYYYMMDD-HHMMSS-SEQ.ext).
  • (2026-03-01) F005 implemented: BlockNote image upload placeholder path is enabled by providing uploadFile to editor configuration for pasted images.
  • (2026-03-01) F006 implemented: Successful upload resolves placeholder to attachment-backed image node using /api/documents/view/<fileId> URL payload from upload handler.
  • (2026-03-01) F007 implemented: Upload failure path now propagates upload/validation errors through editor upload API so users can retry/remove via BlockNote image error controls.
  • (2026-03-01) F008 implemented: Comment content now persists attachment-backed image URLs (document view endpoints) instead of raw data:image bodies.
  • (2026-03-01) F009 implemented: Ticket comment rendering path now uses saved attachment-serving URLs for inline images in BlockNote-rendered comment content.
  • (2026-03-01) F010 implemented: Attachment image serving auth strengthened in /api/documents/view/[fileId] for ticket-associated document access checks.
  • (2026-03-01) F011 implemented: Outbound ticket-comment email flow now maps comment image URLs into ticket document lookup + inline image processing model.
  • (2026-03-01) F012 implemented: Outbound email now builds CID inline attachments for eligible ticket-comment images via storage-backed attachment generation.
  • (2026-03-01) F013 implemented: Outbound comment HTML image src values are rewritten to cid: references matching generated inline attachments.
  • (2026-03-01) F014 implemented: Outbound processing now falls back to original attachment URL when CID conversion/download fails, preserving renderability.
  • (2026-03-01) F015 implemented: Ticket compose state now tracks uploaded clipboard draft images (document/file/url identity) for subsequent cancel handling.
  • (2026-03-01) F016 implemented: Canceling a draft with uploaded clipboard images now prompts keep-vs-delete through confirmation dialog copy and actions.
  • (2026-03-01) F017 implemented: Delete option on cancel now hard-deletes selected draft clipboard images through server action + document deletion pipeline.
  • (2026-03-01) F018 implemented: Draft hard delete now guards against non-owned/not-ticket/non-image/already-referenced artifacts before deletion.
  • (2026-03-01) F019 implemented: Clipboard upload path now validates image MIME prefix and maximum file size before upload begins.
  • (2026-03-01) F020 implemented: Non-image paste/plain-text behavior remains on existing path; clipboard image logic is isolated to image upload flow only.
  • (2026-03-01) F021 implemented: Clipboard image paste flow is now rollout-gated behind ticket-comment-clipboard-images feature flag in ticket details.
  • (2026-03-01) F022 implemented: Added client/server observability logs for upload outcomes, cancel keep/delete actions, and outbound CID vs fallback outcomes.
  • (2026-03-01) T001 implemented: clipboardImageUtils.test.ts verifies image MIME clipboard items are extracted while non-image entries are ignored. EOF && git add ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/tests.json ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/SCRATCHPAD.md && git commit -m "test(T001): cover clipboard image MIME filtering"- (2026-03-01) T002 implemented: clipboardImageUtils.test.ts verifies multi-image clipboard extraction preserves deterministic input order for per-image upload jobs. EOF && git add ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/tests.json ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/SCRATCHPAD.md && git commit -m "test(T002): verify deterministic multi-image upload ordering"- (2026-03-01) T003 implemented: added TicketConversation.clipboard.contract.test.ts asserting upload is wired via editor uploadFile callback and that submit handler does not invoke uploadDocument, enforcing immediate pre-submit upload flow. EOF && git add packages/tickets/src/components/ticket/TicketConversation.clipboard.contract.test.ts ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/tests.json ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/SCRATCHPAD.md && git commit -m "test(T003): assert immediate clipboard upload wiring"- (2026-03-01) T004 implemented: contract coverage verifies pasted-image upload path appends file to FormData and calls uploadDocument with ticketId scope.
  • (2026-03-01) T005 implemented: clipboardImageUtils.test.ts validates deterministic clipboard filename output format. EOF && git add ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/tests.json ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/SCRATCHPAD.md && git commit -m "test(T005): verify deterministic clipboard filename pattern"- (2026-03-01) T006 implemented: contract coverage confirms uploadFile wiring in TicketConversation so BlockNote can render in-flight upload placeholder UI for pasted images.
  • (2026-03-01) T007 implemented: contract test validates successful upload return payload includes attachment-backed URL, enabling placeholder replacement with persisted image node. EOF && git add ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/tests.json ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/SCRATCHPAD.md && git commit -m "test(T007): assert placeholder success replacement payload"- (2026-03-01) T008 implemented: contract test covers explicit upload error throws for validation and upload failures, feeding editor error affordances.
  • (2026-03-01) T009 implemented: contract assertion validates failure propagation strategy that enables editor retry path to re-run upload callback after prior failure.
  • (2026-03-01) T010 implemented: added contract assertions that pasted-image serialization path emits attachment-serving URLs (/api/documents/view/...) and does not embed data:image payload content.
  • (2026-03-01) T011 implemented: blocknoteUtils.image.test.ts now includes non-image paragraph conversion regression assertions for markdown + HTML outputs. EOF && git add ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/tests.json ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/SCRATCHPAD.md && git commit -m "test(T011): add non-image serialization regression assertions"- (2026-03-01) T012 implemented: added CommentItem.clipboardImage.contract.test.ts verifying saved BlockNote JSON is parsed and rendered through RichTextViewer for inline comment image display.
  • (2026-03-01) T013 implemented: route contract coverage asserts ticket-associated document access checks include guard branch for users without resolved ticket/contact scope. EOF && git add ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/tests.json ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/SCRATCHPAD.md && git commit -m "test(T013): cover unauthorized ticket-image route guard branch"- (2026-03-01) T014 implemented: route contract test asserts ticket-associated branch grants access (hasPermission = true) when contact/client scope matches associated ticket.
  • (2026-03-01) T015 implemented: ticketCommentInlineImageEmail.test.ts verifies comment image attachment URLs are collected/mapped for outbound email composition.
  • (2026-03-01) T016 implemented: outbound inline-image unit test asserts one CID attachment is produced per converted comment image.
  • (2026-03-01) T017 implemented: outbound inline-image test asserts HTML image src rewrite from document-view URL to matching cid: reference.
  • (2026-03-01) T018 implemented: outbound inline-image test covers storage/CID failure fallback retaining original attachment URL in HTML.
  • (2026-03-01) T019 implemented: contract test now verifies draft clipboard image state tracking and document/file identity capture during upload.
  • (2026-03-01) T020 implemented: contract assertions verify cancel action opens keep-vs-delete prompt when draft includes uploaded clipboard images. EOF && git add ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/tests.json ee/docs/plans/2026-03-01-ticket-comment-clipboard-image-attachments/SCRATCHPAD.md && git commit -m "test(T020): verify cancel prompt for uploaded draft images"- (2026-03-01) T021 implemented: contract coverage validates keep path handler clears draft state and closes editor without invoking hard-delete action.
  • (2026-03-01) T022 implemented: added clipboardImageDraftActions.contract.test.ts validating hard-delete loop invokes deleteDocument for vetted draft artifacts.
  • (2026-03-01) T023 implemented: draft-delete contract test asserts saved-comment reference guard (already_referenced) based on comment payload token scan.
  • (2026-03-01) T024 implemented: draft-delete contract test validates permission-denied guard when requester lacks document delete permission.
  • (2026-03-01) T025 implemented: clipboardImageUtils.test.ts covers unsupported MIME validation rejection before upload starts.
  • (2026-03-01) T026 implemented: clipboardImageUtils.test.ts validates max-size guard rejects oversized clipboard images with explicit error.
  • (2026-03-01) T027 implemented: TicketDetails.clipboardFlag.contract.test.ts asserts dedicated feature flag default-off gating for clipboard image paste flow.
  • (2026-03-01) T028 implemented: feature-flag contract coverage verifies enabled state wires uploadFile callback to conversation editor flow.
  • (2026-03-01) T029 implemented: contract assertions verify upload logs include ticket/user identifiers plus uploaded document/file artifact identity.
  • (2026-03-01) T030 implemented: contract logging coverage verifies cancel keep/delete actions include selected action and delete-result counts/failure context.
  • (2026-03-01) T031 implemented: ticketEmailSubscriber.inlineImageLogging.contract.test.ts asserts per-image log outcome includes CID vs URL fallback strategy and reason fields.
  • (2026-03-01) T032 implemented: added TicketClipboardFlow.e2e.contract.test.ts to validate paste-upload-save-render wiring from editor upload callback through comment viewer rendering.
  • (2026-03-01) T033 implemented: clipboard-flow contract test covers cancel delete invocation with selected document IDs and editor/draft state teardown.
  • (2026-03-01) T034 implemented: outbound-email contract test verifies subscriber rewrites comment HTML and passes generated inline CID attachments on send path.
  • (2026-03-01) T035 implemented: outbound-email fallback contract test validates URL-preserving behavior when CID conversion fails.