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.
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 backpending; 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 itssendslist 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 artifact | Code source of truth |
|---|---|
| Query/command input schemas | the zod inputSchema on each registerTool call |
| Response shapes | the TypeScript model files (*.model.ts) |
| Event payloads + lifecycle | the Proposal model + ProposalStatus enum |
| Proposal-store ERD | the Drizzle schema (src/approvals/postgres/schema.ts) |
| Per-workflow service send/receive maps | the Nest DI graph (each workflow service’s constructor injections) |
| The per-tool flows | tool → 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.