- Documentation
- /
- Blast
- /
- System Diagram
System Diagram
The Blast Planning and Explosives Management data model, mapped — 65 models, 199 relationships
🔍 For serious exploration, open the Interactive Diagram Viewer — pan, mouse-wheel zoom, fit-to-screen, full-screen, per-module tabs, the full 199-relationship ERD, and a focus mode that draws one model and its neighbours at a chosen depth. Person (71 links), Document (25) and MineSite (12) are role/ownership columns that fan out to nearly everything, so the viewer hides those links by default — a toggle brings them back. Blast (34 links) is the structural spine and stays visible. The diagrams below are the readable, static summary of the principal links only.
Architecture Overview
Ten 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["🧨 Planning & design"]
BlastRequest --> Blast
Blast --> BlastDesign --> BlastDesignApproval
Blast --> BlastRiskAssessment --> BlastHazard
Blast --> BlastBoundary
end
subgraph DRILL["🕳️ Drilling"]
BlastHole --> DrillActivity
BlastHole --> HoleSurvey
BlastHole --> HoleConditionInspection
end
subgraph CHARGE["⚡ Charging & initiation"]
ChargingPlan --> HoleChargePlan
ChargingSession --> HoleChargeActual
ChargingSession --> ChargingQualityCheck
InitiationPlan --> TieInConnection
end
subgraph EXPL["📦 Explosives & stock"]
ExplosiveProduct --> ExplosiveBatch
ExplosivesMagazine --> MagazineInspection
ExplosivesMagazine --> ExplosiveStockLocation
ExplosiveStockLocation --> ExplosiveStockBalance
ExplosiveBatch --> ExplosiveStockTransaction
ExplosivesTransportMovement --> TransportMovementItem
end
subgraph CLEAR["📢 Clearance & firing"]
ClearancePlan --> GuardPost
ClearancePlan --> AreaClearance
PreFireChecklist --> BlastFiring
BlastNotification
WeatherObservation
end
subgraph POST["🌏 Post-blast & environment"]
PostBlastInspection --> ReentryAuthorisation
BlastMonitoringInstrument --> BlastMonitoringRecord
SensitiveReceiver --> BlastReceiverAssessment
FlyrockObservation
FumeObservation
FragmentationAssessment
MuckpileAssessment
end
subgraph MF["🚨 Misfire & reconciliation"]
Misfire --> MisfireTreatment
BlastReconciliation
BlastCostRecord
end
subgraph INC["🔎 Incidents"]
BlastIncident --> Investigation --> InvestigationFinding --> CorrectiveAction
end
subgraph ASSUR["📜 Assurance"]
SourceAuthority --> SourceDocument --> Requirement
ExplosivesManagementPlan --> PlanRequirementLink
Audit --> AuditFinding
PersonAuthorisation
end
Blast --> BlastHole
Blast --> ChargingPlan
Blast --> ChargingSession
Blast --> InitiationPlan
Blast --> ClearancePlan
Blast --> PreFireChecklist
Blast --> BlastNotification
Blast --> WeatherObservation
Blast --> PostBlastInspection
Blast --> BlastMonitoringRecord
Blast --> Misfire
Blast --> BlastReconciliation
Blast --> BlastIncident
Blast --> ExplosiveStockTransaction
BlastHole --> HoleChargePlan
BlastHole --> HoleChargeActual
BlastHole --> Misfire
ExplosiveBatch --> HoleChargeActual
BlastBoundary --> ClearancePlan
Requirement --> PlanRequirementLink
CorrectiveAction --> AuditFinding
(Blast is the hub — 34 relationships touch it. Everything from the hole
pattern to the cost record hangs off it, which is why the viewer's Focus mode
defaults to it.)
Design, Approval and Risk
A design revision supersedes its predecessor rather than overwriting it, and approval is split across independent roles so the pack's segregation-of-duties rule is checkable.
erDiagram
BlastRequest ||--o{ Blast : "blast_request_id"
Blast ||--o{ BlastDesign : "blast_id"
BlastDesign ||--o{ BlastDesign : "supersedes_design_id"
BlastDesign ||--o{ BlastDesignApproval : "blast_design_id"
Blast ||--o{ BlastRiskAssessment : "blast_id"
BlastRiskAssessment ||--o{ BlastHazard : "blast_risk_assessment_id"
Blast ||--o{ BlastBoundary : "blast_id"
MineSite ||--o{ SensitiveReceiver : "mine_site_id"
Blast ||--o{ BlastReceiverAssessment : "blast_id"
SensitiveReceiver ||--o{ BlastReceiverAssessment : "sensitive_receiver_id"
Drilling and Hole Validation
The three records that decide whether a hole may be charged. HoleConditionInspection
.suitable_for_charging is the gate — a false here means no HoleChargeActual
row will ever exist for that hole.
erDiagram
Blast ||--o{ BlastHole : "blast_id"
BlastHole ||--o{ DrillActivity : "blast_hole_id"
BlastHole ||--o{ HoleSurvey : "blast_hole_id"
BlastHole ||--o{ HoleConditionInspection : "blast_hole_id"
Explosives Custody
Batch-level traceability from supplier to hole and back. ExplosiveStockBalance
is the location × batch join; ExplosiveStockTransaction is the ledger.
erDiagram
Organisation ||--o{ ExplosiveProduct : "supplier_organisation_id"
ExplosiveProduct ||--o{ ExplosiveBatch : "explosive_product_id"
MineSite ||--o{ ExplosivesMagazine : "mine_site_id"
ExplosivesMagazine ||--o{ MagazineInspection : "explosives_magazine_id"
ExplosivesMagazine ||--o{ ExplosiveStockLocation : "explosives_magazine_id"
ExplosiveStockLocation ||--o{ ExplosiveStockBalance : "explosive_stock_location_id"
ExplosiveBatch ||--o{ ExplosiveStockBalance : "explosive_batch_id"
ExplosiveBatch ||--o{ ExplosiveStockTransaction : "explosive_batch_id"
ExplosiveStockLocation ||--o{ ExplosiveStockTransaction : "from_location_id"
ExplosiveStockLocation ||--o{ ExplosiveStockTransaction : "to_location_id"
Blast ||--o{ ExplosiveStockTransaction : "blast_id"
ExplosivesTransportMovement ||--o{ TransportMovementItem : "explosives_transport_movement_id"
ExplosiveBatch ||--o{ TransportMovementItem : "explosive_batch_id"
Charging and Initiation
Planned versus actual, hole by hole and deck by deck. Note that
HoleChargeActual carries three batch references — main charge, booster and
detonator — so a suspect batch traces to exact holes.
erDiagram
Blast ||--o{ ChargingPlan : "blast_id"
BlastDesign ||--o{ ChargingPlan : "blast_design_id"
ChargingPlan ||--o{ HoleChargePlan : "charging_plan_id"
BlastHole ||--o{ HoleChargePlan : "blast_hole_id"
ExplosiveProduct ||--o{ HoleChargePlan : "explosive_product_id"
Blast ||--o{ ChargingSession : "blast_id"
ChargingPlan ||--o{ ChargingSession : "charging_plan_id"
ChargingSession ||--o{ HoleChargeActual : "charging_session_id"
BlastHole ||--o{ HoleChargeActual : "blast_hole_id"
ExplosiveBatch ||--o{ HoleChargeActual : "explosive_batch_id"
ExplosiveBatch ||--o{ HoleChargeActual : "booster_batch_id"
ExplosiveBatch ||--o{ HoleChargeActual : "detonator_batch_id"
ChargingSession ||--o{ ChargingQualityCheck : "charging_session_id"
Blast ||--o{ InitiationPlan : "blast_id"
InitiationPlan ||--o{ TieInConnection : "initiation_plan_id"
BlastHole ||--o{ TieInConnection : "from_blast_hole_id"
BlastHole ||--o{ TieInConnection : "to_blast_hole_id"
Clearance and Firing
The gate. BlastFiring requires a PreFireChecklist, and the checklist is only
true when every guard post and area clearance is.
erDiagram
Blast ||--o{ BlastNotification : "blast_id"
Blast ||--o{ ClearancePlan : "blast_id"
BlastBoundary ||--o{ ClearancePlan : "exclusion_boundary_id"
ClearancePlan ||--o{ GuardPost : "clearance_plan_id"
ClearancePlan ||--o{ AreaClearance : "clearance_plan_id"
OperatingArea ||--o{ AreaClearance : "operating_area_id"
Blast ||--o{ WeatherObservation : "blast_id"
Blast ||--o{ PreFireChecklist : "blast_id"
Blast ||--o{ BlastFiring : "blast_id"
PreFireChecklist ||--o{ BlastFiring : "pre_fire_checklist_id"
Post-Blast, Misfire and Reconciliation
ReentryAuthorisation hangs off a specific PostBlastInspection — which is
how "re-entry was authorised against the inspection that cleared the area, not
the one that found the misfire" becomes a fact in the data.
erDiagram
Blast ||--o{ PostBlastInspection : "blast_id"
Blast ||--o{ ReentryAuthorisation : "blast_id"
PostBlastInspection ||--o{ ReentryAuthorisation : "post_blast_inspection_id"
MineSite ||--o{ BlastMonitoringInstrument : "mine_site_id"
Blast ||--o{ BlastMonitoringRecord : "blast_id"
BlastMonitoringInstrument ||--o{ BlastMonitoringRecord : "blast_monitoring_instrument_id"
SensitiveReceiver ||--o{ BlastMonitoringRecord : "sensitive_receiver_id"
Blast ||--o{ FlyrockObservation : "blast_id"
Blast ||--o{ FumeObservation : "blast_id"
Blast ||--o{ FragmentationAssessment : "blast_id"
Blast ||--o{ MuckpileAssessment : "blast_id"
Blast ||--o{ Misfire : "blast_id"
BlastHole ||--o{ Misfire : "suspected_hole_id"
Misfire ||--o{ MisfireTreatment : "misfire_id"
Blast ||--o{ BlastReconciliation : "blast_id"
Blast ||--o{ BlastCostRecord : "blast_id"
Incidents, Investigation and Assurance
The improvement loop, and the compliance spine it answers to.
erDiagram
Blast ||--o{ BlastIncident : "blast_id"
BlastIncident ||--o{ Investigation : "blast_incident_id"
Investigation ||--o{ InvestigationFinding : "investigation_id"
InvestigationFinding ||--o{ CorrectiveAction : "investigation_finding_id"
BlastIncident ||--o{ CorrectiveAction : "blast_incident_id"
Blast ||--o{ CorrectiveAction : "blast_id"
BlastDesign ||--o{ InvestigationFinding : "blast_design_id"
SourceAuthority ||--o{ SourceDocument : "source_authority_id"
SourceDocument ||--o{ SourceDocument : "superseded_by_id"
SourceDocument ||--o{ Requirement : "source_document_id"
MineSite ||--o{ ExplosivesManagementPlan : "mine_site_id"
ExplosivesManagementPlan ||--o{ PlanRequirementLink : "explosives_management_plan_id"
Requirement ||--o{ PlanRequirementLink : "requirement_id"
MineSite ||--o{ Audit : "mine_site_id"
Audit ||--o{ AuditFinding : "audit_id"
Requirement ||--o{ AuditFinding : "requirement_id"
CorrectiveAction ||--o{ AuditFinding : "corrective_action_id"
Person ||--o{ PersonAuthorisation : "person_id"
Application Flow — Request to Close
The order in which the system is actually used, and what gates each step.
flowchart TD
A["📝 Blast request raised"] --> B["📐 Blast design revision"]
B --> C{"Design approved by<br/>geotech · environment · management?"}
C -->|rejected| B
C -->|approved| D["⚠️ Risk assessment + hazards<br/>boundaries + receiver assessment"]
D --> E["🕳️ Drill the pattern"]
E --> F["📏 Survey + condition inspection"]
F --> G{"suitable_for_charging?"}
G -->|no| H["🚫 REDRILL_REQUIRED<br/><i>hole excluded from the charge plan</i>"]
G -->|yes| I["📦 Issue explosives against the blast<br/><i>batch-level, sealed transport</i>"]
H --> I
I --> J["⚡ Charge per plan<br/><i>deviations recorded + approved</i>"]
J --> K["🔗 Tie-in + continuity verified"]
K --> L["📢 Notify · clear the zone · post guards"]
L --> M{"Every guard CONFIRMED_CLEAR<br/>and every area clear?"}
M -->|no| L
M -->|yes| N{"✅ Pre-fire checklist<br/>all 15 checks true?"}
N -->|no| L
N -->|yes| O["🧨 Shotfirer authorised → FIRE"]
O --> P["🔍 Post-blast inspection<br/><i>after the wait period</i>"]
P --> Q{"Misfire indicators?"}
Q -->|yes| R["🚨 Misfire: isolate → assess →<br/>treat → verify independently"]
R --> P
Q -->|no| S["🔓 Re-entry authorised"]
S --> T["📊 Monitoring · fragmentation · muckpile"]
T --> U["🧮 Reconciliation<br/><i>holes · explosives · tonnage</i>"]
U --> V{"Variance within tolerance<br/>and no open misfire?"}
V -->|no| W["⛔ Blast stays open<br/><i>corrective action raised</i>"]
W --> U
V -->|yes| X["🔒 Blast CLOSED"]
Application Flow — Why This Blast Has Not Closed
The demo's BL-2026-00042 sits at RECONCILIATION. Three separate gates
explain why, and each is visible as data.
flowchart TD
S(["BL-2026-00042 · stage RECONCILIATION"]) --> G1{"Reconciliation approved?"}
G1 -->|"NO — 3.5 kg unexplained variance<br/>exceeds the 2 kg tolerance"| B1["stock_reconciled = false<br/>status = REVIEW, no approver"]
B1 --> A1["BL-ACT-2026-00019<br/>AWAITING_VERIFICATION"]
S --> G2{"All reportable incidents<br/>notified and closed?"}
G2 -->|"Vibration exceedance still ACTIVE"| B2["BL-INC-2026-00007<br/>9.4 mm/s vs 5.0 mm/s limit"]
B2 --> A2["BL-ACT-2026-00017<br/>recalibrate the prediction model"]
S --> G3{"All critical actions assigned<br/>and on track?"}
G3 -->|"One action OVERDUE"| B3["BL-ACT-2026-00021<br/>redrill NP480-007"]
A1 --> R(["closed_at stays null"])
A2 --> R
B3 --> R
Reading the Diagrams
A ||--o{ Bmeans 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,*_document_id,mine_site_id) are omitted for readability. The interactive viewer's Full ERD shows all 199, with the person/document/site noise toggleable. Blastis the hub of the domain — the viewer's Focus mode defaults to it, with 34 links.Personhas by far the most (71) because every act in blasting records who did it: requested, designed, supervised, approved, drilled, surveyed, inspected, issued, handled, charged, checked, installed, verified, coordinated, guarded, cleared, authorised, fired, detected, treated, reconciled, investigated, owned, audited.- No FK was dropped in translation — the proforma graph was acyclic, so every
relationship in the source model is present.
Documentwas hoisted abovePersonAuthorisation(the pack declares it after first use).OperatingArea.parent_area_id,SourceDocument.superseded_by_idandBlastDesign.supersedes_design_idare self-references. - Three FK pairs are deliberately two roles onto the same parent, and the
drill-down tabs are labelled accordingly in
tab_config.yaml:ExplosiveStockTransaction.from_location_id/to_location_id,TieInConnection.from_blast_hole_id/to_blast_hole_id, andHoleChargeActual's three batch roles (main charge, booster, detonator). AuditRecordfrom the proforma pack is not present — it duplicated the framework's own audit history and was dropped in translation.
Diagrams are derived from the generated schema metadata
(apps/blast/generated/json/blast_relationship_metadata.json). If the DSL schema
changes, regenerate the metadata (python -m codegen.cli all blast) and update
this page and the viewer's embedded data.