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 $$; | |