Multiple features and improvements: Reports/Rapportage API: - Created REST API endpoints: /api/reports (GET/POST), /api/reports/[id] (GET/PATCH/DELETE) - Added /api/reports/classify endpoint for AI classification - Supabase migrations: reports table + RLS policies - Server utilities: api-client.ts for DRY fetch logic - Type definitions: lib/types/report.ts with Zod schemas - Removed old rapportage-modal component (replaced by split-view) Speech Recorder Refactor: - Moved speech-recorder from intake-specific to shared components/ - Updated treatment-advice-form to use new location - Updated intake actions for speech functionality UI Components (shadcn): - Added dialog, dropdown-menu, toast, toaster components - Added use-toast hook for toast notifications Documentation: - Reorganized docs/release/ → docs/reports/ for better structure - Archived old specs to docs/specs/archive/ - Added screening-system.mdx documentation - Added rapportage-split-view-design.md - Added UI screenshots for troubleshooting Dependencies: - Updated package.json and pnpm-lock.yaml - Regenerated database.types.ts from Supabase 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
110 lines
3.1 KiB
SQL
110 lines
3.1 KiB
SQL
-- Migration: create reports table for universal reporting
|
|
|
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
|
|
|
CREATE TABLE IF NOT EXISTS reports (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
patient_id UUID NOT NULL REFERENCES patients(id) ON DELETE CASCADE,
|
|
created_by UUID REFERENCES practitioners(id),
|
|
type TEXT NOT NULL CHECK (type IN (
|
|
'behandeladvies',
|
|
'vrije_notitie',
|
|
'intake',
|
|
'voortgang',
|
|
'crisis',
|
|
'contact'
|
|
)),
|
|
content TEXT NOT NULL CHECK (char_length(content) >= 20),
|
|
ai_confidence NUMERIC(3,2) CHECK (ai_confidence >= 0 AND ai_confidence <= 1),
|
|
ai_reasoning TEXT,
|
|
structured_data JSONB DEFAULT '{}'::jsonb,
|
|
audio_url TEXT,
|
|
audio_duration_seconds INTEGER,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ,
|
|
updated_by UUID REFERENCES practitioners(id),
|
|
version TEXT,
|
|
parent_report_id UUID REFERENCES reports(id),
|
|
deleted_at TIMESTAMPTZ,
|
|
CONSTRAINT reports_content_length CHECK (char_length(content) <= 5000)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_reports_patient_id ON reports(patient_id)
|
|
WHERE deleted_at IS NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_reports_type ON reports(type)
|
|
WHERE deleted_at IS NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_reports_created_at ON reports(created_at DESC)
|
|
WHERE deleted_at IS NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_reports_created_by ON reports(created_by);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_reports_patient_created ON reports(patient_id, created_at DESC)
|
|
WHERE deleted_at IS NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_reports_content_fts ON reports USING gin(to_tsvector('dutch', content))
|
|
WHERE deleted_at IS NULL;
|
|
|
|
ALTER TABLE reports ENABLE ROW LEVEL SECURITY;
|
|
|
|
CREATE POLICY reports_select_policy ON reports
|
|
FOR SELECT
|
|
USING (
|
|
EXISTS (
|
|
SELECT 1
|
|
FROM practitioners p
|
|
WHERE p.id = reports.created_by
|
|
AND p.user_id = auth.uid()
|
|
)
|
|
);
|
|
|
|
CREATE POLICY reports_insert_policy ON reports
|
|
FOR INSERT
|
|
WITH CHECK (
|
|
EXISTS (
|
|
SELECT 1
|
|
FROM practitioners p
|
|
WHERE p.id = reports.created_by
|
|
AND p.user_id = auth.uid()
|
|
)
|
|
);
|
|
|
|
CREATE POLICY reports_update_policy ON reports
|
|
FOR UPDATE
|
|
USING (
|
|
EXISTS (
|
|
SELECT 1
|
|
FROM practitioners p
|
|
WHERE p.id = reports.created_by
|
|
AND p.user_id = auth.uid()
|
|
)
|
|
)
|
|
WITH CHECK (
|
|
EXISTS (
|
|
SELECT 1
|
|
FROM practitioners p
|
|
WHERE p.id = reports.created_by
|
|
AND p.user_id = auth.uid()
|
|
)
|
|
);
|
|
|
|
CREATE POLICY reports_delete_policy ON reports
|
|
FOR UPDATE
|
|
USING (
|
|
EXISTS (
|
|
SELECT 1
|
|
FROM practitioners p
|
|
WHERE p.id = reports.created_by
|
|
AND p.user_id = auth.uid()
|
|
)
|
|
AND deleted_at IS NULL
|
|
)
|
|
WITH CHECK (deleted_at IS NOT NULL);
|
|
|
|
COMMENT ON TABLE reports IS 'Universal reporting system - AI-powered classification';
|
|
COMMENT ON COLUMN reports.type IS 'Report type: behandeladvies, vrije_notitie, etc.';
|
|
COMMENT ON COLUMN reports.ai_confidence IS 'AI classification confidence (0.0-1.0)';
|
|
COMMENT ON COLUMN reports.structured_data IS 'Extracted entities (DSM codes, medication, etc.)';
|
|
COMMENT ON COLUMN reports.audio_url IS 'Supabase Storage URL for audio recording';
|