8 SQL migration files covering all 10 tables, RLS policies with SECURITY DEFINER helpers, and seed data for SCW1 site + 3 zones. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWxyMibCuGGtSQSqfajDQ7
70 lines
2.2 KiB
PL/PgSQL
70 lines
2.2 KiB
PL/PgSQL
-- supabase/migrations/20260709000003_incidents.sql
|
|
CREATE TYPE incident_type AS ENUM (
|
|
'injury', 'near_miss', 'hazard', 'asset_damage', 'environmental', 'security', 'fire'
|
|
);
|
|
|
|
CREATE TYPE incident_status AS ENUM (
|
|
'reported', 'triaged', 'investigating', 'capa_pending', 'verification', 'closed'
|
|
);
|
|
|
|
CREATE TYPE medical_status AS ENUM (
|
|
'none', 'first_aid', 'medical_treatment', 'lti'
|
|
);
|
|
|
|
CREATE TABLE incidents (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
reference_no TEXT UNIQUE,
|
|
incident_type incident_type NOT NULL,
|
|
site_id UUID NOT NULL REFERENCES sites(id),
|
|
zone_id UUID REFERENCES zones(id),
|
|
reported_by UUID NOT NULL REFERENCES users(id),
|
|
reported_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
description TEXT NOT NULL,
|
|
severity SMALLINT CHECK (severity BETWEEN 1 AND 5),
|
|
status incident_status NOT NULL DEFAULT 'reported',
|
|
injury_involved BOOLEAN NOT NULL DEFAULT false,
|
|
asset_involved BOOLEAN NOT NULL DEFAULT false,
|
|
medical_status medical_status,
|
|
lost_days INT CHECK (lost_days >= 0),
|
|
closed_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Auto-generate reference_no: SITECODE-YYYYMM-#### (e.g. SCW1-202607-0001)
|
|
CREATE OR REPLACE FUNCTION public.generate_incident_reference()
|
|
RETURNS TRIGGER
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
DECLARE
|
|
v_site_code TEXT;
|
|
v_month TEXT;
|
|
v_seq INT;
|
|
BEGIN
|
|
SELECT UPPER(REGEXP_REPLACE(SUBSTRING(name, 1, 6), '[^A-Za-z0-9]', '', 'g'))
|
|
INTO v_site_code
|
|
FROM sites
|
|
WHERE id = NEW.site_id;
|
|
|
|
v_month := TO_CHAR(NEW.reported_at, 'YYYYMM');
|
|
|
|
SELECT COUNT(*) + 1
|
|
INTO v_seq
|
|
FROM incidents
|
|
WHERE site_id = NEW.site_id
|
|
AND TO_CHAR(reported_at, 'YYYYMM') = v_month;
|
|
|
|
NEW.reference_no := v_site_code || '-' || v_month || '-' || LPAD(v_seq::TEXT, 4, '0');
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
CREATE TRIGGER set_incident_reference
|
|
BEFORE INSERT ON incidents
|
|
FOR EACH ROW
|
|
WHEN (NEW.reference_no IS NULL)
|
|
EXECUTE FUNCTION public.generate_incident_reference();
|
|
|
|
CREATE INDEX incidents_site_id_idx ON incidents(site_id);
|
|
CREATE INDEX incidents_reported_by_idx ON incidents(reported_by);
|
|
CREATE INDEX incidents_status_idx ON incidents(status);
|