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
25 KiB
25 KiB
SCRATCHPAD — 2026-02-27 Inbound Email In-App Artifact Persistence (Remaining Work)
Scope Intent
Create a clean, implementation-ready plan containing only remaining work for inbound email artifact persistence in the in-app callback path.
Discovery Notes
- IMAP webhook currently publishes
INBOUND_EMAIL_RECEIVEDand returnshandoff: event_busrather than using in-app processing directly.packages/integrations/src/webhooks/email/imap.ts
- Google and Microsoft webhook handlers already have an in-app processing branch controlled by
isInboundEmailInAppProcessingEnabled(...).packages/integrations/src/webhooks/email/google.tspackages/integrations/src/webhooks/email/microsoft.ts
processInboundEmailInAppcurrently handles ticket/comment logic and calls attachment processing, but does not run embedded extraction or original.emlpersistence.shared/services/email/processInboundEmailInApp.ts
- Workflow definitions mention embedded extraction +
.emlactions, but this remaining-work plan intentionally focuses on in-app callback parity.shared/workflow/workflows/system-email-processing-workflow.ts
Locked Decisions
- Persist only HTML-referenced CID inline images.
- Use deterministic
.emlfilename conventionoriginal-email-<sanitized-message-id>.eml. - App-local in-process async worker mode is allowed.
Open Questions
- None for this planning pass; scope is constrained to remaining in-app gap closure.
Validation Commands
python3 scripts/validate_plan.py ee/docs/plans/2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work
Implementation Log
- 2026-02-27: Completed
F214by validating and activating the remaining-work plan artifact set at:ee/docs/plans/2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work/PRD.mdee/docs/plans/2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work/features.jsonee/docs/plans/2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work/tests.jsonee/docs/plans/2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work/SCRATCHPAD.md
- Rationale: The plan scope existed but had all checklist entries disabled; flipping
F214records that the remaining-work scope artifact is now established and tracked as implementation source-of-truth. - 2026-02-27: Completed
F215by extracting artifact execution into shared orchestrator modules:shared/services/email/processInboundEmailArtifacts.tsshared/services/email/inboundEmailArtifactHelpers.ts- Wired call-sites in
shared/services/email/processInboundEmailInApp.tsfor:- reply-token flow
- thread-header flow
- new-ticket flow
- Decision: Keep orchestration in shared service layer so Google/Microsoft/IMAP in-app paths naturally converge via existing
processInboundEmailInAppentrypoint. - Validation:
npx tsc -p shared/tsconfig.json --noEmit
- Gotcha:
- Repo Vitest config only includes
server/src+../packages; directshared/services/email/__tests__file filters are not discovered by default runner config.
- Repo Vitest config only includes
- 2026-02-27: Completed
F216.persistInboundEmailAttachment(...)now consumesattachmentData.content(base64) when present before any provider download fallback.- File bytes are decoded and fed into storage-backed document persistence, enabling in-app callback payloads (including IMAP/local test payloads) to attach real files without workflow-worker execution.
- 2026-02-27: Completed
F217.persistDocumentForBuffer(...)now performs full persistence chain for in-app artifacts:- inserts
external_files - inserts
documentslinked tofile_id - inserts
document_associationsto the targetticket.
- inserts
- This replaces metadata-only attachment behavior in the in-app path.
- 2026-02-27: Completed
F218.- Added shared
extractEmbeddedImageAttachments(...)helper and wired it inprocessInboundEmailArtifactsBestEffort(...). - In-app path now extracts HTML
data:image/*;base64,...artifacts and feeds them through the same persistence pipeline as normal attachments.
- Added shared
- 2026-02-27: Completed
F219.- Embedded extraction now maps only HTML-referenced
cid:values to inline MIME parts. - Unreferenced inline CID attachments are not synthesized/persisted, matching the locked decision to persist only referenced CID images.
- Embedded extraction now maps only HTML-referenced
- 2026-02-27: Completed
F220.- Synthetic embedded artifacts are emitted with deterministic IDs (
embedded-data-*,embedded-cid-*) and normalized attachment fields (id/name/contentType/size/content). - Orchestrator appends these synthetic records to provider attachments and runs one shared persistence path.
- Synthetic embedded artifacts are emitted with deterministic IDs (
- 2026-02-27: Completed
F221.- Added
.emlpersistence step (persistInboundOriginalEmail) into in-app orchestration for both reply and new-ticket flows. - The original message is persisted as
message/rfc822through the same storage/document association path as other artifacts.
- Added
- 2026-02-27: Completed
F222.- Implemented MIME source selection with precedence in
maybeExtractRawMimeFromEmailData(...):rawMimeBase64sourceMimeBase64rawSourceBase64
- When no source bytes are available,
.emlfallback generation uses deterministic RFC822 assembly (buildDeterministicRfc822Message(...)).
- Implemented MIME source selection with precedence in
- 2026-02-27: Completed
F223..emlpersistence now uses deterministic file naming viabuildOriginalEmailFileName(messageId)withoriginal-email-<sanitized-message-id>.emlconvention.
- 2026-02-27: Completed
F224.- Added artifact-level idempotent claiming via
email_processed_attachmentsprimary key(tenant, provider_id, email_id, attachment_id). - Deterministic attachment IDs now cover:
- provider attachments (
attachment.id) - synthetic embedded artifacts (
embedded-data-*,embedded-cid-*) - original email source (
__original_email_source__).
- provider attachments (
- Added artifact-level idempotent claiming via
- 2026-02-27: Completed
F225.- Artifact pipeline is explicitly best-effort:
- per-attachment failures are logged and processing continues
.emlpersistence failures are logged and do not interrupt ticket/comment return path.
processInboundEmailInAppnow always returns reply/new-ticket outcomes independent of artifact persistence failures.
- Artifact pipeline is explicitly best-effort:
- 2026-02-27: Completed
F226.- Reworked IMAP webhook route (
packages/integrations/src/webhooks/email/imap.ts) to support:- direct in-app processing handoff (
handoff: "in_app") - app-local async in-process queue handoff (
handoff: "in_app_async") - explicit event-bus fallback on in-app failure (
handoff: "event_bus_fallback") when configured.
- direct in-app processing handoff (
- Reworked IMAP webhook route (
- 2026-02-27: Completed
F227.- IMAP webhook payload normalization now enforces ingress caps for:
- per-attachment bytes
- total attachment bytes
- attachment count
- raw MIME bytes.
- Caps are driven by existing IMAP env knobs:
IMAP_MAX_ATTACHMENT_BYTESIMAP_MAX_TOTAL_ATTACHMENT_BYTESIMAP_MAX_ATTACHMENT_COUNTIMAP_MAX_RAW_MIME_BYTES.
- IMAP webhook payload normalization now enforces ingress caps for:
- 2026-02-27: Completed
F228.- Over-limit payload elements now emit structured
ingressSkipReasonsentries with deterministic reason enums:attachment_over_max_bytesattachment_total_bytes_exceededattachment_count_exceededraw_mime_over_max_bytes
- Eligible attachments continue through in-app artifact processing.
- Over-limit payload elements now emit structured
- 2026-02-27: Completed
F229.- Added app-local async IMAP callback queue (
packages/integrations/src/webhooks/email/imapInAppQueue.ts). - Webhook can now defer in-app processing when
IMAP_INBOUND_EMAIL_IN_APP_ASYNC_ENABLED=true, returning quickly with queue metadata.
- Added app-local async IMAP callback queue (
- 2026-02-27: Completed
F230.- Added explicit attachment artifact concurrency bounding in
processInboundEmailArtifactsBestEffort(...)via:IMAP_INBOUND_EMAIL_IN_APP_ARTIFACT_CONCURRENCYINBOUND_EMAIL_IN_APP_ARTIFACT_CONCURRENCY
- Async queue worker concurrency is separately bounded by
IMAP_INBOUND_EMAIL_IN_APP_ASYNC_WORKERS.
- Added explicit attachment artifact concurrency bounding in
- 2026-02-27: Completed
F231.- IMAP webhook now validates and normalizes in-app payload contract fields before processing:
- attachments
content,isInline,contentId - MIME source fields
rawMimeBase64/sourceMimeBase64/rawSourceBase64.
- attachments
- Malformed contract inputs return safe
400responses instead of crashing callback execution.
- IMAP webhook now validates and normalizes in-app payload contract fields before processing:
- 2026-02-27: Completed
F232.- Added IMAP-specific feature-flag helpers in
shared/services/email/inboundEmailInAppFeatureFlag.ts:isImapInboundEmailInAppProcessingEnabledisImapInboundEmailInAppAsyncModeEnabledisImapInboundEmailInAppEventBusFallbackEnabled
- Documented supported flag/env combinations in
docs/inbound-email/setup/imap.md.
- Added IMAP-specific feature-flag helpers in
- 2026-02-27: Completed
F233.- Google and Microsoft webhook handlers already delegate in-app processing to
processInboundEmailInApp(...). - Because
processInboundEmailInAppnow routes all artifact handling throughprocessInboundEmailArtifactsBestEffort(...), provider behavior is unified for attachments, embedded extraction, and.emlpersistence.
- Google and Microsoft webhook handlers already delegate in-app processing to
- 2026-02-27: Completed
F234.- Added in-app integration assertion coverage in:
server/src/test/integration/inboundEmailInApp.webhooks.integration.test.ts
- New scenario asserts ticket document outcomes for:
- regular attachment (
regular.txt) - embedded extraction artifact (
embedded-image-1.png) - deterministic original email
.emldocument.
- regular attachment (
- Added in-app integration assertion coverage in:
- Validation:
cd server && npx vitest run src/test/integration/inboundEmailInApp.webhooks.integration.test.ts --coverage.enabled=false- Result in this environment: suite discovered but DB-gated tests skipped (
describeDbguard).
- 2026-02-27: Completed
F235.- Added local operator runbook:
ee/docs/plans/2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work/GREENMAIL-IMAP-INAPP-RUNBOOK.md
- Runbook includes setup, SMTP send step, log checks, DB verification queries, and UI verification for regular/embedded/
.emlartifact outcomes.
- Added local operator runbook:
- 2026-02-27: Completed
T214.- Added/maintained explicit assertion in
shared/services/email/__tests__/processInboundEmailInApp.test.tsthatprocessInboundEmailArtifactsBestEffort(...)is invoked for the new-ticket flow. - Assertion verifies ordering: comment creation occurs before artifact orchestrator invocation using
invocationCallOrder. - Added shared Vitest alias config in
shared/vitest.config.tsand completed workflow-action mock shape updates required by currentprocessInboundEmailInAppimports.
- Added/maintained explicit assertion in
- Validation:
npx vitest run --config shared/vitest.config.ts shared/services/email/__tests__/processInboundEmailInApp.test.ts -t "contact\\+user forwards both author_id and contact_id" --coverage.enabled=false
- 2026-02-27: Completed
T215.- Verified reply-flow orchestration path invokes
processInboundEmailArtifactsBestEffort(...)only aftercreateCommentFromEmail(...). - Scope validated on reply-token threaded flow in
shared/services/email/__tests__/processInboundEmailInApp.test.tsusing call-order assertion.
- Verified reply-flow orchestration path invokes
- Validation:
npx vitest run --config shared/vitest.config.ts shared/services/email/__tests__/processInboundEmailInApp.test.ts -t "reply-token path resolves sender contact and forwards contact_id for contact-only sender" --coverage.enabled=false
- 2026-02-27: Completed
T216.- Existing integration scenario
IMAP in-app path persists regular attachment, embedded image, and original .eml as ticket documentsasserts attachment-backed document persistence todocumentsand backing file rows inexternal_files. - This covers base64 attachment bytes in inbound payload flowing into persisted file + document records.
- Existing integration scenario
- Validation:
cd server && npx vitest run src/test/integration/inboundEmailInApp.webhooks.integration.test.ts -t "IMAP in-app path persists regular attachment, embedded image, and original .eml as ticket documents" --coverage.enabled=false- Environment note: DB-gated integration suite was skipped in this local session (
describeDb).
- 2026-02-27: Completed
T217.- The same IMAP integration scenario verifies ticket linkage via
document_associationsby selectingdocumentsjoined throughdocument_associationsfiltered to the created ticket. - Assertion confirms attachment document rows are associated to the ticket entity, not just persisted standalone.
- The same IMAP integration scenario verifies ticket linkage via
- Validation:
- Reused targeted integration command from
T216(same assertion source).
- Reused targeted integration command from
- 2026-02-27: Completed
T218.- Added
shared/services/email/__tests__/inboundEmailArtifactHelpers.test.tswith deterministicdata:imageextraction coverage. - Test asserts generated synthetic artifact shape and stable deterministic ID/name/content across repeated extraction calls.
- Added
- Validation:
npx vitest run --config shared/vitest.config.ts shared/services/email/__tests__/inboundEmailArtifactHelpers.test.ts --coverage.enabled=false
- 2026-02-27: Completed
T219.- Added CID extraction unit coverage in
shared/services/email/__tests__/inboundEmailArtifactHelpers.test.tsproving only HTML-referenced CID parts are synthesized. - Test fixture includes referenced and unreferenced inline attachments; assertion verifies only the referenced CID becomes a synthetic artifact.
- Added CID extraction unit coverage in
- Validation:
- Reused helper-unit test command from
T218.
- Reused helper-unit test command from
- 2026-02-27: Completed
T220.- Strengthened IMAP artifact integration assertions in
server/src/test/integration/inboundEmailInApp.webhooks.integration.test.ts:- embedded image document row has
mime_type = image/png - linked
external_filesrow hasmime_type = image/pngand expected decodedfile_size.
- embedded image document row has
- This extends embedded image persistence checks beyond document name presence into persisted type/size contract.
- Strengthened IMAP artifact integration assertions in
- Validation:
cd server && npx vitest run src/test/integration/inboundEmailInApp.webhooks.integration.test.ts -t "IMAP in-app path persists regular attachment, embedded image, and original .eml as ticket documents" --coverage.enabled=false- Environment note: DB-gated integration suite was skipped in this local session (
describeDb).
- 2026-02-27: Completed
T221.- Added MIME source precedence unit assertions in
shared/services/email/__tests__/inboundEmailArtifactHelpers.test.ts. - Coverage verifies decode order:
rawMimeBase64->sourceMimeBase64->rawSourceBase64.
- Added MIME source precedence unit assertions in
- Validation:
npx vitest run --config shared/vitest.config.ts shared/services/email/__tests__/inboundEmailArtifactHelpers.test.ts -t "raw MIME source selection prefers" --coverage.enabled=false
- 2026-02-27: Completed
T222.- Added fallback MIME assembly coverage in
shared/services/email/__tests__/inboundEmailArtifactHelpers.test.ts. - Test asserts deterministic RFC822 output when raw source fields are absent and validates key header/body content.
- Added fallback MIME assembly coverage in
- Validation:
npx vitest run --config shared/vitest.config.ts shared/services/email/__tests__/inboundEmailArtifactHelpers.test.ts -t "deterministic fallback MIME assembly is stable" --coverage.enabled=false
- 2026-02-27: Completed
T223.- Enhanced IMAP in-app integration assertions to verify exactly one
.emldocument is associated with the ticket per inbound message. - Assertion added in
server/src/test/integration/inboundEmailInApp.webhooks.integration.test.tsby filtering associated docs to.emlsuffix and enforcing cardinality1.
- Enhanced IMAP in-app integration assertions to verify exactly one
- Validation:
cd server && npx vitest run src/test/integration/inboundEmailInApp.webhooks.integration.test.ts -t "IMAP in-app path persists regular attachment, embedded image, and original .eml as ticket documents" --coverage.enabled=false- Environment note: DB-gated integration suite was skipped in this local session (
describeDb).
- 2026-02-27: Completed
T224.- Existing IMAP integration assertion in
server/src/test/integration/inboundEmailInApp.webhooks.integration.test.tsverifies deterministic filename format:original-email-<sanitized-message-id>.eml.
- Assertion uses the full expected file name derived from message id normalization.
- Existing IMAP integration assertion in
- Validation:
- Reused targeted IMAP integration command from
T223.
- Reused targeted IMAP integration command from
- 2026-02-27: Completed
T225.- Added duplicate-message idempotency integration scenario in
server/src/test/integration/inboundEmailInApp.webhooks.integration.test.ts. - Scenario calls
processInboundEmailInApptwice for identical IMAP message and asserts provider attachment document name count remains1. - Also corrected deterministic
.emlexpected-name construction in this integration file to match production sanitization.
- Added duplicate-message idempotency integration scenario in
- Validation:
cd server && npx vitest run src/test/integration/inboundEmailInApp.webhooks.integration.test.ts -t "Idempotency: duplicate inbound message does not duplicate provider, embedded, or .eml artifact documents" --coverage.enabled=false- Environment note: DB-gated integration suite was skipped in this local session (
describeDb).
- 2026-02-27: Completed
T226.- Duplicate-message idempotency integration scenario added in
T225asserts embedded image document (embedded-image-1.png) remains single-instance after replay.
- Duplicate-message idempotency integration scenario added in
- Validation:
- Reused targeted duplicate-idempotency integration command from
T225.
- Reused targeted duplicate-idempotency integration command from
- 2026-02-27: Completed
T227.- Duplicate-message idempotency integration scenario added in
T225also asserts deterministic original-email.emldocument remains single-instance after replay.
- Duplicate-message idempotency integration scenario added in
- Validation:
- Reused targeted duplicate-idempotency integration command from
T225.
- Reused targeted duplicate-idempotency integration command from
- 2026-02-27: Completed
T228.- Added integration scenario
Artifact failure: attachment persistence failure is recorded while ticket/comment creation still succeedsinserver/src/test/integration/inboundEmailInApp.webhooks.integration.test.ts. - Test injects a storage upload failure via test mock, asserts
processInboundEmailInAppstill returnscreated, comment row exists, andemail_processed_attachmentsrecordsprocessing_status = failedwith error detail.
- Added integration scenario
- Validation:
cd server && npx vitest run src/test/integration/inboundEmailInApp.webhooks.integration.test.ts -t "Artifact failure: attachment persistence failure is recorded while ticket/comment creation still succeeds" --coverage.enabled=false- Environment note: DB-gated integration suite was skipped in this local session (
describeDb).
- 2026-02-27: Completed
T229.- Extended
server/src/test/integration/imapWebhookHandoff.integration.test.tswith explicit IMAP in-app handoff assertions. - New test verifies
IMAP_INBOUND_EMAIL_IN_APP_PROCESSING_ENABLED=trueroutes webhook toprocessInboundEmailInAppand returnshandoff: in_app.
- Extended
- Validation:
cd server && npx vitest run src/test/integration/imapWebhookHandoff.integration.test.ts --coverage.enabled=false
- 2026-02-27: Completed
T230.- Added IMAP webhook fallback-path assertion in
server/src/test/integration/imapWebhookHandoff.integration.test.ts. - Test verifies disabled in-app flag returns
handoff: event_bus, publishesINBOUND_EMAIL_RECEIVED, and does not call in-app processor.
- Added IMAP webhook fallback-path assertion in
- Validation:
- Reused full IMAP webhook integration run from
T229.
- Reused full IMAP webhook integration run from
- 2026-02-27: Completed
T231.- Added IMAP webhook over-limit single-attachment scenario in
server/src/test/integration/imapWebhookHandoff.integration.test.ts. - Test enforces low
IMAP_MAX_ATTACHMENT_BYTESand asserts skip reasonattachment_over_max_byteswith dropped attachment from normalized payload.
- Added IMAP webhook over-limit single-attachment scenario in
- Validation:
- Reused full IMAP webhook integration run from
T229.
- Reused full IMAP webhook integration run from
- 2026-02-27: Completed
T232.- Added IMAP webhook total-bytes cap scenario in
server/src/test/integration/imapWebhookHandoff.integration.test.ts. - Test configures per-attachment + total cap and asserts overflow artifact skip reason
attachment_total_bytes_exceeded.
- Added IMAP webhook total-bytes cap scenario in
- Validation:
- Reused full IMAP webhook integration run from
T229.
- Reused full IMAP webhook integration run from
- 2026-02-27: Completed
T233.- Added IMAP webhook attachment-count cap scenario in
server/src/test/integration/imapWebhookHandoff.integration.test.ts. - Test sets
IMAP_MAX_ATTACHMENT_COUNT=1and asserts reasonattachment_count_exceededfor excess entries.
- Added IMAP webhook attachment-count cap scenario in
- Validation:
- Reused full IMAP webhook integration run from
T229.
- Reused full IMAP webhook integration run from
- 2026-02-27: Completed
T234.- Added IMAP webhook raw-MIME cap scenario in
server/src/test/integration/imapWebhookHandoff.integration.test.ts. - Test asserts
raw_mime_over_max_bytesreason and confirms normalized payload strips raw MIME source fields before handoff.
- Added IMAP webhook raw-MIME cap scenario in
- Validation:
- Reused full IMAP webhook integration run from
T229.
- Reused full IMAP webhook integration run from
- 2026-02-27: Completed
T237.- Added payload contract acceptance scenario in
server/src/test/integration/imapWebhookHandoff.integration.test.ts. - Test verifies webhook accepts
attachments[].content/isInline/contentIdand MIME source fields (sourceMimeBase64) and forwards normalized values.
- Added payload contract acceptance scenario in
- Validation:
- Reused full IMAP webhook integration run from
T229.
- Reused full IMAP webhook integration run from
- 2026-02-27: Completed
T238.- Added malformed payload validation scenario in
server/src/test/integration/imapWebhookHandoff.integration.test.ts. - Test sends non-string
attachments[].contentand asserts safe400validation response without invoking publish/in-app handlers.
- Added malformed payload validation scenario in
- Validation:
- Reused full IMAP webhook integration run from
T229.
- Reused full IMAP webhook integration run from
- 2026-02-27: Completed
T235.- Added
packages/integrations/src/webhooks/email/imapInAppQueue.test.tswith async queue acceptance/defer behavior coverage. - Test asserts queue accepts callback payload, returns immediately (non-blocking), and begins asynchronous processing without request-thread waiting.
- Added
- Validation:
cd server && npx vitest run ../packages/integrations/src/webhooks/email/imapInAppQueue.test.ts --coverage.enabled=falsecd server && npx vitest run src/test/integration/imapWebhookHandoff.integration.test.ts ../packages/integrations/src/webhooks/email/imapInAppQueue.test.ts --coverage.enabled=false
- 2026-02-27: Completed
T236.- Added async queue concurrency-bound assertion in
packages/integrations/src/webhooks/email/imapInAppQueue.test.ts. - Test sets worker env above max (
99) and verifies active workers cap at8with remaining items queued, then drains to idle.
- Added async queue concurrency-bound assertion in
- Validation:
- Reused combined webhook + queue vitest run from
T235.
- Reused combined webhook + queue vitest run from
- 2026-02-27: Completed
T239.- Added Google webhook integration scenario in
server/src/test/integration/inboundEmailInApp.webhooks.integration.test.tsthat exercises in-app mode with all artifact classes. - Test asserts ticket-associated documents include provider attachment, extracted embedded image, and deterministic original-email
.eml, verifying shared artifact orchestrator behavior.
- Added Google webhook integration scenario in
- Validation:
cd server && npx vitest run src/test/integration/inboundEmailInApp.webhooks.integration.test.ts -t "shared artifact orchestrator" --coverage.enabled=false- Environment note: DB-gated integration suite was skipped in this local session (
describeDb).
- 2026-02-27: Completed
T240.- Added Microsoft webhook integration scenario in
server/src/test/integration/inboundEmailInApp.webhooks.integration.test.tsmirroring Google artifact coverage. - Test verifies in-app processing persists regular attachment, embedded extraction artifact, and deterministic
.emlfor Microsoft path through the shared orchestrator.
- Added Microsoft webhook integration scenario in
- Validation:
- Reused targeted integration command from
T239.
- Reused targeted integration command from
- 2026-02-27: Completed
T241.- Existing IMAP integration scenario (
IMAP in-app path persists regular attachment, embedded image, and original .eml as ticket documents) now serves as explicit coverage for IMAP in-app artifact parity. - Assertions include presence of regular attachment, embedded image artifact, and original-email
.emlon ticket document associations.
- Existing IMAP integration scenario (
- Validation:
- Reused targeted IMAP integration command from earlier artifact tests:
cd server && npx vitest run src/test/integration/inboundEmailInApp.webhooks.integration.test.ts -t "IMAP in-app path persists regular attachment, embedded image, and original .eml as ticket documents" --coverage.enabled=false
- Environment note: DB-gated integration suite was skipped in this local session (
describeDb).
- Reused targeted IMAP integration command from earlier artifact tests:
- 2026-02-27: Completed
T242.- Added Playwright coverage file:
server/src/test/e2e/inbound-email-artifacts-documents.playwright.test.ts
- Test seeds a ticket with three associated document artifacts (regular attachment, embedded image,
.eml), opens ticket detail UI, navigates to Documents tab, and asserts all three are visible.
- Added Playwright coverage file:
- Validation:
cd server && npx playwright test src/test/e2e/inbound-email-artifacts-documents.playwright.test.ts --list
- 2026-02-27: Completed
T243.- Confirmed runbook coverage in:
ee/docs/plans/2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work/GREENMAIL-IMAP-INAPP-RUNBOOK.md
- Document includes environment setup, message-send step, and verification sections (logs, DB, UI) for IMAP in-app artifact validation.
- Confirmed runbook coverage in:
- Validation:
- Manual content verification against runbook sections.