-- ============================================================================ -- INTAKE / TREATMENT ADVICE DOMAIN -- ============================================================================ -- Created: 2026-07-20 -- Source: docs/datamodel/deelmodellen/model-intake-behandeladvies.md (5 -- entiteiten), docs/datamodel/feitenmodellen/feitenmodel-intake-behandeladvies.md, -- besluiten B31-B34. -- -- clinical_intake_assessment hangs off clinical_care_episode (not off -- referral_case) — it starts at some point after the acceptance decision, -- possibly after a wait-list period (status = 'gepland' covers that). -- ============================================================================ -- ============================================================================ -- clinical_intake_assessment -- ============================================================================ CREATE TABLE clinical_intake_assessment ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), clinical_care_episode_id UUID NOT NULL REFERENCES clinical_care_episode(id) ON DELETE RESTRICT, initiation_reason TEXT NOT NULL, -- waardelijst intake_initiation_reason department TEXT NOT NULL, -- waardelijst department status TEXT NOT NULL DEFAULT 'gepland', -- waardelijst intake_status planned_at TIMESTAMPTZ NOT NULL, started_at TIMESTAMPTZ, ended_at TIMESTAMPTZ, abort_reason TEXT, -- waardelijst intake_abort_reason created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ, CONSTRAINT clinical_intake_assessment_status_check CHECK (status IN ('gepland', 'bezig', 'afgerond', 'afgebroken')), CONSTRAINT clinical_intake_assessment_started_required CHECK ( status NOT IN ('bezig', 'afgerond', 'afgebroken') OR started_at IS NOT NULL ), CONSTRAINT clinical_intake_assessment_ended_required CHECK ( status NOT IN ('afgerond', 'afgebroken') OR ended_at IS NOT NULL ), CONSTRAINT clinical_intake_assessment_abort_reason_required CHECK ( status <> 'afgebroken' OR abort_reason IS NOT NULL ) ); CREATE INDEX idx_clinical_intake_assessment_episode ON clinical_intake_assessment(clinical_care_episode_id) WHERE deleted_at IS NULL; CREATE INDEX idx_clinical_intake_assessment_status ON clinical_intake_assessment(status) WHERE deleted_at IS NULL; COMMENT ON TABLE clinical_intake_assessment IS 'model-intake-behandeladvies.md §1.1. Start ná het acceptatiebesluit (B31), niet gelijktijdig met episode-ontstaan — planned_at dekt een eventuele intakewachtlijst-periode. "Maximaal één lopende intake per episode" is een aan/uit-zetbare bedrijfsregel, geen schemabeperking.'; ALTER TABLE clinical_intake_assessment ENABLE ROW LEVEL SECURITY; CREATE POLICY "Enable all for authenticated users" ON clinical_intake_assessment FOR ALL USING (auth.role() = 'authenticated'); CREATE TRIGGER update_clinical_intake_assessment_updated_at BEFORE UPDATE ON clinical_intake_assessment FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================================ -- intake_contact -- ============================================================================ CREATE TABLE intake_contact ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), clinical_intake_assessment_id UUID NOT NULL REFERENCES clinical_intake_assessment(id) ON DELETE CASCADE, occurred_at TIMESTAMPTZ NOT NULL, contact_type TEXT NOT NULL, -- waardelijst intake_contact_type performed_by UUID NOT NULL REFERENCES practitioners(id), notes TEXT, planned_duration_minutes INTEGER, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ, CONSTRAINT intake_contact_duration_non_negative CHECK (planned_duration_minutes IS NULL OR planned_duration_minutes >= 0) ); CREATE INDEX idx_intake_contact_assessment ON intake_contact(clinical_intake_assessment_id) WHERE deleted_at IS NULL; COMMENT ON TABLE intake_contact IS 'model-intake-behandeladvies.md §1.2. Exclusief aan één clinical_intake_assessment; generalisatie naar een bredere consult-/afspraakstructuur is de agenda-ronde.'; ALTER TABLE intake_contact ENABLE ROW LEVEL SECURITY; CREATE POLICY "Enable all for authenticated users" ON intake_contact FOR ALL USING (auth.role() = 'authenticated'); CREATE TRIGGER update_intake_contact_updated_at BEFORE UPDATE ON intake_contact FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================================ -- child_safety_check -- ============================================================================ CREATE TABLE child_safety_check ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), clinical_intake_assessment_id UUID NOT NULL REFERENCES clinical_intake_assessment(id) ON DELETE CASCADE, performed_at TIMESTAMPTZ NOT NULL, performed_by UUID NOT NULL REFERENCES practitioners(id), responsible_for_minors BOOLEAN NOT NULL, minor_count INTEGER, minor_ages TEXT, -- vrije tekst, bewust geen kindrecords (dataminimalisatie) safety_concern BOOLEAN NOT NULL, safety_concern_notes TEXT, action_taken BOOLEAN NOT NULL, action_taken_notes TEXT, pregnancy BOOLEAN NOT NULL, -- vierde vlag, te verifiëren tegen KNMG-meldcode (B34) notes TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ, CONSTRAINT child_safety_check_safety_notes_required CHECK (NOT safety_concern OR safety_concern_notes IS NOT NULL), CONSTRAINT child_safety_check_action_notes_required CHECK (NOT action_taken OR action_taken_notes IS NOT NULL) ); -- maximaal één per intake CREATE UNIQUE INDEX idx_child_safety_check_assessment ON child_safety_check(clinical_intake_assessment_id) WHERE deleted_at IS NULL; COMMENT ON TABLE child_safety_check IS 'model-intake-behandeladvies.md §1.3 (B34). Wet verplichte meldcode / KNMG-kindcheck.'; ALTER TABLE child_safety_check ENABLE ROW LEVEL SECURITY; CREATE POLICY "Enable all for authenticated users" ON child_safety_check FOR ALL USING (auth.role() = 'authenticated'); CREATE TRIGGER update_child_safety_check_updated_at BEFORE UPDATE ON child_safety_check FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================================ -- intake_mdt_review (minimale, voorlopige hook — zie §6 aldaar) -- ============================================================================ CREATE TABLE intake_mdt_review ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), occurred_at TIMESTAMPTZ NOT NULL, participants TEXT NOT NULL, -- vrije tekst; structurering wacht op de MDO-ronde (B14-B15) notes TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ ); COMMENT ON TABLE intake_mdt_review IS 'model-intake-behandeladvies.md §1.4. Geen eigen FK naar clinical_intake_assessment — gekoppeld via treatment_advice.mdt_review_id, telt pas zodra hij aan een vastgesteld advies hangt. LKS 4.0: dwingend voor settings 3-8, optioneel setting 2, n.v.t. vrijgevestigden.'; ALTER TABLE intake_mdt_review ENABLE ROW LEVEL SECURITY; CREATE POLICY "Enable all for authenticated users" ON intake_mdt_review FOR ALL USING (auth.role() = 'authenticated'); -- ============================================================================ -- treatment_advice -- ============================================================================ CREATE TABLE treatment_advice ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), clinical_intake_assessment_id UUID NOT NULL REFERENCES clinical_intake_assessment(id) ON DELETE RESTRICT, decided_at TIMESTAMPTZ NOT NULL, decided_by UUID NOT NULL REFERENCES practitioners(id), -- indicerende regiebehandelaar outcome TEXT NOT NULL, -- waardelijst treatment_advice_outcome recommended_care_program TEXT, -- waardelijst care_program rationale TEXT, mdt_review_id UUID REFERENCES intake_mdt_review(id), replaces_advice_id UUID REFERENCES treatment_advice(id), replacement_reason TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), deleted_at TIMESTAMPTZ, CONSTRAINT treatment_advice_outcome_check CHECK (outcome IN ('in_zorg', 'terugverwijzing', 'doorverwijzing', 'extra_diagnostiek')), CONSTRAINT treatment_advice_care_program_required CHECK ( outcome <> 'in_zorg' OR recommended_care_program IS NOT NULL ), CONSTRAINT treatment_advice_rationale_required CHECK ( outcome = 'in_zorg' OR (rationale IS NOT NULL AND length(trim(rationale)) > 0) ), CONSTRAINT treatment_advice_replacement_reason_required CHECK ( replaces_advice_id IS NULL OR (replacement_reason IS NOT NULL AND length(trim(replacement_reason)) > 0) ), CONSTRAINT treatment_advice_no_self_replace CHECK (replaces_advice_id <> id) ); -- vervangt-keten kan nooit vertakken, zelfde patroon als care_acceptance_decision CREATE UNIQUE INDEX idx_treatment_advice_replaces_unique ON treatment_advice(replaces_advice_id) WHERE replaces_advice_id IS NOT NULL AND deleted_at IS NULL; CREATE INDEX idx_treatment_advice_assessment ON treatment_advice(clinical_intake_assessment_id) WHERE deleted_at IS NULL; COMMENT ON TABLE treatment_advice IS 'model-intake-behandeladvies.md §1.5 (B32-B33). Geen apart voorafgaand advies — dit object zelf geeft de vervolgrichting. doorverwijzing/terugverwijzing zijn LKS-genormeerd volgtijdelijk (via replaces_advice_id); extra_diagnostiek is praktijkgefundeerd, niet LKS-genormeerd.'; ALTER TABLE treatment_advice ENABLE ROW LEVEL SECURITY; CREATE POLICY "Enable all for authenticated users" ON treatment_advice FOR ALL USING (auth.role() = 'authenticated'); CREATE TRIGGER update_treatment_advice_updated_at BEFORE UPDATE ON treatment_advice FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- Een afgeronde intake vereist minimaal één (niet noodzakelijk het laatst -- vervangen) treatment_advice — afgedwongen op applicatieniveau, niet als -- schema-constraint (zou een circulaire FK-afhankelijkheid vereisen). COMMENT ON COLUMN clinical_intake_assessment.status IS 'gepland/bezig/afgerond/afgebroken. Bij afgerond hoort minimaal één treatment_advice (applicatieniveau, geen FK-constraint i.v.m. circulaire afhankelijkheid).';