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
126 lines
5.6 KiB
Markdown
126 lines
5.6 KiB
Markdown
# PRD — Inbound Email In-App Artifact Persistence (Remaining Work)
|
|
|
|
- Slug: `2026-02-27-inbound-email-inapp-artifact-persistence-remaining-work`
|
|
- Date: `2026-02-27`
|
|
- Status: Draft
|
|
|
|
## Summary
|
|
|
|
Close the remaining gaps so inbound email artifact handling is fully supported by **in-app callback-hook processing** (direct or app-local async worker), without requiring workflow-worker/event-bus execution for core artifact persistence.
|
|
|
|
Artifacts in scope:
|
|
1. Standard email attachments become ticket documents with persisted file bytes.
|
|
2. Referenced embedded images (`data:image/...` and HTML-referenced `cid:` images only) become ticket documents.
|
|
3. Original inbound email source is persisted as a deterministic `.eml` ticket document.
|
|
|
|
## Problem
|
|
|
|
Current in-app inbound processing creates tickets/comments, but artifact persistence behavior is incomplete/inconsistent versus target behavior:
|
|
- Attachment processing in in-app path is metadata-centric and does not reliably persist file bytes as full ticket documents.
|
|
- Embedded image extraction/persistence is not executed in the in-app path.
|
|
- Original email `.eml` persistence is not executed in the in-app path.
|
|
- IMAP webhook path is still event-bus handoff oriented and not aligned with in-app callback processing parity.
|
|
|
|
## Goals
|
|
|
|
- Ensure in-app inbound processing (new ticket and reply paths) persists all in-scope artifacts.
|
|
- Keep artifact persistence best-effort and non-blocking for ticket/comment creation.
|
|
- Maintain deterministic idempotency for retries/duplicates.
|
|
- Support IMAP callback execution in the in-app model with bounded processing and payload caps.
|
|
- Keep CPU/memory usage bounded during base64 decode and artifact conversion to avoid request-thread starvation.
|
|
|
|
## Non-goals
|
|
|
|
- Rebuilding document UI.
|
|
- Rewriting comment HTML to hosted image URLs.
|
|
- Persisting unreferenced inline CID parts.
|
|
- Introducing external workflow-worker or event-bus dependency for primary artifact persistence.
|
|
- Full distributed queue platform work (external brokers, multi-service orchestration).
|
|
|
|
## Decisions (Locked)
|
|
|
|
- Persist only CID inline images that are actually referenced by HTML (`cid:` links).
|
|
- Use deterministic source-email filename format: `original-email-<sanitized-message-id>.eml`.
|
|
- App-local in-process async worker mode is allowed.
|
|
|
|
## Users and Primary Flows
|
|
|
|
### Flow A — New inbound email (Google/Microsoft/IMAP)
|
|
|
|
1. In-app callback receives/fetches normalized email payload.
|
|
2. Ticket is created.
|
|
3. Attachment, embedded image, and `.eml` artifacts are processed and attached as ticket documents.
|
|
4. Any artifact failure is logged/recorded without rolling back ticket/comment creation.
|
|
|
|
### Flow B — Reply to existing ticket
|
|
|
|
1. In-app callback resolves thread/reply token and creates comment.
|
|
2. Artifact pipeline persists attachments, referenced embedded images, and `.eml` to the matched ticket.
|
|
3. Duplicate delivery remains idempotent.
|
|
|
|
### Flow C — Duplicate/retry ingress
|
|
|
|
1. Same message arrives again.
|
|
2. Ticket/comment dedupe remains intact.
|
|
3. Artifact persistence dedupes on deterministic keys (no duplicate document rows for same source artifact).
|
|
|
|
## Requirements
|
|
|
|
### Functional
|
|
|
|
- Extend in-app processing to run a unified artifact pipeline after ticket/comment creation for both new and reply flows.
|
|
- Accept attachment bytes in callback payload when available (`attachments[].content` base64) and persist actual files/documents.
|
|
- Reuse/expose embedded image extraction for in-app path:
|
|
- `data:image/*;base64,...` extraction,
|
|
- referenced `cid:` mapping to inline MIME parts,
|
|
- skip unreferenced CID inline parts.
|
|
- Persist one `.eml` document per inbound message in in-app path using available MIME source fields (`rawMimeBase64`/`sourceMimeBase64`/`rawSourceBase64`) or deterministic fallback assembly when required.
|
|
- Apply idempotency to each artifact class:
|
|
- provider attachment,
|
|
- extracted embedded image,
|
|
- original email `.eml`.
|
|
- Wire IMAP webhook path to in-app processing mode with event-bus fallback only when explicitly configured.
|
|
|
|
### Safety / Performance
|
|
|
|
- Enforce ingress caps for IMAP payload processing:
|
|
- per-attachment max bytes,
|
|
- total attachment bytes,
|
|
- attachment count,
|
|
- max MIME bytes for `.eml` persistence.
|
|
- Keep byte-heavy work off the request critical path when async mode is enabled (app-local worker queue).
|
|
- Bound per-message artifact processing concurrency to prevent memory/CPU spikes.
|
|
|
|
### Data / Contract
|
|
|
|
- Normalize/validate inbound payload fields needed by in-app artifact pipeline:
|
|
- `attachments[].id|name|contentType|size|contentId|isInline|content`,
|
|
- `rawMimeBase64`/`sourceMimeBase64`/`rawSourceBase64`,
|
|
- `ingressSkipReasons`.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- In-app processing path (without workflow-worker) can ingest inbound email and produce ticket documents for:
|
|
- regular attachments,
|
|
- referenced embedded images,
|
|
- original `.eml`.
|
|
- Reprocessing the same message does not duplicate artifact documents.
|
|
- Oversize/over-limit artifacts are skipped with structured reasons while ticket/comment ingestion still succeeds.
|
|
- IMAP callback path supports in-app processing mode and honors caps.
|
|
|
|
## Risks
|
|
|
|
- Large base64 payloads may exceed request/body limits if not capped early.
|
|
- Byte decoding in request thread can degrade latency under burst conditions.
|
|
- Mixed provider payload shapes can cause subtle artifact loss if contract normalization is incomplete.
|
|
|
|
## Rollout
|
|
|
|
- Gate IMAP in-app artifact processing behind env/feature flags.
|
|
- Start with controlled tenants/providers, then expand.
|
|
|
|
## References
|
|
|
|
- Existing plan baseline (superseded for remaining-scope tracking):
|
|
- `ee/docs/plans/2026-02-27-inbound-email-embedded-images-and-original-eml/`
|