- scanKiceData: 2025/2026 국어/영어/한국사/생활과 윤리 PDF 스캔 - extractText: pdftotext -raw (problems) / -layout (answers), pdf-parse 폐기 - parseAnswerTable: 홀/짝 분리 + ①..⑤ → 1..5 정규화 - parseProblemPaper: [N~M] passage 범위 + 번호 monotonic 체크 - importKiceSet: ProblemSet/Passage/Problem 멱등 upsert - seed.ts: DEMO_PROBLEMSET(2024 수학) 제거, User/Subject/Tag 만 유지 - CLI: cli:kice-import --year --subject --only --dry-run --sample 270 problems / 26 passages / 9 problem sets 로컬 검증 완료
100 lines
2.6 KiB
TypeScript
100 lines
2.6 KiB
TypeScript
/**
|
|
* Dev seed — creates a default demo user with 수능 과목/태그 preset.
|
|
* Run via: `pnpm prisma:seed` (or `ts-node prisma/seed.ts`).
|
|
*
|
|
* Idempotent: re-running just upserts.
|
|
*/
|
|
|
|
import { PrismaClient, Persona, ReviewIntensity } from '@prisma/client';
|
|
import * as bcrypt from 'bcrypt';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
const DEMO_EMAIL = 'demo@reloop.local';
|
|
const DEMO_PASSWORD = 'demo1234';
|
|
|
|
interface SubjectSeed {
|
|
name: string;
|
|
color: string;
|
|
tags: string[];
|
|
}
|
|
|
|
const SUBJECTS: SubjectSeed[] = [
|
|
{
|
|
name: '국어',
|
|
color: '#ef4444',
|
|
tags: ['문학', '독서(비문학)', '화법과작문', '언어와매체', '고전시가'],
|
|
},
|
|
{
|
|
name: '수학',
|
|
color: '#3b82f6',
|
|
tags: ['미적분', '확률과통계', '기하', '수1 지수로그', '수1 삼각함수', '수2 미분', '수2 적분'],
|
|
},
|
|
{
|
|
name: '영어',
|
|
color: '#22c55e',
|
|
tags: ['문법/어법', '어휘', '빈칸추론', '순서배열', '삽입', '주제/제목', '함축의미'],
|
|
},
|
|
{
|
|
name: '사회탐구',
|
|
color: '#f59e0b',
|
|
tags: ['생활과윤리', '사회문화', '한국지리', '세계사'],
|
|
},
|
|
{
|
|
name: '과학탐구',
|
|
color: '#8b5cf6',
|
|
tags: ['물리1', '화학1', '생명과학1', '지구과학1'],
|
|
},
|
|
];
|
|
|
|
async function main() {
|
|
console.log('🌱 ReLoop seed start');
|
|
|
|
// Demo user
|
|
const hash = await bcrypt.hash(DEMO_PASSWORD, 10);
|
|
const user = await prisma.user.upsert({
|
|
where: { email: DEMO_EMAIL },
|
|
update: {},
|
|
create: {
|
|
email: DEMO_EMAIL,
|
|
password: hash,
|
|
nickname: '데모',
|
|
persona: Persona.mid,
|
|
currentGrade: 4,
|
|
targetGrade: 2,
|
|
reviewIntensity: ReviewIntensity.moderate,
|
|
onboardedAt: new Date(),
|
|
},
|
|
});
|
|
// TODO(phase7): 프로덕션 seed 에서는 평문 비밀번호 stdout 출력 제거
|
|
console.log(` user: ${user.email} (id=${user.id}) password=${DEMO_PASSWORD}`);
|
|
|
|
for (const s of SUBJECTS) {
|
|
const subject = await prisma.subject.upsert({
|
|
where: { userId_name: { userId: user.id, name: s.name } },
|
|
update: { color: s.color },
|
|
create: { name: s.name, color: s.color, userId: user.id },
|
|
});
|
|
console.log(` subject: ${subject.name}`);
|
|
|
|
for (const tagName of s.tags) {
|
|
await prisma.tag.upsert({
|
|
where: { subjectId_name: { subjectId: subject.id, name: tagName } },
|
|
update: {},
|
|
create: { name: tagName, subjectId: subject.id },
|
|
});
|
|
}
|
|
}
|
|
|
|
console.log('✅ seed done');
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|