feat: rapportage API, speech recorder refactor, docs reorganisatie
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>
This commit is contained in:
109
supabase/migrations/20251123_create_reports_table.sql
Normal file
109
supabase/migrations/20251123_create_reports_table.sql
Normal file
@@ -0,0 +1,109 @@
|
||||
-- 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';
|
||||
33
supabase/migrations/20251123_fix_reports_rls_policies.sql
Normal file
33
supabase/migrations/20251123_fix_reports_rls_policies.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
-- Migration: Fix RLS policies for reports table (prototype - open access)
|
||||
-- All authenticated users can read/write all reports
|
||||
|
||||
-- Drop existing restrictive policies
|
||||
DROP POLICY IF EXISTS reports_select_policy ON reports;
|
||||
DROP POLICY IF EXISTS reports_insert_policy ON reports;
|
||||
DROP POLICY IF EXISTS reports_update_policy ON reports;
|
||||
DROP POLICY IF EXISTS reports_delete_policy ON reports;
|
||||
|
||||
-- Create simple policies: all authenticated users can do everything
|
||||
CREATE POLICY reports_select_policy ON reports
|
||||
FOR SELECT
|
||||
USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY reports_insert_policy ON reports
|
||||
FOR INSERT
|
||||
WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY reports_update_policy ON reports
|
||||
FOR UPDATE
|
||||
USING (auth.role() = 'authenticated')
|
||||
WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY reports_delete_policy ON reports
|
||||
FOR UPDATE
|
||||
USING (auth.role() = 'authenticated' AND deleted_at IS NULL)
|
||||
WITH CHECK (auth.role() = 'authenticated' AND deleted_at IS NOT NULL);
|
||||
|
||||
-- Comment for documentation
|
||||
COMMENT ON POLICY reports_select_policy ON reports IS 'Prototype: All authenticated users can read all reports';
|
||||
COMMENT ON POLICY reports_insert_policy ON reports IS 'Prototype: All authenticated users can create reports';
|
||||
COMMENT ON POLICY reports_update_policy ON reports IS 'Prototype: All authenticated users can update reports';
|
||||
COMMENT ON POLICY reports_delete_policy ON reports IS 'Prototype: All authenticated users can soft-delete reports';
|
||||
Reference in New Issue
Block a user