domain

QMax Operations (Service Mesh)

The QMax service mesh: a layered NestJS build exposing the QMax platform as one remote MCP server, split CQRS-style into per-workflow read services and a human-gated approval bus + appliers over a shared proposal store.

DomainCQRS — queries direct, commands via the approval busBeta: read-only, WRITE_MODE=disabled

Overview

The mesh is CQRS, not CRUD — the ratified mental model for the whole system:

  • Queries are normal request/response: MCP tool → workflow service → foundational service → vendor client. No side effects, no bus, no events — a read’s “inner workings” are exactly which vendor reads it fans into, and that fan-out is on each service page.
  • Commands never write directly: propose_* queues a proposal on the Proposal StoreProposal StoreContainerv0.1.0The shared CQRS database: every proposal, its payload, status transitions, decisions, results and per-card widget token....Ownervisionary-engineeringMapView docs and comes back pending; a cleared human approves in the card; only then does the kind’s applier execute the one vendor write. Data flows back only via the proposal record.
  • One shared database — the Approval Bus (command service — owns the queue)Approval Bus (command service — owns the queue)Servicev0.1.0The command side: owns the proposal queue. propose_* only queue; a cleared human approves in the card; only then does th...Publishesproposal-created, proposal-approved +3Subscribespropose-vendor-bill, propose-bill-date-correction +6Ownervisionary-engineeringMapRepoView docs owns the queue, the read side reads the same store. Deliberately not event-sourced, not two datastores.

How to read this catalog (the grain)

  • A message page (query/command/event) is the contract — it renders one hop: who sends, who receives. That’s by design, not a gap.
  • A service page is the behavior — one service per workflow, mirroring src/workflows/*, so its sends list IS that workflow’s exact vendor fan-out.
  • A flow page is the lifecycle — one flow per tool, so you can watch a single tool call travel the system end to end. Read flows end at the vendor services (no events); command flows run the full propose → event → approve → apply chain.

The 9 Phase-2 production workflows map onto this split: 4 reads (Daily Pipeline View — tool-call lifecycleDaily Pipeline View — tool-call lifecycleFlowv0.1.0One daily_pipeline_view call end to end: single-source into ClaritySoft, rolled up by stage. The simplest read path — an...Ownervisionary-engineeringView flowView docs · Cash Flow Tracker — tool-call lifecycleCash Flow Tracker — tool-call lifecycleFlowv0.1.0One cash_flow_tracker call end to end: the query hits CashFlowService, which fans into QBO + Fishbowl + ClaritySoft in p...Ownervisionary-engineeringView flowView docs · KPI Scorecard — tool-call lifecycleKPI Scorecard — tool-call lifecycleFlowv0.1.0One kpi_scorecard call end to end: four sources fold into 7 KPIs; with publish: true the service performs the one direct...Ownervisionary-engineeringView flowView docs · Project Hunter — tool-call lifecycleProject Hunter — tool-call lifecycleFlowv0.1.0One project_hunter call end to end: score the public candidate feed against the domain rubric, cross-reference ClaritySo...Ownervisionary-engineeringView flowView docs) + the account join (Customer Account Join — tool-call lifecycleCustomer Account Join — tool-call lifecycleFlowv0.1.0list_customer_accounts / find_customer_account end to end: the three-system account join (CRM + accounting + inventory) ...Ownervisionary-engineeringView flowView docs) + 5 gated writes (Propose Vendor Bill — command lifecyclePropose Vendor Bill — command lifecycleFlowv0.1.0One propose_vendor_bill call end to end: queue → ProposalCreated → human approve → ProposalApproved → applier routes by ...Ownervisionary-engineeringView flowView docs · Propose Bill-Date Correction — command lifecyclePropose Bill-Date Correction — command lifecycleFlowv0.1.0One propose_bill_date_correction call end to end — the recommended FIRST live command: single reversible field, QBO-only...Ownervisionary-engineeringView flowView docs · Propose Customer Invoice — command lifecyclePropose Customer Invoice — command lifecycleFlowv0.1.0One propose_invoice call end to end: queue → human approve → applier creates the QBO invoice from the approved lines.Ownervisionary-engineeringView flowView docs · Propose Sales Order — command lifecyclePropose Sales Order — command lifecycleFlowv0.1.0One propose_order_entry call end to end: queue → sales approves → applier imports a draft SO (status Estimate) via Fishb...Ownervisionary-engineeringView flowView docs · Propose AR Collections Email — command lifecyclePropose AR Collections Email — command lifecycleFlowv0.1.0One propose_ar_collection_email call end to end: queue → human reviews AND CAN EDIT subject/body → approve is the send →...Ownervisionary-engineeringView flowView docs). Each is an MCP tool and an invocable MCP prompt (the front door).

Where this catalog could be generated from code (Atlas direction)

Catalog artifactCode source of truth
Query/command input schemasthe zod inputSchema on each registerTool call
Response shapesthe TypeScript model files (*.model.ts)
Event payloads + lifecyclethe Proposal model + ProposalStatus enum
Proposal-store ERDthe Drizzle schema (src/approvals/postgres/schema.ts)
Per-workflow service send/receive mapsthe Nest DI graph (each workflow service’s constructor injections)
The per-tool flowstool → workflow service → injected services → clients, walked from qmax-mcp.server.ts

Hand-maintained today (via gen-catalog.mjs in this directory — the tables at the top of that script are the editable source); each row is mechanically derivable — that’s the evaluation this catalog is running.