PRIME PRODUCTS · MISSION CONTROL
AI-first transformation · by TPL · vanos.tpl.one

Docs / 08-transformation/05-technical/integrations-m365-softone

Integrations — M365 & SoftOne

Entra ID SSO, Graph API ingestion, Teams as an assistant surface, meeting transcription flow, and the read-first SoftOne semantic layer.

type: blueprint updated: 2026-07-15 owner: kotsalidis

Integrations — Microsoft 365 & SoftOne

Microsoft 365

Identity: Entra ID everywhere

Entra ID is the single IdP. Open WebUI, n8n, Grafana, Langfuse — all behind OIDC SSO with MFA enforced by the existing conditional-access policies. No local accounts except break-glass admin (sealed, audited). Group membership in Entra drives both app RBAC and RAG ACL filters (rag-and-data-pipeline.md) — one place to onboard/offboard.

Graph API ingestion

  • One app registration per function (ingestion-sharepoint, ingestion-mail, teams-bot), each with least-privilege application scopes (e.g. Sites.Selected pinned to approved sites — not Sites.Read.All; specific shared mailboxes via application access policy — not org-wide Mail.Read).
  • Delta queries for SharePoint/OneDrive and mailboxes per the cadence table in rag-and-data-pipeline.md; calendar read only for the meeting-scribe flow.
  • Admin-consent grants documented per registration in ../../03-Infrastructure/_index.md; quarterly scope review.

Email-order-desk ingestion (REQ-014 pilot — first concrete case)

Evidence: Prime key-account discovery note, 2026-07-13/15 (first sample-corpus batch, 6 emails/5 threads from the cylinders pilot’s shared mailbox, fully distilled from the underlying PDFs).

Hard requirement, confirmed against real sample data: the plain M365 search connector does not expose nested message/rfc822 attachment content (“nested item content is not exposed”) — line items, quantities, prices, and terms live exclusively inside those attachments, which are themselves PDF documents (quotations, purchase orders, manufacturer sales-order acknowledgments, air waybills). Ingestion for this flow must use the Graph API attachments endpoint (/messages/{id}/attachments/$value, recursing into nested rfc822 parts) or IMAP/EWS against the shared mailbox, scoped via an application access policy, plus PDF text extraction with an OCR fallback — not the search-connector path used for general SharePoint/mail RAG ingestion above, and not text-only body parsing.

Draft design, to build out once mailbox access is confirmed (Evangelia, IT):

  • Subject parser (regex) for the pattern VSL: <vessel>, ORDER|QUOTATION: <ref>, VENDOR: <name>, plus MV <NAME> ETA <PORT> for vessel/port/ETA.
  • PDF filename parser — the type + reference is recoverable from the filename convention alone: orders E_ORD_<PO>.pdf, Prime quotations <OfferNo>.PDF, manufacturer sales-order acks <SO> so.pdf, <AWB> Shippers Copy.pdf.
  • Quote↔order matcher on two independent, cross-validating keys: (a) the shared base P.O. id (suffix convention A = quotation, B = order), and (b) the quotation’s Offer No reappearing as the order’s Vendor Reference.
  • Attachment extractor for nested rfc822 + PDF (OCR fallback) line items.
  • Four-tier party model: customer/shipowner-manager → Prime (broker) → manufacturer (observed: Martek Marine/FastCalGas, UK) → port delivery agent — each order references all four.
  • Draft data model: Vessel, Customer, Vendor/Manufacturer, PortAgent, Quotation, Order, SalesOrderAck, LineItem, Shipment/AWB, Thread/Message — currency-aware (EUR and USD both observed in the sample) with a lifecycle status field (RFQ → Quoted → Ordered → Acknowledged → Shipped → Delivered → Closed).
  • Idempotence/dedup across near-duplicate forwards, and per-thread state that keeps the latest valid message in chains with many nested forwards (observed up to 5 deep in the sample).

Open before build: full vendor/vessel range beyond Martek/FastCalGas and the three customers seen, whether the observed PDF templates are consistent across customers, the ERP/DB/spreadsheet landing point for a registered order, the desired approval flow, and how multi-currency/freight-as-separate-line should be handled downstream — see the analysis note’s Open questions.

Teams as an assistant surface

  • Phase 1 (now): a simple Teams bot (Azure Bot registration → webhook into n8n → LiteLLM) for Q&A against the Knowledge Assistant, plus link-out to Open WebUI for anything long-form. Cheap, ships in days, meets users where they are.
  • Phase 2: message extensions / link unfurling (e.g. paste a requisition list → matched IMPA codes inline), and adaptive-card approval buttons for agent human-approval steps (quote drafts, reminder letters).
  • Deliberately not: a custom Copilot-style full client in Teams — Open WebUI is the rich surface.

Meeting transcription flow

Teams recording (or uploaded audio) → n8n picks up via Graph → Whisper large-v3 (Greek/English, on-prem — recordings never leave) → prime-large summary with decisions/actions → draft Obsidian meeting note pushed as a git branch/PR to the vault (../06-knowledge-base/obsidian-vault-blueprint.md) → human reviews and merges. Drafts are drafts; the vault stays curated.

SoftOne ERP

Assumption flag (verify in M2): recent Soft1 versions expose Web Services / REST APIs adequate for scheduled reads of catalog, stock, prices, customers, and open orders. Confirm exact capability, licensing of the WS module, and rate limits with the SoftOne partner before committing the extract design. Fallback: scheduled DB views/exports agreed with the partner.

Read-first: the semantic layer

  • Nightly + on-demand extracts of product catalog, price lists, stock, customers, open orders, receivables aging into PostgreSQL semantic-layer tables: clean English snake_case columns (product_code, impa_code, qty_on_hand, customer_credit_limit…), documented in a data dictionary, stable even if SoftOne schemas move.
  • NL-to-SQL runs over this read replica only — a curated, commented schema small enough for reliable text-to-SQL, with row counts and freshness timestamps surfaced in every answer (“stock as of last night 02:00”). The ERP Query Agent and Report Narrator (../08-ai-portfolio/ai-agent-registry.md) read from here.
  • No direct writes to SoftOne. Ever, in phase 1.

Phase-2 write-backs (gated)

Draft quotes/orders created only via the official Soft1 API as drafts, appearing in the ERP’s own workflow for a human to review and post — approval happens in-ERP, where users already have permissions and audit. Requires SoftOne partner engagement (scoping, WS licensing, test environment) — flagged as an external dependency in ../02-program/risk-register.md.

E-shop

Nightly catalog/stock feed into the semantic layer + embedded product texts for RAG (product Q&A, IMPA matching support). Phase 2: draft product-description generation (Greek/English) pushed to the shop backend as unpublished drafts. No customer/order PII ingested from the shop in phase 1.

Integration security

  • Secrets: all client secrets/certificates and API credentials live in 1Password, referenced as op:// URIs from deployment tooling — never in Compose files, n8n credentials exports, or this vault. (Prime Products 1Password vault provisioning is pending — until then no credential is recorded anywhere, per repo policy.)
  • Certificate credentials over client secrets for Graph app registrations where possible; rotation calendar (≤12 months) owned by the platform engineer.
  • Service accounts per integration, never personal accounts; SoftOne WS user is read-only-scoped in phase 1.
  • Every integration call is logged (n8n execution log + audit DB); Graph and SoftOne extract failures alert to the IT Teams channel.
  • Full zoning/egress model in security-and-operations.md.