Saraswati is the advanced-technology bounded context of the Oshun monorepo. It covers design, manufacturing, deployment, operations, compliance, and market intelligence across 17 technology business units (BUs): electric vehicles, batteries, solar, IoT, electronics, pharma, robotics, drones, telecom, medical devices, fintech hardware, security, e-waste, additive manufacturing, satellite communications, market intelligence, and financials.
This is an implemented domain. The specification below is grounded in the
TypeScript source under libs/saraswati/* and libs/contracts/saraswati. The
phase backlog is TODOS/phase-60.md.
This document is a precise, field-level reference for every entity, enum, schema, guard, factory, table, route, and middleware in the domain. It is intentionally exhaustive: developers implementing a new feature, reviewers auditing compliance fields, or architects tracing a cross-domain contract should be able to find the authoritative definition here rather than hunting through source files.
Package Inventory#
There is no apps/saraswati/* or services/saraswati/* package. The domain is
implemented as 24 libraries under libs/saraswati/ plus one contracts package.
The grouping below — contracts, foundation, business units, cross-BU dashboards
— mirrors the architectural layering described in architecture.md.
Contracts#
@contracts/saraswati(libs/contracts/saraswati) — cross-domain integration schemas and adapters.
Domain foundation#
@saraswati/core(libs/saraswati/core) — shared TypeScript types, Zod schemas, branded ID types, type guards, factory functions.@saraswati/db(libs/saraswati/db) — Drizzle ORM schema, connection pooling, migrations, seed data, Redis cache key namespaces.@saraswati/gateway(libs/saraswati/gateway) — Hono HTTP API gateway, GraphQL, gRPC service definitions, MQTT topic hierarchy, WebSocket/SSE, CQRS/event-sourcing, Kafka event-bus abstraction, middleware.
Business-unit capability libraries#
Each library below owns the full lifecycle for its technology vertical, including domain-specific entities, enums, Zod schemas, type guards, and factory functions.
@saraswati/ev— vehicle design, powertrain, battery pack, chassis, certification, production, fleet, V2G, ADAS.@saraswati/battery— cell catalog, module engineering, testing, production, stationary storage, second-life, next-gen chemistry trackers.@saraswati/solar— panel manufacturing, installation, PAYGO, solar resource, SHS designer, testing.@saraswati/iot— device design, connectivity, platform, smart city, dashboard, zero-trust.@saraswati/electronics— assembly, SMT, testing, production, DFM, AI (digital twin, predictive maintenance, quality inspection).@saraswati/pharma— batch, formulation, GMP, QC, regulatory, drug discovery.@saraswati/robotics— household, construction, waste-sorting, core, SOTA (surgical, swarm).@saraswati/drones— agriculture, delivery, survey, flight, fleet, data, SOTA swarm planner.@saraswati/telecom— network, site, construction, equipment, maintenance, 6G tracker.@saraswati/medical— design, biocompatibility, quality, regulatory, post-market.@saraswati/fintech-hw— POS, ATM, biometric, field service.@saraswati/security— CCTV, access, analytics, SOTA (quantum-safe, blockchain provenance).@saraswati/ewaste— collection, recovery, circular economy, compliance.@saraswati/additive— design, material, applications, fleet.@saraswati/satellite— network, service, terminal, SOTA LEO planner.@saraswati/market-intel— tech markets, EV/energy, intelligence.@saraswati/financials— business-unit financial models, portfolio.
Cross-BU dashboard / operations libraries#
These four libraries aggregate views across the 17 business-unit libraries. They contain no business logic of their own; they compose and project data for operators and managers who need a unified view.
@saraswati/command— technology operations dashboard: KPI aggregation, manufacturing status, supply chain, quality, financial dashboard, regulatory tracker, alert center (phase tasks 60.21.1.x).@saraswati/fleet— vehicle and drone fleet management: fleet overview, EV fleet health, drone mission control, charging infrastructure, fleet scheduler, fleet analytics, driver/pilot performance (60.21.2.x).@saraswati/factory— manufacturing management: electronics MES, pharma dashboard, battery assembly, solar manufacturing, print farm, production planning, NCR manager (60.21.3.x).@saraswati/iot-platform— IoT platform device management: device registry, device detail, smart-city operations, rule engine, OTA manager, data export (60.21.4.x).
Branded ID Types (@saraswati/core/ids.ts)#
Branded IDs are the primary defense against passing the wrong type of ID to a
function. Because each BU has its own entity graph, accidental cross-BU ID
confusion (e.g., passing a DroneId where a VehicleId is expected) would
cause silent data corruption. Branding makes these mistakes into compile-time
type errors.
@saraswati/core defines compile-time branded ID types so that, for example, a
DroneId cannot be passed where a VehicleId is expected. Each is
Brand<string, '...'> over a unique symbol.
Vehicle and mobility: VehicleId, VehicleDesignId, ChargingStationId,
FleetOperatorId.
Battery and energy: BatteryId, BatteryCellId, BatteryModuleId,
BatteryPackId, SolarPanelId, SolarInstallationId, SolarHomeSystemId.
IoT and electronics: DeviceId, IoTDeviceId, GatewayId, PCBDesignId,
ProductionOrderId.
Pharma and medical: PharmaceuticalId, BatchRecordId, MedicalDeviceId,
RegulatorySubmissionId.
Robotics and drones: RobotId, RobotTaskId, DroneId, FlightPlanId.
Telecom and satellite: TelecomTowerId, TowerSiteId, SatelliteId,
VSATTerminalId, GroundStationId.
E-waste and manufacturing: EWasteCollectionId, PrintJobId, PrinterId.
Fintech and security: FintechTerminalId, SecuritySystemId.
Cross-domain: OrganizationId, CustomerId, TechnicianId, ProjectId.
ID helpers: createVehicleId(), createBatteryCellId(),
createBatteryModuleId(), createBatteryPackId(), createDeviceId(),
createIoTDeviceId(), createDroneId(), createRobotId(),
createFlightPlanId(), createRobotTaskId(), createMedicalDeviceId(),
createPharmaceuticalId(), createFintechTerminalId(),
createSecuritySystemId(), createChargingStationId(),
createSolarInstallationId(), createPrintJobId(), createTelecomTowerId(),
createVSATTerminalId() each return randomUUID(). isValidId(id) validates a
UUID v4 string against UUID_REGEX. Asserting casters asVehicleId,
asDroneId, asRobotId, asIoTDeviceId, asBatteryPackId throw TypeError
if the input is not a valid UUID.
Core Domain Objects (@saraswati/core)#
@saraswati/core/index.ts re-exports six type modules: vehicle.ts,
energy.ts, iot.ts, pharma.ts, robotics.ts, telecom.ts,
manufacturing.ts. Every interface, enum, Zod schema, type guard, and factory
function below is defined in that source.
The sections that follow enumerate each entity's fields in full, because the field-level precision matters for downstream consumers (gateway validation, persistence mapping, contract adapters, and compliance audits). For each entity, status enum values are listed in their natural lifecycle order to show how an artifact progresses from creation to retirement.
Vehicle and mobility (vehicle.ts)#
This module defines all electric-vehicle entity types. The Vehicle entity is
the root of the EV hierarchy; FleetVehicle extends it for operational
contexts; ChargingStation is a separate entity for charging infrastructure.
Vehicle (task 60.2.1.1)#
Base electric-vehicle record. Fields: id: VehicleId, vin (ISO 3779),
vehicleType: VehicleType, status: VehicleStatus, designCode,
designVersion, powertrain: Powertrain, chassis: ChassisDesign,
batteryPackId: BatteryPackId, batterySwappable, nominalRangeKm,
topSpeedKmh, optional certification: VehicleCertification,
productionBatch, productionDate, assemblyLine, paygoEnabled, optional
paygoStatus (active | suspended | completed | defaulted),
paygoProvider, colorCode, trimLevel.
VehicleType (9 values): motorcycle, tricycle_cargo, tricycle_passenger,
tricycle_utility, minibus, city_bus, intercity_bus,
delivery_van_light, delivery_van_medium.
VehicleStatus (8 values, the EV lifecycle): design (engineering, no
artifact) → prototype (first builds) → homologation (type-approval review) →
production (released to manufacturing) → active_fleet (in service) →
maintenance (service window) → end_of_life → decommissioned.
Powertrain (task 60.2.1.2)#
The powertrain encodes the full motor-to-wheel drivetrain in structured data,
enabling the PowertrainConfigurator to compute efficiency maps and the
compliance system to verify drive-cycle emissions.
Motor, controller, transmission, and drive-cycle efficiency. Holds
motorType: MotorType, motor power/torque/speed fields, motorEfficiencyMap
(2-D efficiencyMatrix indexed by speed and torque), motorTorqueCurve
(peak/continuous torque vs. speed), motorThermalLimits (maxWindingTempC,
maxMagnetTempC, thermalTimeConstantMin), controllerManufacturer/Model,
controllerParams (FOC parameters: currents, voltage, switching frequency,
d-/q-axis inductance, flux weakening), regenerativeBrakingEnabled,
maxRegenTorqueNm, regenRecoveryPercent, transmissionType (single_speed |
two_speed | cvt), gearRatios, differentialType (open | limited_slip
| torque_vectoring), finalDriveRatio, drivetrainEfficiencyPercent,
co2EmissionsGKm (well-to-wheel).
MotorType (5 values): bldc_hub, bldc_mid_drive, pmsm, induction,
switched_reluctance.
ChassisDesign (task 60.2.1.3)#
Frame geometry, weight distribution, suspension, braking, wheels/tyres,
aerodynamics. FrameMaterial (5): steel_tubular, steel_monocoque,
aluminum_space_frame, chromoly, composite. SuspensionType (7):
telescopic_fork, dual_shock, monoshock, double_wishbone,
mcpherson_strut, trailing_arm, torsion_beam. BrakeType (4):
disc_hydraulic, disc_mechanical, drum, combined_braking. BrakingSystem
carries absEnabled, combinedBrakingSystem (CBS, an India/Ghana regulatory
requirement for two/three-wheelers), regenBrakingIntegrated, and an optional
stoppingDistanceMFromKmh100.
VehicleCertification and CertificationRecord (task 60.2.1.4)#
These types capture the type-approval workflow that every vehicle must pass
before it can be sold in a given market. The recallHistory field ensures that
post-sale safety actions remain on the vehicle's compliance record.
HomologationStandard (10 values): DVLA_GHANA_EV, UN_ECE_R10 (EMC),
UN_ECE_R100 (Li-ion EV battery safety), UN_ECE_R48 (lighting),
UN_ECE_R13_H (passenger braking), UN_ECE_R78 (motorcycle braking),
ECOWAS_EV_STANDARD, IEC_61851 (EV charging), ISO_11451 (EMI immunity),
ISO_6469 (EV safety). CertificationRecord has standard (a
HomologationStandard or free string), certificationNumber, certifyingBody,
issueDate, expiryDate, documentRef, and status in valid | expired |
pending | withdrawn. VehicleCertification aggregates DVLA-Ghana fields,
type-approval fields, UN-ECE type-approval number, a certifications array, a
nextRenewalDue date, and a recallHistory array of
{ recallNumber, description, affectedVehicles, remedyDate, status } where
status is open | completed.
ChargingStation (task 60.2.1.5)#
id: ChargingStationId, station code/name/operator, location (address,
city/region/country, lat/lng), connectors: ChargingConnector[],
maxStationPowerKw, hasDcFastCharge, power-supply flags (gridConnected,
solarBackup, batteryBackupKwh, generatorBackupKva), live status
(isOnline, availablePorts, totalPorts, lastUpdated),
pricing: ChargingPricing, optional networkConfig: ChargingNetworkConfig,
v2gCapable, demandResponseEnabled, accessControl (public | private |
fleet_only | subscription), openingHours.
ConnectorType (10): Type_1_SAE_J1772, Type_2_IEC_62196, CCS_Combo_1,
CCS_Combo_2, CHAdeMO, GB_T_20234, Tesla_NACS, Schuko_CEE,
Three_Pin_UK, CEE_Blue_16A. ChargingPricing.model is per_kwh |
per_hour | per_session | free. ChargingNetworkConfig.ocppVersion is
1.6 | 2.0 | 2.0.1; payment methods are drawn from mobile_money, card,
rfid, app, qr_code.
FleetVehicle (task 60.2.1.6)#
FleetVehicle adds the fields needed to run a vehicle as part of an operated
fleet rather than a manufacturer's inventory. Lifetime counters and the
lifetimeEmissionsSavedKgCo2 field support sustainability reporting.
Extends Vehicle with fleetOperatorId: FleetOperatorId, fleetName, optional
latestTelematics: VehicleTelematics, currentAssignment: DriverAssignment and
assignmentHistory, lifetime usage counters (totalOdometerKm,
totalChargeCount, totalEnergyConsumedKwh, lifetimeEmissionsSavedKgCo2),
service scheduling (nextServiceDueDate, nextServiceDueKm, serviceHistory),
insurance fields, dailyRevenueTarget, and currency. VehicleTelematics
holds timestamp, GPS, speedKmh, heading, socPercent, estimatedRangeKm,
odometricKm, isCharging, chargingStationId, doorLocked, engineOn,
tripId, driverBehaviorScore. DriverAssignment.shiftType is day | night
| split | flexible.
Vehicle schemas, guards, factories#
VehicleTypeSchema (Zod enum, 9 values). ChargingStationSchema validates a
charging-station input with bounded lat/lng, country length 2, currency
length 3, nested connector and pricing objects; ChargingStationInput is its
inferred type. Guards: isVehicle, isFleetVehicle (checks fleetOperatorId),
isChargingStation (delegates to ChargingStationSchema.safeParse). Factories:
createDefaultMotorEfficiencyMap() (5×5 BLDC-hub efficiency grid),
createDefaultBrakingSystem().
Energy and battery (energy.ts)#
This module defines the three-level battery hierarchy (cell → module → pack),
the SolarPanel and SolarHomeSystem types, and the EnergyStorageSystem type
for stationary deployments. The calculateExpectedPanelOutput helper embeds the
NOCT correction formula used by the solar gateway's generation forecast.
Battery (task 60.2.2.1)#
id: BatteryId, serialNumber, chemistry: BatteryChemistry,
applicationType: BatteryApplicationType, rated electrical specs (voltages,
ratedCapacityAh, ratedEnergyKwh, currents, maxCRate), lifecycle state
(stateOfHealth 0–100 with <80 end-of-life threshold, stateOfCharge,
stateOfSafety, cycleCount, totalEnergyThroughputKwh), a degradation model
(degradationRatePercentPerCycle, degradationRatePercentPerYear,
predictedEolDate, predictedRemainingCycles), thermal limits, and status
flags (isHealthy, faultCodes, lastDiagnosticDate, certifications).
BatteryChemistry (6): lfp, nmc, nca, lco, lto, sodium_ion.
BatteryCellFormFactor (6): cylindrical_18650, cylindrical_21700,
cylindrical_26650, prismatic, pouch, blade. BatteryApplicationType
(9): ev_motorcycle, ev_tricycle, ev_bus, ev_van, solar_home_system,
commercial_storage, grid_scale, telecom_backup, ess_residential.
BatteryCell (task 60.2.2.2)#
Per-cell specification: id: BatteryCellId, cellModelCode, manufacturer,
countryOfOrigin, chemistry, formFactor, electrical specs, performance
(maxChargeCRate, maxDischargeCRate, cycleLife to 80% retention,
calendarLifeYears), thermal (thermalRunawayThresholdC,
thermalRunawayPropagationRisk in low | medium | high), physical
dimensions, optional unitCostUsd, optional testData: CellTestData, and
certification flags (un383Certified, iec62133Certified). CellTestData
records lab test results including un383Pass and iec62133Pass.
BatteryModule (task 60.2.2.3)#
id: BatteryModuleId, moduleCode, cellId, cell configuration
(cellsInSeries, cellsInParallel, totalCells, cellConfiguration such as
"7s2p"), computed pack-relevant specs, thermal management
(thermalManagementType, coolingMedium, coolantFlowRateLitresMin,
heaterWatts, thermalManagementRange), bms: BMSSpec, physical fields,
enclosureIpRating, busbarsPlate (copper | nickel_plated_copper |
aluminum), and optional state. ThermalManagementType (4): air, liquid,
phase_change_material, none. BalancingType (3): passive, active,
hybrid. BMSSpec covers chipset, firmware, balancing, socAlgorithm
(coulomb_counting | ekf | ampere_hour_with_correction), sohAlgorithm
(capacity_measurement | internal_resistance | degradation_model),
protection thresholds, and communicationInterface (can | lin | i2c |
spi | rs485).
BatteryPack (task 60.2.2.4)#
id: BatteryPackId, packCode, optional serialNumber, moduleId, module
arrangement, pack-level electrical specs, coolingSystem: PackCoolingSystem,
safety: PackSafetyFeatures, structural fields (enclosureType in
cell_to_pack | module_to_pack | cell_to_body; structuralMaterial),
physical/energy-density fields, lifecycle state, and a second-life block:
secondLifeStatus (in_vehicle | second_life_stationary |
awaiting_assessment | recycling) and secondLifeMinimumSoh.
PackSafetyFeatures tracks un38_3Certified, ece_r100Certified,
iec62619Certified, venting, fire suppression (fireSuppressantType in
aerosol | dry_powder | fm200 | novec), and thermal-propagation barriers.
SolarPanel (task 60.2.2.5)#
id: SolarPanelId, model/manufacturer, panelType: SolarPanelType, STC
electrical specs (1000 W/m², 25 °C, AM 1.5), temperature coefficients, NOCT
performance, degradation (firstYearDegradationPercent,
annualDegradationPercent, performanceWarrantyYears,
performanceWarrantyMinPercent, productWarrantyYears), physical dimensions,
electrical-safety voltages, certification flags (iecCertified for IEC 61215,
iecSafetyCertified for IEC 61730, tuvCertified, lightingGlobalCertified),
and cost. SolarPanelType (6): monocrystalline_perc,
monocrystalline_topcon, polycrystalline, thin_film_cigs, thin_film_cdte,
bifacial.
SolarHomeSystem (task 60.2.2.6)#
id, skuCode, name, tier: SHSTier, components (panel, panelCount,
totalPanelWp, battery chemistry/capacity/energy, chargeControllerType (pwm
| mppt), chargeControllerRatingA, optional inverterWatts), load
configuration (maxDailyConsumptionWh, autonomyDays, peakLoadW,
includedLoads: SHSLoad[], totalDailyConsumptionWh), optional
paygo: PAYGOConfig, quality fields (qualityStandard, veraSolCertified,
qualityTierPerLightingGlobal), pricing, and warrantyYears. SHSTier (5):
tier_1 through tier_5, the IEC TR 61836 / Lighting Global multi-tier
framework. PAYGOConfig carries lockEnabled (remote disable on missed
payment), paymentPlatform, freeDays, paymentFrequency (daily | weekly
| monthly), and the finance terms in GHS.
EnergyStorageSystem (task 60.2.2.7)#
Stationary storage record: id, systemCode, application: ESSApplication,
battery specs, performance: ESSPerformanceSpec, power electronics
(inverterTopology in on_grid | off_grid | hybrid, gridFormingCapable,
uninterruptibleSwitchoverMs), management flags (bmsIntegration,
emsEnabled, scadaInterface), physical fields (formFactor in rack_mounted
| wall_mounted | floor_standing | containerized), safety, grid-connection
fields (antiIslandingProtection), lifecycle, and lcoe. ESSApplication (8):
residential_self_consumption, commercial_peak_shaving, industrial_ups,
telecom_backup, grid_frequency_regulation, grid_peak_shaving,
off_grid_community, hybrid_solar_diesel_replacement.
Energy schemas, guards, factories#
BatteryChemistrySchema (Zod enum, 6 values), BatterySchema,
SolarPanelSchema (with efficiencyPercent capped at 30 and degradation
bounds). Guards: isBatteryHealthy (stateOfHealth >= 80, isHealthy, no
fault codes), isBatteryEndOfLife (stateOfHealth < 80),
isSolarPanelWithinWarranty.
calculateExpectedPanelOutput(panel, ambientTempC, irradianceWm2) applies a
NOCT cell-temperature and irradiance correction:
peakPowerWp × irradianceFactor × tempFactor. Factory:
createDefaultESSPerformance() (94% round-trip efficiency, 200 ms response,
3500 cycles at rated DOD).
IoT and electronics (iot.ts)#
This module covers IoT devices, sensor readings, connectivity profiles, PCB designs, electronic assemblies, and smart-city assets. It is the largest type module in the domain because IoT and electronics span both high-frequency telemetry (millions of readings per day) and slow-moving design artifacts (PCB revisions that change rarely but carry extensive compliance metadata).
IoTDevice (task 60.2.3.1)#
id: IoTDeviceId, deviceId (EUI-64 or UUID), name,
deviceType: IoTDeviceType, manufacturer/model, firmwareVersion,
hardwareVersion, connectivity: ConnectivityProfile, optional gatewayId,
deployment fields (site, address, lat/lng, date, deploymentHeightM),
telemetrySchema: TelemetrySchema, alertRules: AlertRule[], live status
(isOnline, lastSeenAt, lastTelemetryAt, batteryLevelPercent,
signalStrengthDbm, rssi, snr), maintenance fields, and ownership
(ownerOrganizationId, projectId).
IoTDeviceType (14): air_quality_sensor, water_meter, electricity_meter,
waste_bin_sensor, street_light_controller, traffic_sensor, flood_sensor,
weather_station, structural_monitor, soil_sensor, gateway,
edge_compute, tracking_device, environmental_monitor. TelemetrySchema is
a record of field name →
{ type, unit, sensorType, min?, max?, precision?, description }. AlertRule
has field, operator (>, >=, <, <=, ==, !=, change_exceeds),
threshold, severity (critical | high | medium | low | info),
notificationChannels (subset of email, sms, push, webhook), and
cooldownMinutes.
ConnectivityProfile (task 60.2.3.5)#
The connectivity profile allows the same IoTDevice entity to cover a LoRaWAN
soil-moisture sensor and a 5G edge-compute node without a proliferation of
subtypes. The optional secondary and fallback protocols model devices with
redundant radios.
primaryProtocol, optional secondaryProtocol and fallbackProtocol, optional
lorawanConfig, nbIotConfig, wifiConfig, quality metrics
(targetUplinkIntervalSec, maxTransmissionLatencyMs, minRssiDbm), data
fields (payloadFormatVersion, payloadEncoding in binary | json | cbor
| protobuf, maxPayloadBytes), and uptime targets. ConnectivityProtocol
(12): lorawan, nb_iot, lte_m, sigfox, zigbee, zwave, ble, wifi,
ethernet, cellular_4g, cellular_5g, satellite. LoRaWANConfig carries
devEui, appEui, appKey (stored encrypted), activationMode (OTAA |
ABP), spreadingFactor (7–12), bandwidthKhz (125 | 250 | 500), codingRate
(4/5–4/8), and networkServerId.
SensorReading (task 60.2.3.2)#
The sequenceNumber and uplinkId fields implement requirement 2 (telemetry
identity) — they allow the ingest pipeline to detect and discard duplicates and
to reconstruct the exact order of readings from a device without relying on
wall-clock timestamps alone.
timestamp (ISO 8601 with milliseconds), deviceId: IoTDeviceId,
sensorType: SensorType, value (number, string, or boolean), unit,
quality: SensorQuality, optional calibration fields (rawValue,
calibrationOffset, calibrationFactor, lastCalibrationDate), and context
(sequenceNumber for ordering/deduplication, batteryLevelPercent,
signalStrengthDbm, uplinkId — the LoRaWAN frame counter or message ID).
SensorType (28 values, including temperature, humidity, pressure,
pm2_5, pm10, co2, voc, no2, co, o3, noise_db, water_flow,
water_level, soil_moisture, soil_temperature, solar_irradiance,
wind_speed, rainfall, fill_level, vibration, tilt, acceleration,
gps_latitude, gps_longitude, power_kwh, current_a, voltage_v,
binary_event). SensorQuality (5): good, uncertain, bad,
sensor_error, out_of_range.
PCB (task 60.2.3.3)#
id: PCBDesignId, designCode, projectName, revisionNumber, optional
customerId, PCB specs (layerCount, dimensions, surfaceFinish,
copperWeightOz, trace/spacing minima, ipcClass, tgC), assembly fields
(smdComponents, throughHoleComponents, hasBga, hasFinePitchMm,
doubleSided, hasConformalCoating), BOM (bomRevision,
bomItems: BOMItem[], totalBomCostUsd), test requirements (ictRequired,
aoiRequired, xrayRequired, functionalTestRequired, testCoveragePercent),
optional latestTestResults: PcbTestResult[], file references, status
(draft | under_review | approved | in_production | obsolete), and
standards flags (ulCertified, ceCertified, fccCertified). IpcClass is
Class_1 | Class_2 | Class_3. SurfaceFinish (7): HASL,
HASL_lead_free, ENIG, ENEPIG, OSP, Immersion_Tin, Immersion_Silver.
BOMItem carries reference designators, MPN, mslLevel (Moisture Sensitivity
Level 1–6), roHsCompliant, and approved alternates. PcbTestResult.testType
is AOI | ICT | FCT | X-Ray | Visual.
ElectronicAssembly (task 60.2.3.4)#
id, assemblyCode, version, pcbId, optional enclosure: EnclosureSpec,
cableHarnesses: CableHarness[], externalConnectors, test references,
assembly metadata (toolsRequired, estimatedAssemblyTimeMin), environmental
ratings, and status (design | prototype | production | obsolete).
EnclosureSpec.mountingType is din_rail | wall_mount | rack_mount |
desktop | handheld | panel_mount.
SmartCityAsset (task 60.2.3.6)#
id, assetCode, assetType: SmartCityAssetType, location (lat/lng, address,
ward, district, city), optional iotDeviceId, isSmartEnabled, free-form
specs, status (active | inactive | fault | maintenance |
decommissioned), inspection dates, ownership, smart-capability flags
(remotlyControlled, dataCollectionEnabled, alertingEnabled), install date.
SmartCityAssetType (9): street_light, waste_bin, water_meter,
air_quality_node, traffic_light, parking_sensor, noise_monitor,
flood_gauge, weather_station.
IoT schemas, guards, factories#
SensorReadingSchema, IoTDeviceSchema. Guards: isIoTDevice,
isSensorReading, isDeviceOnline (default 10-minute offline threshold),
isSensorReadingInRange (rejects bad/sensor_error quality, then checks
against the device's telemetry-schema min/max). Factory:
createLoRaWANConnectivityProfile(devEui, appEui, uplinkIntervalSec).
Pharmaceutical and medical (pharma.ts)#
This module covers both pharmaceuticals and medical devices because their
compliance concerns overlap (regulatory submissions, GMP, ISO standards) and
they share the RegulatorySubmission cross-BU type. The clinical evaluation
types implement the ISO 14971 risk-analysis structure required by EU MDR.
Pharmaceutical (task 60.2.4.1)#
id: PharmaceuticalId, productCode, internationalNonproprietaryName (INN),
brandName, dosageForm: DosageForm, strength, route: PharmaceuticalRoute,
therapeuticClass (ATC Level 3), atcCode (WHO ATC code),
apiComposition: APIComposition[], excipients: ExcipientList[], regulatory
fields (fdaGhanaRegistrationNumber, fdaGhanaRegistrationExpiry,
nafdacNigeriaNumber, whoPrequalificationNumber, regulatoryStatus), quality
fields (pharmacopoeiaCompliance, shelfLifeMonths, storageConditions,
packagingType, primaryPackagingMaterial), schedule flags (isNarcotic,
isControlledSubstance, scheduleClass), and Ghana-specific flags
(essentialMedicineGhana, nhisListed).
Pharmaceutical.regulatoryStatus (7): not_started, in_preparation,
submitted, under_review, approved, rejected, expired. DosageForm has
25 values (tablet, coated_tablet, sustained_release_tablet, capsule,
hard_capsule, soft_gel_capsule, oral_solution, oral_suspension, syrup,
elixir, injection_solution, injection_suspension, powder_for_injection,
cream, ointment, gel, suppository, dry_powder_inhaler,
metered_dose_inhaler, transdermal_patch, eye_drops, ear_drops,
nasal_spray, granules, sachets, lyophilized_powder).
PharmaceuticalRoute has 13 values (oral, parenteral_iv, parenteral_im,
parenteral_sc, topical, inhalation, rectal, vaginal, ophthalmic,
otic, nasal, transdermal, sublingual).
BatchRecord (task 60.2.4.2)#
The batch record is the primary GMP artifact. It must be traceable to its pharmaceutical, its equipment (with qualification status), and every deviation raised during production. The qualified-person sign-off field implements the EU-style QP release requirement.
id: BatchRecordId, batchNumber, productId, batch details (batchSize,
batchUnit, theoreticalYield, actualYield, yieldPercent), schedule dates,
shelfLifeMonths, manufacturing fields (manufacturingSite,
manufacturingRoom, equipmentUsed: EquipmentUsed[],
processParameters: ProcessParameter[]), personnel (productionSupervisorId,
qcAnalystId, qualifiedPersonId — the EU QP or equivalent),
qcResults: QCTestResult[], qcStatus (pass | fail | conditional_pass |
retest | pending), release fields, status (planned | in_production |
qc_testing | released | rejected | quarantine),
deviations: Deviation[], changeControls, recall flags, and storage fields.
EquipmentUsed.qualificationType is OQ | PQ | DQ | IQ. Deviation.type
is critical | major | minor.
MedicalDevice (task 60.2.4.3)#
id: MedicalDeviceId, deviceCode, name, genericName,
deviceClass: MedicalDeviceClass, intendedUse, indicationsForUse,
classification codes (gmdnCode, unspscCode, isoMdnCode), device-character
flags (isInVitroDiagnostic, isImplantable, isSterile,
sterilizationMethod, hasElectronics, hasSoftware, softwareSafetyClass in
A | B | C per IEC 62304, contactWithPatient, contactDuration,
invasive, surgicallyInvasive), regulatory fields
(regulatoryPathway: RegulatoryPathway, regulatoryStatus, authority numbers),
manufacturing-quality flags (iso13485Certified, gmpCertified), and
post-market fields (udiCode, udiIssuerAgency in GS1 | HIBCC | ICCBBA,
pmsRequired, pmcfRequired, vigilanceReportingRequired).
MedicalDeviceClass (4): class_i, class_iia, class_iib, class_iii.
RegulatoryPathway (10): fda_510k, fda_pma, fda_de_novo,
eu_mdr_class_i, eu_mdr_notified_body, who_prequalification,
ghana_fda_class_i, ghana_fda_class_ii, ghana_fda_class_iii,
iso_13485_only. MedicalDevice.regulatoryStatus (5): not_started,
in_preparation, submitted, approved, rejected.
ClinicalEvaluation (task 60.2.4.4)#
evaluationId, deviceId, evaluationDate, clinicalEvaluatorId (medically
qualified per EU MDR), clinicalDataSources: ClinicalDataSource[], optional
equivalentDeviceClaim, state-of-the-art fields, risks: RiskEntry[] (ISO
14971 risk analysis), overallResidualRisk (acceptable | unacceptable),
benefit-risk fields (benefitRiskConclusion in positive | negative |
inconclusive), and outcome (clinicalEvaluationConclusion in
device_conforms | requires_additional_data | negative). RiskEntry
carries probability and severity on 1–5 ISO 14971 scales and a computed
riskScore.
GMPFacility (task 60.2.4.5)#
id, facilityCode, name, siteAddress, licenseNumber, licenseExpiry,
cleanRooms: CleanRoomSpec[], totalCleanRoomAreaM2,
qualifiedEquipment: GmpEquipment[], GMP-certification flags
(whoGmpCertified, fdaGhanaApproved, iso9001Certified),
utilities-qualification flags (purifiedWaterSystemValidated,
wfiSystemValidated, hvacSystemValidated, compressedAirQualityVerified,
nitrogenQualityVerified), capacity fields, personnel counts
(qualifiedPersonCount, pharmacistsCount, qcPersonnelCount), and inspection
fields (lastInspectionOutcome in satisfactory | deficiencies_observed |
warning_letter | import_alert, outstandingCAPAs).
CleanRoomSpec.isoClassification is ISO_5 | ISO_6 | ISO_7 | ISO_8 (ISO
14644); euGmpClassification is A | B | C | D (EU GMP Annex 1).
Pharma schemas, guards, factories#
MedicalDeviceClassSchema, PharmaceuticalSchema (the ATC code is validated
against /^[A-Z]\d{2}[A-Z]{2}\d{2}$/). Guards: isMedicalDeviceClass,
requiresNotifiedBody (true for class_iib and class_iii),
requiresClinicalTrial (true for class_iii or surgicallyInvasive),
isBatchReleaseReady (qcStatus === 'pass', status === 'qc_testing', all
deviations closed or minor). Helpers: calculateBatchYieldPercent,
isPharmaceuticalExpired, daysToExpiryFromDate.
Robotics and drones (robotics.ts)#
This module covers both robotics and drones because their operational patterns
are similar — task scheduling, telemetry, safety checks, and compliance — and
they share the geo-coordinate and waypoint types. The GCAA 400-m altitude cap
enforced in isFlightPlanSafe is a hard invariant, not a configurable
threshold.
Robot (task 60.2.5.1)#
id: RobotId, robotId, serialNumber, name, robotType: RobotType,
model, manufacturer, firmware/hardware versions, hardware
(actuators: Actuator[], sensors: RobotSensor[],
navigationMode: NavigationMode, aiCapabilities: AICapability[], aiChip,
computeUnit), power fields, physical fields, communication
(communicationProtocols, remoteControlEnabled, telemetryEnabled), status
(active | inactive | maintenance | charging | fault |
decommissioned), deployment fields, performance metrics
(totalOperatingHours, totalTasksCompleted, averageTaskSuccessRate,
uptimePercent), and safety fields (safetyStandard such as ISO 10218 / ISO
15066, emergencyStopEnabled, collisionAvoidanceEnabled,
geofencingEnabled).
RobotType (10): household_cleaning, household_cooking_assist,
household_eldercare, construction_rebar_tying, construction_bricklaying,
construction_plastering, construction_surveying, waste_sorting_optical,
waste_sorting_magnetic, waste_sorting_ai. NavigationMode (8): slam,
gps, beacon, hybrid_slam_gps, visual_odometry, lidar, teleoperated,
fixed_path. Actuator.type is servo | stepper | bldc | pneumatic |
hydraulic | linear_actuator. RobotSensor.type has 13 values including
lidar_2d, lidar_3d, camera_rgb, camera_depth, camera_thermal,
hyperspectral, x_ray, magnetic.
RobotTask (task 60.2.5.2)#
id: RobotTaskId, taskCode, robotId, taskType: RobotTaskType, priority
(critical | high | medium | low), status: RobotTaskStatus,
parameters (work area, waypoints, repeat count, speed/force limits, material
type, quality threshold, custom params), scheduling fields, location context,
results (completionPercent, outputMetrics, qualityScore), and error/safety
fields (errorCode, safetyEventsCount, humanInterventionRequired).
RobotTaskType (13): clean_floor, clean_surface, cook_meal,
serve_medication, tie_rebar, lay_bricks, apply_plaster, survey_site,
sort_waste_optical, sort_waste_magnetic, transport_material, charge,
diagnostic. RobotTaskStatus (7): queued, assigned, in_progress,
paused, completed, failed, cancelled.
Drone (task 60.2.5.3)#
id: DroneId, droneId, serialNumber, droneType: DroneType, model,
manufacturer, firmwareVersion, GCAA registration fields
(gcaaRegistrationNumber, registrationExpiry, operatorCertificationNumber,
insurance fields), performance specs (payload, takeoff/empty weight, flight time
with and without payload, maxRangeKm, maxHoverAltitudeM, maxSpeedMs,
maxWindSpeedMs, maxRainfallTolerance in none | light | moderate),
hardware (motorSpec, flightController, sensorSuite), power, communication,
status (active | inactive | maintenance | grounded | in_flight |
decommissioned), position/usage counters, availablePayloads, and compliance
flags (remoteIdEnabled, utmEnabled). DroneType (6):
multirotor_quadcopter, multirotor_hexacopter, multirotor_octocopter,
fixed_wing, vtol_fixed_wing, single_rotor.
DroneFlightController.redundancyLevel is none | dual_gps |
triple_redundant.
FlightPlan (task 60.2.5.4)#
The flight plan captures everything GCAA requires for a safe, authorized sortie: airspace class, BVLOS authorization, geofence geometry, weather minimums, and the return-to-home battery threshold. The gateway rejects any plan that violates the 400-m AGL cap at creation time, not just at runtime.
id: FlightPlanId, planCode, droneId, missionType, pilotId,
pilotLicenseNumber, airspace-authorization fields (gcaaFlightPermitNumber,
permitExpiry, operationalArea polygon), flight geometry
(homeBase: GeoCoordinate, waypoints: Waypoint[], totalDistanceKm,
estimatedDurationMin, min/max altitude), airspace fields
(airspaceRestrictions: AirspaceRestriction[], airspaceClass A–G,
vlosRequired, bvlosAuthorized, nightFlightAuthorized), safety parameters
(geofenceEnabled, geofenceGeometry, rthAltitudeM, rthTrigger in
low_battery | signal_loss | both, minReturnBatteryPercent,
maxWindSpeedAutoLandMs), weatherRequirements: WeatherRequirements, payload
configuration, grid/survey parameters, status (draft | pending_approval |
approved | ready | active | completed | cancelled | aborted),
schedule timestamps, and results. Waypoint extends GeoCoordinate with
speedMs, loiterTimeS, action (take_photo | start_video | stop_video
| spray | land | rtl | survey_row), heading, gimbalPitchDeg.
AirspaceRestriction.type is ctr | tma | atz | restricted | danger |
prohibited | temporary.
DronePayload (task 60.2.5.5)#
id, payloadCode, name, payloadType: DronePayloadType, manufacturer,
model, weight, power requirement, mountType (top_mount | bottom_gimbal |
side_mount | belly_hook), type-specific specs, capacity fields
(tankCapacityL, maxCargoKg), compatibleDroneModels, and status
(available | attached | maintenance | decommissioned).
DronePayloadType (10): camera_rgb, camera_multispectral, camera_thermal,
lidar_scanner, radar, agricultural_sprayer, delivery_box, cargo_hook,
loudspeaker, gas_detector.
Robotics schemas, guards, factories#
RobotTypeSchema (10 values), DroneSchema, WaypointSchema,
FlightPlanSchema (requires at least two waypoints). Guards: isDroneAirworthy
(status === 'active', battery >= 30%, batteryFlightCycles < 200),
isFlightPlanSafe (current wind within limit, maxAltitudeM <= 400 — the Ghana
GCAA general altitude cap — and minReturnBatteryPercent >= 15),
isRobotReadyForTask (status === 'active', battery >= 20%, no current
task). Factories: createDefaultWeatherRequirements(droneType),
estimateDroneFlightTime(drone, payloadWeightKg, windSpeedMs).
Telecom and satellite (telecom.ts)#
This module covers telecom tower infrastructure and satellite communications. Both categories depend on geospatial positioning (PostGIS geometry columns) and regulatory permits — NCA for towers, NCA certification for ground stations — because their physical siting is governed by spectrum and land-use regulation.
TelecomTower (task 60.2.6.1)#
id: TelecomTowerId, siteId, name, towerType: TowerType, location
(address, community, district/region/country, lat/lng,
elevationAmslM), structural: TowerStructuralSpec, tenants: TowerTenant[],
maxTenantCount, antennas: TowerAntenna[], backhaulConnections (each with
type microwave | fiber | satellite, capacityGbps, provider,
primaryLink), powerSystem: TowerPowerSystem, land-lease fields, status
(active | inactive | under_construction | maintenance |
decommissioned), inspection dates, and revenue fields.
TowerStructuralSpec.upliftAvailableKg is the remaining structural capacity for
new tenants; TowerAntenna.polarization is horizontal | vertical |
cross_polar. TowerType (8): monopole, guyed_mast,
self_supporting_lattice, rooftop_monopole, rooftop_frame,
ground_based_lattice, camouflaged_tree, camouflaged_flagpole.
TowerSite (task 60.2.6.2)#
id, siteId, location, land-owner fields, land-lease fields, access fields
(accessRoadType in tarmac | gravel | dirt | none,
accessRoadCondition, gatedAccess, securityGuard), utilities, permit fields
(buildingPermitNumber, ncaConstructionPermitNumber, epaClearanceNumber),
optional environmentalAssessment: EnvironmentalAssessment, site-survey dates,
and status (surveyed | acquired | permitted | under_construction |
operational | decommissioned). EnvironmentalAssessment records ICNIRP /
Ghana EPA radiation compliance.
Satellite (task 60.2.6.3)#
id, noradId, name, operator, orbitType: SatelliteOrbitType, orbital
parameters, coverage fields (coverageRegions, coverageArea polygon),
uplinkBands and downlinkBands (arrays of FrequencyBand), bandwidth fields
(totalCapacityGbps, availableCapacityGbps, beamType in wide_beam |
spot_beam | steerable_beam, numberOfBeams), roundTripLatencyMs, and
operational fields (launchDate, expectedEndOfLifeDate, currentStatus in
operational | degraded | retired). SatelliteOrbitType (4): leo, meo,
geo, heo. FrequencyBand (8): l_band, s_band, c_band, x_band,
ku_band, ka_band, v_band, q_band.
VSATTerminal (task 60.2.6.4)#
id: VSATTerminalId, terminalId, serialNumber, antenna fields
(antennaType in dish_parabolic | flat_panel_esim | phased_array,
diameter, gain, transmit power), frequency fields, modem fields, service fields
(serviceProvider, satelliteName, serviceType in star | mesh |
hybrid), bandwidth fields (downloadMbps, uploadMbps,
contractedBandwidthMbps, contendedRatio, burstableUpTo), installation
fields (customer, address, lat/lng, azimuthDeg, elevationDeg), status
(active | inactive | maintenance | fault), uptimePercent,
lastHeartbeatAt, signalLevelDb, and billing fields.
GroundStation (task 60.2.6.5)#
id: GroundStationId, stationCode, name, operatedBy, location,
antennas: GroundStationAntenna[], processing fields (processingCapacity,
satelliteModems, demodulatorCount), networkConnections (each with type
fiber | microwave | ip_vpn), power fields, regulatory fields
(ncaCertified, ncaCertExpiry, ncaLicenseNumber), status (operational |
maintenance | offline), maintenance dates, and service fields
(activeTerminals, totalBandwidthMbps). GroundStationAntenna.type is
parabolic_dish | phased_array | turnstile.
Telecom schemas, guards, factories#
TelecomTowerSchema, VSATTerminalSchema. Guards: isTowerCapacityAvailable
(checks structural.upliftAvailableKg against an additional payload),
isVSATTerminalOnline (default 15-minute threshold). Helper:
calculateTowerRevenue (sums tenant monthly rent). Factory:
createDefaultPowerSystem(gridAvailable, solarKwp).
E-waste, additive, security, fintech, and shared (manufacturing.ts)#
This module groups the five remaining business-unit entity types along with the
shared cross-BU types (ManufacturingOrder, QualityTestResult,
RegulatorySubmission, MaintenanceRecord, SupplyChainEvent,
MarketDataPoint) that are used across multiple business units. The shared
types are defined here rather than in their primary BU because they are truly
cross-cutting — a RegulatorySubmission applies equally to pharmaceuticals,
medical devices, and vehicles.
EWasteItem (task 60.2.7.1)#
itemId, itemType: EWasteItemType, brand/model/age, weightKg, condition
(working | partially_working | broken | crushed),
hazardClass: HazardClass, optional
materialCompositionEstimate: MaterialCompositionEstimate, chain-of-custody
fields (serialNumber, dataWipingRequired, dataWipingCertificate), and
processingRoute (refurbishment | component_harvest | material_recovery |
safe_disposal). EWasteItemType (17 values from mobile_phone to
telecom_equipment). HazardClass (5): non_hazardous, low_hazard,
medium_hazard, high_hazard, restricted_export (Basel Convention).
MaterialCompositionEstimate itemizes recoverable masses including gold_g,
silver_g, palladium_g, cobalt_kg, lithium_kg, lead_kg, mercury_g.
RecoveredMaterial (task 60.2.7.2)#
id, recoveryBatchCode, collectionId: EWasteCollectionId, recoveryDate,
processingFacilityId, material spec (materialType: RecoverableMaterial,
grade: MaterialGrade, weightKg, purityPercent), assay fields, value fields
(spotPriceUsdPerKg, estimatedValueUsd, actualSaleValueGhs, buyer/sale
fields), Basel-Convention fields (exportPermitNumber, destinationCountry),
and a chainOfCustody array. RecoverableMaterial (14): gold, silver,
palladium, platinum, copper, aluminum, steel, cobalt,
lithium_carbonate, nickel, plastic_abs, plastic_hdpe, glass,
ferrites. MaterialGrade (6): doré, refined_99_5, refined_99_9,
commercial_grade, industrial_grade, scrap.
PrintJob (task 60.2.7.3)#
id: PrintJobId, jobCode, printerId: PrinterId, optional customerId,
projectName, partName, quantity, design-file references, print parameters
(material: PrintMaterial, layerHeightMicron, infillPercent,
infillPattern in grid | honeycomb | gyroid | triangles | lines |
rectilinear, shellCount, printSpeedMms, temperatures, support settings),
sliced dimensions, estimates, quality requirements (dimensionalToleranceMm,
surfaceRoughnessRaUm, requiresPostProcessing, postProcessingSteps,
requiresInspection), and results (status in queued | printing | paused
| completed | failed | cancelled, qualityResult in pass | fail |
conditional_pass). PrintMaterial (14 values, including
metal_stainless_316l, metal_titanium_ti64, metal_aluminum_almg,
metal_inconel_625, concrete).
AdditiveManufacturingMaterial (task 60.2.7.4)#
id, materialCode, name, materialType: PrintMaterial, manufacturer,
diameter (1.75mm | 2.85mm | spool | powder_kg), mechanical/thermal
properties, drying requirements, available colors, cost fields, and stock fields
(quantityKgOnHand, reorderPointKg, supplier, leadTimeDays).
SecuritySystem (task 60.2.7.5)#
id: SecuritySystemId, systemCode, name, systemType (cctv_only |
access_control_only | intrusion_only | integrated), customerId, install
fields, location, CCTV fields (cameras: SecurityCamera[], totalCameras,
activeCameras, vmsServer, nvrModel, storageCapacityTb, retentionDays),
access-control fields (accessPoints: AccessControlPoint[]), alarmZones (each
with type perimeter | interior | panic | fire | flood), AI-analytics
fields, monitoring fields, and status (active | inactive | maintenance |
alarm). SecurityCamera.type is fixed | ptz | panoramic | fisheye |
thermal; AccessControlPoint.authMethods is a subset of pin, card,
fingerprint, face, iris, qr.
Fintech hardware (POSTerminal, ATM, Kiosk, BiometricDevice —#
tasks 60.2.8.1–60.2.8.4)
FintechTerminalType (9): pos_countertop, pos_mobile, pos_pin_pad,
atm_standalone, atm_drive_through, kiosk_banking, kiosk_government,
kiosk_telecom, kiosk_retail.
POSTerminal: id: FintechTerminalId, terminalId, serialNumber,
terminalType (the three pos_* values), manufacturer/model/firmware, PCI
fields (pciPtsCertNumber, pciPtsCertExpiry, pciPtsVersionApproved,
pciDssCompliant, emvL1Certified, emvL2Certified, emvContactless),
payment-method flags (acceptsChip, acceptsMagstripe, acceptsContactless,
acceptsQrCode, acceptsMobileMoney, mobileMoneySupportedNetworks),
connectivity, hardware, deployment fields, status (active | inactive |
fault | decommissioned), and usage counters.
ATM: id, terminalId, serialNumber, terminalType (atm_standalone |
atm_drive_through), PCI fields (pciHsmCertNumber, pciDssCompliant),
cash-management fields (cashCassettes, cashCapacityUnits,
denominationsSupported, cashLevelPercent, lowCashAlert), biometric flags,
hardware, network, deployment fields, status (active | inactive | fault
| out_of_cash | maintenance), and performance fields.
Kiosk: id, terminalId, serialNumber, terminalType (the four kiosk_*
values), purpose, hardware capability flags, OS/software platform,
connectivity, deployment fields, status (active | inactive | fault |
maintenance).
BiometricDevice: id, deviceCode, manufacturer/model, modality
(fingerprint | face | iris | palm_vein | finger_vein | multi_modal),
sensor specs, performance metrics (falseMatchRate, falseNonMatchRate,
failureToEnrollRate, enrollmentTimeS, verificationTimeMs per ISO/IEC
19795), standards-compliance flags (iso19794Compliant, fips201Compliant,
fidoCertified), operating conditions, and applications.
Shared cross-BU domain types (task 60.2.9.x)#
These six types appear in the domain model wherever a concept applies across
multiple business units. They are defined once in manufacturing.ts and
re-exported from the @saraswati/core barrel.
ManufacturingOrder<T> (60.2.9.1) — generic production order with productSpec
of type T, billOfMaterials (each line has status available | on_order
| shortage), qualityRequirements, traceability fields, and status (draft
| confirmed | material_procurement | in_production | quality_check |
completed | cancelled).
QualityTestResult (60.2.9.2) — parameters array with per-parameter
specification, measuredValue, pass, and uncertainty; overallResult
(pass | fail | conditional_pass | retest); optional certificate fields
and dispositionDecision (accept | reject | rework | scrap |
concession).
RegulatorySubmission (60.2.9.3) — productType (pharmaceutical |
medical_device | vehicle | food | chemical), authority,
submissionType (initial_registration | renewal | variation |
line_extension | labeling_change | type_approval), requiredDocuments,
status (9 values: not_started, in_preparation, submitted,
under_review, additional_info_required, approved, rejected, withdrawn,
expired), fees, and a queries array.
MaintenanceRecord (60.2.9.4) — maintenanceType (scheduled | corrective |
predictive | inspection | overhaul | emergency), usage-at-maintenance
fields, partsReplaced, softwareUpdated/newFirmwareVersion, cost fields,
findings, and next-due fields.
SupplyChainEvent (60.2.9.5) — eventType (11 values from purchase_order
through disposal), location, material reference, actor, transaction reference,
value, qualityStatus (passed | failed | hold | pending), and status
(planned | in_transit | completed | exception).
MarketDataPoint (60.2.9.6) — businessUnit, metricName, metricCategory
(market_size | market_share | growth_rate | price | demand |
competition | regulatory | technology), geography, timePeriod,
value, unit, source, confidenceLevel (0–1), isProjected,
projectionCagr, and optional competitor fields.
Shared schemas: ManufacturingOrderSchema, QualityTestResultSchema,
MarketDataPointSchema. Guards: isQualityTestPassed,
isManufacturingOrderComplete, isRegSubmissionApproved,
isRegSubmissionExpired, isHighHazardEWaste. Helpers: estimateEWasteValue
(values a composition estimate against per-material USD/kg prices, with
documented default prices), createDefaultMaintenanceRecord.
Persistence (@saraswati/db)#
@saraswati/db is the single data layer for the entire domain. All persistence
decisions — table structure, indexes, geospatial columns, time-series
hypertables, vector columns, connection pools, and cache TTLs — are centralized
here. The separation between the OLTP pool (getPool) and the telemetry-ingest
pool (getTelemetryPool) exists because telemetry writes are high-frequency and
should not block ordinary CRUD operations.
The domain database is saraswati (PostgreSQL with the PostGIS, TimescaleDB,
and pgvector extensions). The connection URL is the SARASWATI_DATABASE_URL
environment variable. The schema is defined with Drizzle ORM in
libs/saraswati/db/src/schema.ts.
Shared enums#
These four enums are reused across many tables to avoid per-table duplication. Per-BU enums with domain-specific values are listed separately below.
saraswati_status (active, inactive, maintenance, decommissioned,
pending); saraswati_priority (critical, high, medium, low);
saraswati_quality_status (pass, fail, conditional_pass, retest,
pending); saraswati_regulatory_status (not_started, in_preparation,
submitted, under_review, additional_info_required, approved, rejected,
withdrawn, expired).
Tables#
All tables use a gen_random_uuid() UUID primary key and created_at /
updated_at timestamps. Tables, grouped by schema area:
- Vehicle records (60.1.2.1) —
saraswati_vehicle_designs,saraswati_vehicles,saraswati_charging_stations,saraswati_vehicle_service_history. - Battery (60.1.2.2) —
saraswati_battery_cells,saraswati_battery_modules,saraswati_battery_packs, and the TimescaleDB hypertablesaraswati_battery_telemetry. - Solar (60.1.2.3) —
saraswati_solar_panels,saraswati_solar_home_systems,saraswati_solar_installations, and the hypertablesaraswati_solar_telemetry. - IoT (60.1.2.4) —
saraswati_iot_devicesand the hypertablesaraswati_iot_telemetry. - Electronics (60.1.2.5) —
saraswati_pcb_designs,saraswati_production_orders,saraswati_component_inventory. - Pharmaceutical (60.1.2.6) —
saraswati_pharmaceuticals,saraswati_batch_records,saraswati_gmp_facilities. - Robotics (60.1.2.7) —
saraswati_robots,saraswati_robot_tasks,saraswati_robot_maintenance_logs. - Drones (60.1.2.8) —
saraswati_drones,saraswati_flight_plans. - Telecom (60.1.2.9) —
saraswati_telecom_towers. - Medical devices (60.1.2.10) —
saraswati_medical_devices,saraswati_regulatory_submissions,saraswati_post_market_events. - Fintech hardware (60.1.2.11) —
saraswati_fintech_terminals. - Security systems (60.1.2.12) —
saraswati_security_systems,saraswati_alarm_events. - E-waste (60.1.2.13) —
saraswati_ewaste_collections,saraswati_recovered_materials. - Additive manufacturing (60.1.2.14) —
saraswati_printers,saraswati_print_jobs. - Satellite (60.1.2.15) —
saraswati_vsat_terminals,saraswati_ground_stations. - Market intelligence (60.1.2.16) —
saraswati_market_intelligence. - Financial models (60.1.2.17) —
saraswati_financial_models.
Per-table enums#
The schema defines additional Postgres enums beyond the four shared ones,
including saraswati_vehicle_type, saraswati_vehicle_status,
saraswati_motor_type, saraswati_battery_chemistry,
saraswati_battery_cell_form_factor, saraswati_solar_panel_type,
saraswati_shs_tier, saraswati_iot_device_type,
saraswati_connectivity_protocol, saraswati_production_order_status (15
values: draft, confirmed, material_procurement, ready_to_produce,
smt_in_progress, smt_complete, tht_in_progress, tht_complete,
aoi_inspection, ict_testing, functional_testing, rework,
quality_approved, shipped, cancelled), saraswati_dosage_form (14
values), saraswati_robot_type, saraswati_robot_task_status,
saraswati_drone_type, saraswati_mission_type (11 values: aerial_survey,
photogrammetry, lidar_mapping, agricultural_spraying,
infrastructure_inspection, pipeline_inspection, delivery,
search_and_rescue, security_patrol, environmental_monitoring,
telecoms_relay), saraswati_tower_type, saraswati_medical_device_class,
saraswati_fintech_terminal_type, saraswati_ewaste_item_type,
saraswati_hazard_class, saraswati_printer_technology (8 values: fdm,
sla, sls, dmls, mjf, binder_jetting, dlp, concrete_printing),
saraswati_orbit_type, saraswati_frequency_band.
Keys, indexes, and constraints#
Each table carries a natural-key unique index — design_code, vin,
serial_number, station_code, cell_model_code, module_code, pack_code,
order_number, device_id, batch_number, facility_code, robot_id,
task_code, drone_id, plan_code, site_id, device_code,
submission_number, terminal_id, system_code, event_id,
collection_code, recovery_batch_code, printer_id, job_code,
station_code, data_point_code, model_code — plus secondary indexes on
status, type, customer/fleet, geographic, and date columns. Foreign keys link
the hierarchy: vehicles → vehicle designs and battery packs; battery packs →
modules → cells; battery packs → vehicles; solar installations → solar home
systems → panels; production orders → PCB designs; batch records → and
regulatory submissions → pharmaceuticals; robot tasks and maintenance logs →
robots; flight plans → drones; regulatory submissions and post-market events →
medical devices; alarm events → security systems; recovered materials → e-waste
collections; print jobs → printers; battery/solar/IoT telemetry → their parent
records.
Drizzle relations#
schema.ts declares Drizzle relations for the parent/child graph above:
vehicleDesignsRelations, vehiclesRelations, batteryPacksRelations,
batteryModulesRelations, solarHomeSystemsRelations,
solarInstallationsRelations, iotDevicesRelations, pcbDesignsRelations,
pharmaceuticalsRelations, robotsRelations, dronesRelations,
medicalDevicesRelations, securitySystemsRelations,
eWasteCollectionsRelations, printersRelations.
Time-series storage (TimescaleDB)#
Three hypertables hold telemetry. Continuous aggregates roll up raw readings into hourly and daily summaries so dashboard queries do not scan the full raw table. Retention policies evict old raw data after the policy window while keeping aggregates indefinitely.
saraswati_battery_telemetry (partition key time, 1-day chunks) records
per-pack SoC/SoH, voltage, current, power, min/max/avg temperatures, cell
voltages, balancing state, error_flags, and charging state.
saraswati_solar_telemetry (7-day chunks) records per-installation panel power,
battery voltage/current/SoC, load power, irradiance, ambient/panel temperature,
daily yield, and PAYGO status. saraswati_iot_telemetry (7-day chunks) records
per-device JSONB readings, battery level, signal strength, sequence number,
LoRaWAN frame port, raw payload, and processing latency. migrations.ts creates
these hypertables via createHypertables(), builds three continuous aggregates
(saraswati_iot_telemetry_hourly, saraswati_battery_telemetry_daily,
saraswati_solar_telemetry_daily) via createContinuousAggregates(), and sets
retention policies via setupRetentionPolicies(): raw IoT telemetry 90 days,
raw battery telemetry 30 days, raw solar telemetry 90 days (aggregates kept).
Geospatial storage (PostGIS)#
createSpatialIndices() adds a SRID-4326 geom POINT column, populates it from
the table's lat/lng pair, and creates a GiST index for seven tables:
saraswati_charging_stations, saraswati_vehicles, saraswati_telecom_towers,
saraswati_iot_devices, saraswati_solar_installations, saraswati_drones,
saraswati_vsat_terminals.
Vector storage (pgvector)#
pgvector columns support three AI/ML use cases that require nearest-neighbor
search over high-dimensional embeddings. The ivfflat cosine-similarity index
makes similarity queries fast at scale.
addVectorColumns() adds embedding columns and ivfflat cosine-similarity
indexes: saraswati_pcb_designs.design_embedding (vector(1536), for
defect-detection clustering), saraswati_ewaste_collections.item_embedding
(vector(1536), for material classification), and
saraswati_iot_devices.telemetry_pattern_embedding (vector(768), for anomaly
detection).
Extensions and setup#
installExtensions() creates postgis, postgis_topology, timescaledb,
vector, and pgcrypto. runDatabaseSetup() runs, in order:
installExtensions, createHypertables, createContinuousAggregates,
addVectorColumns, createSpatialIndices, setupRetentionPolicies.
Connection pooling#
The two-pool design separates concerns: the OLTP pool handles ordinary requests and can be safely saturated by concurrent API traffic without blocking the telemetry ingest path.
getPool() returns a shared pg Pool keyed off SARASWATI_DATABASE_URL with
defaults of 20 max / 2 min connections, a 30-second idle timeout, a 10-second
connection timeout, a 30-second statement timeout, and
application_name = 'saraswati_service'. getDb() wraps it in a Drizzle
instance. getTelemetryPool() is a separate, higher-throughput pool (30 max / 5
min connections, 10-second statement timeout,
application_name = 'saraswati_telemetry_ingest') for high-frequency telemetry
writes. getPoolStats() exposes total/idle/waiting counts; closeConnections()
drains both pools on shutdown.
Seed data#
seed.ts seeds reference data (task 60.1.2.19): reference battery cells (real
commercially available cells used in the African EV market, e.g. the
CATL-LFP-280AH-3V2 prismatic LFP cell), solar panels, and market-intelligence
data points.
Redis caching (cache.ts)#
CACHE_KEYS defines per-BU cache key namespaces under the saraswati: prefix
for all BUs. CACHE_TTL defines TTLs in seconds, from very short
(REALTIME_TELEMETRY 5 s, DRONE_POSITION 3 s, VEHICLE_POSITION 10 s,
ALARM_STATUS 15 s, TERMINAL_HEARTBEAT 30 s) through dashboard
(DASHBOARD_REALTIME 30 s, FLEET_STATUS 60 s) and operational
(PRODUCTION_STATUS 300 s, PRINTER_STATUS 120 s) to reference data
(MARKET_DATA 1 h, BATTERY_SPECS and SOLAR_PANEL_SPECS 24 h,
MATERIAL_PRICES 30 min). PUBSUB_CHANNELS defines Redis pub/sub channel names
for IoT, battery, EV, solar, drone, security, manufacturing, and financial
events. RATE_LIMIT_KEYS defines rate-limit key builders for telemetry ingest,
API requests, and SMS alerts. The module also exports cache payload types:
CachedDronePosition, CachedVehiclePosition, CachedBatteryTelemetry,
CachedSolarInstallation, CachedFleetDashboard.
API Surface (@saraswati/gateway)#
The gateway is a Hono application (libs/saraswati/gateway/src/app.ts). It
mounts all 17 business units under /api/v1/{bu}/. The exported app is the
composed application; individual BU route modules are also exported for
composition.
The middleware chain, system endpoints, and BU routing described below are the same for every business unit. Understanding the chain once means understanding every BU's request lifecycle.
Global middleware chain#
Middleware runs in declaration order. Each layer adds a capability: security headers, CORS, distributed tracing, structured logging, Prometheus metrics, rate limiting, and optional JWT auth. The order matters — tracing and logging must wrap rate limiting and auth so that rejected requests are still attributed.
In order: secureHeaders(); CORS (allows localhost:3000/5173/4200,
saraswati.oshun.io, dashboard.oshun.io); distributed tracing
(tracing('@saraswati/gateway')); structured logging with correlation IDs
(structuredLogger); Prometheus HTTP metrics (httpMetrics); a global rate
limit of 500 requests/minute per IP on /api/*; and optional JWT auth
(optionalAuth) on /api/*.
System endpoints#
These endpoints support infrastructure concerns — health checks for load-balancer probes, metrics for Prometheus scraping, OpenAPI docs for client generation, and the circuit-breaker snapshot for operations dashboards.
GET /health— returnsstatus, service name, version, the list of 17 business units, andbuCount: 17.GET /ready— readiness check; returns 503 if any circuit breaker is open.GET /metrics— Prometheus exposition (text/plain; version=0.0.4).GET /openapi.json— theSARASWATI_OPENAPI_SPECOpenAPI document.GET /graphql/schema— the GraphQL SDL.POST /graphql— executable GraphQL endpoint for cross-BU dashboard queries and mutations; resolved byexecuteSaraswatiGraphQL.GET /circuit-breakers— circuit-breaker health snapshot.GET /ws/status,GET /ws/sse/:channel,POST /ws/inject— WebSocket/SSE status, the SSE stream, and a development-only event injector.
Business-unit routing#
Under /api/v1, each BU is mounted with a per-BU rate limit and then its route
module: /ev, /battery, /solar, /iot (with a separate higher limit on
/iot/telemetry), /electronics, /pharma, /robotics, /drones,
/telecom, /medical, /fintech-hw, /security, /ewaste, /additive,
/satellite, /market-intel, /financials. WebSocket routes are mounted at
the root.
Representative endpoints#
The EV route module (/api/v1/ev) is representative of the pattern every BU
follows. Reading it once gives a reader the mental model for all 17 BUs. Every
route is guarded by requireBUAccess('ev'); write routes additionally require a
minimum role.
GET /ev/designs,GET /ev/designs/:id— list and fetch vehicle designs.POST /ev/designs(saraswati_engineer) — create a design, validated by a ZodCreateVehicleDesignSchema.PATCH /ev/designs/:id/status(saraswati_manager) — transition a design throughdraft|in_review|approved|deprecated.GET /ev/fleet,GET /ev/fleet/:vin— paginated fleet listing and per-vehicle lookup.POST /ev/fleet/assign(saraswati_manager) — assign a vehicle to an operator/driver.POST /ev/fleet/telemetry(saraswati_technician) — ingest a telemetry reading, validated byVehicleTelemetrySchema.GET /ev/fleet/:vehicleId/telemetry— recent readings for a vehicle.GET /ev/charging-stations,GET /ev/charging-stations/:id,POST /ev/charging-stations(saraswati_engineer).GET /ev/analytics/fleet-summary,GET /ev/analytics/range-estimate.
The remaining BUs follow the same shape (libs/saraswati/gateway/src/routes/):
electronics (PCB designs, production orders, component inventory, yield
analytics); robotics (robots, robot tasks with single-active-task enforcement,
telemetry, analytics); drones (drones, flight plans with a GCAA 400-m altitude
check on creation, flight-plan execution, analytics); telecom (towers, tenant
provisioning with an upliftAvailableKg capacity check, analytics); medical
(devices with a notified-body flag for class IIb/III, regulatory submissions);
fintech-hw (terminals, deployments, analytics); security (systems, alarm
ingestion, active alarms); ewaste (collections with precious-metal value
estimation, processing with material recovery, analytics); additive (printers,
print jobs with printer-availability enforcement, analytics); satellite (VSAT
terminals, ground stations, analytics); market-intel (data points, the Ghana
EV-market reference dataset, competitors); financials (financial models with NPV
computation and a Newton-Raphson IRR estimate, model summaries, portfolio
roll-up). The financials routes additionally require the saraswati_manager
role on every endpoint.
The current route modules persist into in-memory Maps rather than
@saraswati/db; that data layer is built and verified independently.
Authentication and RBAC (middleware/auth.ts)#
The six-level role hierarchy ensures that read-only viewers cannot trigger
writes, field technicians cannot change business-unit configuration, and only
managers and above can access the financials BU. The buScopes claim enables
multi-tenant deployments where a user has access to only a subset of the 17
business units.
JWT bearer tokens. JWTPayload has sub, email, role, optional buScopes,
optional siteId, iat, exp. parseJWT base64url-decodes the payload,
rejects expired tokens, and requires the sub/email/role claims and a known
role.
SaraswatiRole (6, lowest to highest clearance): saraswati_viewer (1,
read-only), saraswati_technician (2, field ops), saraswati_engineer (3,
domain configuration), saraswati_manager (4, BU management),
saraswati_director (5, cross-BU oversight), super_admin (6).
ROLE_HIERARCHY maps each to its numeric level.
SaraswatiBU (17): ev, battery, solar, iot, electronics, pharma,
robotics, drones, telecom, medical, fintech_hw, security, ewaste,
additive, satellite, market_intel, financials. An empty buScopes array
means unrestricted access.
Middleware: optionalAuth() (sets auth context if a valid token is present),
authenticate() (rejects requests without a valid token), requireRole(min)
(403 if the user's level is below the minimum), requireBUAccess(bu) (403 if a
scoped user lacks the BU). getAuthContext(c) retrieves the context;
createMockToken builds a test-only JWT.
Rate limiting (middleware/rate-limit.ts)#
Per-BU rate limits reflect each BU's expected traffic pattern. Telemetry endpoints receive the highest limits because IoT and battery ingest is continuous; financials and fintech-hw receive the lowest because they are low-volume, high-sensitivity endpoints.
SlidingWindowRateLimiter implements a sliding-window counter with periodic
cleanup. BU_RATE_LIMITS defines per-BU profiles (requests per 60-second
window): telemetry endpoints iot_telemetry 10,000, battery_telemetry and
solar_telemetry 5,000; operations ev/battery/solar/iot 500,
electronics/robotics/drones/telecom/satellite/security 300,
ewaste/additive 200; regulated pharma/medical 200; strict fintech_hw
and financials 60, market_intel 100; default 100. rateLimitForBU(bu)
applies the matching profile and emits X-RateLimit-Limit,
X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After headers; over
limit returns HTTP 429 with a RATE_LIMITED error body.
Other middleware#
middleware/ also provides Prometheus metrics (httpMetrics, registry, and
BU-specific recorders such as recordEVFleetMetrics, recordBatteryMetrics),
OpenTelemetry-style tracing (tracing, startChildSpan, W3C traceparent
parsing), structured logging (structuredLogger, Logger, correlation IDs),
and circuit breakers (CircuitBreaker, callWithBreaker, CircuitOpenError,
getCircuitBreakerHealth) with CircuitState open/closed/half-open semantics.
GraphQL (graphql/)#
The GraphQL endpoint exists specifically to serve the cross-BU dashboard libraries, which need to query multiple business units in a single round trip. REST routes do not cross BU boundaries; GraphQL does.
SARASWATI_GRAPHQL_SCHEMA (task 60.1.3.2) is the SDL for cross-BU queries. Its
Query type exposes saraswatiOverview, fleetSummary (unified across EVs,
drones, and robots), energyDashboard, manufacturingPipeline,
supplyChainEvents, marketIntelSummary, regulatoryCompliance, and per-BU
queries (evFleet, batteryHealth, solarPortfolio, iotNetwork,
droneFleet). Its Mutation type exposes operations such as assignVehicle,
triggerBatteryAssessment, and activateSolarPaygo. executeSaraswatiGraphQL
resolves operations; validateQueryFields checks requested fields.
gRPC service definitions (proto/services.ts)#
Task 60.1.3.5. TypeScript Protocol-Buffer message and service interfaces for
four real-time services: IRoboticsService (ROBOTICS_PROTO — motor-control
commands and sensor feedback), IDroneService (DRONES_PROTO — flight
telemetry and command/control), IIoTGatewayService (IOT_GATEWAY_PROTO —
high-frequency edge-gateway telemetry ingestion), and IManufacturingService
(MANUFACTURING_PROTO — machine-to-machine process control). Message types
include RobotCommand, RobotTelemetry, DroneTelemetry, DroneCommand,
IoTUplink, QualityGateRequest/QualityGateResponse, and ProductionEvent,
with shared GRPCTimestamp, GRPCLocation, and GRPCStatus (gRPC status codes
0–16) types.
MQTT topic hierarchy (mqtt.ts)#
Task 60.1.3.6. MQTT is used for device-to-gateway communication where the broker
fan-out model fits better than HTTP request-response — particularly for IoT
devices that push telemetry asynchronously. MQTT_TOPICS builds topics on the
pattern saraswati/{siteId}/{bu}/{entityId}/{stream} — for example
saraswati/{siteId}/ev/{vehicleId}/telemetry,
saraswati/{siteId}/battery/{packId}/alerts,
saraswati/{siteId}/iot/{deviceEUI}/{sensorType},
saraswati/{siteId}/drone/{droneId}/commands, plus the global
saraswati/gateway/status and saraswati/paygo/{systemId} topics. TOPIC_QOS
sets per-topic MQTT QoS levels. The module exports message types
(MQTTEVTelemetry, MQTTBatteryAlert, MQTTSolarTelemetry,
MQTTPAYGOCommand, MQTTIoTUplink, MQTTDroneCommand,
MQTTManufacturingEvent), serialization helpers, and an IMQTTClient
abstraction.
API versioning (versioning/api-versioning.ts)#
Task 60.21.5.5. URI-based versioning (/api/v1/, /api/v2/) with content
negotiation fallback (Accept: application/vnd.saraswati.v2+json). APIVersion
records label, semver, status (current | deprecated | sunset |
preview), and lifecycle dates. The deprecation policy emits RFC 8594 Sunset
and Deprecation headers and an RFC 8288 Link header to the migration guide;
versions are sunset at least six months after deprecation. BreakingChange
classifies breaking vs. non-breaking changes.
Events#
WebSocket / SSE channels (routes/websocket.ts)#
Task 60.1.3.4. WebSocket/SSE channels serve consumers that need sub-second updates — fleet management UIs tracking vehicle positions, factory dashboards watching production line events, security operations centers monitoring alarm feeds. Each channel is typed so that subscribers know the exact shape of every message.
A PubSubBus fans messages out to subscribers. WSChannel (8): ev_telemetry,
battery_alerts, solar_live, iot_stream, drone_tracking,
manufacturing_events, security_alarms, system_health. Each WSMessage
carries channel, event, timestamp, and payload. Typed publishers:
publishEVTelemetry, publishBatteryAlert, publishSolarEvent,
publishIoTReading, publishDronePosition, publishManufacturingEvent,
publishSecurityAlarm. The SSE endpoint GET /ws/sse/:channel streams a
channel as text/event-stream with a 1-second heartbeat and a 5-minute
auto-close.
Kafka event-bus abstraction (events/kafka-event-bus.ts)#
Task 60.21.5.3. Kafka is the durable, high-throughput backbone for events that need to survive gateway restarts, be consumed by multiple independent downstream services, or be retained for compliance. The partition and retention strategy is tuned per event category to balance throughput, ordering, and storage cost.
Topics follow saraswati.{bu}.{category}, where BUCode is the 17-BU set and
EventCategory (5) is telemetry, commands, events, alerts, audit.
buildTopicRegistry() generates a TopicConfig for every (BU, category) pair:
telemetry topics have 16 partitions, round-robin partitioning, and 7-day
retention; command topics 4 partitions, entity-keyed, 30-day retention; event
topics 4 partitions, entity-keyed, log-compacted (event sourcing); alert topics
8 partitions, site-keyed, 14-day retention; audit topics 4 partitions,
entity-keyed, 1-year retention (compliance). All topics use replication factor 3
and a 1-MiB max message size. computePartition(key, n) implements a
Kafka-compatible Murmur2 hash. buildDLQTopicName(topic) produces the
saraswati.dlq.{topic} dead-letter topic; messages are routed to the DLQ after
maxRetries failures with failure metadata appended. SaraswatiEventBus is an
in-process implementation mirroring Kafka semantics (partitions, consumer
groups, offsets, consumer lag, DLQ) for testing and local development; the
documented production path is to back the same interface with kafkajs or
@confluentinc/kafka-javascript.
CQRS / event sourcing (cqrs/cqrs.ts)#
Task 60.21.5.4. CQRS separates the write path (commands that change state) from
the read path (queries that read projections). This matters in Saraswati because
telemetry ingest is write-heavy and dashboard queries are read-heavy; keeping
them on the same path would cause contention. Separates command (write) and
query (read) paths. Command carries commandType, aggregateId,
correlationId, optional causationId, issuedAt, issuedBy. DomainEvent
carries eventId, eventType, aggregateId, aggregateType,
sequenceNumber, occurredAt, causationCommandId, payload. CommandResult
returns success, the raised events, and validation errors. Command
handlers append events to an event store; aggregates are reconstituted by
replaying events, with snapshots taken every SNAPSHOT_INTERVAL events to bound
replay time. Read models are projections updated asynchronously for eventual
consistency.
Cross-Domain Integration Contracts (@contracts/saraswati)#
@contracts/saraswati exports five integration modules, each defining Zod
schemas plus an adapter class. The module index re-exports brigid.ts,
asase.ts, freya.ts, cybele.ts, maat.ts.
Each contract exists because a neighboring domain needs a specific slice of Saraswati's data model but should not depend directly on Saraswati's internal types. The Zod schema defines the shape of the cross-domain message; the adapter class converts between Saraswati's internal entities and the contracted form. This means Saraswati can evolve its internal model without breaking its neighbors as long as the adapter continues to produce a valid contracted output.
- Brigid (
brigid.ts, task 60.20.1) — Saraswati manufacturing ↔ Brigid industrial automation: factory-automation interface for CEM electronics lines, energy-system integration, robotics integration adapter, shared MES event bus, predictive-maintenance data sharing. - Asase (
asase.ts, task 60.20.2) — Saraswati EV fleet / drones / IoT / solar ↔ Asase agriculture: delivery EV fleet integration, agricultural drone connector, soil/weather/crop IoT network, cold-chain monitoring, solar-powered irrigation-pump controller. - Freya (
freya.ts, task 60.20.3) — Saraswati ↔ Freya e-commerce: last-mile delivery fleet, smart-retail IoT, packaging electronics (freshness and anti-tamper sensors), fintech-hardware deployment for Freya POS/kiosks, warehouse robotics. - Cybele (
cybele.ts, task 60.20.4) — Saraswati ↔ Cybele construction: construction robotics, smart-building IoT, EV-charging-infrastructure planning, rooftop/carport solar, data-center equipment provisioning, construction drone survey. - Maat (
maat.ts, task 60.20.5) — Saraswati R&D / IP / PLM ↔ Maat knowledge management. Five Zod schemas with adapters:RDProjectSchema+RDProjectTrackerAdapter(NASA TRL 1–9 progression, TRL-jump feasibility, monthly burn, IP recommendation);IPAssetSchema+IPPortfolioManagerAdapter(composite IP score from claims, territory, and BU-revenue weights; income-approach valuation; 20-year patent term);PLMDataSchema+PLMDataSharingAdapter(PLMLifecycleStageconcept|design|validate|launch|sustain|eol; readiness score and A–F grade);TechScoutingSchema+TechScoutingAdapter(Gartner hype-cycle maturity, BU-relevance matrix, adoption recommendationmonitor|pilot|invest|divest);StandardsTrackingSchema+StandardsTrackingAdapter(standards bodies includingIEC,ISO,IEEE,ETSI,DVLA_Ghana,Ghana_FDA,NCA_Ghana,GRA,ECOWAS; urgency and compliance-gap scoring). The Maat-facing BU enum uses the longer-form valuesev_mobility,battery_storage,solar_energy,iot_agritech,contract_electronics,pharma,robotics,drone_services,telecom_infra,medical_devices,satellite_comms,additive_manufacturing.
Validation, Invariants, and Configuration#
Validation#
Input validation in the gateway catches malformed requests before they reach business logic. The constraints below are embedded in Zod schemas that run at every create/update route. The pharmacy ATC-code regex and the solar-panel efficiency cap are examples of domain knowledge encoded directly in the schema layer rather than deferred to application code.
@saraswati/core ships Zod schemas for the primary domain objects
(ChargingStationSchema, BatterySchema, SolarPanelSchema,
SensorReadingSchema, IoTDeviceSchema, PharmaceuticalSchema, DroneSchema,
WaypointSchema, FlightPlanSchema, TelecomTowerSchema,
VSATTerminalSchema, ManufacturingOrderSchema, QualityTestResultSchema,
MarketDataPointSchema). Notable embedded constraints: latitude bounded to
[-90, 90] and longitude to [-180, 180]; country codes length 2 and currency
codes length 3; solar-panel efficiencyPercent capped at 30 and degradation
bounds enforced; the pharmaceutical ATC code matched against
/^[A-Z]\d{2}[A-Z]{2}\d{2}$/; FlightPlanSchema requires at least two
waypoints; confidenceLevel bounded to [0, 1]. Gateway routes validate request
bodies with route-local Zod schemas before mutating state.
Domain invariants#
These invariants are enforced in two places: as type-guard functions in
@saraswati/core (for business logic) and as gateway-route checks (for API
enforcement). The dual enforcement means a violation cannot slip in through
either path.
- Battery state of health below 80% is the end-of-life threshold
(
isBatteryEndOfLife); a healthy battery additionally has no fault codes (isBatteryHealthy). - A pharmaceutical batch is release-ready only when QC has passed, the batch is
in
qc_testing, and every deviation is closed or minor (isBatchReleaseReady). - A medical device of class IIb or III requires a notified body
(
requiresNotifiedBody); class III or surgically invasive devices require a clinical trial (requiresClinicalTrial). - A flight plan is safe only when current wind is within the plan limit, maximum
altitude is at or below 400 m (the Ghana GCAA general cap), and the minimum
return-battery percentage is at least 15 (
isFlightPlanSafe). The drones route additionally rejects flight-plan creation when the requested altitude exceeds 400 m AGL. - A drone is airworthy only when active, with battery at or above 30% and fewer
than 200 battery flight cycles (
isDroneAirworthy). - A robot is ready for a task only when active, with battery at or above 20% and
no current task (
isRobotReadyForTask); the robotics route enforces a single active task per robot. - Telecom tower tenant provisioning is rejected when the requested equipment
weight exceeds the tower's
upliftAvailableKg. - E-waste items in
high_hazardorrestricted_exportclasses are high-hazard (isHighHazardEWaste);restricted_exportcorresponds to Basel-Convention restriction, and recovered-material cross-border movement carries anexportPermitNumber.
Configuration and environment inputs#
SARASWATI_DATABASE_URL— PostgreSQL connection string for thesaraswatidatabase; required bygetPool()andgetTelemetryPool().LOG_LEVEL— whendebug, the connection pool logs new client connections.NODE_ENV— whenproduction, the gateway returns a generic error message on unhandled errors and thePOST /ws/injectdevelopment endpoint is disabled.@saraswati/dbpool sizing is tunable throughPoolConfig(maxConnections,minConnections,idleTimeoutMs,connectionTimeoutMs,statementTimeoutMs).
V2 Racing EV Consumption Surface#
The V2 game project's racing ecosystem reuses Saraswati's electric-vehicle
powertrain engineering to model racing drivetrains. The
@v2/racing-ecosystem-bridge service (in the V2 monorepo, not in
libs/saraswati/) lists @saraswati/ev among its source-of-truth packages;
Saraswati itself has no dependency on V2.
The bridge instantiates Saraswati's real PowertrainConfigurator and feeds it
the racing vehicle's motor preference, building a PowertrainConfig for the
in-game car. @saraswati/ev already provides production-grade
hybrid and electric vehicle modeling — it models the full motor-to-wheel
drivetrain, including hybrid configurations alongside pure-electric ones, so
the racing surface inherits that engineering for free: the configurator computes
the drivetrain efficiency that the bridge reports back. When that efficiency or
configuration is unacceptable, the bridge raises
saraswati-ev-powertrain-invalid (hard) or
saraswati-ev-powertrain-inefficient (a warning), each tagged with
sourcePackageName: '@saraswati/ev', so EV powertrain constraints surface to
the vehicle author rather than silently shipping.
This is an authoring / content-cook surface only: the bridge rejects live
race-frame RPCs and carries mayInfluenceRollback: false, so Saraswati's EV
model shapes vehicles offline and never runs inside the deterministic race
simulation. See V2/docs/integration/racing-ecosystem-bridge.md;
V2/ue/Tools/check-v2-racing-ecosystem-bridge.py enforces the wiring.
Grounding: apps/v2/racing-ecosystem-bridge/src/racing-ecosystem-bridge.ts;
libs/saraswati/ev/.
Verification Expectations#
Per the architecture document, changes to Saraswati require package-level lint,
typecheck, and unit-test coverage. Each capability library carries its own
vitest.config.ts and a primary test file; several BUs additionally carry a
state-of-the-art (*-sota.test.ts) test file. Regulated BUs — pharma, medical
devices, fintech hardware, EVs, batteries, telecom, and e-waste — require
contract, compliance, audit, and data-retention tests in addition to the
package-level checks.