Skip to content

[edoc] E-Document Messages V3 — framework primitives + Spike-EDI#8373

Draft
Groenbech96 wants to merge 3 commits into
mainfrom
edoc-messages-v3-spike
Draft

[edoc] E-Document Messages V3 — framework primitives + Spike-EDI#8373
Groenbech96 wants to merge 3 commits into
mainfrom
edoc-messages-v3-spike

Conversation

@Groenbech96
Copy link
Copy Markdown
Contributor

@Groenbech96 Groenbech96 commented May 28, 2026

Summary

Foundational V3 architecture for E-Document Messages — the second primitive alongside Documents — landed in E-Document Core, plus a thin spike (Spike-EDI) that exercises all four V3 quadrants end-to-end without touching any production handler.

This PR is draft for architectural review. It's a foundation: it does not migrate any existing handler (PEPPOL Responses, MX Payment Complement, FR Collected, BC Remittance, etc.) to the new model. Migration sequencing is deferred.

The two primitives

Document Message
Has its own BC identity? Yes — E-Document row No — relates to an existing E-Document
Test Does the wire artifact get an identity, or does it only affect existing identities?
Example (in) PEPPOL Invoice -> Purchase Invoice PEPPOL Invoice Response -> parent status
Example (out) MX Payment Complement FR Collected, BC Remittance notification

Full mental model: App/docs/e-document-messages_V3.md. V1 and V2 drafts are included alongside so the design evolution is visible.

What's in core

  1. Data: "E-Document Message" table, supporting enums (Type / Status / Trigger Source), typed inbound buffer with optional inline payload, lookup temp buffer.

  2. Three message-side interfaces with strict ownership split:

    • IEDocumentMessageType — identity, applicability, state-transition intent, UX delegation
    • IEDocumentMessageReader — inbound parse (pure IO)
    • IEDocumentMessageWriter — outbound generate (pure IO)
  3. Apply Context — the Type declares intent (SetParentStatus, SignalIgnored, SetErrorStatus, AddLogNote) on an "E-Doc. Msg. Apply Context" codeunit. The Type never mutates state directly. Framework reads the declared intent and executes uniformly: lock parent's Service Status, persist transition, write "E-Document Log" entries, fire workflow event, update message internal status.

  4. Two opt-in transport extensions on the existing connector contracts:

    • IDocumentSenderMessages (extends IDocumentSender, single SendMessage method)
    • IDocumentReceiverMessages (extends IDocumentReceiver, two-stage ListMessages + DownloadMessage — the typed buffer carries an optional inline payload so connectors with batch / webhook APIs skip the second call)

    Existing document-only connectors are unchanged. Framework uses is / as to test for support — same idiom as ISentDocumentActions extending IDocumentSender today.

  5. Orchestrators: "E-Doc. Send Message" (outbound), "E-Doc. Receive Messages" (inbound dispatcher), "E-Doc. Apply Message" (shared post-event step).

  6. 12 new role-paired Service Status values (40-51). Receiver / Sender prefix describes who acted on the parent document — direction-neutral, so the same value reads correctly whether we are the sender or receiver of the parent. PEPPOL BIS 63 sequence, MLR latest-wins, FR Collected, MX payment acknowledged all map cleanly.

  7. GetSupportedMessages() on IStructuredDataType — a format declares its native message vocabulary; existing implementers ship a no-op stub.

  8. UI: Send Message + Receive Messages actions on the E-Document card and on E-Document Purchase Draft.

What's in Spike-EDI

A thin implementer app (not part of the product) covering all four V3 quadrants:

Quadrant Demonstrated by
Outbound Document Sales Invoice posting -> Contoso Invoice XML on Outbound mailbox row
Inbound Document Mailbox Inbound row -> existing receive pipeline -> Purchase staging
Outbound Message Send Message action -> Contoso Invoice Ack writer -> Outbound mailbox row
Inbound Message Process Inbound Messages -> reader parses -> Ack Type declares Receiver Accepted on the Apply Context -> framework persists transition + logs

The ContosoMailbox table simulates the network: its OnInsert trigger clones every inserted row to the opposite direction with Insert(false). One connector write produces both the audit row and the partner echo — the demo path is zero-click between send and receive. A real connector would not need this; production traffic crosses an actual network.

Spike walkthrough: Spike-EDI/README.md.

What's explicitly out of scope

The foundation deliberately stops short. Real concerns that the spike will help shape next:

  • Workflow event design for messages (signature, payload context, granularity)
  • Profile model — Document Sending Profile vs new Message Sending Profile
  • Trigger registry shape — direct subscribers vs central registry
  • Concurrency mechanics — lock placement, retry, idempotency
  • Unresolved-message quarantine — schema, retention, admin UI
  • Phasing & migration sequencing for existing handlers
  • Overlap with IDocumentAction — synchronous REST post-send actions (Approval, Cancellation queries) coexist with V3 Messages until a future cleanup re-models cancellation-as-Message where the protocol has a real wire artifact

See V3 §8 for the full deferred list.

Test plan

  • Build and publish E-Document Core (this PR) and Spike-EDI (the PR app) onto a fresh tenant.
  • Configure an E-Document Service with Format = Contoso Invoice and Service Integration V2 = Contoso Connector. Attach to a Document Sending Profile for a test customer.
  • Outbound Document: post a Sales Invoice. Mailbox shows Outbound/Document row + auto-twinned Inbound/Document row. E-Document Log shows the Send event.
  • Inbound Document: run inbound on the service. Existing pipeline picks up the twinned Inbound/Document row, populates Purchase Draft, finishes to Purchase Invoice.
  • Outbound Message: from the outbound E-Document, click Send Message, pick Contoso Invoice Ack. Mailbox shows Outbound/Message + auto-twinned Inbound/Message row. Service Status unchanged (apply runs but Ack is buyer-driven so it transitions the parent).
  • Inbound Message: from Mailbox, click Process Inbound Messages. Parent Service Status advances to Receiver Accepted. E-Document Log shows the parse, the apply, and the status transition entries. Re-running is idempotent — no second Inbound row is created (already Processed).
  • Build and publish E-Document Core without Spike-EDI. Verify existing PEPPOL / Avalara / Pagero connectors still build (the four interfaces are opt-in extensions, not modifications).

Reviewer guide

Suggested reading order:

  1. App/docs/e-document-messages_V3.md §1-2 — the two primitives + generation pattern
  2. App/docs/e-document-messages_V3.md §3 — state transition mechanism (Type declares intent, framework executes)
  3. App/src/Document/Message/Interfaces/ + App/src/Integration/Interfaces/IDocument*Messages.Interface.al — the contracts
  4. App/src/Document/Message/EDocApplyMessage.Codeunit.al — where intent gets executed uniformly
  5. Spike-EDI/src/ContosoMessages/ContosoAckType.Codeunit.al — the simplest possible Type implementation

Magnus Hartvig Grønbech and others added 3 commits May 28, 2026 15:58
Introduces the V3 Messages framework into E-Document Core. A Message
relates to an existing E-Document (does not produce a BC document) and
drives state on the parent via role-paired Service Status values.

Core additions:
- "E-Document Message" table + supporting enums (Type, Status, Trigger
  Source) and lookup/buffer temp tables.
- Type/Reader/Writer interface split — IEDocumentMessageType owns
  identity + applicability + state-transition intent + UX; Reader and
  Writer are pure IO.
- Apply Context — Type declares intent (parent status, ignore reason,
  error, log notes); framework executes uniformly (lock, persist, log
  via EDocumentLog, fire event).
- Opt-in interface extensions IDocumentSenderMessages and
  IDocumentReceiverMessages on the transport layer. Existing
  document-only connectors are unaffected; framework uses is/as to
  test for support (same idiom as ISentDocumentActions today).
- Orchestrators: E-Doc. Send Message (outbound), E-Doc. Receive
  Messages (inbound dispatcher), E-Doc. Apply Message (shared
  post-event step).
- 12 new role-paired Service Status values (40-51) describing who
  acted on the parent document: Receiver / Sender prefix keeps the
  status direction-neutral.
- GetSupportedMessages() on IStructuredDataType so a format declares
  its native message vocabulary; existing implementers ship a no-op
  stub.
- Send Message + Receive Messages actions on the E-Document card and
  on E-Document Purchase Draft.

Helper: EDocumentHelper now opens the E-Document card directly for
outbound rows (V2 import pipeline only branches on inbound).

App id range 6340-6360 reserved for the framework codeunits.

Design doc: src/Apps/W1/EDocument/App/docs/e-document-messages_V3.md

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Thin implementer app (not part of the product) that wires the V3
Messages framework through a fictional XML format and a mock
connector. Validates all four V3 quadrants:

  Outbound Document  — Sales Invoice -> Contoso Invoice XML
  Inbound Document   — Contoso Invoice XML -> Purchase staging
  Outbound Message   — User triggers Contoso Invoice Ack
  Inbound Message    — Partner echo Ack -> parent Service Status

Contents:
- ContosoConnector — implements all four transport interfaces
  (IDocumentSender, IDocumentReceiver, IDocumentSenderMessages,
  IDocumentReceiverMessages). Reads / writes only its own mailbox
  table; zero framework calls.
- ContosoMailbox — table simulating the network. OnInsert clones each
  row to the opposite direction with Insert(false), so a single
  connector write produces both the audit row and the partner echo.
  Page exposes View Content and Process Inbound Messages.
- ContosoFormat — Contoso Invoice format implementing the "E-Document"
  interface (outbound Create) plus IStructuredDataType +
  IStructuredFormatReader (inbound ReadIntoDraft into the Purchase
  staging tables). Advertises native message support via
  GetSupportedMessages.
- ContosoMessages — Contoso Invoice Ack: Type (declares intent on the
  Apply Context — 'ACCEPTED' -> Receiver Accepted, 'REJECTED' ->
  Receiver Rejected; never mutates state directly), Reader, Writer.

Adds Spike-EDI to the EDocumentCore workspace.

See Spike-EDI/README.md for the manual demo path and V3 design doc
links.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Foundational design for V3 plus the V1 and V2 drafts it builds on, so
the iteration is visible.

  lifecycle-messages_V1.md
      Generalizes the inbound PEPPOL Responses proposal driven by
      French e-reporting (Collected / Refused / Negative Collected).
      First framing as "Lifecycle Messages".

  e-document-messages_V2.md (supersedes V1)
      Comprehensive cut: introduces document-vs-message distinction,
      format ownership, bi-directionality. Mixed primitives with
      phasing, worked examples, and open calls.

  e-document-messages_V3.md (supersedes V2)
      Foundation only — trims to the mental model an implementer
      needs before reading or writing code. Two primitives (Document,
      Message), uniform generation pattern, parallel inbound entry
      points (existing IDocumentReceiver unchanged; opt-in
      IDocumentReceiverMessages added), Type-owns-semantics /
      framework-owns-execution split, role-paired Service Status
      vocabulary, two-table data model. Phasing, workflow events,
      profile schema, concurrency mechanics, IDocumentAction overlap
      — all deferred until the spike grounds them. V3 reflects the
      finalized signatures from Spike-EDI.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the AL: Apps (W1) Add-on apps for W1 label May 28, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Could not find a linked ADO work item. Please link one by using the pattern 'AB#' followed by the relevant work item number. You may use the 'Fixes' keyword to automatically resolve the work item when the pull request is merged. E.g. 'Fixes AB#1234'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AL: Apps (W1) Add-on apps for W1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant