nurse-handover-simulator / supabase_init.sql
LearningnRunning's picture
feat: Add SQL scripts for complete database reset and initialization, including table and function definitions for sessions, chat history, handoff records, and sbar drafts. Implement foreign key constraints and triggers for automatic session management and updated timestamps.
2f230ab
-- =====================================================
-- Supabase 초기 μ„€μ • 톡합 슀크립트 (μ™„μ „ μ΄ˆκΈ°ν™” 버전)
-- κ°„ν˜Έ μΈμˆ˜μΈκ³„ ꡐ윑 ν”Œλž«νΌ
-- μ‹€ν–‰ μˆœμ„œ: 이 νŒŒμΌμ„ Supabase SQL Editorμ—μ„œ ν•œ 번만 μ‹€ν–‰ν•˜μ„Έμš”
-- =====================================================
-- =====================================================
-- 1. κΈ°λ³Έ ν…Œμ΄λΈ” 생성 (μ˜μ‘΄μ„± μˆœμ„œλŒ€λ‘œ)
-- =====================================================
-- 1.1 patients ν…Œμ΄λΈ” (ν™˜μž κΈ°λ³Έ 정보)
CREATE TABLE patients (
id VARCHAR(50) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
age INTEGER NOT NULL,
gender VARCHAR(10) NOT NULL,
weight INTEGER,
height INTEGER,
diagnosis VARCHAR(200) NOT NULL,
admission_date DATE NOT NULL,
attending_physician VARCHAR(100),
allergies VARCHAR(200),
comorbidities TEXT,
room_number VARCHAR(20),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
COMMENT ON TABLE patients IS 'ν™˜μž κΈ°λ³Έ 정보';
-- 1.2 scenarios ν…Œμ΄λΈ” (μΈμˆ˜μΈκ³„ μ‹œλ‚˜λ¦¬μ˜€)
CREATE TABLE scenarios (
id VARCHAR(50) PRIMARY KEY,
patient_id VARCHAR(50) NOT NULL,
title VARCHAR(200) NOT NULL,
day INTEGER NOT NULL,
handoff_situation VARCHAR(200),
vitals JSONB,
labs JSONB,
orders JSONB,
nursing_notes JSONB,
physical_exam JSONB,
imaging JSONB,
surgery_info JSONB,
discharge_education JSONB,
hospital_day INTEGER,
status_badge VARCHAR(20),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT scenarios_patient_fkey
FOREIGN KEY (patient_id)
REFERENCES patients(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
COMMENT ON TABLE scenarios IS 'μΈμˆ˜μΈκ³„ μ‹œλ‚˜λ¦¬μ˜€';
-- 1.3 sessions ν…Œμ΄λΈ” (μ„Έμ…˜ 관리) - session_idλ₯Ό PK둜
CREATE TABLE sessions (
session_id VARCHAR(100) PRIMARY KEY,
student_id VARCHAR(100) NOT NULL,
scenario_id VARCHAR(50) NOT NULL,
status VARCHAR(20) DEFAULT 'active',
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
ended_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT sessions_scenario_fkey
FOREIGN KEY (scenario_id)
REFERENCES scenarios(id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
COMMENT ON TABLE sessions IS 'TSID 기반 μ±„νŒ… μ„Έμ…˜ 관리 ν…Œμ΄λΈ”';
COMMENT ON COLUMN sessions.session_id IS 'TSID 기반 μ„Έμ…˜ μ‹λ³„μž (PRIMARY KEY)';
-- 1.4 chat_history ν…Œμ΄λΈ” (학생과 AI κ°„μ˜ μ±„νŒ… 기둝)
CREATE TABLE chat_history (
id SERIAL PRIMARY KEY,
session_id VARCHAR(100) NOT NULL,
student_id VARCHAR(100) NOT NULL,
scenario_id VARCHAR(50) NOT NULL,
role VARCHAR(20) NOT NULL CHECK (role IN ('user', 'assistant')),
message TEXT NOT NULL,
timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT chat_history_session_fkey
FOREIGN KEY (session_id)
REFERENCES sessions(session_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
COMMENT ON TABLE chat_history IS '학생과 AI κ°„μ˜ μ±„νŒ… 기둝';
-- 1.5 handoff_records ν…Œμ΄λΈ” (μΈμˆ˜μΈκ³„ 기둝 및 평가)
CREATE TABLE handoff_records (
id SERIAL PRIMARY KEY,
session_id VARCHAR(100),
student_id VARCHAR(100) NOT NULL,
scenario_id VARCHAR(50) NOT NULL,
submitted_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
situation TEXT,
background TEXT,
assessment TEXT,
recommendation TEXT,
total_score FLOAT,
category_scores JSONB,
strengths JSONB,
improvements JSONB,
detailed_feedback TEXT,
missing_critical_info JSONB,
safety_concerns JSONB,
CONSTRAINT handoff_records_scenario_fkey
FOREIGN KEY (scenario_id)
REFERENCES scenarios(id)
ON DELETE RESTRICT
ON UPDATE CASCADE,
CONSTRAINT handoff_records_session_fkey
FOREIGN KEY (session_id)
REFERENCES sessions(session_id)
ON DELETE SET NULL
ON UPDATE CASCADE
);
COMMENT ON TABLE handoff_records IS 'ν•™μƒμ˜ μΈμˆ˜μΈκ³„ 기둝 및 AI 평가 κ²°κ³Ό';
COMMENT ON COLUMN handoff_records.session_id IS 'μ±„νŒ… μ„Έμ…˜ ID (nullable)';
-- 1.6 sbar_drafts ν…Œμ΄λΈ” (μž‘μ„± 쀑인 SBAR μž„μ‹œ μ €μž₯)
CREATE TABLE sbar_drafts (
id SERIAL PRIMARY KEY,
session_id VARCHAR(100) NOT NULL UNIQUE,
student_id VARCHAR(100) NOT NULL,
scenario_id VARCHAR(50) NOT NULL,
situation TEXT DEFAULT '',
background TEXT DEFAULT '',
assessment TEXT DEFAULT '',
recommendation TEXT DEFAULT '',
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT sbar_drafts_session_fkey
FOREIGN KEY (session_id)
REFERENCES sessions(session_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
COMMENT ON TABLE sbar_drafts IS 'μž‘μ„± 쀑인 SBAR μž„μ‹œ μ €μž₯';
-- =====================================================
-- 2. 인덱슀 생성 (μ„±λŠ₯ μ΅œμ ν™”)
-- =====================================================
-- patients
CREATE INDEX idx_patients_name ON patients(name);
-- scenarios
CREATE INDEX idx_scenarios_patient ON scenarios(patient_id);
CREATE INDEX idx_scenarios_day ON scenarios(day);
-- sessions
CREATE INDEX idx_sessions_student ON sessions(student_id);
CREATE INDEX idx_sessions_scenario ON sessions(scenario_id);
CREATE INDEX idx_sessions_status ON sessions(status);
CREATE INDEX idx_sessions_started ON sessions(started_at DESC);
-- chat_history
CREATE INDEX idx_chat_history_session ON chat_history(session_id);
CREATE INDEX idx_chat_history_student ON chat_history(student_id);
CREATE INDEX idx_chat_history_timestamp ON chat_history(timestamp);
-- handoff_records
CREATE INDEX idx_handoff_student ON handoff_records(student_id);
CREATE INDEX idx_handoff_scenario ON handoff_records(scenario_id);
CREATE INDEX idx_handoff_session ON handoff_records(session_id);
CREATE INDEX idx_handoff_submitted ON handoff_records(submitted_at DESC);
-- sbar_drafts
CREATE INDEX idx_sbar_session ON sbar_drafts(session_id);
CREATE INDEX idx_sbar_student ON sbar_drafts(student_id);
-- =====================================================
-- 3. 트리거 ν•¨μˆ˜ 및 트리거 생성
-- =====================================================
-- updated_at μžλ™ μ—…λ°μ΄νŠΈ ν•¨μˆ˜
CREATE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- μ„Έμ…˜ μ’…λ£Œ μ‹œ ended_at μžλ™ μ—…λ°μ΄νŠΈ ν•¨μˆ˜
CREATE FUNCTION update_session_ended_at()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.status = 'completed' OR NEW.status = 'archived' THEN
IF NEW.ended_at IS NULL THEN
NEW.ended_at = NOW();
END IF;
END IF;
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- μžλ™ μ„Έμ…˜ 생성 ν•¨μˆ˜ (chat_history insert μ‹œ)
CREATE FUNCTION auto_create_session()
RETURNS TRIGGER AS $$
BEGIN
-- session_idκ°€ sessions에 μ—†μœΌλ©΄ μžλ™ 생성
IF NOT EXISTS (SELECT 1 FROM sessions WHERE session_id = NEW.session_id) THEN
INSERT INTO sessions (session_id, student_id, scenario_id, status)
VALUES (NEW.session_id, NEW.student_id, NEW.scenario_id, 'active')
ON CONFLICT (session_id) DO NOTHING;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 트리거 생성
CREATE TRIGGER update_patients_updated_at
BEFORE UPDATE ON patients
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_scenarios_updated_at
BEFORE UPDATE ON scenarios
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_sessions_updated_at
BEFORE UPDATE ON sessions
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_session_on_status_change
BEFORE UPDATE ON sessions
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION update_session_ended_at();
CREATE TRIGGER update_sbar_drafts_updated_at
BEFORE UPDATE ON sbar_drafts
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- chat_history insert μ‹œ sessions μžλ™ 생성
CREATE TRIGGER auto_create_session_trigger
BEFORE INSERT ON chat_history
FOR EACH ROW
EXECUTE FUNCTION auto_create_session();
-- =====================================================
-- 4. Row Level Security (RLS) μ„€μ •
-- =====================================================
-- RLS ν™œμ„±ν™”
ALTER TABLE patients ENABLE ROW LEVEL SECURITY;
ALTER TABLE scenarios ENABLE ROW LEVEL SECURITY;
ALTER TABLE sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE chat_history ENABLE ROW LEVEL SECURITY;
ALTER TABLE handoff_records ENABLE ROW LEVEL SECURITY;
ALTER TABLE sbar_drafts ENABLE ROW LEVEL SECURITY;
-- μ •μ±… 생성 (λͺ¨λ“  μ‚¬μš©μž μ ‘κ·Ό ν—ˆμš©)
CREATE POLICY "patients_all_access" ON patients
FOR ALL USING (true) WITH CHECK (true);
CREATE POLICY "scenarios_all_access" ON scenarios
FOR ALL USING (true) WITH CHECK (true);
CREATE POLICY "sessions_all_access" ON sessions
FOR ALL USING (true) WITH CHECK (true);
CREATE POLICY "chat_history_all_access" ON chat_history
FOR ALL USING (true) WITH CHECK (true);
CREATE POLICY "handoff_records_all_access" ON handoff_records
FOR ALL USING (true) WITH CHECK (true);
CREATE POLICY "sbar_drafts_all_access" ON sbar_drafts
FOR ALL USING (true) WITH CHECK (true);
-- =====================================================
-- μ™„λ£Œ λ©”μ‹œμ§€
-- =====================================================
DO $$
BEGIN
RAISE NOTICE '';
RAISE NOTICE '╔══════════════════════════════════════════════════════════════╗';
RAISE NOTICE 'β•‘ βœ… Supabase μ™„μ „ μ΄ˆκΈ°ν™” μ™„λ£Œ! β•‘';
RAISE NOTICE 'β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•';
RAISE NOTICE '';
RAISE NOTICE 'πŸ“Š μƒμ„±λœ ν…Œμ΄λΈ”:';
RAISE NOTICE ' 1. patients (ν™˜μž 정보)';
RAISE NOTICE ' 2. scenarios (μ‹œλ‚˜λ¦¬μ˜€)';
RAISE NOTICE ' 3. sessions (μ„Έμ…˜ 관리 - session_idκ°€ PK)';
RAISE NOTICE ' 4. chat_history (μ±„νŒ… 기둝)';
RAISE NOTICE ' 5. handoff_records (μΈμˆ˜μΈκ³„ 기둝)';
RAISE NOTICE ' 6. sbar_drafts (SBAR μ΄ˆμ•ˆ)';
RAISE NOTICE '';
RAISE NOTICE 'πŸ”— μ™Έλž˜ ν‚€:';
RAISE NOTICE ' - scenarios β†’ patients';
RAISE NOTICE ' - sessions β†’ scenarios';
RAISE NOTICE ' - chat_history β†’ sessions (μžλ™ 생성 트리거)';
RAISE NOTICE ' - handoff_records β†’ sessions, scenarios';
RAISE NOTICE ' - sbar_drafts β†’ sessions';
RAISE NOTICE '';
RAISE NOTICE '⚑ μžλ™ κΈ°λŠ₯:';
RAISE NOTICE ' - chat_history insert μ‹œ sessions μžλ™ 생성';
RAISE NOTICE ' - μ„Έμ…˜ μ™„λ£Œ μ‹œ ended_at μžλ™ μ„€μ •';
RAISE NOTICE ' - updated_at μžλ™ κ°±μ‹ ';
RAISE NOTICE '';
RAISE NOTICE 'πŸ“‹ λ‹€μŒ 단계:';
RAISE NOTICE ' uv run python init_db.py - μ‹œλ‚˜λ¦¬μ˜€ 데이터 λ‘œλ“œ';
RAISE NOTICE '';
END $$;