feat(prisma): kice text fields + Passage model — 7A.1

- ProblemSet.audioUrls Json? (영어 듣기 mp3 배열)
- Problem 에 bodyText/choices/answerNumber/passageId/needsReview 추가
- Problem @@index([passageId]) 로 역방향 조회 보장
- 신규 Passage 모델 (공통 지문 [N~M] 분리용)
- examRound 추가 거부 — 기존 examType 이 이미 'sat'|'mock-june'|'mock-sept'|'academy' 커버
- .gitignore 에 data/kice/ (저작권 자료)

migration: 20260411183246_kice_text_fields
shadow DB INDEX 권한 이슈는 mariadb 에서 GRANT 로 해결
This commit is contained in:
reloop
2026-04-12 03:32:59 +09:00
parent b12192eddf
commit e2e3e4bd6f
3 changed files with 69 additions and 1 deletions

3
.gitignore vendored
View File

@@ -17,3 +17,6 @@ backend/dist
.claude/state/session*
.claude/state/*.lock
.claude/sessions/
# KICE PDFs (저작권 자료 — repo 에 커밋 금지, mailu-dev 에 직접 배치)
data/kice/

View File

@@ -0,0 +1,31 @@
-- AlterTable
ALTER TABLE `problem_sets` ADD COLUMN `audioUrls` JSON NULL;
-- AlterTable
ALTER TABLE `problems` ADD COLUMN `answerNumber` INTEGER NULL,
ADD COLUMN `bodyText` TEXT NULL,
ADD COLUMN `choices` JSON NULL,
ADD COLUMN `needsReview` BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN `passageId` INTEGER NULL;
-- CreateTable
CREATE TABLE `passages` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`problemSetId` INTEGER NOT NULL,
`startNumber` INTEGER NOT NULL,
`endNumber` INTEGER NOT NULL,
`bodyText` TEXT NOT NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
INDEX `passages_problemSetId_idx`(`problemSetId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateIndex
CREATE INDEX `problems_passageId_idx` ON `problems`(`passageId`);
-- AddForeignKey
ALTER TABLE `problems` ADD CONSTRAINT `problems_passageId_fkey` FOREIGN KEY (`passageId`) REFERENCES `passages`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `passages` ADD CONSTRAINT `passages_problemSetId_fkey` FOREIGN KEY (`problemSetId`) REFERENCES `problem_sets`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -160,13 +160,18 @@ model ReviewSchedule {
model ProblemSet {
id Int @id @default(autoincrement())
title String
examType String // "sat" | "mock-june" | "mock-sept" | "academy" | ...
/// examType 허용값: "sat" | "mock-june" | "mock-sept" | "academy"
examType String
year Int
subjectName String
sourceUrl String?
/// 영어 과목의 듣기 음원 파일 경로 배열 (data/kice/ 상대경로).
/// 예: ["2026/영어/영어영역듣기평가음원/01_문제 01.mp3", ...]
audioUrls Json?
createdAt DateTime @default(now())
problems Problem[]
passages Passage[]
@@unique([year, examType, subjectName])
@@map("problem_sets")
@@ -181,15 +186,44 @@ model Problem {
difficulty Float
baseCorrectRate Float?
topic String?
/// KICE 파싱 결과 — 본문 텍스트 (선택지 제외)
bodyText String? @db.Text
/// KICE 파싱 결과 — 선택지 객체 { "1": "...", "2": "...", "3": "...", "4": "...", "5": "..." }
choices Json?
/// KICE 파싱 결과 — 정답 번호 1..5
answerNumber Int?
/// 공통 지문 FK (국어 독서/문학, 영어 지문, 사탐 자료 등)
passageId Int?
passage Passage? @relation(fields: [passageId], references: [id], onDelete: SetNull)
/// 파싱 엣지케이스 플래그 — 수동 보정 대상
needsReview Boolean @default(false)
createdAt DateTime @default(now())
studyLogs StudyLog[]
@@unique([problemSetId, number])
@@index([problemSetId])
@@index([passageId])
@@map("problems")
}
/// 평가원 기출의 [N~M] 공통 지문을 담는 컨테이너.
/// 여러 Problem 이 같은 Passage 를 공유할 수 있음.
model Passage {
id Int @id @default(autoincrement())
problemSetId Int
problemSet ProblemSet @relation(fields: [problemSetId], references: [id], onDelete: Cascade)
startNumber Int
endNumber Int
bodyText String @db.Text
createdAt DateTime @default(now())
problems Problem[]
@@index([problemSetId])
@@map("passages")
}
model SkillSnapshot {
id Int @id @default(autoincrement())
userId Int