Domain · Specifications

Maat Domain — Technical Specifications

The foundational types live in libs/maat/core/src/organization.ts.

12sections22 minread

On this page

Maat — Portfolio Intelligence and Business Management Platform

This document specifies what is implemented in the Maat domain. It is grounded in the source under libs/maat/*, apps/maat/*, and libs/contracts/maat/. Every entity, field, enum value, event, endpoint, permission, and count below was read from source: libs/maat/core/src/ {organization,event-bus,redis-namespace}.ts, libs/maat/*/src/index.ts, libs/maat/finance/src/v2-persistence-ledger.ts, libs/maat/strategy/src/v2-fighting-game-live-ops-calendar.ts, libs/maat/dashboard/src/v2-balance-dashboard.ts, libs/maat/negotiation-intelligence/src/procurement-program.ts, libs/maat/knowledge/src/knowledge-graph-neo4j-schema.ts, libs/maat/sdk/src/typed-client.ts, apps/maat/api-gateway/src/{app,openapi/spec,middleware/api-versioning, realtime/websocket-server}.ts, and the apps/maat/* route trees. Where a capability is present only as a scaffold or is named in a phase backlog, it is labelled accordingly.


1. Domain Object Model (@maat/core)#

The foundational types live in libs/maat/core/src/organization.ts. This single file defines the entire shared domain vocabulary for the Maat platform: branded ID types that prevent accidental cross-type assignment, frozen enum value arrays, Zod schemas for every entity, and a complete set of constructor, serializer, and type guard functions. There is no ORM — all entities are in-memory value objects that can be validated, constructed, and serialized without a database.

For each entity, organization.ts follows a consistent pattern:

  • A *Draft interface accepts loosely typed inputs (strings, partial objects).
  • create<Entity>(draft) validates and normalises the draft, throwing on invalid input.
  • create<Entity>WithDefaults(overrides?) deep-merges a DeepPartial over a built-in default object, making test setup concise.
  • serialize<Entity>(value) / deserialize<Entity>(serialized) provide JSON round-trip helpers.
  • is<Entity>(value) is an unknown-narrowing type guard.

1.1 Branded Identifier Types#

To prevent accidental cross-type mixing at compile time (passing an AgentId where an OrganizationId is expected), every entity identifier is a branded string type. Each type enforces a known prefix pattern and has a dedicated constructor function. The table below lists the 13 entity ID types and their regex patterns, all case-insensitive.

organization.ts defines a Brand<T, B> helper and these branded string IDs, each with a regex pattern and a create*Id constructor:

Type Pattern (case-insensitive)
OrganizationId org_[a-z0-9][a-z0-9_-]{2,62}
OperatingCompanyId opco_[a-z0-9][a-z0-9_-]{2,62}
BusinessUnitId bu_[a-z0-9][a-z0-9_-]{2,62}
MarketId market_[a-z0-9][a-z0-9_-]{2,62}
CompetitorId competitor_[a-z0-9][a-z0-9_-]{2,62}
ProjectId project_[a-z0-9][a-z0-9_-]{2,62}
KPIId kpi_[a-z0-9][a-z0-9_-]{2,62}
RiskId risk_[a-z0-9][a-z0-9_-]{2,62}
AgentId agent_[a-z0-9][a-z0-9_-]{2,62}
ScenarioId scenario_[a-z0-9][a-z0-9_-]{2,62}
DashboardId dashboard_[a-z0-9][a-z0-9_-]{2,62}
AlertId alert_[a-z0-9][a-z0-9_-]{2,62}
AuditEventId audit_[a-z0-9][a-z0-9_-]{2,62}

ISODateString (YYYY-MM-DD) and ISODateTimeString (UTC ISO-8601) are also branded; isISODateString, createISODateString, isISODateTimeString, and createISODateTimeString validate and construct them.

1.2 Enums and Literal-Union Value Arrays#

Rather than TypeScript enum declarations, every enumerated set is expressed as a frozen *_VALUES as const array with a derived union type. This pattern makes the full value set available at runtime (for validation, UI dropdowns, and API responses) while also providing compile-time type narrowing.

The following table lists all value arrays and their members.

Value array Members
LEGAL_ENTITY_TYPE_VALUES HOLDING_COMPANY, CONGLOMERATE, PRIVATE_LIMITED, PUBLIC_LIMITED, PARTNERSHIP, COOPERATIVE, NON_PROFIT, STATE_OWNED
LEGAL_STRUCTURE_MODEL_VALUES SINGLE_ENTITY, HOLDING_WITH_SUBSIDIARIES, MULTI_HOLDING, FEDERATED
OWNERSHIP_MODEL_VALUES PRIVATELY_HELD, PUBLICLY_TRADED, STATE_OWNED, MIXED
OPERATING_COMPANY_INDUSTRY_SECTOR_VALUES AGRICULTURE, MANUFACTURING, ENERGY, LOGISTICS, FINANCIAL_SERVICES, TECHNOLOGY, HEALTHCARE, CONSUMER_GOODS, REAL_ESTATE, PROFESSIONAL_SERVICES
OPERATING_COMPANY_BOARD_ROLE_VALUES CHAIRPERSON, EXECUTIVE_DIRECTOR, NON_EXECUTIVE_DIRECTOR, INDEPENDENT_DIRECTOR
MARKET_GEOGRAPHIC_REGION_VALUES GHANA, WEST_AFRICA, PAN_AFRICAN, GLOBAL
COMPETITOR_THREAT_LEVEL_VALUES LOW, MEDIUM, HIGH, CRITICAL
PROJECT_STATUS_VALUES PROPOSED, APPROVED, IN_PROGRESS, COMPLETED, CANCELLED
KPI_METRIC_TYPE_VALUES FINANCIAL, OPERATIONAL, STRATEGIC, ESG
KPI_MEASUREMENT_FREQUENCY_VALUES REAL_TIME, DAILY, WEEKLY, MONTHLY, QUARTERLY, ANNUALLY
KPI_TREND_DIRECTION_VALUES INCREASING, DECREASING, STABLE
KPI_THRESHOLD_COMPARATOR_VALUES GT, GTE, LT, LTE
KPI_THRESHOLD_SEVERITY_VALUES INFO, WARNING, CRITICAL
REGULATION_JURISDICTION_VALUES GHANA, ECOWAS, AFCFTA, INTERNATIONAL
RISK_CATEGORY_VALUES MARKET, CREDIT, OPERATIONAL, REGULATORY, POLITICAL, ENVIRONMENTAL, SUPPLY_CHAIN
RISK_REVIEW_CADENCE_VALUES WEEKLY, MONTHLY, QUARTERLY, SEMI_ANNUALLY, ANNUALLY
AGENT_CLASS_VALUES STRATEGY, ENGINEERING, FINANCE, OPERATIONS, RESEARCH, COMPLIANCE
AGENT_TASK_PRIORITY_VALUES LOW, MEDIUM, HIGH, URGENT
AGENT_TASK_STATUS_VALUES QUEUED, IN_PROGRESS, BLOCKED
SCENARIO_CATEGORY_VALUES BASE_CASE, BEST_CASE, WORST_CASE, CUSTOM
DASHBOARD_OWNER_TYPE_VALUES USER, AGENT
DASHBOARD_LAYOUT_TYPE_VALUES GRID, FREEFORM
DASHBOARD_DATA_SOURCE_MODE_VALUES PULL, PUSH
DASHBOARD_PERMISSION_SUBJECT_TYPE_VALUES USER, ROLE, AGENT
DASHBOARD_PERMISSION_LEVEL_VALUES VIEWER, EDITOR, OWNER
ALERT_SEVERITY_VALUES INFO, WARNING, CRITICAL, EMERGENCY
ALERT_ACTION_PRIORITY_VALUES LOW, MEDIUM, HIGH, URGENT
ALERT_ESCALATION_CHANNEL_VALUES EMAIL, SMS, SLACK, PAGER
ALERT_ACKNOWLEDGMENT_STATUS_VALUES UNACKNOWLEDGED, ACKNOWLEDGED
AUDIT_EVENT_TYPE_VALUES CREATE, UPDATE, DELETE, APPROVE, REJECT, ASSIGN, ESCALATE, ACKNOWLEDGE, RESOLVE
AUDIT_EVENT_ACTOR_TYPE_VALUES USER, AGENT
AUDIT_COMPLIANCE_CLASSIFICATION_VALUES PUBLIC, INTERNAL, CONFIDENTIAL, RESTRICTED
SYNERGY_CATEGORY_VALUES REVENUE, COST, KNOWLEDGE, OPERATIONAL

1.3 Core Entities#

The 15 root entities are Organization, OperatingCompany, BusinessUnit, Market, Competitor, Project, KPI, Regulation, Risk, Agent, Scenario, Dashboard, Alert, AuditEvent, and Synergy. Each has a matching *Draft interface (loosely typed inputs accepted by the create* constructor) and an exported Zod schema. The detailed field specifications follow.

Organization#

The top-level entity representing the holding group that owns the portfolio companies.

Field Type Meaning
id OrganizationId Branded organization identifier
name string Non-empty trimmed name
legalEntityStructure LegalEntityStructure Entity type, structure model, ownership model, and registrations (≥ 1, exactly one isPrimary)
incorporationJurisdiction IncorporationJurisdiction countryCode, optional stateOrRegion/city, legalRegime, regulator
foundingDate ISODateString Incorporation date
missionStatement string Non-empty mission text
operatingCompanies OrganizationOperatingCompany[] ≥ 1 references: companyId, name, strategicRole, ownershipPercent
consolidatedFinancialSummary ConsolidatedFinancialSummary currencyCode, fiscalYear, revenue, grossProfit, ebitda, netIncome, totalAssets, totalLiabilities, shareholdersEquity, operatingCashFlow, freeCashFlow, debtToEquityRatio

OperatingCompany#

Represents one of the seven portfolio companies. Captures Ghana-specific regulatory identifiers (GRA TIN, SSNIT employer number) alongside standard company metadata, reflecting the platform's Ghana-first compliance posture.

Field Type Meaning
id OperatingCompanyId Branded company identifier
name string Company name
industrySector OperatingCompanyIndustrySector Sector classification
isicClassificationCode string ISIC code (section letter + 2–4 digits)
ghanaRegistrationNumber string Registrar of Companies number (prefix C/CS/BN/CG/RGD + 3–12 digits)
graTaxIdentificationNumber string GRA TIN (leading letter + 8–12 digits)
ssnitEmployerNumber string SSNIT employer number (5–12 digits)
headquartersLocation OperatingCompanyHeadquartersLocation countryCode, optional region, city, optional address/postal code
subsidiaries OperatingCompanySubsidiaryReference[] subsidiaryCompanyId, name, ownershipPercent
ceo OperatingCompanyExecutiveReference executiveId, fullName, title, appointedAt
boardMembers OperatingCompanyBoardMember[] memberId, fullName, role, appointedAt, optional termEndAt
annualRevenueRange OperatingCompanyAnnualRevenueRange currencyCode, fiscalYear, minimum, maximum

BusinessUnit#

A division within an operating company, with its own product lines, factory locations, P&L summary, and workforce count.

Fields: id, parentCompanyId, name, graTaxIdentificationNumber, ssnitEmployerNumber, productLines[] (name, category, annualOutputUnits), factoryLocations[] (siteCode, countryCode, region, city, primaryProducts[]), employeeCount, capacityUtilizationPercent, and profitAndLossSummary (currencyCode, fiscalYear, revenue, costOfGoodsSold, grossProfit, operatingExpenses, operatingProfit, netProfit).

Market#

Describes a market segment that portfolio companies operate in or are evaluating for entry, including size estimates (TAM/SAM/SOM) and a regulatory complexity index.

Fields: id, name, geographicRegion, sectorClassification, sizeEstimates (currencyCode, referenceYear, tam, sam, som), annualGrowthRatePercent, competitiveIntensityScore, regulatoryComplexityIndex.

Competitor#

Tracks a named competitor with its market share, strengths, weaknesses, a timestamped timeline of recent moves, a threat level, and an intelligence freshness timestamp so stale competitive data is always visible.

Fields: id, name, marketSharePercent, strengths[], weaknesses[], recentMovesTimeline[] (happenedAt, headline, summary), threatLevel, intelligenceFreshnessTimestamp.

Project#

A tracked initiative owned by a business unit, with budget allocation, actual spend, milestones, assigned agents, and a reference to the risk register.

Fields: id, owningBusinessUnitId, name, description, status, budgetAllocation (currencyCode, amount), actualSpend, timelineMilestones[] (milestoneId, name, targetDate, optional completionDate), assignedAgents[] (agentId, role, allocationPercent), riskRegisterReference.

KPI#

A Key Performance Indicator with a target value, actual value, measurement frequency, trend direction, and a set of threshold alerts that fire when the metric crosses configured boundaries.

Fields: id, name, description, metricType, targetValue (value, unit), actualValue, measurementFrequency, trendDirection, thresholdAlerts[] (alertId, thresholdValue, comparator, severity, message), responsibleBusinessUnitId.

Regulation#

A regulatory requirement from a specific body, in a specific jurisdiction, with compliance requirements, associated penalties, and a list of affected business units. Note that Regulation has no branded ID — it is identified by jurisdictionCode + regulationIdentifier.

Fields: jurisdiction, regulatoryBodyName, regulationIdentifier, effectiveDate, complianceRequirements[] (requirementId, description, isMandatory, optional dueDate), penaltyStructure (optional currencyCode, optional min/max monetary penalty, nonMonetaryPenalties[]), affectedBusinessUnitIds[].

Risk#

A risk entry in a risk register, with a composite risk score derived from likelihood and impact scores, mitigation strategies, an owner reference, and a review schedule with a next-review date.

Fields: id, category, likelihoodScore, impactScore, compositeRiskScore, mitigationStrategies[], ownerReference (ownerId, ownerName, ownerRole), reviewSchedule (cadence, nextReviewDate, optional lastReviewedDate).

Agent#

An AI agent registration record. Each agent has a class (strategy, engineering, finance, operations, research, or compliance), a capability list validated against the AGENT_CAPABILITY_MATRIX, assigned tools, a memory context window size, a performance score, and a current task queue.

Fields: id, agentClass, name, capabilities[], assignedTools[], memoryContextWindow, performanceScore, currentTaskQueue[] (AgentTaskQueueItem: taskId, title, priority, status). The constructor checks each capability against AGENT_CAPABILITY_MATRIX, a per-AgentClass map of allowed capability strings.

Scenario#

A named simulation scenario with probabilistic weighting, outcome projections (a record of metric names to numeric values), and sensitivity parameters that bound the key assumptions.

Fields: id, name, description, scenarioCategory, assumptions[], timeHorizonMonths, probabilityWeight, simulatedOutcomes (record of string → number), sensitivityParameters[] (parameterName, baseValue, minimumValue, maximumValue).

Dashboard#

A configurable dashboard entity owned by a user or agent, with a grid or freeform layout, widget definitions with pixel positions, data-source bindings, refresh interval, and per-subject access permissions.

Fields: id, ownerReference (ownerId, ownerType, displayName), layoutConfiguration (layoutType, columns, rowHeight), widgetDefinitions[] (widgetId, widgetType, title, position {x,y,width,height}), dataSourceBindings[] (bindingId, widgetId, sourceKey, mode), refreshIntervalSeconds, accessPermissions[] (subjectType, subjectId, permissionLevel), lastViewedTimestamp.

Alert#

A system alert representing a condition requiring attention, with an escalation chain that automatically escalates to successively higher-level targets after configurable timeout windows.

Fields: id, severity, category, title, description, sourceSystem, affectedEntities[] (entityType, entityId), recommendedActions[] (actionId, description, priority, optional ownerId), acknowledgmentStatus, escalationChain[] (level, target, channel, triggerAfterMinutes).

AuditEvent#

An immutable audit record capturing who did what to which entity, with before/after state snapshots, a compliance classification, and a correlation ID for distributed tracing.

Fields: id, eventType, actor (actorType, actorId, optional actorDisplayName), targetEntity (entityType, entityId, optional entityName), actionPerformed, previousStateSnapshot, newStateSnapshot, timestamp, correlationId, complianceClassification.

Synergy#

A quantified inter-company synergy opportunity, linking a source business unit to a target business unit with an estimated annual value, a realization timeline, a probability score, and prerequisite dependencies. Note that Synergy has no branded ID.

Fields: sourceBusinessUnitId, targetBusinessUnitId, category, estimatedAnnualValue (currencyCode, amount, referenceFiscalYear), realizationTimeline (plannedStartDate, targetRealizationDate), probabilityScore, dependencyPrerequisites[] (code, description).

1.4 Constructors, Serialization, and Type Guards#

For each of the 15 entities, organization.ts exports the following — all must be present when adding a new entity:

  • create<Entity>(draft) — validates and normalises a *Draft, throwing on invalid input;
  • create<Entity>WithDefaults(overrides?) — deep-merges a DeepPartial over a built-in default object;
  • serialize<Entity>(value) / deserialize<Entity>(serialized) — JSON round-trip helpers;
  • is<Entity>(value)unknown-narrowing type guard.

The Ghana-identifier schemas GhanaCompanyRegistrationNumberSchema, GRATaxIdentificationNumberSchema, and SSNITEmployerNumberSchema are exported for reuse by any library that needs to validate these identifiers independently.


2. Domain Event System (@maat/core)#

Defined in libs/maat/core/src/event-bus.ts. There is no Redis-backed bus; the implementation is a typed in-process bus. Events are the mechanism by which domain activities (market signals, agent completions, strategy decisions, compliance alerts, simulation progress) notify other parts of the system without creating direct library dependencies between them.

2.1 Event Types#

All domain events conform to exactly five types, each with its own Zod payload schema. MaatDomainEventTypeSchema is a Zod enum of these five values:

Event type Payload schema
MarketIntelligenceEvent MarketIntelligenceEventPayloadSchema
AgentTaskEvent AgentTaskEventPayloadSchema
StrategyDecisionEvent StrategyDecisionEventPayloadSchema
ComplianceAlertEvent ComplianceAlertEventPayloadSchema
SimulationStateEvent SimulationStateEventPayloadSchema

2.2 Base Envelope#

Every event extends a shared base envelope, ensuring consistent tracing metadata regardless of event type. BaseMaatEventSchema requires: eventId (UUID), eventType, schemaVersion (literal 1), organizationId, source, correlationId, optional causationId, optional traceId, and occurredAt (ISO-8601 with offset). MaatDomainEventSchema is a discriminated union on eventType.

2.3 Event Payloads#

The five event payload schemas carry the following domain-specific fields. Note the bounded numeric fields (confidence, impact scores) and the discriminated status enums — these enforce domain invariants at the schema level.

Event Payload fields
MarketIntelligenceEvent marketId, signalType (PRICE_MOVEMENT / DEMAND_SHIFT / SUPPLY_DISRUPTION / COMPETITOR_ACTIVITY / REGULATORY_CHANGE), severity (INFO/WARNING/CRITICAL), confidence (0–1), summary, affectedSectors[], metrics (record of string → number)
AgentTaskEvent taskId, agentId, taskType (INTELLIGENCE_SCAN / STRATEGY_SIMULATION / FINANCIAL_ANALYSIS / SUPPLY_CHAIN_OPTIMIZATION / COMPLIANCE_REVIEW), status (QUEUED/ASSIGNED/IN_PROGRESS/BLOCKED/COMPLETED/FAILED), priority (LOW/MEDIUM/HIGH/URGENT), optional dueAt, optional details
StrategyDecisionEvent decisionId, strategyId, decisionType (INVESTMENT / DIVESTMENT / EXPANSION / PARTNERSHIP / RESTRUCTURE / RISK_MITIGATION), rationale, confidence (0–1), expectedImpactScore (−100…100), approvedBy[] (≥ 1)
ComplianceAlertEvent alertId, jurisdiction (GHANA/ECOWAS/AFCFTA/INTERNATIONAL), regulationCode, severity (WARNING/CRITICAL/EMERGENCY), title, description, optional dueAt, impactedBusinessUnits[]
SimulationStateEvent simulationId, scenarioId, runId, state (INITIALIZING/RUNNING/PAUSED/COMPLETED/FAILED), progressPercent (0–100), horizonMonths (positive int), summary

2.4 Bus API#

The InMemoryMaatEventBus class and its supporting utilities form the complete bus API:

  • MAAT_EVENT_SCHEMAS — record mapping each event type to its Zod schema.
  • parseMaatDomainEvent(event) — validates an unknown payload, routing by eventType to the matching schema.
  • createMaatEvent(draft) — fills eventId (randomUUID()), schemaVersion (1), and occurredAt (new Date().toISOString()) defaults, then validates.
  • InMemoryMaatEventBus — class with publish(input) (parses then dispatches), subscribe(eventType, handler), subscribeAll(handler), getSubscriberCount(eventType?), and clearSubscriptions(). Each subscribe* call returns an unsubscribe function. Handlers run via Promise.allSettled; if any reject, dispatch throws an AggregateError.

3. Redis Namespace Builder (@maat/core)#

libs/maat/core/src/redis-namespace.ts provides a pure key-string builder; it does not open a Redis connection. Its purpose is to centralize the key-prefix convention so that all services are guaranteed to use consistent, non-colliding namespace strings when a Redis integration is eventually wired in.

createMaatRedisNamespacePrefixes(options?) accepts basePrefix (default maat), environment, and separator (default :), and returns MaatRedisNamespacePrefixes. When an environment is provided, the root prefix becomes maat:<environment> — keeping dev, staging, and production namespaces separate on a shared Redis instance.

Prefix field Default value
root maat (or maat:<environment> when an environment is given)
agentState maat:agent:state
intelligenceCache maat:intelligence:cache
strategyResults maat:strategy:results
dashboardState maat:dashboard:state
rateLimiting maat:rate:limit

createMaatRedisKeyBuilder(prefixes?) returns a MaatRedisKeyBuilder with agentState, intelligenceCache, strategyResult, dashboardState, and rateLimit key-composing functions. assertUniqueNamespacePrefixes(prefixes) throws if any two prefixes collide. MAAT_REDIS_NAMESPACES and MAAT_REDIS_KEYS are the default-configured singletons.


4. Library Surface#

libs/maat/ contains 19 libraries, all published as @maat/<name>. Each library's src/index.ts exports a <NAME>_LIBRARY package-name constant plus the per-feature modules below. The implementation modules are pure TypeScript; no library imports a database driver (pg, drizzle, neo4j-driver, redis/ioredis). The only external runtime SDK is @anthropic-ai/sdk, imported by @maat/intelligence in world-model-simulator.ts and report-generation-pipeline.ts.

The table below shows status and module counts as read from each library's src/index.ts. A "scaffold" status means the library exists with a project.json and package.json but its source files contain minimal stubs — it is a placeholder for planned work, not a reduced-size implementation.

Library Status Module count (index.ts)
@maat/core implemented 3 modules (event-bus, organization, redis-namespace)
@maat/agents implemented 28 modules
@maat/capital implemented 15 modules
@maat/compliance implemented 20 modules
@maat/digital-twin implemented 20 modules
@maat/finance implemented 21 modules
@maat/integrations implemented 7 modules (one per portfolio company)
@maat/intelligence implemented 30 modules
@maat/knowledge implemented 21 modules
@maat/projects implemented 15 modules
@maat/reporting implemented 15 modules
@maat/risk implemented 15 modules
@maat/sdk implemented 10 modules
@maat/strategy implemented 21 modules
@maat/supply-chain implemented 20 modules
@maat/workforce implemented 15 modules
@maat/dashboard scaffold 1 module — only the V2 balance-dashboard contract (§7)
@maat/negotiation-intelligence scaffold 1 module — procurement-program (§4.1)

Note: @maat/dashboard is not a general dashboard aggregation layer. Its only source file beyond the V2 contract is a .gitkeep. Dashboard entity types (Dashboard, widgets, layouts, permissions) live in @maat/core.

4.1 @maat/negotiation-intelligence — Procurement Program (Phase 179.7.1)#

Defined in negotiation-intelligence/src/procurement-program.ts. This module seeds the Concordia shared bargaining substrate with Maat's procurement-program configuration: the tracks Maat negotiates under, the levers it uses, and the approval thresholds that gate high-value decisions. The agent mediation behaviour itself is still planned for a later phase.

It exports:

  • ProcurementTrackSchema — enum of procurement tracks.
  • ProcurementLeverSchema — enum of negotiation levers.
  • ApprovalThresholdSchema — object with an approval threshold definition.
  • ProcurementProgramSchema — the full program object.
  • findApprovalThreshold(...) — selects the threshold applicable to a value.
  • toMaatExtensionDefaults(program) — projects a program into Concordia extension defaults.

5. API Gateway (apps/maat/api-gateway)#

apps/maat/api-gateway is a Hono application (not Fastify). It is a JWT-authenticated reverse-dispatch gateway that sits in front of per-domain upstream services, providing a single authenticated entry point for all Maat API consumers. Rather than each downstream service managing its own auth and organization access enforcement, the gateway handles both centrally. Source: apps/maat/api-gateway/src/app.ts.

5.1 Authentication and Authorization#

  • createAuthMiddleware verifies a Bearer JWT with HS256 using MAAT_JWT_SECRET (falls back to a development secret).
  • MaatJwtClaimsSchema requires sub, orgId, roles[], permissions[], and optional exp/iat.
  • MaatPermissionSchema enumerates 23 permission strings: gateway:admin plus read/write pairs for intelligence, strategy, agents, finance, supply-chain, digital-twin, compliance, knowledge, dashboard, simulation, and worker.
  • requirePermission(permission) allows the request if the caller holds the permission or the platform-admin role.
  • ensureOrganizationAccess rejects cross-org access unless the caller is a platform-admin.

5.2 Routes#

The gateway exposes a set of infrastructure routes directly, plus domain-service proxy routes for each of the 11 registered services. The infrastructure routes are:

Method Path Description
GET /health Gateway liveness
GET /ready Readiness; reports routesRegistered count
GET /api/v1/services List registered domain services (gateway:admin)
GET /api/v1/audit/requests Query the request audit trail (compliance:read)
GET /api/v1/realtime/rooms WebSocket room snapshot (gateway:admin)
POST /api/v1/realtime/dashboard/update Broadcast a dashboard update (dashboard:write)
POST /api/v1/realtime/agents/status Broadcast agent status (agents:write)
POST /api/v1/realtime/market/alert Broadcast a market alert (intelligence:write)
POST /api/v1/realtime/simulation/progress Broadcast simulation progress (simulation:write)
GET /api/docs Swagger UI
GET /api/docs/openapi.json Generated OpenAPI 3.1 spec

Each of the 11 domain services additionally mounts a router under its base path (/api/v1/intelligence, /api/v1/strategy, /api/v1/agents, /api/v1/finance, /api/v1/supply-chain, /api/v1/digital-twin, /api/v1/compliance, /api/v1/knowledge, /api/v1/dashboard, /api/v1/simulation, /api/v1/worker) exposing:

  • GET /health — service registration status (requires the read permission);
  • POST /dispatch — forwards an organizationId/path/method/query/body request to the upstream service URL (requires the write permission). Upstream URLs come from MAAT_<SERVICE>_SERVICE_URL env vars, defaulting to http://maat-<service>:3000.

5.3 Middleware#

apps/maat/api-gateway/src/middleware/ provides three middleware modules:

  • api-versioning.tsMAAT_API_VERSIONS (currently only v1, CURRENT_API_VERSION = 'v1'); attaches X-Api-Version* headers, emits Deprecation/Sunset headers for deprecated versions, and rejects unknown versions when enforceKnownVersions is set.
  • rate-limit.tscreateMaatRateLimitMiddleware for /api/v1/*.
  • request-response-logging.ts — logging middleware plus InMemoryMaatRequestAuditTrail, an in-memory audit store with a filterable list({ limit, organizationId, outcome }).

5.4 Realtime WebSocket Server#

apps/maat/api-gateway/src/realtime/websocket-server.ts defines MaatRealtimeWebSocketServer. This server handles live data delivery for the five Next.js web apps — pushing dashboard updates, agent status changes, market alerts, and simulation progress without requiring each app to poll. RealtimeChannelSchema enumerates four channels: dashboard, agents, market-alerts, simulation. Clients send subscribe/unsubscribe/heartbeat commands; rooms are keyed channel:org[:entity]. Org-scoped access is enforced per room. Broadcast methods: broadcastDashboardUpdate, broadcastAgentStatus, broadcastMarketAlert, broadcastSimulationProgress.


6. SDK (@maat/sdk)#

libs/maat/sdk/src/typed-client.ts provides MaatClient, a typed client whose transport is a pluggable HttpAdapter. The SDK is designed to work in tests and integration contexts without a live server: when no adapter is supplied the client falls back to MockHttpAdapter, giving consumers type-safe request/response shapes even before the real backend is wired.

  • MaatClientConfigbaseUrl, apiKey, environment (production/staging/development/local), optional defaultCurrency (default GHS), defaultTimezone (default Africa/Accra), timeoutMs (default 30000), maxRetries (default 3), modules, and debug.
  • Sub-clients on MaatClient: companies (CompanyClient), finance (FinanceClient), risks (RiskClient), scenarios (ScenarioClient), reporting (ReportingClient).
  • forCompany(companyId) returns a ScopedCompanyClient; ping() probes /api/v1/health.
  • Response envelopes: ApiResponse<T> (data + meta) and PaginatedResponse<T> (adds pagination). FilterClause supports operators eq, neq, gt, gte, lt, lte, in, contains, startsWith.

The other SDK modules are cli-tool, react-components, webhook-manager, api-key-manager, batch-operations, sse-streaming, plugin-architecture, offline-mode, and sdk-docs-generator.


7. V2 Cross-Domain Contracts#

Maat owns three contracts that serve the separate V2 (fighting-game) program. They are implemented inside the Maat libraries because Maat provides the business authority — financial transaction governance, season calendar, and balance analytics — even in the context of a competitive game. A key invariant of all three contracts is that rollback frames must never call Maat services: real-time combat simulation is deterministic and must not depend on external service availability.

7.1 Finance Persistence Ledger — @maat/finance/v2-persistence-ledger#

This subsection defines the V2 Persistence Ledger Contract: Maat finance is the single source of truth for every V2 currency mutation, and the engine holds only a reconciling cache. The TypeScript authority lives in libs/maat/finance/src/v2-persistence-ledger.ts, the V2 service wrapper is published as @v2/maat-finance-ledger (depending on @maat/finance at workspace:*), and the in-engine policy struct is FV2MaatFinanceLedgerPolicy in V2/ue/Source/V2Persistence/Public/V2PersistenceTypes.h.

v2-persistence-ledger.ts exports V2_MAAT_FINANCE_LEDGER_CONTRACT_ID (v2.persistence.maat-finance-ledger.v1) and V2_MAAT_FINANCE_OFFLINE_CACHE_MODE (v2-engine-ledger-cache-reconcile-on-sync).

Transaction types are grant, spend, refund, adjust, migration. Decision reasons include approved-online-authority, approved-offline-cache, invalid-transaction-shape, region-price-mismatch, regulatory-cap-exceeded, refund-reference-required, and refund-window-expired. V2MaatFinanceRegionalPricingPolicy carries region-aware PPP pricing and regulatory transaction/daily-spend caps.

Required behaviour:

  1. Spend decisions verify region-aware PPP pricing.
  2. Spend and refund decisions check regulatory caps and refund windows before the entry is mirrored.
  3. Approved offline entries carry a Maat decision id and reconcile on next online sync.
  4. Rollback frames never call Maat finance services.

The Unreal side mirrors this in FV2MaatFinanceLedgerPolicy, whose SourceOfTruthPackageName defaults to @maat/finance and whose bRequiresOnlineReconciliation flag marks cached offline entries that must be re-validated against Maat on the next online sync. ApplyMaatFinanceTransaction consumes the policy to apply region-priced spend/refund deltas to the engine currency ledger; it never participates in deterministic combat and never influences rollback. The reciprocal @v2/maat-finance-ledger service composes @maat/finance as its source of truth (sourceOfTruthPackageName: MAAT_FINANCE_PACKAGE_NAME), flags inEngineLedgerCache: true and reconcileOnNextOnlineSync: true, and pins mayInfluenceRollback: false.

7.2 Live-Ops Calendar — @maat/strategy/v2-fighting-game-live-ops-calendar#

This subsection defines the V2 Fighting-Game Live-Ops Calendar Contract, served to the V2 program through the @v2/maat-live-service-calendar package (depending on @maat/strategy at workspace:*). Maat strategy is authoritative for the season calendar and Crown Points economy; the V2 wrapper marks standaloneV2LiveCalendarReplaced: true, asserting that there is no separate V2 calendar schema, and exposes the engine read hooks Rank.GetCrownPoints and Esports.QualifyForFinals.

libs/maat/strategy/src/v2-fighting-game-live-ops-calendar.ts exports MAAT_V2_LIVE_OPS_CALENDAR_SOURCE_OF_TRUTH_ID, the Pro Circuit tier values (MAAT_V2_PRO_CIRCUIT_TIER_VALUES), and the live-ops event kinds (MAAT_V2_LIVE_OPS_EVENT_KIND_VALUES). Types include MaatV2LiveOpsSeason, MaatV2ProCircuitEvent, MaatV2AnniversaryEvent, MaatV2CharityEvent, MaatV2BalanceRampWindow, and MaatV2CrownPointsRule. The functions calculateMaatV2CrownPoints(input) and buildMaatV2FightingGameLiveOpsCalendar(...) compute Crown Points and assemble the calendar. Maat owns seasons, ranked-season windows, Crown Points pool sizing and tier scoring, the Pro Circuit calendar, and anniversary/charity/balance-ramp windows. Rollback frames never call the calendar.

7.3 Balance Dashboard — @maat/dashboard/v2-balance-dashboard#

This subsection defines the V2 Balance Dashboard Contract, exposed to the V2 program as @v2/maat-balance-dashboard. That service composes three Maat libraries — @maat/intelligence (trend and anomaly detection), @maat/dashboard (panel/manifest governance), and @maat/reporting (scorecards and operational KPI charts) — each pinned at workspace:*; it deliberately does not depend on @maat/analytics. The wrapper sets standaloneV2DashboardReplaced: true, confirming there is no standalone V2 balance dashboard, and pins mayInfluenceRollback: false.

libs/maat/dashboard/src/v2-balance-dashboard.ts exports MAAT_V2_BALANCE_DASHBOARD_ID (maat.v2.balance-dashboard) and buildMaatV2BalanceDashboardSurface(input). The contract declares the companion @maat/reporting and @maat/intelligence package names by reference; it does not import them. MAAT_V2_BALANCE_DASHBOARD_EVENT_TOPICS lists eight topics: v2.match.ended, v2.match.combat.move.used, v2.match.combat.damage.applied, v2.match.combat.attack.blocked, v2.match.combat.frame-data.drift, v2.match.balance.ab-result.published, v2.match.balance.ptb-signal.recorded, and v2.match.performance.frame-budget-exceeded. Panel kinds: pick-rate, win-rate, win-rate-on-block, frame-data-drift, hot-cold-heatmap, ab-publication, release-gate. The output is a dashboard/reporting artifact; it is off rollback and must not influence deterministic combat simulation.


8. Knowledge Graph Schema (@maat/knowledge)#

libs/maat/knowledge/src/knowledge-graph-neo4j-schema.ts defines an in-memory graph schema (TypeScript records and Zod validation; no neo4j-driver dependency). The schema is designed for a future Neo4j projection: every node record carries a neo4jLabel field, and relationship types are modelled to map directly onto Neo4j relationship labels.

The vocabulary is:

  • KG_NODE_TYPE_VALUES: ORGANIZATION, PERSON, PRODUCT, MARKET, REGULATION, TECHNOLOGY, LOCATION, EVENT, CONCEPT.
  • KG_RELATIONSHIP_TYPE_VALUES: COMPETES_WITH, SUPPLIES_TO, REGULATED_BY, LOCATED_IN, INVENTED_BY, PART_OF.
  • KnowledgeGraphNodeRecord (nodeId, nodeType, neo4jLabel, properties, createdAt, updatedAt, version) and KnowledgeGraphRelationshipRecord model nodes and edges.

9. Frontend Applications#

apps/maat/ contains 11 application roots: 5 implemented Next.js web apps, 1 implemented Hono service app, and 4 bootstrap scaffold service apps.

9.1 Implemented Next.js Apps (5)#

Each app targets a distinct user persona: portfolio-level executives use the dashboard app, operations teams use agent-console, analysts use intel, investors use the investor portal, and strategists use the war room. Each runs on its own Next.js port (e.g. dashboard on 3055) and has build/start/lint/ typecheck/test Nx targets.

App Package Routes (route groups)
dashboard maat-dashboard-app (auth)/login, (dashboard)/portfolio, (dashboard)/company, (dashboard)/company/[companyId], (dashboard)/alerts, (dashboard)/layout-builder; API routes /api/auth/login, /api/auth/logout
agent-console @maat/agent-console (console)tasks, approvals, fleet, conversations, analytics
intel @maat/intel (intel)landscape, news, pricing, regulatory, sizing
investor @maat/investor (portal)dashboard, portfolio, explore, simulate, onboard
war-room @maat/war-room (war-room)scenario, market-entry, strategy-canvas, synergies, capital

9.2 Implemented Service App (1)#

api-gateway (maat-api-gateway-app) — the Hono gateway described in §5.

9.3 Scaffold Service Apps (4)#

agents (maat-agents-app), intelligence (maat-intelligence-app), simulation (maat-simulation-app), and worker (maat-worker-app) each contain only a bootstrap<name>() function returning an "<name> initialized" string. They are placeholders for future deployable services.


10. Technology Stack#

The table below summarizes the technology choices for the domain. The most important entry for new contributors is the last row: there is no persistence layer wired in. All domain state lives in-memory. The Redis namespace and Neo4j schema modules are forward-looking contracts, not active connections.

Layer Technology
Language TypeScript (Node.js)
Validation Zod
Gateway framework Hono (@hono/zod-validator, @hono/swagger-ui)
Gateway auth jsonwebtoken (HS256)
Frontend Next.js (App Router)
LLM SDK @anthropic-ai/sdk (used only in @maat/intelligence)
Build Nx with @nx/js:tsc (libs / gateway) and next build (web apps)
Testing Vitest (@nx/vite:test)
Persistence None — all domain state is in-memory value objects

There is no PostgreSQL, Drizzle, Neo4j driver, or Redis client wired into the domain. The "Redis namespace" and "Neo4j schema" modules produce keys and record shapes for a future datastore integration but do not connect to one.


11. Validation Rules#

The @maat/core Zod schemas enforce a set of domain invariants at construction time. These rules apply to all entities and must be respected in any code that creates or modifies Maat domain objects.

Entity-level rules:

  • Strict objects — every entity schema uses .strict(), rejecting unknown keys.
  • ID patterns — IDs must match their prefixed regex (§1.1).
  • CurrencycurrencyCode must be a 3-letter ISO 4217 code; country codes must be 2-letter ISO codes.
  • Percent fields0 ≤ value ≤ 100; probability/score fields0 ≤ value ≤ 1; fiscal years — integer 1900 ≤ year ≤ 9999.
  • Ghana GH jurisdiction — a LegalEntityRegistration with jurisdictionCode === 'GH' must use a Ghana company registration number.
  • Exactly one primary registrationLegalEntityStructure.registrations must contain exactly one entry with isPrimary === true.
  • Board terms — a board member's termEndAt cannot precede appointedAt.
  • Non-empty collectionsOrganization.operatingCompanies and LegalEntityStructure.registrations require at least one entry.
  • Agent capabilitiescreateAgent rejects capabilities not listed for the agent's class in AGENT_CAPABILITY_MATRIX.

Event validation rules (enforced by event-bus.ts): eventId must be a UUID, schemaVersion must be the literal 1, occurredAt must be ISO-8601 with offset, confidence values are bounded 0–1, expectedImpactScore is bounded −100…100, and StrategyDecisionEvent.approvedBy requires at least one approver.


12. Acceptance Criteria#

A Maat change is acceptable when all of the following conditions hold:

  1. New or changed @maat/core entities ship the full set — interface, *Draft, *_VALUES arrays for any new enum, Zod schema, create*, create*WithDefaults, serialize*/deserialize*, and is* — and are re-exported from index.ts.
  2. Every schema is .strict() and every constructor throws on invalid input.
  3. npx tsc --noEmit and npx vitest run pass in the affected library directory (Nx may be bypassed per repository policy).
  4. New API gateway routes declare a MaatPermission, enforce ensureOrganizationAccess for org-scoped data, and are reflected in the generated OpenAPI spec.
  5. New domain events extend BaseMaatEventSchema, are added to MaatDomainEventTypeSchema and MAAT_EVENT_SCHEMAS, and validate through parseMaatDomainEvent.
  6. V2 contract changes preserve the rollback-exclusion and source-of-truth-ownership rules in §7.