-- ============================================================ -- MODULE 4: Incidentmanagement & Milieu — Check & Act -- Phoenix Metals HSEQ VBS — SQL Migration v1.0 -- ============================================================ -- Scope: BRZO incidenten, Arbowet art.9 meldingsplicht, -- Omgevingswet/Bal emissie-registratie, CAPA -- VBS Elementen: VBS-07 (Continue Verbetering), VBS-04 (Noodplan) -- ============================================================ -- ───────────────────────────────────────────── -- 4A. INCIDENTEN REGISTRATIE -- ───────────────────────────────────────────── -- Onderscheid: Arbo (letsel) vs Procesveiligheid (LOPC) vs Milieu (spill/emissie) -- Classificatie: Near-miss, Onveilige situatie, Incident, Ernstig incident -- Meldingsplicht: Arbowet art.9, BRZO Bijlage III -- ───────────────────────────────────────────── ALTER TABLE incident_items RENAME TO incident_items_legacy; CREATE TABLE incidents ( -- ─── Identificatie ─── id INTEGER PRIMARY KEY AUTOINCREMENT, incident_code TEXT NOT NULL UNIQUE, -- Bijv. INC-2026-0410-001 title TEXT NOT NULL, -- Korte beschrijving -- ─── Classificatie ─── incident_domain TEXT NOT NULL CHECK(incident_domain IN ( 'arbo', -- Arbeidsongeval / letsel 'process_safety', -- Loss of Primary Containment (LOPC), procesdeviatie 'environmental', -- Spill, emissie, bodemverontreiniging 'security', -- Inbraak, sabotage 'property_damage', -- Materiaal/apparatuurschade 'near_miss', -- Bijna-ongeval (geen effect, wel potentieel) 'unsafe_condition', -- Onveilige situatie (proactief gemeld) 'unsafe_act' -- Onveilige handeling (proactief gemeld) )), incident_type TEXT NOT NULL CHECK(incident_type IN ( 'near_miss', -- Bijna-ongeval 'minor_incident', -- Klein incident (Eerste hulp, kleine spill) 'significant_incident',-- Significant (Medisch behandeld, LOPC < 10kg) 'major_incident', -- Ernstig (Ziekenhuis, LOPC > 10kg, milieu-impact) 'catastrophic' -- Katastrofaal (Dood, massale spill, evacuatie) )) DEFAULT 'near_miss', severity TEXT NOT NULL CHECK(severity IN ( 'negligible', -- Verwaarloosbaar 'minor', -- Gering 'moderate', -- Matig 'major', -- Ernstig 'catastrophic' -- Katastrofaal )) DEFAULT 'minor', -- ─── Tijdstip & Locatie ─── date_occurred TEXT NOT NULL, -- Wanneer gebeurde het? date_detected TEXT, -- Wanneer ontdekt? (kan later zijn) date_reported TEXT DEFAULT CURRENT_TIMESTAMP, -- Wanneer gemeld? location TEXT NOT NULL, -- Precieze locatie area_zone TEXT, -- ATEX-zone indien relevant equipment_tag TEXT, -- Betrokken equipment tag process_unit TEXT, -- Procesunit -- ─── Beschrijving ─── description TEXT NOT NULL, -- Wat is er gebeurd? (gedetailleerd) immediate_impact TEXT, -- Directe gevolgen (letsel, spill hoeveelheid, etc.) involved_persons TEXT, -- JSON array: betrokken personen number_of_casualties INTEGER DEFAULT 0, -- Aantal gewonden number_of_fatalities INTEGER DEFAULT 0, -- Aantal doden first_aid_required INTEGER DEFAULT 0, medical_treatment_required INTEGER DEFAULT 0, hospitalization_required INTEGER DEFAULT 0, lost_time_injury INTEGER DEFAULT 0, -- Verleturen? lost_time_days INTEGER DEFAULT 0, -- Aantal verleturen -- ─── Substance betrokken ─── substance_involved INTEGER DEFAULT 0, -- Was een gevaarlijke stof betrokken? related_substance_id INTEGER, -- FK naar substance_library substance_quantity_released REAL, -- Hoeveelheid vrijgekomen (kg) substance_quantity_unit TEXT DEFAULT 'kg', release_pathway TEXT, -- Lucht, water, bodem, riolering containment_type TEXT, -- Primaire containmentsysteem dat faalde -- ─── Milieu-impact specifiek ─── environmental_impact TEXT CHECK(environmental_impact IN ( 'none', 'minor_local', 'moderate_local', 'significant_regional', 'major_widespread' )) DEFAULT 'none', spill_contained INTEGER DEFAULT 0, -- Spill ingedamd? spill_reached_drain INTEGER DEFAULT 0, -- Spill bereikt riolering/water? spill_reached_soil INTEGER DEFAULT 0, -- Spill bereikt bodem? spill_reached_water INTEGER DEFAULT 0, -- Spill bereikt oppervlaktewater? air_emission_exceeded INTEGER DEFAULT 0, -- Emissie boven grenswaarde? noise_complaint INTEGER DEFAULT 0, -- Geluidsklacht? -- ─── Relaties met andere modules ─── related_risk_scenario_id INTEGER, -- FK:gekoppeld HAZOP/RI&E scenario related_moc_id INTEGER, -- FK: was er een MoC gerelateerd? related_ptw_id INTEGER, -- FK: was er een vergunning actief? -- ─── Meldingsplicht ─── reporting_required INTEGER DEFAULT 0, -- Externe meldingsplicht? reporting_authority TEXT, -- Wie moet gemeld worden? (Arbeidsinspectie, DCMR, OD Rijk) reporting_deadline TEXT, -- Uiterste meldingsdatum reporting_completed INTEGER DEFAULT 0, reporting_reference TEXT, -- Referentienummer autoriteit mir_required INTEGER DEFAULT 0, -- Melding Incident Regeling (RIVM)? mir_number TEXT, -- MIR referentienummer brzo_major_accident INTEGER DEFAULT 0, -- BRZO Major Accident? -- ─── Status ─── status TEXT DEFAULT 'reported' CHECK(status IN ( 'reported', -- Gemeld 'acknowledged', -- Erkend door supervisor 'investigating', -- Onderzoek loopt 'root_cause_analysis', -- RCA in uitvoering 'capa_pending', -- Correctieve acties nog open 'capa_in_progress', -- CAPA uitvoering bezig 'closed', -- Afgerond 'escalated' -- Geëscaleerd naar hoger niveau )), investigation_required INTEGER DEFAULT 0, investigation_method TEXT CHECK(investigation_method IN ( '5_why', 'tripod', 'fishbone', 'bow_tie', 'fault_tree', 'taproot', 'simple_review' )), -- ─── Melder ─── reported_by TEXT NOT NULL, -- Naam melder reporter_role TEXT, -- Functie melder reporter_department TEXT, -- Afdeling anonymous_report INTEGER DEFAULT 0, -- Anoniem gemeld? (VBS-07-004) reporter_contact TEXT, -- Telefoon/email (indien niet anoniem) -- ─── Supervisor ─── acknowledged_by TEXT, acknowledged_at TEXT, -- ─── Investigation Lead ─── investigation_lead TEXT, investigation_team TEXT, -- JSON array: teamleden investigation_start_date TEXT, investigation_due_date TEXT, investigation_completion_date TEXT, -- ─── Immediate Actions ─── immediate_actions TEXT, -- Direct genomen acties scene_secured INTEGER DEFAULT 0, -- Plaats incident veiliggesteld? evidence_preserved INTEGER DEFAULT 0, -- Bewijsmateriaal veiliggesteld? witnesses_interviewed INTEGER DEFAULT 0, -- Getuigen gehoord? -- ─── Lessons Learned ─── lessons_learned TEXT, -- Lessen voor organisatie lessons_distributed INTEGER DEFAULT 0, -- Verspreid via toolbox? (VBS-07-005) procedure_updates TEXT, -- Welke procedures moeten bijgewerkt? training_required INTEGER DEFAULT 0, -- Is bijwerktraining nodig? -- ─── AI Analysis (Kas) ─── ai_analysis_enabled INTEGER DEFAULT 1, ai_analysis_status TEXT DEFAULT 'pending' CHECK(ai_analysis_status IN ( 'pending', 'running', 'completed', 'failed', 'skipped' )), ai_analysis_result TEXT, -- JSON: 5-why suggestions, barrier analysis, HAZOP cross-check ai_analysis_date TEXT, -- ─── Media ─── evidence_files TEXT, -- JSON array: foto/document paden photo_urls TEXT, -- JSON array: foto URLs -- ─── Metadata ─── notes TEXT, created_date TEXT DEFAULT CURRENT_TIMESTAMP, updated_date TEXT DEFAULT CURRENT_TIMESTAMP, -- ─── Foreign Keys ─── FOREIGN KEY (related_substance_id) REFERENCES substance_library(id) ON DELETE SET NULL, FOREIGN KEY (related_risk_scenario_id) REFERENCES risk_scenarios(id) ON DELETE SET NULL, FOREIGN KEY (related_moc_id) REFERENCES moc_requests(id) ON DELETE SET NULL, FOREIGN KEY (related_ptw_id) REFERENCES ptw_permits(id) ON DELETE SET NULL ); CREATE INDEX idx_inc_status ON incidents(status); CREATE INDEX idx_inc_domain ON incidents(incident_domain); CREATE INDEX idx_inc_type ON incidents(incident_type); CREATE INDEX idx_inc_severity ON incidents(severity); CREATE INDEX idx_inc_location ON incidents(location); CREATE INDEX idx_inc_date ON incidents(date_occurred); CREATE INDEX idx_inc_substance ON incidents(related_substance_id); CREATE INDEX idx_inc_reporter ON incidents(reported_by); CREATE INDEX idx_inc_investigation ON incidents(investigation_required); CREATE INDEX idx_inc_ai ON incidents(ai_analysis_status); -- ───────────────────────────────────────────── -- 4B. INCIDENT ONDERZOEK (Root Cause Analysis) -- ───────────────────────────────────────────── -- Ondersteunt: 5-Why, Tripod Beta, Bow-Tie -- VBS-07-002: Tripod / 5-Why onderzoek structuur -- ───────────────────────────────────────────── CREATE TABLE incident_investigations ( id INTEGER PRIMARY KEY AUTOINCREMENT, incident_id INTEGER NOT NULL, -- ─── Methode ─── method TEXT NOT NULL CHECK(method IN ( '5_why', 'tripod_beta', 'bow_tie', 'fishbone', 'fault_tree', 'taproot', 'simple_review' )), investigation_date TEXT NOT NULL, lead_investigator TEXT NOT NULL, team_members TEXT, -- JSON array -- ─── Tijdlijn (Wat gebeurde er?) ─── timeline TEXT, -- Chronologische tijdlijn gebeurtenissen -- ─── Directe Oorzaak ─── direct_cause TEXT NOT NULL, -- Wat was de directe oorzaak? (fysiek/menselijk) direct_cause_category TEXT CHECK(direct_cause_category IN ( 'human_error', -- Menselijke fout 'equipment_failure', -- Apparatuur faalde 'procedure_not_followed', -- Procedure niet gevolgd 'procedure_inadequate', -- Procedure onvoldoende 'design_flaw', -- Ontwerpfout 'external_factor', -- Externe factor (weer, leverancier) 'unknown' -- Onbekend )), -- ─── 5-Why Analyse ─── why_1 TEXT, -- Waarom gebeurde dit? (Directe oorzaak) why_2 TEXT, -- Waarom was dat? why_3 TEXT, -- Waarom was dat? why_4 TEXT, -- Waarom was dat? why_5 TEXT, -- Waarom was dat? (Root cause) root_cause TEXT, -- Conclusie: basisoorzaak -- ─── Tripod Beta ─── tripod_hazard TEXT, -- Het gevaar (Hazard) tripod_barrier_failed TEXT, -- Welke barrière faalde? tripod_barrier_type TEXT CHECK(tripod_barrier_type IN ( 'prevention', 'control', 'mitigation', 'emergency_response' )), tripod_underlying_causes TEXT, -- Onderliggende oorzaken (JSON) tripod_preconditions TEXT, -- Voorwaarden die bijdroegen (JSON) -- ─── Falende Barrières (Bow-Tie) ─── barriers_identified TEXT, -- JSON: welke preventieve barrières waren aanwezig? barriers_failed TEXT, -- JSON: welke barrières faalden? barriers_effective TEXT, -- JSON: welke barrières werkten? barrier_gap_analysis TEXT, -- Analyse van de gaten -- ─── Bijdragende Factoren ─── contributing_factors TEXT, -- JSON array: [{factor: "...", type: "human/technical/organizational"}] organizational_factors TEXT, -- Bijv. tijdsdruk, bezuiniging, training tekort cultural_factors TEXT, -- Bijv. meldcultuur, just culture, normalisatie van afwijking -- ─── HAZOP Cross-Check ─── hazop_scenario_known INTEGER DEFAULT 0, -- Stond dit scenario al in onze HAZOP? hazop_scenario_id INTEGER, -- FK naar risk_scenarios (indien gekend) hazop_deviation_type TEXT, -- Welke HAZOP deviatie? (More flow, Less temp, etc.) risk_assessment_gap TEXT, -- Was dit scenario niet geïdentificeerd? Waarom? -- ─── Conclusie ─── summary TEXT, -- Samenvatting onderzoek systemic_issues TEXT, -- Geconstateerde systeemproblemen recommendations TEXT, -- Aanbevelingen (JSON) -- ─── Status ─── status TEXT DEFAULT 'in_progress' CHECK(status IN ( 'in_progress', 'draft_report', 'review', 'approved', 'rejected', 'archived' )), approved_by TEXT, approval_date TEXT, -- ─── Metadata ─── attachments TEXT, -- JSON: bijlage paden notes TEXT, created_date TEXT DEFAULT CURRENT_TIMESTAMP, updated_date TEXT DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (incident_id) REFERENCES incidents(id) ON DELETE CASCADE, FOREIGN KEY (hazop_scenario_id) REFERENCES risk_scenarios(id) ON DELETE SET NULL ); CREATE INDEX idx_inv_incident ON incident_investigations(incident_id); CREATE INDEX idx_inv_method ON incident_investigations(method); CREATE INDEX idx_inv_status ON incident_investigations(status); -- ───────────────────────────────────────────── -- 4C. CORRECTIEVE & PREVENTIEVE ACTIES (CAPA) -- ───────────────────────────────────────────── -- VBS-07-003: Alle bevindingen leiden tot CAPA -- ───────────────────────────────────────────── CREATE TABLE capa_actions ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- ─── Bron ─── source_type TEXT NOT NULL CHECK(source_type IN ( 'incident', -- Uit incident onderzoek 'investigation', -- Uit RCA/Tripod 'audit', -- Uit audit bevinding 'inspection', -- Uit inspectie 'complaint', -- Uit klacht 'management_review', -- Uit management review 'external' -- Externe bron (toezichthouder) )), source_id INTEGER NOT NULL, -- FK naar bron (incident, investigation, etc.) source_reference TEXT, -- Leesbare referentie (bijv. INC-2026-0410-001) -- ─── Actie ─── action_type TEXT NOT NULL CHECK(action_type IN ( 'corrective', -- Correctief: verwijder oorzaak van bestaand probleem 'preventive', -- Preventief: voorkom dat het (weer) gebeurt 'improvement' -- Verbetering: algemeen procesverbetering )), title TEXT NOT NULL, description TEXT NOT NULL, -- ─── Classificatie ─── priority TEXT DEFAULT 'medium' CHECK(priority IN ('critical','high','medium','low')), category TEXT CHECK(category IN ( 'procedural', -- Procedure wijziging 'technical', -- Technische aanpassing 'training', -- Training/instructie 'organizational', -- Organisatorische verandering 'behavioral', -- Gedragsbeïnvloeding 'design', -- Ontwerp/constructie wijziging 'maintenance', -- Onderhoudsmaatregel 'emergency_preparedness' -- Noodvoorziening verbetering )), -- ─── Toewijzing ─── assigned_to TEXT NOT NULL, -- Verantwoordelijke assigned_department TEXT, assigned_by TEXT, -- Wie heeft opgedragen? due_date TEXT NOT NULL, completion_date TEXT, -- ─── Voortgang ─── status TEXT DEFAULT 'open' CHECK(status IN ( 'open', -- Nieuw, nog niet gestart 'in_progress', -- Bezig 'completed', -- Afgerond 'verified', -- Geverifieerd door 2e persoon 'overdue', -- Overtijd 'cancelled', -- Geannuleerd (met reden) 'escalated' -- Geëscaleerd )), progress INTEGER DEFAULT 0, -- 0-100% verification_method TEXT, -- Hoe wordt effectiviteit geverifieerd? verified_by TEXT, verification_date TEXT, effectiveness_check TEXT, -- Was de actie effectief? (na x weken) -- ─── Relatie ─── related_risk_scenario_id INTEGER, -- Update naar risk_scenarios? related_moc_id INTEGER, -- MoC nodig voor deze actie? related_ptw_id INTEGER, -- PtW benodigd? -- ─── Metadata ─── notes TEXT, attachments TEXT, created_date TEXT DEFAULT CURRENT_TIMESTAMP, updated_date TEXT DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (related_risk_scenario_id) REFERENCES risk_scenarios(id) ON DELETE SET NULL, FOREIGN KEY (related_moc_id) REFERENCES moc_requests(id) ON DELETE SET NULL, FOREIGN KEY (related_ptw_id) REFERENCES ptw_permits(id) ON DELETE SET NULL ); CREATE INDEX idx_capa_source ON capa_actions(source_type, source_id); CREATE INDEX idx_capa_status ON capa_actions(status); CREATE INDEX idx_capa_priority ON capa_actions(priority); CREATE INDEX idx_capa_assigned ON capa_actions(assigned_to); CREATE INDEX idx_capa_due ON capa_actions(due_date); -- ───────────────────────────────────────────── -- 4D. MILIEUMETINGEN & EMISSIEREGISTRATIE -- ───────────────────────────────────────────── -- Omgevingswet / Bal: emissiegrenswaarden -- BRZO: milieu-monitoring rond installatie -- Periodieke logging: afval, water, lucht, energie -- ───────────────────────────────────────────── CREATE TABLE environmental_metrics ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- ─── Meting Type ─── metric_type TEXT NOT NULL CHECK(metric_type IN ( 'air_emission', -- Luchtemissie (VOS, NOx, SOx, stof) 'water_discharge', -- Afvalwaterlozing (COD, BOD, metalen) 'waste_production', -- Afvalproductie (gevaarlijk, niet-gevaarlijk) 'energy_consumption', -- Energieverbruik (elektriciteit, gas) 'noise_level', -- Geluidsniveau (dB(A)) 'soil_quality', -- Bodemkwaliteit (monsters) 'groundwater', -- Grondwaterkwaliteit 'odor', -- Geurmeting 'environmental_incident' -- Milieu-incident meting )), parameter_name TEXT NOT NULL, -- Bijv. "VOS totaal", "DMC concentratie", "COD" parameter_code TEXT, -- Bijv. "VOS-01", "COD-AFW-01" -- ─── Meetwaarde ─── value REAL NOT NULL, unit TEXT NOT NULL, -- Bijv. "mg/m³", "kg/uur", "ton/jaar", "dB(A)" measurement_date TEXT NOT NULL, measurement_period TEXT, -- "2026-Q1", "2026-04", "2026-W15" measurement_method TEXT, -- Bijv. "Continue monitoring", "Pompmonsters", "NEN-EN 14791" measurement_device TEXT, -- Bijv. "MCERTS geijkte monitor" -- ─── Locatie ─── source_location TEXT NOT NULL, -- Emissiepunt (bijv. "Bron 1: Elektrolyse uitlaat") emission_point_id TEXT, -- Officieel emissiepunt nummer (Bal vergunning) process_unit TEXT, -- ─── Grenswaarden ─── permit_limit REAL, -- Vergunningsgrenswaarde permit_limit_unit TEXT, alert_threshold REAL, -- 80% van grenswaarde (waarschuwing) percentage_of_limit REAL, -- value / permit_limit * 100 -- ─── Status ─── compliance_status TEXT DEFAULT 'compliant' CHECK(compliance_status IN ( 'compliant', -- Binnen grenswaarde 'warning', -- > 80% van grenswaarde 'non_compliant', -- Boven grenswaarde 'exceedance', -- Significante overschrijding 'not_measured' -- Geen meting beschikbaar )), -- ─── Stof koppeling ─── related_substance_id INTEGER, -- FK naar substance_library (bijv. DMC voor VOS) -- ─── Relatie ─── related_incident_id INTEGER, -- FK naar incidents (indien milieu-incident) -- ─── Metadata ─── measured_by TEXT, laboratory TEXT, -- Extern lab (indien monstername) lab_report_number TEXT, notes TEXT, created_date TEXT DEFAULT CURRENT_TIMESTAMP, updated_date TEXT DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (related_substance_id) REFERENCES substance_library(id) ON DELETE SET NULL, FOREIGN KEY (related_incident_id) REFERENCES incidents(id) ON DELETE SET NULL ); CREATE INDEX idx_env_type ON environmental_metrics(metric_type); CREATE INDEX idx_env_parameter ON environmental_metrics(parameter_name); CREATE INDEX idx_env_date ON environmental_metrics(measurement_date); CREATE INDEX idx_env_compliance ON environmental_metrics(compliance_status); CREATE INDEX idx_env_location ON environmental_metrics(source_location); CREATE INDEX idx_env_substance ON environmental_metrics(related_substance_id); -- ───────────────────────────────────────────── -- 4E. AFVALSTROMEN REGISTRATIE -- ───────────────────────────────────────────── -- LMA-plicht, Europese afvalcode (EURAL) -- ───────────────────────────────────────────── CREATE TABLE waste_streams ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- ─── Classificatie ─── waste_code TEXT NOT NULL, -- EURAL code (bijv. "06 01 01*" = gevaarlijk afval) waste_name TEXT NOT NULL, -- Beschrijving waste_category TEXT NOT NULL CHECK(waste_category IN ( 'hazardous', -- Gevaarlijk afval (*) 'non_hazardous', -- Niet-gevaarlijk 'inert' -- Inert (beton, steen) )), physical_state TEXT CHECK(physical_state IN ( 'solid', 'liquid', 'sludge', 'gas', 'mixed' )), -- ─── Hoeveelheid ─── quantity REAL NOT NULL, unit TEXT DEFAULT 'ton', period TEXT NOT NULL, -- "2026-Q1", "2026-04" -- ─── Herkomst ─── source_process TEXT, -- Bijv. "Elektrolyse", "Onderhoud" source_location TEXT, process_unit TEXT, -- ─── Afvoer ─── disposal_method TEXT CHECK(disposal_method IN ( 'recycling', 'incineration', 'incineration_energy', 'landfill', 'chemical_treatment', 'biological_treatment', 'physical_treatment', 'reuse', 'storage' )), disposal_contractor TEXT, -- Naam afvoerder disposal_permit_number TEXT, -- Vervoersdocument/Afvalstroomnummer transport_date TEXT, -- ─── Stof koppeling ─── related_substance_id INTEGER, -- ─── Metadata ─── notes TEXT, created_date TEXT DEFAULT CURRENT_TIMESTAMP, updated_date TEXT DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (related_substance_id) REFERENCES substance_library(id) ON DELETE SET NULL ); CREATE INDEX idx_waste_category ON waste_streams(waste_category); CREATE INDEX idx_waste_period ON waste_streams(period); CREATE INDEX idx_waste_code ON waste_streams(waste_code); CREATE INDEX idx_waste_disposal ON waste_streams(disposal_method); -- ───────────────────────────────────────────── -- 4F. INCIDENT GETUIGENVERKLARINGEN -- ───────────────────────────────────────────── CREATE TABLE incident_witnesses ( id INTEGER PRIMARY KEY AUTOINCREMENT, incident_id INTEGER NOT NULL, witness_name TEXT NOT NULL, witness_role TEXT, witness_department TEXT, statement TEXT NOT NULL, -- Verklaring van getuige interview_date TEXT, interviewed_by TEXT, attachments TEXT, created_date TEXT DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (incident_id) REFERENCES incidents(id) ON DELETE CASCADE ); CREATE INDEX idx_witness_incident ON incident_witnesses(incident_id); -- ============================================================ -- EINDE MODULE 4 MIGRATIE -- ============================================================