Vertaalt de FCO-IM-feitenrondes en logische modellen naar 37 nieuwe PostgreSQL-tabellen, verdeeld over vier migraties: - create_reference_data: één generieke value_list_item-tabel (spelregel 3.1 #1) i.p.v. ~30 losse waardelijst-tabellen, met alle startwaarden uit model-aanmelding.md/model-instroom.md/model-intake-behandeladvies.md. - create_person_client_domain: person, address, contact_detail, client, client_relation, referrer, practice_organization, client_general_practitioner, insurance, consent, client_portal_account (model-aanmelding.md §2.1-2.9, 2.14, 2.16). BSN als bsn_hash (SHA-256), conform de platform-privacyregel — geen raw BSN, geen reversibele encryptie. - create_referral_domain: 20 entiteiten uit model-instroom.md (referral_ request t/m episode_team_involvement), inclusief de vervangt-constraints als partial unique index (voorkomt vertakking) en de XOR-check op clinical_care_episode tussen acceptatiebesluit en Wvggz-mandaat. - create_intake_treatment_advice_domain: 5 entiteiten uit model-intake-behandeladvies.md. Scope: dit zijn nieuwe, additieve tabellen naast de bestaande prototype- tabellen (patients, screenings, intakes, patients.is_john_doe, intakes.kindcheck_data) — die tabellen zijn bewust niet aangeraakt. Wiring van de live app op dit schema, en migratie van prototype-data, is een aparte, nog te nemen beslissing. Migraties zijn nog niet toegepast op een database. decision_authority_id (care_acceptance_decision) is tijdelijk nullable zonder FK — het doeltabel volgt uit de bevoegdheidsronde (B16). Perifere waardelijst-kolommen zijn TEXT met een verwijzing naar de bedoelde lijst in een comment, geen harde FK naar value_list_item — applicatievalidatie (Zod) dekt die laag; business-kritieke uitkomsten (decision_outcome, treatment_advice_outcome, mandate_type) hebben wel een CHECK-constraint.
568 lines
32 KiB
SQL
568 lines
32 KiB
SQL
-- ============================================================================
|
|
-- REFERRAL / INSTROOM DOMAIN
|
|
-- ============================================================================
|
|
-- Created: 2026-07-20
|
|
-- Source: docs/datamodel/deelmodellen/model-instroom.md (20 entiteiten),
|
|
-- docs/datamodel/feitenmodellen/feitenmodel-instroom.md, besluiten B21-B30.
|
|
--
|
|
-- Design principles carried over from the model documents:
|
|
-- - referral_case has NO status column — the current state is derived from
|
|
-- the event timeline (signal_case_assignment/screening_activity/
|
|
-- case_information_request/care_acceptance_decision/case_withdrawal/
|
|
-- case_consolidation). See model-instroom.md §5. Application code (or a
|
|
-- read-model view, per the UX review) computes "actuele stand", not this
|
|
-- schema.
|
|
-- - "vervangt"-relations (care_acceptance_decision, professional_referral,
|
|
-- municipal_care_assignment) are enforced unique-if-set (partial unique
|
|
-- index) so the chain can never fork.
|
|
-- - `medewerker`/beslisser references point at the existing `practitioners`
|
|
-- table (already used by the prototype screening/intake schema).
|
|
-- - `decision_authority_id` on care_acceptance_decision is left nullable
|
|
-- for now: the target table for decision authority does not exist yet
|
|
-- (bevoegdheidsronde, B16/B33). The model calls it "verplicht"; enforcing
|
|
-- NOT NULL today would make every insert impossible. Tighten once that
|
|
-- ronde delivers a real authority table.
|
|
-- ============================================================================
|
|
|
|
-- ============================================================================
|
|
-- referral_request
|
|
-- ============================================================================
|
|
CREATE TABLE referral_request (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
person_id UUID REFERENCES person(id) ON DELETE RESTRICT,
|
|
person_identified_at TIMESTAMPTZ,
|
|
person_identified_by UUID REFERENCES practitioners(id),
|
|
initiated_at TIMESTAMPTZ NOT NULL,
|
|
initiator_type TEXT NOT NULL, -- waardelijst initiator_type
|
|
referrer_id UUID REFERENCES referrer(id),
|
|
requested_scope TEXT NOT NULL,
|
|
presenting_need_text TEXT NOT NULL,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT referral_request_person_identification CHECK (
|
|
(person_id IS NULL AND person_identified_at IS NULL AND person_identified_by IS NULL)
|
|
OR (person_id IS NOT NULL AND person_identified_at IS NOT NULL AND person_identified_by IS NOT NULL)
|
|
)
|
|
);
|
|
|
|
COMMENT ON TABLE referral_request IS 'model-instroom.md §2.1. person_id optioneel: crisisaanmelding met onbekende identiteit (B26) — geen placeholder-persoon, de koppeling is een eigen feit.';
|
|
|
|
ALTER TABLE referral_request ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON referral_request FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_referral_request_updated_at BEFORE UPDATE ON referral_request FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- referral_submission
|
|
-- ============================================================================
|
|
CREATE TABLE referral_submission (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
received_at TIMESTAMPTZ NOT NULL,
|
|
channel TEXT NOT NULL, -- waardelijst submission_channel
|
|
source_reference TEXT, -- vrije tekst of naam verwijzer; "onbekend" toegestaan
|
|
recorded_by UUID REFERENCES practitioners(id),
|
|
raw_note TEXT,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
COMMENT ON TABLE referral_submission IS 'model-instroom.md §2.2. Nooit overschreven door een latere aanvulling — een aanvulling is een nieuwe submission.';
|
|
|
|
ALTER TABLE referral_submission ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON referral_submission FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_referral_submission_updated_at BEFORE UPDATE ON referral_submission FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- submission_document
|
|
-- ============================================================================
|
|
CREATE TABLE submission_document (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
submission_id UUID NOT NULL REFERENCES referral_submission(id) ON DELETE CASCADE,
|
|
document_type TEXT NOT NULL, -- waardelijst document_type
|
|
document_reference UUID NOT NULL, -- documentopslag
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX idx_submission_document_submission ON submission_document(submission_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE submission_document IS 'model-instroom.md §2.3.';
|
|
|
|
ALTER TABLE submission_document ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON submission_document FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_submission_document_updated_at BEFORE UPDATE ON submission_document FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- submission_request_link
|
|
-- ============================================================================
|
|
CREATE TABLE submission_request_link (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
submission_id UUID NOT NULL REFERENCES referral_submission(id) ON DELETE CASCADE,
|
|
referral_request_id UUID NOT NULL REFERENCES referral_request(id) ON DELETE CASCADE,
|
|
established_at TIMESTAMPTZ NOT NULL,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
UNIQUE (submission_id, referral_request_id)
|
|
);
|
|
|
|
CREATE INDEX idx_submission_request_link_request ON submission_request_link(referral_request_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE submission_request_link IS 'model-instroom.md §2.4. "representeert" vs "vult_aan" is niet opgeslagen — af te leiden als vroegste established_at per referral_request_id.';
|
|
|
|
ALTER TABLE submission_request_link ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON submission_request_link FOR ALL USING (auth.role() = 'authenticated');
|
|
|
|
-- ============================================================================
|
|
-- submission_duplicate_assessment
|
|
-- ============================================================================
|
|
CREATE TABLE submission_duplicate_assessment (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
submission_id UUID NOT NULL REFERENCES referral_submission(id) ON DELETE CASCADE,
|
|
duplicate_of_submission_id UUID NOT NULL REFERENCES referral_submission(id) ON DELETE CASCADE,
|
|
assessed_by UUID NOT NULL REFERENCES practitioners(id),
|
|
assessed_at TIMESTAMPTZ NOT NULL,
|
|
reason TEXT NOT NULL,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT submission_duplicate_not_self CHECK (submission_id <> duplicate_of_submission_id)
|
|
);
|
|
|
|
COMMENT ON TABLE submission_duplicate_assessment IS 'model-instroom.md §2.5. Niet-destructief: beide submissions blijven bestaan.';
|
|
|
|
ALTER TABLE submission_duplicate_assessment ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON submission_duplicate_assessment FOR ALL USING (auth.role() = 'authenticated');
|
|
|
|
-- ============================================================================
|
|
-- referral_case
|
|
-- ============================================================================
|
|
CREATE TABLE referral_case (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
person_id UUID REFERENCES person(id) ON DELETE RESTRICT,
|
|
person_identified_at TIMESTAMPTZ,
|
|
person_identified_by UUID REFERENCES practitioners(id),
|
|
opened_at TIMESTAMPTZ NOT NULL,
|
|
presenting_need_summary TEXT NOT NULL,
|
|
legal_framework TEXT NOT NULL, -- waardelijst wettelijk_kader
|
|
zpm_referral_type TEXT, -- waardelijst zpm_verwijstype
|
|
gp_informed_at DATE,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT referral_case_person_identification CHECK (
|
|
(person_id IS NULL AND person_identified_at IS NULL AND person_identified_by IS NULL)
|
|
OR (person_id IS NOT NULL AND person_identified_at IS NOT NULL AND person_identified_by IS NOT NULL)
|
|
)
|
|
);
|
|
|
|
COMMENT ON TABLE referral_case IS 'model-instroom.md §2.6. Geen statusveld — zie §5 aldaar en de opmerking bovenaan dit bestand. legal_framework/zpm_referral_type/gp_informed_at hersteld van het oudere AANMELDING (B21-B27).';
|
|
|
|
ALTER TABLE referral_case ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON referral_case FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_referral_case_updated_at BEFORE UPDATE ON referral_case FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- Now that referral_case exists: wire the consent scope FK from the person/client migration
|
|
ALTER TABLE consent
|
|
ADD CONSTRAINT consent_scope_referral_case_fk FOREIGN KEY (scope_referral_case_id) REFERENCES referral_case(id) ON DELETE SET NULL;
|
|
|
|
-- ============================================================================
|
|
-- submission_case_assignment
|
|
-- ============================================================================
|
|
CREATE TABLE submission_case_assignment (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
submission_id UUID NOT NULL REFERENCES referral_submission(id) ON DELETE CASCADE,
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE CASCADE,
|
|
assigned_at TIMESTAMPTZ NOT NULL,
|
|
assigned_by UUID NOT NULL REFERENCES practitioners(id),
|
|
reason TEXT,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
UNIQUE (submission_id, referral_case_id)
|
|
);
|
|
|
|
CREATE INDEX idx_submission_case_assignment_case ON submission_case_assignment(referral_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE submission_case_assignment IS 'model-instroom.md §2.7 (hernoemd van signal_case_assignment). Toewijzing is een gebeurtenis, geen overschrijfbaar veld.';
|
|
|
|
ALTER TABLE submission_case_assignment ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON submission_case_assignment FOR ALL USING (auth.role() = 'authenticated');
|
|
|
|
-- ============================================================================
|
|
-- request_case_link
|
|
-- ============================================================================
|
|
CREATE TABLE request_case_link (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_request_id UUID NOT NULL REFERENCES referral_request(id) ON DELETE CASCADE,
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE CASCADE,
|
|
since_date DATE NOT NULL,
|
|
reason TEXT,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
UNIQUE (referral_request_id, referral_case_id)
|
|
);
|
|
|
|
COMMENT ON TABLE request_case_link IS 'model-instroom.md §2.8. reason verplicht (applicatieniveau) zodra een request aan >1 case gekoppeld is.';
|
|
|
|
ALTER TABLE request_case_link ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON request_case_link FOR ALL USING (auth.role() = 'authenticated');
|
|
|
|
-- ============================================================================
|
|
-- case_consolidation
|
|
-- ============================================================================
|
|
CREATE TABLE case_consolidation (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
primary_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE RESTRICT,
|
|
related_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE RESTRICT,
|
|
overlap_assessed_at TIMESTAMPTZ,
|
|
designated_at TIMESTAMPTZ NOT NULL,
|
|
designated_by UUID NOT NULL REFERENCES practitioners(id),
|
|
reason TEXT NOT NULL,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT case_consolidation_no_self CHECK (primary_case_id <> related_case_id)
|
|
);
|
|
|
|
-- een case kan hoogstens één keer de niet-leidende rol vervullen
|
|
CREATE UNIQUE INDEX idx_case_consolidation_related_unique ON case_consolidation(related_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE case_consolidation IS 'model-instroom.md §2.9 (hernoemd van access_case_consolidation). Geen speciale decision_authority vereist (administratieve correctie). Transitieve cykels niet uitgesloten op schemaniveau — applicatieverantwoordelijkheid.';
|
|
|
|
ALTER TABLE case_consolidation ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON case_consolidation FOR ALL USING (auth.role() = 'authenticated');
|
|
|
|
-- ============================================================================
|
|
-- screening_activity
|
|
-- ============================================================================
|
|
CREATE TABLE screening_activity (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE CASCADE,
|
|
performed_at TIMESTAMPTZ NOT NULL,
|
|
activity_type TEXT NOT NULL, -- waardelijst screening_activity_type
|
|
performed_by UUID NOT NULL REFERENCES practitioners(id),
|
|
notes TEXT,
|
|
funded BOOLEAN NOT NULL DEFAULT false,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX idx_screening_activity_case ON screening_activity(referral_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE screening_activity IS 'model-instroom.md §2.10. Directe koppeling aan referral_case — de aparte "screening"-groeperingsentiteit is vervallen (reviewronde 19 juli).';
|
|
|
|
ALTER TABLE screening_activity ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON screening_activity FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_screening_activity_updated_at BEFORE UPDATE ON screening_activity FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- case_information_request
|
|
-- ============================================================================
|
|
CREATE TABLE case_information_request (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE CASCADE,
|
|
requested_at TIMESTAMPTZ NOT NULL,
|
|
requested_by UUID NOT NULL REFERENCES practitioners(id),
|
|
requested_information TEXT NOT NULL,
|
|
resolved_by_submission_id UUID REFERENCES referral_submission(id),
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_case_information_request_resolved_submission ON case_information_request(resolved_by_submission_id) WHERE resolved_by_submission_id IS NOT NULL AND deleted_at IS NULL;
|
|
CREATE INDEX idx_case_information_request_case ON case_information_request(referral_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE case_information_request IS 'model-instroom.md §2.11. Geen besluituitkomst en geen statusfase (B21/vraag 5) — een gedateerd gebeurtenisfeit; kan zich ook ná een eerder besluit voordoen tijdens heroverweging.';
|
|
|
|
ALTER TABLE case_information_request ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON case_information_request FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_case_information_request_updated_at BEFORE UPDATE ON case_information_request FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- care_acceptance_decision
|
|
-- ============================================================================
|
|
CREATE TABLE care_acceptance_decision (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE RESTRICT,
|
|
decided_at TIMESTAMPTZ NOT NULL,
|
|
decided_by UUID NOT NULL REFERENCES practitioners(id),
|
|
decision_authority_id UUID, -- ref decision_authority — tabel volgt uit bevoegdheidsronde (B16); tijdelijk geen FK/NOT NULL
|
|
content_match BOOLEAN NOT NULL,
|
|
capacity_available BOOLEAN,
|
|
program_context TEXT, -- waardelijst care_program of vrije tekst
|
|
decision_outcome TEXT NOT NULL, -- waardelijst decision_outcome
|
|
follow_up_route TEXT NOT NULL, -- waardelijst follow_up_route
|
|
rationale TEXT,
|
|
replaces_decision_id UUID REFERENCES care_acceptance_decision(id),
|
|
replacement_reason TEXT,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT care_acceptance_decision_outcome_check CHECK (decision_outcome IN ('geaccepteerd', 'afgewezen')),
|
|
CONSTRAINT care_acceptance_decision_rationale_required CHECK (
|
|
decision_outcome <> 'afgewezen' OR (rationale IS NOT NULL AND length(trim(rationale)) > 0)
|
|
),
|
|
CONSTRAINT care_acceptance_decision_replacement_reason_required CHECK (
|
|
replaces_decision_id IS NULL OR (replacement_reason IS NOT NULL AND length(trim(replacement_reason)) > 0)
|
|
),
|
|
CONSTRAINT care_acceptance_decision_no_self_replace CHECK (replaces_decision_id <> id)
|
|
);
|
|
|
|
-- vervangt-keten kan nooit vertakken (B23 / reviewronde 19 juli, kritieke bevinding)
|
|
CREATE UNIQUE INDEX idx_care_acceptance_decision_replaces_unique ON care_acceptance_decision(replaces_decision_id) WHERE replaces_decision_id IS NOT NULL AND deleted_at IS NULL;
|
|
CREATE INDEX idx_care_acceptance_decision_case ON care_acceptance_decision(referral_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE care_acceptance_decision IS 'model-instroom.md §2.12. Geen apart voorafgaand screeningsadvies (B21). Concurrency bij gelijktijdige heroverwegingen (SELECT ... FOR UPDATE op de keten-tail) is applicatieverantwoordelijkheid.';
|
|
|
|
ALTER TABLE care_acceptance_decision ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON care_acceptance_decision FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_care_acceptance_decision_updated_at BEFORE UPDATE ON care_acceptance_decision FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- case_withdrawal
|
|
-- ============================================================================
|
|
CREATE TABLE case_withdrawal (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE CASCADE,
|
|
withdrawn_at TIMESTAMPTZ NOT NULL,
|
|
recorded_by UUID NOT NULL REFERENCES practitioners(id),
|
|
note TEXT,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX idx_case_withdrawal_case ON case_withdrawal(referral_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE case_withdrawal IS 'model-instroom.md §2.13. Geen beslisbevoegdheid vereist; kan op elk moment, ook ná een positief besluit (B24).';
|
|
|
|
ALTER TABLE case_withdrawal ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON case_withdrawal FOR ALL USING (auth.role() = 'authenticated');
|
|
|
|
-- ============================================================================
|
|
-- professional_referral
|
|
-- ============================================================================
|
|
CREATE TABLE professional_referral (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_request_id UUID NOT NULL REFERENCES referral_request(id) ON DELETE RESTRICT,
|
|
referrer_id UUID NOT NULL REFERENCES referrer(id),
|
|
referral_date DATE NOT NULL,
|
|
echelon TEXT, -- waardelijst echelon
|
|
suspected_condition TEXT,
|
|
is_readmission BOOLEAN NOT NULL DEFAULT false,
|
|
replaces_referral_id UUID REFERENCES professional_referral(id),
|
|
replacement_reason TEXT,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT professional_referral_replacement_reason_required CHECK (
|
|
replaces_referral_id IS NULL OR (replacement_reason IS NOT NULL AND length(trim(replacement_reason)) > 0)
|
|
),
|
|
CONSTRAINT professional_referral_no_self_replace CHECK (replaces_referral_id <> id)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_professional_referral_replaces_unique ON professional_referral(replaces_referral_id) WHERE replaces_referral_id IS NOT NULL AND deleted_at IS NULL;
|
|
CREATE INDEX idx_professional_referral_request ON professional_referral(referral_request_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE professional_referral IS 'model-instroom.md §2.14. Correctie/aanvulling = nieuw, vervangend record, geen nieuw request (was open punt 1, opgelost).';
|
|
|
|
ALTER TABLE professional_referral ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON professional_referral FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_professional_referral_updated_at BEFORE UPDATE ON professional_referral FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- municipal_care_assignment
|
|
-- ============================================================================
|
|
CREATE TABLE municipal_care_assignment (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_request_id UUID NOT NULL REFERENCES referral_request(id) ON DELETE RESTRICT,
|
|
legal_framework TEXT NOT NULL, -- waardelijst municipal_legal_framework
|
|
municipality_code TEXT NOT NULL,
|
|
assignment_number TEXT NOT NULL,
|
|
product_category TEXT NOT NULL, -- waardelijst municipal_product_category
|
|
product_code TEXT NOT NULL,
|
|
volume NUMERIC NOT NULL,
|
|
unit TEXT NOT NULL, -- waardelijst municipal_product_unit
|
|
frequency TEXT NOT NULL,
|
|
start_date DATE NOT NULL,
|
|
end_date DATE,
|
|
issued_at TIMESTAMPTZ NOT NULL,
|
|
replaces_assignment_id UUID REFERENCES municipal_care_assignment(id),
|
|
replacement_reason TEXT,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT municipal_care_assignment_replacement_reason_required CHECK (
|
|
replaces_assignment_id IS NULL OR (replacement_reason IS NOT NULL AND length(trim(replacement_reason)) > 0)
|
|
),
|
|
CONSTRAINT municipal_care_assignment_no_self_replace CHECK (replaces_assignment_id <> id)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_municipal_care_assignment_replaces_unique ON municipal_care_assignment(replaces_assignment_id) WHERE replaces_assignment_id IS NOT NULL AND deleted_at IS NULL;
|
|
CREATE UNIQUE INDEX idx_municipal_care_assignment_number ON municipal_care_assignment(municipality_code, assignment_number) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE municipal_care_assignment IS 'model-instroom.md §2.15 (voorstel, juridisch onderzoek 19 juli). Naast, niet in plaats van professional_referral (Jeugdwet kent een eigen professionele verwijsroute).';
|
|
|
|
ALTER TABLE municipal_care_assignment ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON municipal_care_assignment FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_municipal_care_assignment_updated_at BEFORE UPDATE ON municipal_care_assignment FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- legal_mandate
|
|
-- ============================================================================
|
|
CREATE TABLE legal_mandate (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE RESTRICT,
|
|
mandate_type TEXT NOT NULL, -- waardelijst mandate_type
|
|
decision_reference TEXT NOT NULL,
|
|
decided_by_role TEXT NOT NULL, -- waardelijst mandate_decider_role
|
|
decided_at TIMESTAMPTZ NOT NULL,
|
|
medical_statement_reference UUID, -- documentopslag
|
|
effectuated_at TIMESTAMPTZ NOT NULL,
|
|
valid_from TIMESTAMPTZ NOT NULL,
|
|
valid_until TIMESTAMPTZ,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT legal_mandate_type_check CHECK (mandate_type IN ('crisismaatregel', 'zorgmachtiging')),
|
|
CONSTRAINT legal_mandate_medical_statement_required CHECK (
|
|
mandate_type <> 'crisismaatregel' OR medical_statement_reference IS NOT NULL
|
|
)
|
|
);
|
|
|
|
CREATE INDEX idx_legal_mandate_case ON legal_mandate(referral_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE legal_mandate IS 'model-instroom.md §2.16 (voorstel, juridisch onderzoek 19 juli). Geen vervangt-relatie: een crisismaatregel die overgaat in een zorgmachtiging is een nieuw mandaat.';
|
|
|
|
ALTER TABLE legal_mandate ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON legal_mandate FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_legal_mandate_updated_at BEFORE UPDATE ON legal_mandate FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- crisis_encounter_note
|
|
-- ============================================================================
|
|
CREATE TABLE crisis_encounter_note (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE CASCADE,
|
|
occurred_at TIMESTAMPTZ NOT NULL,
|
|
recorded_by UUID NOT NULL REFERENCES practitioners(id),
|
|
fact_type TEXT NOT NULL, -- waardelijst crisis_fact_type
|
|
description TEXT NOT NULL,
|
|
structured_value JSONB,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX idx_crisis_encounter_note_case ON crisis_encounter_note(referral_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE crisis_encounter_note IS 'model-instroom.md §2.17 (voorstel). Werkt al zonder geïdentificeerde persoon. 14-dagen-identificatienudge hangt aan referral_request.person_identified_at IS NULL, geen constraint hier.';
|
|
|
|
ALTER TABLE crisis_encounter_note ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON crisis_encounter_note FOR ALL USING (auth.role() = 'authenticated');
|
|
|
|
-- ============================================================================
|
|
-- clinical_care_episode
|
|
-- ============================================================================
|
|
CREATE TABLE clinical_care_episode (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
originating_decision_id UUID REFERENCES care_acceptance_decision(id) ON DELETE RESTRICT,
|
|
originating_mandate_id UUID REFERENCES legal_mandate(id) ON DELETE RESTRICT,
|
|
started_at TIMESTAMPTZ NOT NULL,
|
|
ended_at TIMESTAMPTZ,
|
|
end_reason TEXT, -- waardelijst episode_end_reason
|
|
possible_continuation_of_episode_id UUID REFERENCES clinical_care_episode(id),
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ,
|
|
|
|
CONSTRAINT clinical_care_episode_origin_xor CHECK (
|
|
(originating_decision_id IS NOT NULL AND originating_mandate_id IS NULL)
|
|
OR (originating_decision_id IS NULL AND originating_mandate_id IS NOT NULL)
|
|
),
|
|
CONSTRAINT clinical_care_episode_end_reason_required CHECK (
|
|
ended_at IS NULL OR end_reason IS NOT NULL
|
|
),
|
|
CONSTRAINT clinical_care_episode_no_self_continuation CHECK (possible_continuation_of_episode_id <> id)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_clinical_care_episode_decision ON clinical_care_episode(originating_decision_id) WHERE originating_decision_id IS NOT NULL AND deleted_at IS NULL;
|
|
CREATE UNIQUE INDEX idx_clinical_care_episode_mandate ON clinical_care_episode(originating_mandate_id) WHERE originating_mandate_id IS NOT NULL AND deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE clinical_care_episode IS 'model-instroom.md §2.18 (alleen ontstaan/einde — volledig episodemodel is een ander deelgebied). XOR: ontstaat óf uit een acceptatiebesluit óf uit een mandaat. possible_continuation_of_episode_id is een zorginhoudelijke aanwijzing, GEEN NZa-trajectnummertoets.';
|
|
|
|
ALTER TABLE clinical_care_episode ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON clinical_care_episode FOR ALL USING (auth.role() = 'authenticated');
|
|
CREATE TRIGGER update_clinical_care_episode_updated_at BEFORE UPDATE ON clinical_care_episode FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============================================================================
|
|
-- case_urgency_assessment
|
|
-- ============================================================================
|
|
CREATE TABLE case_urgency_assessment (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
referral_case_id UUID NOT NULL REFERENCES referral_case(id) ON DELETE CASCADE,
|
|
assessed_at TIMESTAMPTZ NOT NULL,
|
|
assessed_by UUID NOT NULL REFERENCES practitioners(id),
|
|
assessed_in_role TEXT NOT NULL, -- waardelijst urgency_assessor_role
|
|
urgency_level TEXT NOT NULL, -- waardelijst urgency_level
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX idx_case_urgency_assessment_case ON case_urgency_assessment(referral_case_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE case_urgency_assessment IS 'model-instroom.md §2.19. Herhaalbaar, laatste assessed_at geldt; geen vervangt-relatie (lagere inzet dan een acceptatiebesluit).';
|
|
|
|
ALTER TABLE case_urgency_assessment ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON case_urgency_assessment FOR ALL USING (auth.role() = 'authenticated');
|
|
|
|
-- ============================================================================
|
|
-- episode_team_involvement (minimale, voorlopige hook — zie besluitenlog §10 punt 3)
|
|
-- ============================================================================
|
|
CREATE TABLE episode_team_involvement (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
clinical_care_episode_id UUID NOT NULL REFERENCES clinical_care_episode(id) ON DELETE CASCADE,
|
|
team_reference TEXT NOT NULL, -- vrije tekst; geen Team-entiteit vóór de zorgteam-ronde
|
|
involved_since TIMESTAMPTZ NOT NULL,
|
|
recorded_by UUID NOT NULL REFERENCES practitioners(id),
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX idx_episode_team_involvement_episode ON episode_team_involvement(clinical_care_episode_id) WHERE deleted_at IS NULL;
|
|
|
|
COMMENT ON TABLE episode_team_involvement IS 'model-instroom.md §2.20. Bewust minimaal — geen rollen, geen bevoegdheid, geen individueel lidmaatschap. Wordt vervangen/geabsorbeerd door het volledige zorgteam-model (besluitenlog §10 punt 3).';
|
|
|
|
ALTER TABLE episode_team_involvement ENABLE ROW LEVEL SECURITY;
|
|
CREATE POLICY "Enable all for authenticated users" ON episode_team_involvement FOR ALL USING (auth.role() = 'authenticated');
|