System Diagram

The Progressive Rehabilitation and Mine Closure data model, mapped — 47 models, 161 relationships

🔍 For serious exploration, open the Interactive Diagram Viewer — pan, mouse-wheel zoom, fit-to-screen, full-screen, per-module tabs, the full 161-relationship ERD, and a focus mode that draws one model and its neighbours at a chosen depth. Person (43 links), MineSite (22) and Evidence (19) are role/site/attachment 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

Eleven 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 PLAN["📋 Plans & obligations"]
        SourceAuthority --> SourceDocument --> Requirement
        ClosurePlan --> PlanRequirementLink
        ClosurePlan --> ClosureAssumption
        ClosurePlan --> ClosureObjective
    end

    subgraph DOM["🗺️ Domains & land use"]
        ClosureDomain --> DomainLandUse
        PostMiningLandUse --> DomainLandUse
        ClosureDomain --> DomainObjective
        ClosureDomain --> LandAvailabilityEvent
    end

    subgraph CRIT["✅ Completion criteria"]
        CompletionCriterion --> DomainCriterion --> CriterionAssessment
    end

    subgraph REHAB["🌱 Rehabilitation delivery"]
        DisturbanceEvent
        RehabilitationPrescription --> RehabilitationWork
        RehabilitationCampaign --> RehabilitationWork
        RehabilitationWork --> WorkMaterial
        RehabilitationWork --> WorkInspection
    end

    subgraph MON["📈 Monitoring & results"]
        MonitoringProgram --> MonitoringSchedule
        MonitoringLocation --> MonitoringSchedule
        MonitoringSchedule --> MonitoringEvent --> MonitoringResult
    end

    subgraph DONE["🏁 Certification & relinquishment"]
        CertificationApplication --> CertificationCriterion
        RelinquishmentApplication --> RelinquishmentDomain
        ClosureReview
    end

    subgraph RISK["⚠️ Risk, findings & actions"]
        ClosureRisk
        Finding --> CorrectiveAction
    end

    subgraph STK["🤝 Stakeholders & commitments"]
        Stakeholder --> EngagementEvent
        Stakeholder --> ClosureCommitment
    end

    subgraph COST["💰 Closure cost"]
        ClosureCostEstimate --> ClosureCostItem
        ActualClosureCost
    end

    subgraph SITE["⛏️ Sites, areas & people"]
        Organisation --> Person
        MineSite --> SpatialArea
    end

    subgraph EVD["📚 Evidence & governance"]
        Document --> Evidence
        Approval
    end

    Requirement --> PlanRequirementLink
    MineSite --> ClosurePlan
    ClosurePlan --> ClosureDomain
    SpatialArea --> ClosureDomain
    ClosurePlan --> CompletionCriterion
    ClosureObjective --> DomainObjective
    ClosureDomain --> DomainCriterion
    ClosureDomain --> DisturbanceEvent
    ClosureDomain --> RehabilitationPrescription
    ClosureDomain --> RehabilitationWork
    CompletionCriterion --> MonitoringSchedule
    MonitoringEvent --> Finding
    CriterionAssessment --> Finding
    ClosureRisk --> CorrectiveAction
    ClosureCommitment --> CorrectiveAction
    DomainCriterion --> CertificationCriterion
    CriterionAssessment --> CertificationCriterion
    ClosureDomain --> CertificationApplication
    CertificationApplication --> RelinquishmentDomain
    ClosureDomain --> RelinquishmentDomain
    ClosureDomain --> ClosureCostItem
    RehabilitationWork --> ActualClosureCost
    ClosurePlan --> ClosureReview

(ClosureDomain is the hub of the model — 20 relationships touch it. It is where the plan, the land, the criteria, the work, the monitoring, the cost and the certification all meet, which is exactly the pack's design intent: the domain, not the site and not the plan, is the operational unit of closure.)


Obligations to Plan

Where a requirement came from, and how the plan answers it. The PlanRequirementLink join is the audit surface a regulator reads first.

erDiagram
    SourceAuthority ||--o{ SourceDocument : "source_authority_id"
    SourceDocument ||--o{ SourceDocument : "superseded_by_id"
    Document ||--o{ SourceDocument : "local_document_id"
    SourceDocument ||--o{ Requirement : "source_document_id"
    MineSite ||--o{ ClosurePlan : "mine_site_id"
    ClosurePlan ||--o{ ClosurePlan : "supersedes_plan_id"
    Document ||--o{ ClosurePlan : "document_id"
    ClosurePlan ||--o{ PlanRequirementLink : "closure_plan_id"
    Requirement ||--o{ PlanRequirementLink : "requirement_id"
    ClosurePlan ||--o{ ClosureAssumption : "closure_plan_id"
    ClosurePlan ||--o{ ClosureObjective : "closure_plan_id"

Domains, Land Use and Area State

The spatial and operational spine. Spatial areas and closure domains each self-nest; the four area-state columns live on ClosureDomain and LandAvailabilityEvent is the audit trail between them.

erDiagram
    MineSite ||--o{ SpatialArea : "mine_site_id"
    SpatialArea ||--o{ SpatialArea : "parent_area_id"
    MineSite ||--o{ ClosureDomain : "mine_site_id"
    SpatialArea ||--o{ ClosureDomain : "spatial_area_id"
    ClosurePlan ||--o{ ClosureDomain : "closure_plan_id"
    ClosureDomain ||--o{ ClosureDomain : "parent_domain_id"
    MineSite ||--o{ PostMiningLandUse : "mine_site_id"
    ClosureDomain ||--o{ DomainLandUse : "closure_domain_id"
    PostMiningLandUse ||--o{ DomainLandUse : "post_mining_land_use_id"
    ClosureObjective ||--o{ DomainObjective : "closure_objective_id"
    ClosureDomain ||--o{ DomainObjective : "closure_domain_id"
    ClosureDomain ||--o{ DisturbanceEvent : "closure_domain_id"
    ClosureDomain ||--o{ LandAvailabilityEvent : "closure_domain_id"

Completion Criteria

A criterion is defined once at plan level, localised per domain, and judged by dated assessments. A criterion revision supersedes its predecessor rather than overwriting it.

erDiagram
    ClosurePlan ||--o{ CompletionCriterion : "closure_plan_id"
    CompletionCriterion ||--o{ CompletionCriterion : "supersedes_criterion_id"
    ClosureDomain ||--o{ DomainCriterion : "closure_domain_id"
    CompletionCriterion ||--o{ DomainCriterion : "completion_criterion_id"
    DomainCriterion ||--o{ CriterionAssessment : "domain_criterion_id"
    Evidence ||--o{ CriterionAssessment : "evidence_id"

The one FK dropped in translation. The pack also carried DomainCriterion.currentAssessmentId → CriterionAssessment, which forms a true 2-cycle with CriterionAssessment.domainCriterionId. The child side is load-bearing — an assessment must know what it judged — so the pointer back was dropped. The latest assessment is reachable by ordering a criterion's assessments by assessment_date.


Rehabilitation Delivery

The approved treatment, what was actually delivered against it, and the hold-point inspections that prove it. A prescription revision supersedes its predecessor.

erDiagram
    ClosureDomain ||--o{ RehabilitationPrescription : "closure_domain_id"
    RehabilitationPrescription ||--o{ RehabilitationPrescription : "supersedes_prescription_id"
    Document ||--o{ RehabilitationPrescription : "document_id"
    MineSite ||--o{ RehabilitationCampaign : "mine_site_id"
    RehabilitationCampaign ||--o{ RehabilitationWork : "rehabilitation_campaign_id"
    RehabilitationPrescription ||--o{ RehabilitationWork : "rehabilitation_prescription_id"
    ClosureDomain ||--o{ RehabilitationWork : "closure_domain_id"
    Organisation ||--o{ RehabilitationWork : "contractor_organisation_id"
    RehabilitationWork ||--o{ WorkMaterial : "rehabilitation_work_id"
    RehabilitationWork ||--o{ WorkInspection : "rehabilitation_work_id"
    SpatialArea ||--o{ WorkMaterial : "source_spatial_area_id"

Monitoring

Programs define what is measured and why; a schedule pins a parameter to a location and, critically, to the completion criterion it serves; events and results are the evidence.

erDiagram
    MineSite ||--o{ MonitoringProgram : "mine_site_id"
    MineSite ||--o{ MonitoringLocation : "mine_site_id"
    ClosureDomain ||--o{ MonitoringLocation : "closure_domain_id"
    SpatialArea ||--o{ MonitoringLocation : "spatial_area_id"
    MonitoringProgram ||--o{ MonitoringSchedule : "monitoring_program_id"
    MonitoringLocation ||--o{ MonitoringSchedule : "monitoring_location_id"
    CompletionCriterion ||--o{ MonitoringSchedule : "completion_criterion_id"
    MonitoringSchedule ||--o{ MonitoringEvent : "monitoring_schedule_id"
    MonitoringProgram ||--o{ MonitoringEvent : "monitoring_program_id"
    MonitoringLocation ||--o{ MonitoringEvent : "monitoring_location_id"
    MonitoringEvent ||--o{ MonitoringResult : "monitoring_event_id"

(MonitoringSchedule.completion_criterion_id is the link that makes the criteria testable. Without it a monitoring program is data collection; with it, every criterion can be traced to the measurements that will decide it.)


Risk, Findings and Corrective Actions

The improvement loop. Findings come from exceedances and failed assessments; actions come from findings, risks and commitments alike.

erDiagram
    MineSite ||--o{ ClosureRisk : "mine_site_id"
    ClosureDomain ||--o{ ClosureRisk : "closure_domain_id"
    ClosurePlan ||--o{ ClosureRisk : "closure_plan_id"
    MonitoringEvent ||--o{ Finding : "monitoring_event_id"
    CriterionAssessment ||--o{ Finding : "criterion_assessment_id"
    ClosureDomain ||--o{ Finding : "closure_domain_id"
    Finding ||--o{ CorrectiveAction : "finding_id"
    ClosureRisk ||--o{ CorrectiveAction : "closure_risk_id"
    ClosureCommitment ||--o{ CorrectiveAction : "commitment_id"

Stakeholders, Commitments and Cost

What was promised and to whom, and what it costs. Both chains close back onto delivery evidence.

erDiagram
    MineSite ||--o{ Stakeholder : "mine_site_id"
    Organisation ||--o{ Stakeholder : "organisation_id"
    Stakeholder ||--o{ EngagementEvent : "stakeholder_id"
    Stakeholder ||--o{ ClosureCommitment : "stakeholder_id"
    Requirement ||--o{ ClosureCommitment : "requirement_id"
    MineSite ||--o{ ClosureCostEstimate : "mine_site_id"
    ClosureCostEstimate ||--o{ ClosureCostEstimate : "supersedes_estimate_id"
    ClosureCostEstimate ||--o{ ClosureCostItem : "closure_cost_estimate_id"
    ClosureDomain ||--o{ ClosureCostItem : "closure_domain_id"
    RehabilitationWork ||--o{ ClosureCostItem : "rehabilitation_work_id"
    ClosureDomain ||--o{ ActualClosureCost : "closure_domain_id"
    RehabilitationWork ||--o{ ActualClosureCost : "rehabilitation_work_id"

Certification and Relinquishment

Progressive certification is per domain and carries each criterion with its assessment. Relinquishment is whole-of-site and carries a readiness row per domain.

erDiagram
    ClosureDomain ||--o{ CertificationApplication : "closure_domain_id"
    Document ||--o{ CertificationApplication : "application_document_id"
    CertificationApplication ||--o{ CertificationCriterion : "certification_application_id"
    DomainCriterion ||--o{ CertificationCriterion : "domain_criterion_id"
    CriterionAssessment ||--o{ CertificationCriterion : "criterion_assessment_id"
    ClosurePlan ||--o{ RelinquishmentApplication : "closure_plan_id"
    RelinquishmentApplication ||--o{ RelinquishmentDomain : "relinquishment_application_id"
    ClosureDomain ||--o{ RelinquishmentDomain : "closure_domain_id"
    CertificationApplication ||--o{ RelinquishmentDomain : "certification_application_id"
    ClosurePlan ||--o{ ClosureReview : "closure_plan_id"

Application Flow — Disturbance to Certification

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

flowchart TD
    A["⛏️ Disturbance event<br/><i>area, volume, topsoil stripped</i>"] --> B["🗺️ Closure domain<br/><i>disturbed hectares</i>"]
    B --> C{"Mining finished<br/>with this ground?"}
    C -->|no| C2["Stays NOT_AVAILABLE<br/><i>milestone date recorded</i>"]
    C2 --> C
    C -->|yes| D["📗 Land availability event<br/>→ AVAILABLE"]
    D --> E["📐 Rehabilitation prescription<br/><i>approved before work starts</i>"]
    E --> F["🌱 Rehabilitation work<br/><i>campaign, contractor, quantities</i>"]
    F --> G{"Hold point inspection<br/>passes?"}
    G -->|no| G2["🔁 Rework — stage returns<br/>to REWORK_REQUIRED"]
    G2 --> F
    G -->|yes| H["📗 → REHABILITATED → MONITORING"]
    H --> I["📈 Monitoring schedule<br/><i>tied to a completion criterion</i>"]
    I --> J["📊 Events + results<br/><i>over the assessment period</i>"]
    J --> K{"Enough events?<br/><i>minimum_monitoring_events</i>"}
    K -->|no| J
    K -->|yes| L["⚖️ Criterion assessment<br/><i>assessed · reviewed · approved</i>"]
    L --> M{"All applicable criteria<br/>MET or disclosed?"}
    M -->|no| N["🚩 Finding → corrective action<br/><i>criterion stays AT_RISK / NOT_MET</i>"]
    N --> I
    M -->|yes| O["🏁 Certification application<br/><i>each criterion + its assessment</i>"]
    O --> P{"Decision"}
    P -->|"APPROVED with conditions"| Q["📗 → CERTIFIED<br/>conditions become commitments"]
    P -->|"INFORMATION_REQUEST"| I
    Q --> R["🤝 Relinquishment readiness<br/><i>one row per domain</i>"]

Application Flow — Why a Criterion Cannot Just Be Marked Met

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

flowchart TD
    S(["DomainCriterion at NOT_ASSESSED"]) --> R["📊 Monitoring results accumulate"]
    R --> Q{"Values inside the<br/>target range?"}
    Q -->|"yes — but that's not enough"| K1["Still NOT_ASSESSED"]
    K1 --> K2["⚖️ CriterionAssessment written<br/><i>period, evidence, confidence, limitations</i>"]
    K2 --> K3{"Reviewed by a second person?"}
    K3 -->|no| K2
    K3 -->|yes| K4{"Approved?"}
    K4 -->|no| K2
    K4 -->|yes| K5["✅ result recorded<br/>MET · PARTIALLY_MET · NOT_MET · AT_RISK"]
    K5 --> K6["DomainCriterion.status follows<br/><i>the assessment, not the raw data</i>"]
    Q -->|no| N["🚩 Finding raised<br/>→ corrective action"]
    N --> R
    K5 -.->|"PARTIALLY_MET"| D["📄 Disclosed in the application —<br/>a conditional decision, not a deferral"]

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, mine_site_id, evidence_id) are omitted for readability. The interactive viewer's Full ERD shows all 161, with the person/site/evidence noise toggleable.
  • ClosureDomain is the hub of the model — the viewer's Focus mode is the fastest way to see its 20 links. Person has the most (43) because every closure act records who did it: owned, accountable, responsible, prepared, reviewed, approved, assessed, inspected, authorised, detected, assigned, verified, submitted, captured, accepted.
  • One FK was dropped in translation: DomainCriterion.current_assessment_id, which formed a true 2-cycle with CriterionAssessment.domain_criterion_id. See the Completion Criteria section above. Everything else in the source model is present. Seven self-references are kept: SpatialArea.parent_area_id, ClosureDomain.parent_domain_id, ClosurePlan.supersedes_plan_id, CompletionCriterion.supersedes_criterion_id, RehabilitationPrescription.supersedes_prescription_id, ClosureCostEstimate.supersedes_estimate_id and SourceDocument.superseded_by_id.
  • One pointer is deliberately not a foreign key: Approval.entity_type + entity_id is a polymorphic reference — an approval can hang off a plan, a prescription, an assessment, a certification application, a cost estimate or a relinquishment application — so it is a type/id pair, not an edge.

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