Core architectural tenets, table schema, runtime component diagram, multi-domain design, DataSource architecture, and known technical debt register. All tenets are derived from EDRv6 and are non-negotiable — violating them introduces state that cannot be versioned, audited, or switched at runtime.
6 Tenets 3 Active Domains 8 Open Debt ItemsRules are rows in _tbl_calcrule_rules, grouped by profile in _tbl_calcrule_profiles. JSON files under nexus/rules/ are the one-time migration seed only. Once imported they are not the source of truth.
_tbl_calcrule_rules, not editing a file._tbl_sys_rules, _tbl_sys_classes, _tbl_sys_properties._tbl_calcrule_profiles.is_active = 1 is the single toggle within a domain. The Flask admin panel flips it; the FastAPI engine reads it on every request. Domain scope is mandatory — activating the EDR profile must not deactivate the TCO profile. The domain column enforces this isolation.
UPDATE _tbl_calcrule_profiles SET is_active = 0 WHERE domain = 'edr'; UPDATE _tbl_calcrule_profiles SET is_active = 1 WHERE id = <target>;
| Layer | Prefix | Example |
|---|---|---|
| Source raw | src_ | src_excel_rules |
| Staging | stg_ | stg_calcrule_import |
| Master/Dimension | dim_ | dim_technology |
| System/Meta | _tbl_<domain>_<entity> | _tbl_calcrule_profiles |
Every component runs against the real database. Tests use a real SQLite file in a temp directory, not in-memory mocks. If a rule does not exist in the DB, it does not exist.
All runtimes (browser, Python standalone, Databricks, Snowflake) consume /api/profiles/active. They do not load rules independently. Any runtime that reads rules from a file is in violation of Tenet 1.
Every endpoint that executes rules, reads profiles, writes rules, or accesses datasource connectors must require a valid X-API-Key header. There is no "internal" or "trusted" endpoint that bypasses authentication. Read-only GET profile endpoints tolerate unauthenticated access only in air-gapped local dev environments — never in any networked deployment.
Current implementation: require_api_key dependency in nexus/auth.py. Target: per-key RBAC with expiry and scope constraints (see GAP-02).
CREATE TABLE _tbl_calcrule_profiles (
id INTEGER PRIMARY KEY,
slug TEXT UNIQUE NOT NULL, -- machine name e.g. tco-dc-cooling
name TEXT NOT NULL, -- display name
description TEXT,
technology_variants TEXT DEFAULT '[]', -- JSON array
domain TEXT NOT NULL DEFAULT 'tco', -- bounded context: tco / edr / pfp
is_active INTEGER NOT NULL DEFAULT 0, -- active within domain only
version TEXT DEFAULT '1.0.0',
created_at DATETIME,
updated_at DATETIME
);
CREATE TABLE _tbl_calcrule_rules (
id INTEGER PRIMARY KEY,
profile_id INTEGER NOT NULL REFERENCES _tbl_calcrule_profiles(id),
rule_id TEXT NOT NULL, -- e.g. infra_001_servers_per_rack
name TEXT NOT NULL,
formula TEXT NOT NULL,
output TEXT,
rule_type TEXT, -- infrastructure / capex / opex / tco / scoring
technology TEXT, -- NULL = applies to all technologies
priority INTEGER DEFAULT 0,
enabled INTEGER NOT NULL DEFAULT 1,
excel_source TEXT,
excel_baseline REAL,
description TEXT,
created_at DATETIME,
updated_at DATETIME,
UNIQUE (profile_id, rule_id)
);
See Data Model for the full schema including target tables (_tbl_calcrule_rule_audit, _tbl_api_keys) and PFP rule JSON schema.
Browser / Revit Plugin / CLI
├── GET /ui/index.html (SPA — Calc, Rules, Graph, Inspector tabs)
├── GET /api/profiles/active ──────────────────────────────────────┐
├── POST /pfp/clearance │
├── POST /pfp/select │
├── POST /api/profiles/{key}/run │
└── PATCH/DELETE /rules/{id} (auth-gated write ops) │
│
FastAPI Engine (port 8010 prod / 8012 dev) │
├── nexus/api/app.py (22 routes) │
├── nexus/api/routes_rule_editor.py (7 routes) │
├── nexus/core/profile_store.py (SQLite read) ◄──────────────┘
├── nexus/core/pfp_pipeline.py (formula pipeline)
├── nexus/core/pfp_table_pipeline.py (table pipeline)
├── nexus/core/dynamic_rule_engine.py (TCO/EDR)
├── nexus/core/edr_pipeline.py
├── nexus/core/ingestion_pipeline.py + datasource.py
└── ui/index.html (mounted at /ui/ as StaticFiles)
Flask Admin (port 8011)
├── admin/models.py (Profile, CalculationRule SQLAlchemy models)
├── admin/admin.db (SQLite — shared with FastAPI via filesystem)
└── admin/seed_pfp.py (PFP profile seeder — import format only)
Dockerised stack (docker-compose.yml)
├── nexus-engine → FastAPI (port 8010)
└── nexus-admin → Flask admin (port 8011)
The FastAPI engine reads the SQLite file directly (no Flask context required) via profile_store.py, which uses a plain sqlite3 connection. This avoids a circular dependency between the two services while keeping both pointing at the same DB file.
The SPA (ui/index.html) is a single-file Vanilla JS ES2020 application served as static files. It has no build pipeline. All JS modules (Settings, Profiles, Rules, Calc, Inspector, Graph, Tabs) are IIFE-scoped within the file.
is_active within domain).WHERE domain = ? before flipping flags.WHERE domain = ? AND is_active = 1.Nexus is a multi-domain platform. Each domain is a bounded context with its own profile, connectors, entity types, and API execution endpoints. Profile is_active is scoped to domain — activating a PFP profile does not affect the TCO or EDR domains.
| Profile | tco-dc-cooling — 229 rules post-cleanup, v2.4.0 |
| Connector | YAML baseline + Excel seed |
| Endpoints | POST /execute, POST /api/profiles/tco/run |
| Entity | CalculationContext (server, rack, financial, technology) |
| Technologies | traditional, rdhx, dlc, grc |
| Output | CAPEX, OPEX, TCO by technology variant |
| Profile | edr-entity-validation — 19+ rules, v1.0.0 |
| Connector | Access database → FACT tables (via datasource.py + ingestion_pipeline.py) |
| Endpoints | POST /edr/validate, POST /edr/validate/batch, POST /ingest |
| Entity | EngineeringEntity (tag, class, attributes, properties) |
| Output | quality_tier, completeness_score, violations array |
| Profiles | pfp-clearance-hdb (535 formula rules), pfp-table (430 table rows) |
| Rule files | nexus/rules/pfp/clearance_hdb.json, clearance_fs.json, table_hdb.json, table_fs.json |
| Endpoints | POST /pfp/clearance, POST /pfp/select, POST /pfp/sza, POST /api/profiles/pfp_table/run |
| Client | Pyrometrix Ltd (Revit plugin integration) |
| Tests | 62 dedicated PFP tests (24 formula + 38 table) — all passing |
| Output | clearance_mm, top_mm, side_mm, bottom_mm, error, product_code |
Two separate datasource systems exist in Nexus and do not currently interact.
nexus/core/datasource.py + ingestion_pipeline.py. Connects to external systems to extract entity rows for EDR validation. Supports: SQLite, CSV, JSON, Excel, Access (.accdb), PostgreSQL, ODBC, REST API. Configured via YAML files in nexus/config/datasources/. Fed through IngestionPipeline → EDRPipeline. Not rule-aware.
nexus/core/profile_store.py. Reads calculation rules from admin/admin.db (_tbl_calcrule_rules). Supplies rules to all execution pipelines (TCO, EDR, PFP). Uses plain sqlite3, not the connector layer.
Bridge the two systems. profile_store.py gains a configurable backend; when the NEXUS_RULE_STORE env var points to a remote DB (or DeltaPrism graph engine), rules are sourced from there rather than the local SQLite. No changes to the rule execution engine or API surface required.
| ID | Item | Description | Status |
|---|---|---|---|
| AD-01 | is_active domain scope | Single boolean across all profiles | Fixed M-03 |
| AD-02 | Standalone HTML | nexus-tco-standalone.html baked ALL_RULES | Fixed 2026-03-24 |
| AD-03 | BaseConnector informal | YAML/JSON connector not a BaseConnector subclass | Open — M-03 |
| AD-04 | Formula sandbox | eval() in restricted namespace — not production-safe for cloud | Open — M-05 |
| AD-05 | Auth gaps | 18 of 22 routes unauthenticated | P0 — GAP-01 |
| AD-06 | Single shared key | No RBAC, no expiry, no per-client identity | P1 — GAP-02 |
| AD-07 | Rule source drift | JSON files and DB can drift; seeding may contaminate | P1 — GAP-04 |
| AD-08 | No audit trail | PATCH/DELETE leave no history — critical in fire-safety domain | P1 — GAP-05 |
| AD-09 | SQLite not HA | admin.db on disk — instance termination loses all rule edits | P2 — GAP-09 |
| AD-10 | DeltaPrism migration | Rules are graph nodes; SQLite flattens relationships | Future |