System Diagram

The Solar Farm Maintenance Operations Hub data model, mapped — 50 models, 143 relationships

🔍 For serious exploration, open the Interactive Diagram Viewer — pan, mouse-wheel zoom, fit-to-screen, full-screen, per-module tabs, the full 143-relationship ERD, and a focus mode that draws one model and its neighbours at a chosen depth. Person (31 links), WorkOrder (22) and Asset (15) are role/work/equipment columns that fan out to nearly everything, so the viewer hides those links by default — a toggle brings them back. The diagrams below are the readable, static summary of the principal links only.


Architecture Overview

Eight areas mirror the sidebar menu. Every arrow means "one row of the left model is referenced by many rows of the right model".

flowchart LR
    subgraph ASSET["🔆 Assets & portfolio"]
        Portfolio --> SolarFarm
        SolarFarm --> SiteZone
        SiteZone --> AssetLocation
        AssetType --> Asset
        SolarFarm --> Asset
    end

    subgraph REQ["⚠️ Requests & defects"]
        AlarmEventReference --> ServiceRequest
        ServiceRequest --> Defect
        Defect --> OperationalImpact
        Defect --> PriorityAssessment
        WeatherEvent
    end

    subgraph WORK["🛠️ Work management"]
        MaintenanceTemplate --> MaintenanceTemplateTask
        WorkOrder --> WorkTask
        WorkOrder --> WorkAssignment
        WorkOrder --> WorkDependency
        WorkOrder --> WorkStatusHistory
    end

    subgraph SAFE["🦺 Safety & access"]
        WorkOrder --> IsolationReference
        WorkOrder --> AccessRequirement
        WorkOrder --> SafetyDocument
        Competency --> PersonCompetency
    end

    subgraph FIELD["🔧 Field execution"]
        Inspection --> InspectionResult
        WorkOrder --> Measurement
        WorkOrder --> Evidence
        WorkOrder --> TestResult
        WorkOrder --> ReturnToService
        ReturnToService --> Verification
        WorkOrder --> Closeout
    end

    subgraph PART["📦 Parts & warranty"]
        Part --> PartStock
        WorkOrder --> PartUsage
        WorkOrder --> RemovedComponent
        RemovedComponent --> WarrantyClaim
    end

    subgraph VEG["🌿 Vegetation & site"]
        VegetationZone --> VegetationInspection
    end

    subgraph ADMIN["🏢 Administration"]
        Organisation --> Person
        InspectionTemplate --> InspectionTemplateItem
    end

    Asset --> AlarmEventReference
    Defect --> WorkOrder
    Defect --> WarrantyClaim
    Defect --> Verification
    Defect --> Closeout
    WorkOrder --> Inspection
    SolarFarm --> VegetationZone

(WorkOrder is the hub of execution — 22 relationships touch it — because every field record, safety reference, part transaction and closure act hangs off the job. Person has the most links (31) because every maintenance act records who: requested, assessed, approved, planned, supervised, assigned, isolated, inspected, measured, tested, returned, verified, closed.)


Assets, Portfolio and Location

The equipment being maintained. SiteZone and Asset each self-nest; an asset lives at a location within a zone of a farm, and carries a type.

erDiagram
    Organisation ||--o{ Portfolio : "owner_organisation_id"
    Person ||--o{ Portfolio : "manager_person_id"
    Portfolio ||--o{ SolarFarm : "portfolio_id"
    Organisation ||--o{ SolarFarm : "owner_organisation_id"
    SolarFarm ||--o{ SiteZone : "solar_farm_id"
    SiteZone ||--o{ SiteZone : "parent_zone_id"
    SolarFarm ||--o{ AssetLocation : "solar_farm_id"
    SiteZone ||--o{ AssetLocation : "site_zone_id"
    AssetType ||--o{ Asset : "asset_type_id"
    SolarFarm ||--o{ Asset : "solar_farm_id"
    AssetLocation ||--o{ Asset : "asset_location_id"
    Asset ||--o{ Asset : "parent_asset_id"
    Asset ||--o{ AssetRelationship : "source_asset_id"
    Asset ||--o{ AssetRelationship : "target_asset_id"
    Organisation ||--o{ SourceSystem : "owner_organisation_id"

Detection — Alarms, Requests and Defects

The three doors into the system converge on Defect, which carries its own impact and priority.

erDiagram
    SolarFarm ||--o{ AlarmEventReference : "solar_farm_id"
    Asset ||--o{ AlarmEventReference : "asset_id"
    SourceSystem ||--o{ AlarmEventReference : "source_system_id"
    AlarmEventReference ||--o{ ServiceRequest : "alarm_event_reference_id"
    SolarFarm ||--o{ ServiceRequest : "solar_farm_id"
    ServiceRequest ||--o{ Defect : "service_request_id"
    DefectCategory ||--o{ Defect : "defect_category_id"
    Asset ||--o{ Defect : "asset_id"
    Defect ||--o{ Defect : "parent_defect_id"
    Defect ||--o{ OperationalImpact : "defect_id"
    Defect ||--o{ PriorityAssessment : "defect_id"
    SolarFarm ||--o{ WeatherEvent : "solar_farm_id"

Work Management

The planned response. A work order can be generated from a maintenance template, sits under a defect, and self-nests for parent/child jobs.

erDiagram
    AssetType ||--o{ MaintenanceTemplate : "asset_type_id"
    MaintenanceTemplate ||--o{ MaintenanceTemplateTask : "maintenance_template_id"
    Defect ||--o{ WorkOrder : "defect_id"
    MaintenanceTemplate ||--o{ WorkOrder : "maintenance_template_id"
    WorkOrder ||--o{ WorkOrder : "parent_work_order_id"
    SolarFarm ||--o{ WorkOrder : "solar_farm_id"
    WorkOrder ||--o{ WorkTask : "work_order_id"
    WorkOrder ||--o{ WorkAssignment : "work_order_id"
    WorkOrder ||--o{ WorkDependency : "work_order_id"
    WorkOrder ||--o{ WorkDependency : "related_work_order_id"
    WorkOrder ||--o{ WorkStatusHistory : "work_order_id"

Safety and Access

Making the job safe before it starts. IsolationReference carries the full proved-dead sequence; SafetyDocument joins a work order to a controlled document.

erDiagram
    WorkOrder ||--o{ IsolationReference : "work_order_id"
    Asset ||--o{ IsolationReference : "asset_id"
    WorkOrder ||--o{ AccessRequirement : "work_order_id"
    WorkOrder ||--o{ SafetyDocument : "work_order_id"
    Document ||--o{ SafetyDocument : "document_id"
    Competency ||--o{ PersonCompetency : "competency_id"
    Person ||--o{ PersonCompetency : "person_id"
    Document ||--o{ PersonCompetency : "evidence_document_id"

Field Execution and the Three Acts of Closure

The field record, then the three deliberately separate closure steps. This is the model's core assurance argument.

erDiagram
    AssetType ||--o{ InspectionTemplate : "asset_type_id"
    InspectionTemplate ||--o{ InspectionTemplateItem : "inspection_template_id"
    InspectionTemplate ||--o{ Inspection : "inspection_template_id"
    WorkOrder ||--o{ Inspection : "work_order_id"
    Asset ||--o{ Inspection : "asset_id"
    Inspection ||--o{ InspectionResult : "inspection_id"
    InspectionTemplateItem ||--o{ InspectionResult : "inspection_template_item_id"
    WorkOrder ||--o{ Measurement : "work_order_id"
    Asset ||--o{ Measurement : "asset_id"
    WorkOrder ||--o{ Evidence : "work_order_id"
    WorkOrder ||--o{ TechnicianNote : "work_order_id"
    WorkOrder ||--o{ TestResult : "work_order_id"
    Evidence ||--o{ TestResult : "evidence_id"
    WorkOrder ||--o{ ReturnToService : "work_order_id"
    Defect ||--o{ Verification : "defect_id"
    ReturnToService ||--o{ Verification : "return_to_service_id"
    Defect ||--o{ Closeout : "defect_id"
    WorkOrder ||--o{ Closeout : "work_order_id"

Parts and Warranty

Lightweight materials and recovery. A required part is issued, used, and — if it failed under warranty — booked out as a removed component and claimed.

erDiagram
    Part ||--o{ PartStock : "part_id"
    StockLocation ||--o{ PartStock : "stock_location_id"
    WorkOrder ||--o{ PartRequirement : "work_order_id"
    Part ||--o{ PartRequirement : "part_id"
    WorkOrder ||--o{ PartUsage : "work_order_id"
    Part ||--o{ PartUsage : "part_id"
    WorkOrder ||--o{ RemovedComponent : "work_order_id"
    Part ||--o{ RemovedComponent : "part_id"
    Defect ||--o{ WarrantyClaim : "defect_id"
    RemovedComponent ||--o{ WarrantyClaim : "removed_component_id"
    Organisation ||--o{ WarrantyClaim : "manufacturer_organisation_id"

Vegetation

A specialist stream with the same shape as the electrical work: a managed zone, inspected against target and intervention heights, raising defects and work like any other.

erDiagram
    SolarFarm ||--o{ VegetationZone : "solar_farm_id"
    SiteZone ||--o{ VegetationZone : "site_zone_id"
    VegetationZone ||--o{ VegetationInspection : "vegetation_zone_id"
    WorkOrder ||--o{ VegetationInspection : "work_order_id"
    Defect ||--o{ VegetationInspection : "defect_id"

Application Flow — Detection to Closeout

The order in which the system is actually used, and what gates each step.

flowchart TD
    A["📟 Alarm / inspection / operator request"] --> B["🧾 Service request"]
    B --> C["⚠️ Defect<br/><i>impact + priority assessed</i>"]
    C --> D{"Work needed?"}
    D -->|yes| E["🛠️ Work order planned + assigned"]
    E --> F{"Isolation required?"}
    F -->|yes| G["🔌 Isolation applied → PROVED_DEAD → released"]
    F -->|no| H
    G --> H["🚧 Access arranged · SWMS accepted"]
    H --> I["🔧 Field work<br/><i>tasks, measurements, evidence, tests</i>"]
    I --> J{"Parts replaced?"}
    J -->|yes| K["📦 Part used · component removed<br/>→ warranty claim if applicable"]
    J -->|no| L
    K --> L["♻️ Return to service<br/><i>isolation restored · alarms cleared · output confirmed</i>"]
    L --> M["🔎 Verification<br/><i>independent — ACCEPTED / REJECTED / FURTHER_WORK / MONITOR</i>"]
    M --> N{"Accepted?"}
    N -->|no| I
    N -->|yes| O["🏁 Closeout<br/><i>failure mode · root cause · capacity restored</i>"]
    O --> P["Defect → CLOSED"]

Application Flow — Why "Work Finished" Is Not "Defect Closed"

The single most important distinction in the domain, drawn out.

flowchart TD
    S(["Technician finishes physical work"]) --> R1["♻️ ReturnToService written<br/><i>is the EQUIPMENT safe to run?</i>"]
    R1 --> R2{"Isolation restored · protection normal<br/>· alarms cleared · output confirmed?"}
    R2 -->|no| R1
    R2 -->|yes| V1["🔎 Verification written<br/><i>is the DEFECT actually resolved?</i>"]
    V1 --> V2{"Independent check —<br/>accepted?"}
    V2 -->|"REJECTED / FURTHER_WORK"| B["↩️ Back to field work"]
    V2 -->|"MONITOR"| M["⏱️ Follow-up scheduled<br/><i>follow_up_due_at</i>"]
    V2 -->|"ACCEPTED"| C1["🏁 Closeout written<br/><i>the DEFECT is formally closed</i>"]
    C1 --> C2["Defect.defect_status → CLOSED<br/>client_accepted_by recorded"]

Reading the Diagrams

  • A ||--o{ B means one row of A is referenced by many rows of B (the label is the foreign-key column on B).
  • These static diagrams show principal links only — the role columns that appear on nearly every model (*_person_id, work_order_id, asset_id, solar_farm_id) are omitted for readability. The interactive viewer's Full ERD shows all 143, with the person/work/asset noise toggleable.
  • WorkOrder is the hub of execution (22 links) and Person has the most (31), because every maintenance act records who performed each role — the viewer's Focus mode is the fastest way to see one model's neighbourhood.
  • No foreign key was dropped in translation — the pack had no true reference cycle. Four self-references are kept: SiteZone.parent_zone_id, Asset.parent_asset_id, Defect.parent_defect_id and WorkOrder.parent_work_order_id. The AuditRecord model was dropped (the framework provides audit history); everything else in the source model is present.
  • One pointer is deliberately not a foreign key in spirit: AlarmEventReference and the external_* / raw_reference_url columns are governed references to events and records that live in external systems (SCADA, CMMS, drone platforms), not edges into them.

Diagrams are derived from the generated schema metadata (apps/solarfarm/generated/json/solarfarm_relationship_metadata.json). If the DSL schema changes, regenerate the metadata (python -m codegen.cli all solarfarm), rebuild the viewer (python apps/solarfarm/scripts/build_diagram_viewer.py) and update this page.