2df7b24ac9
asyncpg prepared statement 는 single-command 만 허용. 원래 한 파일이던 study_sessions 스키마(CREATE TABLE x2 + CREATE INDEX x8)를 143~146 분할 패턴 따라 10개로 분리. 164: CREATE TABLE study_sessions 165~169: study_sessions 인덱스 5개 (partial) 170: CREATE TABLE study_session_assets 171~173: study_session_assets 인덱스 3개 문제: cannot insert multiple commands into a prepared statement 원인: _run_migrations 가 conn.exec_driver_sql 로 단일 prepared statement 실행
54 lines
2.3 KiB
SQL
54 lines
2.3 KiB
SQL
-- 164_study_sessions.sql
|
|
-- iPad 손글씨 학습 세션 + 모바일 암기노트/퀴즈 — Phase 1 MVP (1/10)
|
|
-- plan: ~/.claude/plans/scalable-chasing-stonebraker.md
|
|
--
|
|
-- asyncpg prepared statement 는 single-command 만 허용.
|
|
-- 원래 한 파일이던 학습 세션 스키마를 10개로 분리:
|
|
-- 164: CREATE TABLE study_sessions
|
|
-- 165~169: study_sessions 인덱스 5개
|
|
-- 170: CREATE TABLE study_session_assets
|
|
-- 171~173: study_session_assets 인덱스 3개
|
|
--
|
|
-- 자격증(certification) + 어학(language) 두 도메인을 모두 받는 일반 학습 세션.
|
|
-- iPad write / 모바일 review / 모바일 quiz 가 같은 데이터를 공유.
|
|
--
|
|
-- 핵심 원칙:
|
|
-- - study_type 으로 도메인 분기. metadata jsonb 가 도메인별 자유 메타.
|
|
-- - 단일 *_document_id 컬럼 금지. 모든 미디어 연결은 study_session_assets.
|
|
-- - documents 본체는 절대 삭제하지 않음 (assets 만 cascade).
|
|
-- - Phase 1 미사용 필드 (review_state / quiz / ocr / ai_summary / prompt) 는 NULL 허용,
|
|
-- 자동 로직은 Phase 2~4 별도 PR 에서 활성.
|
|
|
|
CREATE TABLE IF NOT EXISTS study_sessions (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
study_type VARCHAR(30) NOT NULL DEFAULT 'certification',
|
|
certification VARCHAR(120),
|
|
language_code VARCHAR(20),
|
|
learning_level VARCHAR(80),
|
|
subject VARCHAR(120),
|
|
topic VARCHAR(200),
|
|
source_text TEXT,
|
|
source_page INTEGER,
|
|
mode VARCHAR(30) NOT NULL DEFAULT 'copy',
|
|
prompt_question TEXT,
|
|
expected_answer TEXT,
|
|
metadata JSONB,
|
|
target_count INTEGER,
|
|
repetition_count INTEGER NOT NULL DEFAULT 0,
|
|
strokes_json JSONB,
|
|
canvas_width INTEGER,
|
|
canvas_height INTEGER,
|
|
schema_version INTEGER NOT NULL DEFAULT 1,
|
|
ocr_text TEXT,
|
|
user_corrected_text TEXT,
|
|
ai_summary TEXT,
|
|
review_state VARCHAR(20),
|
|
next_review_at TIMESTAMPTZ,
|
|
last_quiz_at TIMESTAMPTZ,
|
|
correct_count INTEGER NOT NULL DEFAULT 0,
|
|
incorrect_count INTEGER NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|