Domain · Architecture

Brigid Domain — Architecture

Libraries live under libs/brigid/ in four bands — foundation, capability domains, vertical-industry libraries, and support modules.

11sections11 minread1diagrams

On this page

Industrial Automation Intelligence bounded context (libs/brigid/*, apps/brigid/*; TODO Phase 59). Architectural overview: layered package structure, the shared @brigid/core type system, the engineering and condition-monitoring algorithms in the capability libraries, the Hono API surface, persistence design, and the cross-domain boundary — with honest implemented-vs-planned status.


Brigid is the industrial-automation bounded context for the Oshun platform. It provides the type system, engineering calculations, condition-monitoring and AI algorithms, persistence schema, and application surfaces for factory automation, industrial energy, maintenance, robotics, process industries, OT cybersecurity, and the technical workforce — the full stack from plant-floor sensor to operational dashboard.

The domain exists because industrial operations generate a category of data and decision-making fundamentally different from commerce, content, or finance: physical safety constraints, deterministic control paths, OT-grade cybersecurity requirements, multi-site equipment hierarchies, and calibration records that must survive regulatory audit. Brigid keeps all of that logic in one place so that partner domains (Asase, Freya, Cybele, Saraswati, Maat) can consume plant intelligence without re-implementing it.

Brigid is an implemented TypeScript workspace — 238 source files across 24 library packages (libs/brigid/*) and five application services (apps/brigid/*), all @brigid/*-scoped. There are zero Rust or Python files in the domain today: the polyglot stack the package README aspires to (Rust edge control, Python ML, Kafka/MQTT/OPC-UA transport, WASM HMI) is roadmap, not code. Everything described below as "implemented" is real, runnable TypeScript; everything else is explicitly labelled (planned).

Workspace Shape#

Libraries live under libs/brigid/ in four bands — foundation, capability domains, vertical-industry libraries, and support modules. Application services live under apps/brigid/ and expose those libraries as operational workflows.

text
apps/brigid/
  api/          ← Hono HTTP / SSE / WebSocket surface  (@brigid/api)
  factory-os/   ← factory operations dashboard         (@brigid/factory-os)
  energy/       ← energy management system             (@brigid/energy-ms)
  maintenance/  ← maintenance management               (@brigid/maintenance-ms)
  training/     ← training academy / LMS               (@brigid/training-lms)

libs/brigid/
  core/  db/  cross-domain/  sota-enhancements/         ← foundation
  factory/  machines/  ai-industrial/  energy/          ← capability domains
  maintenance/  robotics/  digital-twin/  cybersecurity/
  weighing/  supply-chain/  training/  materials/
  market-intel/  financials/
  mining/  oil-gas/  packaging/  agricultural-mech/      ← verticals
  water/  hvac/

Note three app package names differ from their directory names: apps/brigid/energy is @brigid/energy-ms, apps/brigid/maintenance is @brigid/maintenance-ms, apps/brigid/training is @brigid/training-lms — and @brigid/energy-ms (app) is distinct from @brigid/energy (library).

Architectural Layers#

Brigid is organised in layers, each depending only on the layers below it.

Foundation@brigid/core is the shared vocabulary. Its barrel (libs/brigid/core/src/index.ts) re-exports nine modules: equipment, maintenance, energy, robotics, security, business, units, validators, standards, plus schemas. The type system is aligned to ISA-95, IEC 61131-3, ISO 12100, IEC 61511, IEC 62443, ISA-18.2 and ISA-101. Identifiers are plain string fields (equipmentId, sensorId, workOrderId) — there are no branded ID types. @brigid/db is the Drizzle ORM schema for a dedicated PostgreSQL database (TimescaleDB + pgvector). @brigid/cross-domain is the only sanctioned exit point, and @brigid/sota-enhancements carries forward-looking modules (edge AI, 5G remote ops, AR/VR, generative AI, RL, federated learning, digital thread/quantum) over the same foundation contracts.

Capability domains — each library owns one industrial concern while sharing the foundation contracts: @brigid/factory (line design + control-system integration), @brigid/machines (phase-gate machine build), @brigid/ai-industrial (vision, predictive maintenance, optimisation), @brigid/energy, @brigid/maintenance, @brigid/robotics, @brigid/digital-twin, @brigid/cybersecurity, @brigid/weighing, @brigid/supply-chain, @brigid/training, @brigid/materials, @brigid/market-intel, @brigid/financials.

Vertical industries@brigid/mining, @brigid/oil-gas, @brigid/packaging, @brigid/agricultural-mech, @brigid/water, @brigid/hvac add domain-specific concepts on top of the core types and the maintenance lifecycle; they extend, never replace, the shared foundation.

Applications — the five apps/brigid/* services compose libraries into deployable workflows; the api service is the integration point for external callers and partner domains.

The Foundation in Depth#

@brigid/core — type system, schemas, validators, standards#

equipment.ts defines the ISA-95 asset ladder (EquipmentLevel: enterprise → site → area → production_line → work_cell → equipment_unit → control_module), the base Equipment record, and specialisations (Machine, Sensor, Actuator, PLC, SCADASystem/SCADAPoint, HMITerminal, ControlLoop, ProductionLine, SafetySystem/SafetyInstrumentedFunction). maintenance.ts, energy.ts, robotics.ts, security.ts, and business.ts cover the work-order/calibration/spare-part, energy-asset, robot/twin, OT-security/ training, and BOM/production/quality/market models respectively.

schemas.ts is where the contracts become enforceable. It ships Zod schemas that reject malformed payloads at ingestion, and crucially encode domain invariants as refinements, not just shapes:

  • OEEMetricsSchema refines oee === availability × performance × quality (within 0.001) — an OEE record that violates the identity cannot be stored.
  • SensorSchema.tag is regex-validated against the ISA-5.1 instrument-tag pattern (/^[A-Z]{1,4}-\d{3,4}([A-Z])?$/, e.g. TT-101), and rangeMax > rangeMin is refined.
  • CalibrationRecordSchema.measurementPoints requires .min(3) ("At least 3 calibration points required (ISO 17025)").
  • ProductionOrderSchema refines plannedEndDate >= plannedStartDate; BatteryBankSchema refines usableCapacity <= nominalCapacity.

validators.ts is genuinely physics-based, not generic CRUD. It implements validatePressureDrop (Darcy-Weisbach with a Churchill/Haaland friction factor and laminar/transition/turbulent branching off the Reynolds number), validateHeatTransfer (counter-current LMTD duty), validateElectricalLoad (three-phase full-load current, NEMA voltage-imbalance derating, Ghana-ECG power-factor penalty), and validateStructuralStress (σ = F/A against yield/safety-factor). The data-quality half flags rather than drops bad telemetry: checkSensorRange, checkRateOfChange, checkStuckValue, checkSpike (modified Z-score over median absolute deviation), composed by assessDataQuality into a good | suspect | bad verdict with diagnostic flags.

standards.ts is a real reference registry — IEC_STANDARDS, ISO_STANDARDS, ANSI_ISA_STANDARDS, NFPA_STANDARDS, API_STANDARDS, ASME_STANDARDS, plus GHANA_REGULATIONS — keyed and queryable via getApplicableStandards(domain).

@brigid/db — persistence schema#

libs/brigid/db/src/schema.ts defines the Drizzle tables and PostgreSQL enums (brigid_equipment_status, brigid_equipment_level, brigid_work_order_status, brigid_energy_source_type, brigid_robot_type, brigid_security_level, brigid_certificate_status, brigid_production_order_status, brigid_alarm_priority, and the two maintenance enums). Worth noting: the persisted brigid_work_order_status enum is the 13-value core lifecycle minus pending_approval — the application/type layer carries one more state than the column. Tables cover sites → factories → areas → lines → work-cells, equipment, sensors/actuators/PLCs, work orders, spare parts, energy systems (solar arrays, battery banks), water plants, robots/cells/programs, digital twins, security assessments + vulnerabilities, training programs + certifications, materials batches, and calibration records, wired with relations(...).

Four tables are time-series: brigid_sensor_telemetry (each row carries value, unit, a quality flag, rawValue, source), brigid_water_quality_readings, brigid_oee_records, and brigid_condition_readings. These are declared as plain tables in Drizzle, then converted to TimescaleDB hypertables via raw SQL in migrations.ts (CREATE EXTENSION timescaledb; SELECT create_hypertable(...)). The same file enables vector and adds an embedding vector(1536) column with an ivfflat cosine index to brigid_ai_embeddings — pgvector isn't expressible through drizzle-orm/pg-core directly, so it lives in the migration.

Capability Algorithms#

The capability libraries are where the domain depth lives. A representative sample, each grounded in real exported functions:

  • @brigid/factoryfactory/src/production.ts implements calculateTaktTime, balanceLine (work-content distribution against takt), sizeBuffer, calculateOEE (six-big-loss decomposition), analyzeBottleneck, scheduleJobs (FIFO/SPT/EDD/CR/SLACK and a genetic dispatcher), runDESSimulation (discrete- event line model), and optimizeLayout (A/E/I/O/U/X relationship-code SLP). factory/src/safety.ts is functional-safety engineering: performLOPA (layer-of-protection analysis to a residual SIL), calculateSIFPFDavg across voting architectures (1oo12oo3), designSIF, generateProofTestProcedure, generateESDMatrix, and assessMachineRisk (ISO 13849 S/F/P risk graph). factory/src/scada.ts carries an AlarmManagementSystem class (ISA-18.2 alarm state machine and flood/KPI analysis) and ISA-101 HMI screen/faceplate generation.
  • @brigid/ai-industrialai-industrial/src/predictive-maint.ts is not a wrapper: it ships a radix-2 Cooley-Tukey FFT, bearing fault-frequency calculation (BPFO/BPFI/BSF/FTF), ISO 10816 RMS-velocity severity classification, an OilAnalysisPredictor (ASTM D-series thresholds), a MotorCurrentSignatureAnalyzer (broken-rotor-bar sidebands, eccentricity, RSH), a RemainingUsefulLifeEstimator with three real models (Wiener first-passage, Paris-law crack growth, Weibull survival), an AnomalyScorer (Mahalanobis distance with Gauss-Jordan covariance inversion + CUSUM), and a ThermalImagingAnalyzer (BFS connected-component hotspot detection + OLS trend projection). Sibling modules cover computer vision, process optimisation, robotics AI, and edge AI.
  • @brigid/maintenancemaintenance/src/kpi-analytics.ts computes MTBF/MTTR and availability, benchmarks them, builds Pareto downtime breakdowns, ages the work-order backlog, and scores maintenance maturity. maintenance/src/spare-parts.ts implements calculateEOQ (with inverseNormalCDF/normalCDF for service-level safety stock), VED and ABC classification, reorder evaluation, and part interchangeability.
  • @brigid/energyenergy/src/solar.ts is Ghana-specific: a GHANA_MONTHLY_PSH irradiance table, SolarIrradianceAnalyzer, sizePVSystem, configureStrings, modelPVPerformance, analyzeShadingLoss, and technology-keyed degradation forecasting. BESS, grid-hybrid, and power-quality modules sit alongside.
  • @brigid/roboticsrobotics/src/robot-safety.ts implements a SafetyZoneCalculator (ISO/TS 15066 speed-and-separation distances), a RobotRiskAssessment (ISO 13849), a CollisionDetectionSimulator (AABB/sphere), a RobotEnergyMonitor, a MultiRobotCoordinator, and an HRI workspace designer.

Component and Data Flow#

The path from raw sensor reading to operational decision, and out to partner domains, runs through the layers as follows:

flowchart TD subgraph Edge[Plant floor] SENS[Sensors / PLC / SCADA] end subgraph App[apps/brigid] API[@brigid/api Hono\nREST + SSE + WS] FOS[factory-os] EMS[energy-ms] MMS[maintenance-ms] LMS[training-lms] end subgraph Core[Foundation libs/brigid] CORE[@brigid/core\nschemas + validators + standards] DB[(@brigid/db\nPostgres + TimescaleDB + pgvector)] end subgraph Cap[Capability + vertical libs] AI[@brigid/ai-industrial] MAINT[@brigid/maintenance] FAC[@brigid/factory] ENE[@brigid/energy] end XD[@brigid/cross-domain\nadapters + Zod contracts] CONS[Asase · Freya · Cybele · Saraswati · Maat] SENS -->|telemetry batch / WS| API API -->|validate + enrich| CORE CORE -->|persist| DB API --> FOS & EMS & MMS & LMS DB --> AI & MAINT & FAC & ENE AI -->|RUL / anomaly| MAINT MAINT -->|predictive work order| API FAC -->|OEE / alarms| API ENE -->|dispatch plan| EMS API --> XD --> CONS CONS -->|provision / maintenance request| XD --> API
  1. Telemetry arrives as REST batches; PLC/SCADA events arrive over the factory WebSocket. @brigid/core validates and enriches with industrial semantics (ISA-5.1 tags, OEE identity, data-quality flags) before anything is stored.
  2. Relational records go to PostgreSQL tables; high-volume streams go to TimescaleDB hypertables, keeping ingestion off the transactional path.
  3. AI and vertical libraries consume stored telemetry to produce predictions, maintenance recommendations, and production decisions.
  4. App services expose approved state to dashboards and partner domains — partner domains always through @brigid/cross-domain, never via direct library imports.

Application Surface#

apps/brigid/api/src/app.ts builds a Hono application: secureHeaders, CORS, logger, prettyJSON, a 100-req/min rate limiter on /api/*, and an optional JWT middleware that populates an auth context if a Bearer token is present (protected handlers call requireRole(); absent/invalid tokens leave the context unset and are rejected downstream). Health lives at /health and /ready; the functional API mounts at /api/v1 with route groups equipment, telemetry, maintenance, energy, ai, training, and cross-domain.

telemetry.ts accepts batches of ≤1000 readings, validates each, and keeps them sorted by timestamp (so out-of-order arrivals are inserted in time order, not rejected), returning 202 when any reading is accepted. cross-domain.ts exposes equipment-provision and maintenance-request POSTs that append CrossDomainEvents (EQUIPMENT_PROVISION_REQUESTED, CROSS_DOMAIN_MAINTENANCE_REQUEST) to a queue replayed over the GET /api/v1/cross-domain/telemetry/subscribe SSE stream. websocket.ts defines the FactoryWSMessageType union (SCADA_UPDATE, ALARM_ACTIVE, ALARM_CLEARED, OEE_UPDATE, ASSET_STATUS_CHANGE, WORK_ORDER_UPDATE, plus SUBSCRIBE/UNSUBSCRIBE/PING/PONG) and a createWebSocketHandler().

Two honest caveats at the app layer. First, the route handlers persist into in-memory Map structures (telemetryStore, provisionRequests, eventQueue) — the @brigid/db schema is the persistence target, but the API routes are not yet wired to it. Second, the /ws/factory route currently returns connection metadata (and 426 Upgrade Required on a raw upgrade); a real WebSocket needs the @hono/node-ws adapter (createNodeWebSocket), which the app does not yet mount. Both are real seams, honestly reported rather than faked.

Persistence#

Brigid's design uses four storage technologies, each matched to an access pattern: PostgreSQL for domain records, work orders, financials, and audit history; TimescaleDB hypertables for telemetry and condition streams; Redis for caches and hot dashboard state; and object storage for CAD files, inspection media, robot programs (program_url is a MinIO reference), and reports. The schema and migrations are implemented; the runtime wiring from the app layer is the in-memory caveat above.

Cross-Domain Boundary#

@brigid/cross-domain is the single integration seam. Its barrel (cross-domain/src/index.ts) exports five adapter families — asase-integration.ts, freya-integration.ts, cybele-integration.ts, saraswati-integration.ts, maat-integration.ts — each mapping Brigid DTOs into a consumer-facing shape (e.g. Asase gets food-processing/cold-chain/mechanization line designs; Maat gets OEE/utilisation/RUL/energy analytics). cross-domain/src/api-contracts.ts holds the Zod request/response schemas (BrigidEquipmentProvisioningRequest/Response, BrigidEnergyIntegrationRequest, BrigidMaintenanceServiceRequest/Response, BrigidTelemetryEvent, BrigidTrainingEnrolmentRequest, BrigidCertificationRecord), all keyed by a requestingDomain enum of asase | freya | cybele | saraswati | maat. The libs/brigid README also names a @contracts/brigid package; the authoritative implemented contracts are the ones in @brigid/cross-domain.

The boundary lets Brigid refactor its internal model without breaking consumers, and stops consumers depending on Brigid internals. Brigid owns the engineering control systems; consumers own their product economics — Cybele the built environment, Saraswati the technology products, Asase agricultural economics, Freya brand and design, Maat organisation-wide rollups.

Invariants, Failure Modes, and Extension Points#

Invariants (enforced in code, not aspiration): OEE must equal availability × performance × quality; sensor tags must match the ISA-5.1 pattern; calibration records need ≥3 measurement points; production end-dates must not precede start-dates; usable battery capacity must not exceed nominal. These live as Zod refinements in core/src/schemas.ts and fail loudly on violation.

Safety and audit invariants (design-level, partly type-backed): workflows touching safety-critical assets (robot cells, safety-instrumented functions, control paths) carry deterministic fail-safe state — SafetySystem.failSafeAction and bypassProcedure exist precisely to record it; @brigid/factory's LOPA/SIF functions compute the protection layers and PFDavg that back it. Calibration and maintenance records are intended to be immutable after signoff, with corrections as append-only events.

Failure modes a maintainer must respect: telemetry ingestion tolerates out-of-order and degraded-quality data (flagged, not dropped); the data-quality validators classify rather than discard; the OEE/calibration schemas reject inconsistent records outright rather than coercing them. Singular covariance in the AnomalyScorer falls back to identity rather than producing NaNs. The app's in-memory stores mean state is process-local and non-durable until the DB wiring lands — do not treat the API as a system of record yet.

Extension points: a new vertical is a new libs/brigid/<name> package that imports @brigid/core and the maintenance lifecycle and adds only its specific types; a new shared concept is a type + Zod schema in @brigid/core (high blast radius — every library imports core); a new external consumer is a new *-integration.ts adapter plus contract schema in @brigid/cross-domain; a new API capability is a route group mounted under /api/v1 in app.ts; forward- looking capabilities land in @brigid/sota-enhancements over the same contracts.

Status Summary#

Implemented: the @brigid/core type system, Zod schemas with domain invariants, physics and data-quality validators, and standards registry; the @brigid/db Drizzle schema + TimescaleDB/pgvector migrations; the capability algorithms across factory, ai-industrial, maintenance, energy, robotics, and the verticals; the @brigid/cross-domain adapters and contracts; the Hono API with REST routes, the SSE cross-domain stream, and the WebSocket message model.

Planned / not yet wired: API persistence (routes use in-memory Maps; the DB is the target); the live WebSocket upgrade (@hono/node-ws adapter not mounted); a published platform-event catalog and the Kafka/MQTT/OPC-UA transport; and the Rust/Python/WASM components named in the README. These are labelled as seams here rather than presented as done.

Verification Expectations#

Changes run the affected packages' Vitest suites, type checks, linting, and contract checks, plus integration tests for affected app services. Industrial- safety, OT-cybersecurity, and control-path changes additionally require focused tests around validation, deterministic fallback behaviour, audit events, and permission boundaries — the areas where a silent error becomes a physical one.