3084f291e1c97e20880ce711820093c0bb67efd6
ReLoop v2
잊기 전에 다시 만나는 학습법. 페르소나 기반 망각 곡선으로 개인화된 복습 간격을 자동으로 계산하는 적응형 학습 플랫폼.
수능, 자격증, 어학, 취미 학습 — 어떤 공부든 ReLoop이 기억을 관리합니다.
핵심 기능
| 기능 | 설명 |
|---|---|
| 적응형 복습 스케줄링 | 페르소나 + 문제 난이도에 따라 "정답률이 기준 아래로 떨어지는 시점"을 자동 계산해 복습 큐에 넣습니다 |
| KICE 기출 문제집 | 2025/2026 수능 수학 4단원(공통/확률과 통계/미적분/기하) 92문항을 PDF에서 자동 크롭한 이미지로 제공 |
| 모의고사 모드 | 실제 시험처럼 타이머 + OMR 답안 선택 + 자동 채점 + 학습 기록 일괄 생성 |
| Solved.ac PS 연동 | Solved.ac 계정에서 최신 백준 풀이 이력을 동기화해 복습 큐에 추가 |
| 통계 대시보드 | 학습 히트맵, 단원별·PS 정답률, 숙련도 성장 곡선을 시각화 |
| PWA 지원 | 모바일 홈 화면에 앱으로 설치 가능 |
기술 스택
| 영역 | 기술 |
|---|---|
| Backend | NestJS 10 + Prisma 5 + MariaDB |
| Frontend | Next.js 14 (App Router) + React 18 + styled-components 6 |
| 인증 | JWT (passport-jwt) |
| 보안 | helmet, @nestjs/throttler (60req/min), CORS whitelist |
| 아이콘 | Phosphor React |
| 폰트 | Pretendard + Inter + JetBrains Mono |
| 배포 | PM2 on Debian VM, nginx reverse proxy |
| PDF 처리 | poppler-utils (pdftotext, pdftoppm, pdfinfo) |
| OCR | Codex CLI Vision (codex exec -i) |
프로젝트 구조
reloop-v2/
├── backend/ # NestJS API 서버
│ ├── src/
│ │ ├── auth/ # JWT 인증 (login, register, me)
│ │ ├── dashboard/ # 대시보드 요약 API
│ │ ├── forget/ # 페르소나 망각 곡선 엔진
│ │ ├── me/ # 프로필, 아바타 업로드
│ │ ├── problem-sets/ # 문제집 CRUD + 파싱 모듈
│ │ │ └── parsing/ # PDF 파싱 엔진 (범용, 전략 패턴)
│ │ │ ├── strategies/ # kice.ts, math.ts
│ │ │ └── ocr-fallback/ # Codex Vision OCR
│ │ ├── reviews/ # 복습 큐 관리
│ │ ├── stats/ # 통계 API
│ │ ├── study-logs/ # 학습 기록 + 모의고사 일괄 제출
│ │ ├── subjects/ # 과목 관리
│ │ └── tags/ # 태그 관리
│ ├── prisma/
│ │ ├── schema.prisma # DB 스키마
│ │ ├── seed.ts # 데모 데이터 시드
│ │ └── migrations/ # 마이그레이션 히스토리
│ ├── scripts/
│ │ ├── kice-import.ts # KICE PDF 임포트 CLI
│ │ └── ocr-fix.ts # OCR 보정 CLI
│ └── uploads/ # 문제 이미지, 아바타 (git 제외)
├── frontend/ # Next.js 프론트엔드
│ ├── src/
│ │ ├── app/ # App Router 페이지들
│ │ │ ├── dashboard/ # 대시보드 (채움/빈 상태)
│ │ │ ├── exams/ # 문제집 카탈로그
│ │ │ ├── study/
│ │ │ │ ├── exam/[id]/ # 모의고사 시험 화면
│ │ │ │ └── history/ # 학습 기록 히스토리
│ │ │ ├── review/ # 복습 세션
│ │ │ ├── solve/[id]/ # 개별 문제 풀기
│ │ │ ├── study-logs/[id]/ # 학습 기록 상세
│ │ │ ├── stats/ # 통계
│ │ │ ├── subjects/ # 과목 및 태그 관리
│ │ │ ├── profile/ # 프로필 + 설정 통합
│ │ │ ├── pricing/ # 플랜 (공개/로그인 분기)
│ │ │ ├── onboarding/ # 신규 사용자 온보딩
│ │ │ ├── login/ + register/ # 인증
│ │ │ ├── privacy/ terms/ contact/ # 법적 페이지
│ │ │ └── page.tsx # 랜딩 페이지
│ │ ├── components/
│ │ │ ├── ui/ # Button, Card, Icon, Toast, Select, DatePicker, ...
│ │ │ ├── layout/ # AppShell, SideNav, BottomNav
│ │ │ ├── auth/ # AuthCard (로그인/회원가입 통합)
│ │ │ ├── dashboard/ # EmptyDashboard
│ │ │ └── legal/ # LegalLayout
│ │ ├── lib/ # api.ts, auth.ts, constants.ts, exam-date.ts
│ │ └── styles/ # theme.ts (디자인 토큰, 애니메이션)
│ └── public/ # 정적 파일, PWA manifest, 아이콘
├── data/kice/ # KICE 원본 PDF (git 제외, 저작권)
│ ├── 2025/{국어,수학,영어,...}/
│ └── 2026/{국어,수학,영어,...}/
├── docs/ # 상세 매뉴얼
│ ├── algorithm.md # 망각 곡선 알고리즘 상세
│ ├── architecture.md # 시스템 아키텍처
│ ├── user-guide.md # 사용자 가이드
│ ├── admin-guide.md # 운영/배포 가이드
│ └── pdf-pipeline.md # PDF 파싱 파이프라인
└── Plans.md # 개발 계획 + 진행 상황
알고리즘 요약
상세 내용: docs/algorithm.md
ReLoop은 FSRS 대신 자체 페르소나 기반 망각 곡선을 사용합니다.
핵심 수식
실력 감쇄: S(t) = S₀ × exp(-λ × t)
정답 확률: P = sigmoid(k × (S(t) - D))
- S₀ (0~1): 마지막 학습 시점의 실력. 맞으면 올라가고 틀리면 떨어짐
- λ (lambda): 페르소나별 망각 속도. senior(0.1)은 느리게, crammer(0.6)은 빠르게 잊음
- D: 문제 난이도 (0~1)
- k: sigmoid 기울기 (기본 4.0)
복습 시점 결정
"정답 확률 P가 사용자의 기준(P_threshold) 아래로 떨어지는 시점"을 다음 복습일로 잡습니다.
| 복습 민감도 | P_threshold | 의미 |
|---|---|---|
| 엄격 (strict) | 0.7 | 70% 이하로 떨어지면 복습 |
| 균형 (moderate) | 0.5 | 50% 이하 |
| 여유 (relaxed) | 0.35 | 35% 이하 |
페르소나
| 페르소나 | λ (망각속도) | 복습 주기 경향 |
|---|---|---|
| Senior | 0.1 | 7~14일 (느린 망각) |
| Mid | 0.2 | 2~5일 |
| Junior | 0.4 | 1~2일 (빠른 망각) |
| Crammer | 0.6 | 매일~격일 |
S₀ 업데이트 규칙
| 결과 | 새 S₀ |
|---|---|
| 정답 | S₀ × 0.5 + 0.6 |
| 부분 | S₀ × 0.7 + 0.3 |
| 오답 | S₀ × 0.5 |
빠른 시작
필수 조건
- Node.js 20+
- pnpm 9+
- MariaDB/MySQL 8+
- poppler-utils (
pdftotext,pdftoppm,pdfinfo)
설치 및 실행
# 1. 클론
git clone ssh://git@your-gitea:2222/hanarang/reloop-v2.git
cd reloop-v2
# 2. 백엔드
cd backend
pnpm install
cp .env.example .env # DATABASE_URL, JWT_SECRET 편집
pnpm prisma migrate dev
pnpm prisma:seed # 데모 계정 생성
pnpm dev # http://localhost:3001
# 3. 프론트엔드 (새 터미널)
cd frontend
pnpm install
cp .env.example .env.local # NEXT_PUBLIC_API_URL 편집
pnpm dev # http://localhost:3000
# 4. (선택) KICE 기출 임포트
# data/kice/ 에 PDF 배치 후:
cd backend
pnpm cli:kice-import --year=2026
데모 계정
| 이메일 | 비밀번호 |
|---|---|
| demo@reloop.local | demo1234 |
환경 변수
Backend (backend/.env)
| 변수 | 필수 | 기본값 | 설명 |
|---|---|---|---|
DATABASE_URL |
O | — | mysql://user:pass@host:3306/reloop_v2 |
JWT_SECRET |
O | — | 32자 이상 랜덤 문자열 |
JWT_EXPIRES_IN |
— | 7d |
토큰 만료 기간 |
CORS_ORIGINS |
— | http://localhost:3000 |
쉼표 구분 허용 도메인 |
PORT |
— | 3001 |
API 서버 포트 |
Frontend (frontend/.env.local)
| 변수 | 필수 | 기본값 |
|---|---|---|
NEXT_PUBLIC_API_URL |
— | http://localhost:3001/api |
배포
상세 내용: docs/admin-guide.md
# 서버에서
cd /path/to/reloop-v2
# 백엔드
cd backend && pnpm install && pnpm prisma:deploy && pnpm build
pm2 restart reloop-api
# 프론트엔드
cd frontend && pnpm install && pnpm build
cp -r .next/static .next/standalone/.next/
cp -r public .next/standalone/
pm2 restart reloop-web
API 요약
상세 내용: docs/architecture.md
| Method | Endpoint | 설명 |
|---|---|---|
| POST | /api/auth/register |
회원가입 |
| POST | /api/auth/login |
로그인 (JWT 발급) |
| GET | /api/auth/me |
내 정보 |
| PATCH | /api/me/profile |
프로필 수정 |
| POST | /api/me/avatar |
아바타 업로드 |
| GET | /api/dashboard/summary |
대시보드 요약 |
| GET | /api/problem-sets |
문제집 목록 |
| GET | /api/problem-sets/:id |
문제집 상세 (문항 + 지문) |
| GET | /api/study-logs |
학습 기록 목록 |
| POST | /api/study-logs |
학습 기록 생성 |
| GET | /api/study-logs/:id |
학습 기록 상세 |
| PATCH | /api/study-logs/:id |
학습 기록 수정 |
| POST | /api/study-logs/from-problem-set |
모의고사 일괄 제출 |
| GET | /api/reviews/queue |
오늘의 복습 큐 |
| POST | /api/reviews/:id/submit |
복습 결과 제출 |
| GET | /api/subjects |
과목 목록 |
| GET | /api/stats/subjects |
과목별 통계 |
| GET | /api/stats/mastery-path |
숙련도 성장 곡선 |
라이선스
UNLICENSED (비공개)
Description
Languages
TypeScript
81.2%
HTML
18.7%