Domain · Architecture

Saraswati Domain — Architecture

Each library is an Nx project with package.json, project.json,

8sections11 minread1diagrams

On this page

Architectural overview of the Saraswati advanced-technology bounded context: its library federation, the foundation/business-unit/dashboard layering, the gateway HTTP surface, and an honest account of what is wired together versus what is implemented but not yet composed.


Saraswati is the advanced-technology bounded context of the Oshun monorepo. It answers one sprawling question: how does a technology company design, manufacture, deploy, operate, and stay compliant across a wide portfolio of frontier industrial products — electric vehicles, batteries, solar systems, IoT devices, contract electronics, pharmaceuticals, robots, drones, telecom towers, medical devices, payment terminals, security systems, e-waste, 3D-printed parts, and satellite ground equipment? Rather than force a single universal "product" entity to cover every category, Saraswati carves each technology vertical into its own capability library with its own concrete entities, lifecycle enums, compliance records, and telemetry shapes.

The domain lives entirely under libs/saraswati/ (24 libraries) plus the @contracts/saraswati package under libs/contracts/saraswati. There are no apps/saraswati/* or services/saraswati/* packages — Saraswati is a library-and-gateway domain. Roughly 350 tracked files carry it, of which ~34 are Vitest suites. Consumers (cross-domain partners, dashboards) reach Saraswati's HTTP surface through @saraswati/gateway, and reach its data shapes through @saraswati/core and the cross-domain contracts.

A new engineer should understand one structural fact up front: Saraswati is a federation of independently-buildable libraries, not a strict top-down dependency tree. The libraries are unified by a shared naming convention, a shared design vocabulary (branded IDs, Zod validation, lifecycle status enums), and the gateway that fronts them — but they are deliberately loosely coupled at the import level. That looseness is the most important and most misread property of the domain, and the sections below are explicit about where wiring exists and where it does not.


The Three Library Groups#

text
libs/contracts/saraswati/          ← cross-domain integration contracts

libs/saraswati/
  core/  db/  gateway/             ← foundation (types · persistence · HTTP boundary)
  ev/ battery/ solar/ iot/ electronics/ pharma/ robotics/ drones/
  telecom/ medical/ fintech-hw/ security/ ewaste/ additive/ satellite/
  market-intel/ financials/        ← 17 business-unit capability libraries
  command/ fleet/ factory/ iot-platform/   ← 4 cross-BU dashboard libraries

Each library is an Nx project with package.json, project.json, tsconfig.json, a vitest.config.ts, and a src/index.ts barrel. Every library carries its own src/ids.ts defining branded ID types and create* helpers for its entities — so the ID discipline is replicated per library rather than centralized. Every library builds, lints, and tests on its own.

Foundation: core, db, gateway#

@saraswati/core (libs/saraswati/core/src/) is the shared type catalog. Its index.ts re-exports seven entity modules — vehicle.ts, energy.ts, iot.ts, pharma.ts, robotics.ts, telecom.ts, manufacturing.ts — plus ids.ts. Each module defines TypeScript interfaces, Zod schemas, type guards, and factory functions for its slice of the portfolio, along with compile-time branded ID types (VehicleId, BatteryPackId, DroneId, IoTDeviceId, …, each a Brand<string, '…'>) so an ID of one kind cannot be passed where another is expected. Crucially, core is not pure data: it embeds real domain computation. energy.ts carries calculateExpectedPanelOutput(panel, ambientTempC, irradianceWm2), which applies a NOCT cell-temperature and irradiance correction; robotics.ts carries isFlightPlanSafe, which encodes the Ghana GCAA 400 m AGL altitude cap as a hard guard. These are domain-specific algorithms and invariants, not CRUD scaffolding.

@saraswati/db (libs/saraswati/db/src/) is a real, runnable persistence layer: a Drizzle ORM schema (schema.ts) over the saraswati PostgreSQL database, plus connection.ts (pooling), migrations.ts, seed.ts, and cache.ts (Redis key namespaces). migrations.ts installs the PostGIS, TimescaleDB, and pgvector extensions via installExtensions(db) and configures TimescaleDB hypertables for battery, solar, and IoT telemetry. The schema defines shared enums (saraswatiStatus, saraswatiRegulatoryStatus, …) and per-business-unit tables with PostGIS geometry columns and pgvector embedding columns. This layer is complete and exercisable against a live database.

@saraswati/gateway (libs/saraswati/gateway/src/) is the HTTP boundary: a Hono application (app.ts) that mounts the 17 business units under /api/v1/{bu}/. It wraps every request in a production-grade middleware chain — secureHeaders, CORS scoped to Oshun origins, distributed tracing, structuredLogger with correlation IDs, Prometheus httpMetrics, a global 500 req/min rate limit plus per-BU limits via rateLimitForBU, and optionalAuth (JWT). System endpoints expose /health, /ready (gated on circuit-breaker state), /metrics, /openapi.json, /graphql, and /circuit-breakers. Beyond REST, the gateway carries a GraphQL schema and executor (graphql/), gRPC service definitions (proto/services.ts), an MQTT topic hierarchy (mqtt.ts), WebSocket/SSE channels (routes/websocket.ts), a Kafka event-bus abstraction (events/kafka-event-bus.ts), CQRS/event-sourcing primitives (cqrs/cqrs.ts), API versioning, and a benchmarking harness.

The 17 business-unit capability libraries#

Each of ev, battery, solar, iot, electronics, pharma, robotics, drones, telecom, medical, fintech-hw, security, ewaste, additive, satellite, market-intel, and financials owns the full lifecycle for one technology vertical. They are organized internally by concern — e.g. libs/saraswati/ev/src/{design,powertrain,battery,chassis,certification,production,fleet,v2g,autonomous}/ and libs/saraswati/battery/src/{cell,module,production,testing,stationary,second-life,next-gen}/.

These libraries contain the domain's real engineering content. ev's powertrain/powertrain.ts ships a MOTOR_CATALOG of representative hub and mid-drive motors with peak/continuous torque, efficiency, and thermal limits, and a PowertrainConfigurator that selects a motor and sizes a drivetrain from vehicle requirements. battery's cell/cell-catalog.ts carries manufacturer cell specs (CATL, BYD, Samsung SDI, LG, EVE) with a comparison/grading engine. financials's bu-models/bu-models.ts computes IRR with a real bisection solver (computeIRR(cashFlows, tolerance = 1e-7, maxIter = 200)) and portfolio/portfolio.ts computes NPV over a cash-flow series. Each library verifies its own correctness in a *.test.ts suite, and the SOTA-flavored verticals add a *-sota.test.ts.

The 4 cross-BU dashboard libraries#

command (technology operations: KPI aggregation, manufacturing status, supply chain, quality, financial dashboard, regulatory tracker, alert center), fleet (vehicle/drone fleet management), factory (manufacturing management: MES, pharma dashboard, battery/solar/print-farm lines, NCR manager), and iot-platform (device registry, smart-city ops, rule engine, OTA, data export) aggregate operational views that span multiple business units. They own projection and roll-up logic — not business rules — and each carries its own ids.ts and snapshot types.


How the Libraries Actually Relate#

The single most important architectural correction to make against any "layered foundation" reading is that the import graph is far looser than the naming suggests. Verified from the source:

  • Business-unit libraries are self-contained. Of the 17, only ev imports @saraswati/core (in two files: design/vehicle-design.ts and powertrain/powertrain.ts). The other 16 redefine the types they need locally. core is therefore best understood as a comprehensive parallel type catalog and a home for shared cross-cutting types, not a base that every BU compiles against.
  • The gateway does not import the business-unit libraries. Each route module (routes/ev.ts, routes/battery.ts, routes/remaining-bus.ts, …) declares its own inline Zod request schemas and serves from process-local in-memory Map stores (~30 across the route files). The gateway is a complete, exercisable HTTP API in its own right; it is not a thin shell over the BU computation modules.
  • The gateway does not import @saraswati/db. No file under libs/saraswati/gateway/src/ references @saraswati/db. The Drizzle persistence layer and the gateway are both implemented but are not yet wired to each other — the HTTP API currently persists to memory, and the database layer is driven independently.
  • The dashboard libraries do not import the business-unit libraries. They are self-contained projections that compute over data shapes passed to them, not live readers of BU state.

This is a deliberate composition style: maximally independent, individually buildable libraries unified by convention and by the gateway's HTTP contract. The cost is that "all 17 BUs build on the foundation" is aspirational at the import level; the benefit is that any library can be developed, tested, and shipped without dragging in the rest of the domain.

flowchart TD consumers["Consumers<br/>(dashboards · partner domains)"] subgraph gw["@saraswati/gateway (Hono)"] mw["middleware: auth · rate-limit · metrics<br/>tracing · logger · circuit-breaker"] routes["routes/* — inline Zod +<br/>in-memory Map stores"] extra["GraphQL · gRPC defs · MQTT topics<br/>WebSocket/SSE PubSub · Kafka bus · CQRS"] end core["@saraswati/core<br/>7 type modules + branded IDs<br/>(NOCT calc · 400m flight guard)"] db["@saraswati/db<br/>Drizzle · PostGIS · TimescaleDB · pgvector"] bus["17 BU capability libs<br/>ev · battery · solar · … · financials<br/>(MOTOR_CATALOG · IRR · cell catalog)"] dash["4 dashboard libs<br/>command · fleet · factory · iot-platform"] contracts["@contracts/saraswati<br/>brigid · asase · freya · cybele · maat"] neighbors["Neighbor domains<br/>Brigid · Asase · Freya · Cybele · Maat"] consumers -->|HTTP / GraphQL / WS| gw mw --> routes --> extra core -. imported only by ev .-> bus contracts <--> neighbors consumers -->|typed contracts| contracts db -. implemented, not wired .-> gw bus -. not imported by .-> gw dash -. self-contained projections .-> bus

Eventing, Streaming, and Real-Time Seams#

Saraswati models several real-time transports. Each is implemented as far as the sandbox honestly allows, with explicit seams where a managed broker would otherwise be required:

  • WebSocket / SSEroutes/websocket.ts runs a real in-process PubSubBus fanning typed WSMessage values to subscribers across eight channels (ev_telemetry, battery_alerts, solar_live, iot_stream, drone_tracking, manufacturing_events, security_alarms, system_health); the SSE endpoint streams a channel as text/event-stream. This path is live, not stubbed.
  • Kafka event busevents/kafka-event-bus.ts is a topic-modeling layer: a buildTopicName(bu, category) convention (saraswati.{bu}.{telemetry|commands|events|alerts|audit}), a partition-key strategy (round-robin for telemetry, entity-keyed for ordering), DLQ naming (saraswati.dlq.{topic}), and an in-process SaraswatiEventBus class. Its own comment is explicit: "For production use, replace with kafkajs or @confluentinc/kafka-javascript." It is an honest abstraction over a broker, not a live Kafka connection.
  • gRPCproto/services.ts is a set of TypeScript message-type interfaces for robotics/drone/IoT/manufacturing control, documented as "generate from .proto files with protoc-gen-ts" in production. Definitions, not a running server.
  • MQTTmqtt.ts defines an AWS-IoT/HiveMQ-style topic hierarchy (saraswati/{siteId}/{bu}/{entityId}/{stream}) for device communication.
  • CQRS / event sourcingcqrs/cqrs.ts separates command and query paths, appending domain events and reconstituting aggregates by replay.

Read these as a coherent eventing design with one live in-process bus and clearly-labelled boundaries where external infrastructure plugs in.


Cross-Domain Integration#

@contracts/saraswati is the only sanctioned crossing point between Saraswati and its neighbors. Its index.ts re-exports five modules, each a set of Zod schemas plus typed adapter result interfaces:

  • brigid.ts — Saraswati manufacturing ↔ Brigid industrial automation (CEM production orders against IPC-7711/7721 SMT accuracy classes, energy-system integration, robotics, a shared MES event bus, predictive-maintenance sharing).
  • asase.ts — EV fleet / drones / IoT / solar ↔ Asase agriculture (delivery fleets, agricultural drones, soil/weather IoT, cold chain, solar irrigation).
  • freya.ts — Saraswati ↔ Freya e-commerce (last-mile fleet, smart-retail IoT, packaging electronics, fintech-hardware deployment, warehouse robotics).
  • cybele.ts — Saraswati ↔ Cybele construction (construction robotics, smart-building IoT, EV-charging planning, rooftop solar, data-center equipment, survey drones).
  • maat.ts — R&D / IP / PLM ↔ Maat knowledge management (TRL tracking, IP portfolio, PLM sharing, technology scouting, standards tracking).

The contract boundary keeps Saraswati's internal model free to change while giving each consumer a typed, versioned slice rather than general access to all 17 business units. Two further boundaries are enforced by convention rather than contract: Oya owns drone flight and swarm primitives that @saraswati/drones operations build on, and Galatea owns humanoid embodied AI where @saraswati/robotics extends only into task-specific industrial machines. cross-domain.test.ts validates the contract schemas.


Compliance as a Cross-Cutting Concern#

Seven categories are regulated — pharma, medical devices, fintech hardware, EVs, batteries, telecom, and e-waste — and each owns a category-specific compliance entity rather than a shared one, because the concepts do not generalize: a GMP BatchRecord (with qualified-person sign-off and Deviation tracking) is nothing like a PCI PTS/DSS certificate, an NCA tower permit, or a UN-ECE vehicle homologation record. The domain enforces four cross-cutting invariants:

  1. Evidence integrity — every regulated decision preserves the evidence packet, standard, jurisdiction, reviewer identity, and timestamp; compliance evidence is append-only once recorded.
  2. Telemetry identity — ingested readings preserve source device identity and a sequenceNumber/uplinkId for ordering and deduplication.
  3. Versioned configuration — firmware and device-config changes are versioned and reconstructable.
  4. Model-assumption provenance — financial and generation projections retain their inputs and model version so they can be re-derived.

Guards in core encode hard rules directly: isBatchReleaseReady (QC passed, status qc_testing, all deviations closed or minor), requiresNotifiedBody (medical class IIb/III), requiresClinicalTrial, isFlightPlanSafe (the 400 m cap). Changes to regulated libraries are expected to add contract, compliance, audit, and data-retention tests on top of the standard lint/typecheck/unit coverage.


SOTA and Next-Generation Modules#

Several verticals carry forward-looking analysis and planning modules under sota/ or next-gen/ directories. These are real computational tools, not deployed systems, and should be read as decision-support: drones/src/sota/swarm-planner.ts computes multi-drone survey coverage and 3-D conflict detection; security/src/sota/quantum-safe.ts performs post-quantum algorithm sizing and a q-day threat-timeline assessment; battery/src/next-gen/ tracks solid-state, sodium-ion, EU battery-passport, and recycling readiness; telecom/src/sota/6g-tracker.ts and satellite/src/sota/leo-planner.ts follow the same tracker/planner pattern. They compute against real parameters but do not control fielded hardware.


Status Summary — Implemented vs. Not Yet Wired#

  • Implemented and self-consistent: all 24 libraries plus contracts build, lint, and test independently; core's type catalog and domain calculators; the BU capability libraries' domain algorithms (powertrain config, cell catalogs, NPV/IRR, coverage planning); the gateway's full middleware chain, REST surface, GraphQL schema/executor, in-process PubSub bus, and topic/CQRS modeling; the Drizzle/PostGIS/TimescaleDB/pgvector schema and migrations; the five cross-domain contracts.
  • Implemented but not composed: @saraswati/db is not imported by the gateway — REST routes persist to in-memory Map stores, so the HTTP API and the database layer are not yet a single pipeline. The 17 BU computation libraries are not imported by the gateway either; the route handlers reimplement validation inline. Wiring the gateway to db and to the BU libraries is the domain's primary integration gap.
  • Honest infrastructure seams: the Kafka bus, gRPC definitions, and MQTT topics model their transports but defer to external brokers/codegen in production, as their own comments state.

A note on a stale comment: gateway/src/app.ts opens with "All 19 business units are mounted," but the code mounts and reports exactly 17 (buCount: 17). Seventeen is correct; the 19 is a leftover.


Verification Expectations#

The bar for regulated categories is deliberately higher than for ordinary code, because errors in pharma, medical, or fintech logic carry legal and safety consequences. Every change requires package-level lint, typecheck, and test coverage. Regulated domains — pharma, medical devices, fintech hardware, EVs, batteries, telecom, and e-waste — additionally require contract, compliance, audit, and data-retention tests, and any change to a core guard that encodes a regulatory invariant (the 400 m cap, batch-release readiness, notified-body thresholds) must be covered by a test asserting the specific rule, not merely the data shape.