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
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
99 lines
14 KiB
Markdown
99 lines
14 KiB
Markdown
# 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`
|
|
|
|
## Links / References
|
|
|
|
- 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.
|