처음엔 파서를 어떻게 만들지보다 화면이 궁금했어요. FastAPI에 문제·세션·시도 모델을 잡고, 더미 문제를 심어서 푸는 화면부터 세웠습니다. PDF는 아직 안 붙었는데도 한 문제씩 넘기는 감각이 나오니까 만들 맛이 나더라고요.


PDF에서 뽑은 725문항이 세션 하나가 되고, 어디까지 풀었는지가 남는다

PDF를 얹고 세션 이름만 붙이면 준비 끝

한 문제와 보기 네 개만 남기고 나머지는 치운다

내가 고른 보기는 빨강, 정답은 초록으로 같이 켜진다

오늘 밀린 분량과 오답·북마크·건너뛴 문제를 세션별로 모은다

다음에 이 문제를 언제 다시 볼지 그 자리에서 알려준다
어떤 서비스인가요?
자격증 덤프 PDF를 올리면 문항·보기·정답을 뽑아 한 문제씩 풀게 해주고, 틀린 문제를 망각 곡선에 맞춰 다시 물어보는 웹앱이에요
어떤 계기로 만들게 됐나요?
자격증 덤프는 PDF로만 있는데, 폰으로 확대해서 보기도 불편하고 내가 어디까지 봤는지도 모르겠더라고요. 마침 OCR도 궁금해서 파이프라인을 직접 만들어 봤습니다
주로 어떤 분이 쓰나요?
덤프 PDF로 자격증을 준비하는 사람이요. 사실은 저 혼자 쓰려고 만든 도구예요
지금은 안 하기로 한 게 있나요?
로그인을 안 넣었어요. 혼자 쓰는 도구라 계정이 붙는 순간 만들 게 두 배가 됩니다
드래그해서 얹으면 파일 이름과 크기만 확인하고 끝이에요.
이름이 나중에 목록에서 이 문제집을 부르는 이름이 됩니다.
보기를 고르고 제출하면 그 화면에서 바로 채점돼요. 숫자키와 Enter로만 끝까지 갈 수 있습니다.
홈에 "복습 3"처럼 떠 있고, 누르면 오늘 몫만 큐로 나옵니다.
맞히면 간격이 벌어지고 틀리면 다음에 열 때 맨 앞으로 돌아옵니다.
처음엔 파서를 어떻게 만들지보다 화면이 궁금했어요. FastAPI에 문제·세션·시도 모델을 잡고, 더미 문제를 심어서 푸는 화면부터 세웠습니다. PDF는 아직 안 붙었는데도 한 문제씩 넘기는 감각이 나오니까 만들 맛이 나더라고요.
PDF를 올리면 서버가 받아서 쪽마다 글자를 뽑게 했어요. 처음부터 OCR을 돌릴 생각은 없었고, 글자층이 있는 PDF는 PyMuPDF로 긁고 글자가 거의 안 나오는 쪽만 Tesseract로 넘기는 식으로 갈랐습니다. 덤프처럼 텍스트가 살아 있는 파일은 OCR을 아예 안 타니까 훨씬 빨랐고요.
문제집마다 번호를 매기는 방식이 제각각이에요. "1.", "문제 1)", "Q1"... 이걸 파서 안에 계속 넣다 보니 문제집 하나 늘 때마다 파서를 뜯게 되더라고요. 그래서 규칙을 바깥 파일로 빼고, 텍스트를 보고 어느 규칙이 제일 잘 맞는지 점수로 고르게 바꿨습니다. ExamTopics 덤프는 형식이 워낙 일정해서 전용 규칙을 따로 하나 뒀어요.
받아 둔 덤프 중에 열람 암호가 걸린 게 있었어요. 비밀번호를 받아서 임시로 풀고, 끝나면 그 임시 파일을 덮어쓰고 지우게 했습니다. 비밀번호는 어디에도 저장하지 않고 그 요청 안에서만 씁니다.
문제만 쌓아 두니까 정작 "내가 어디까지 봤는지"가 없더라고요. 업로드 한 건이 곧 학습 세션 하나가 되게 만들고, 세션이 현재 문제 번호를 들고 있게 했습니다. 그때부터 화면이 목록 → 세션 → 문제로 정리됐어요.
카드가 여기저기 흩어져 있고, 그라디언트에 색 점에 설명문까지 붙어서 정작 문제가 안 읽혔어요. 홈을 세로 한 줄기로 다시 짜고 장식을 다 뺐습니다. 그러면서 알게 된 게, 화면에 있던 북마크·스킵·단축키 안내가 아무 데도 연결돼 있지 않았다는 거였어요. 눌러도 아무 일이 없는 버튼이었습니다. 지울지 붙일지 정해야 했고, 붙이는 쪽으로 갔습니다.
앞에서 뒤로 훑고 나면 그걸로 끝이더라고요. 한 번 푼 문제는 다시 안 나오니까 사흘 뒤엔 기억에 없고요. 그래서 문제마다 다음 복습일을 들고 있는 카드를 두고, 정오답을 넣으면 다음 날짜를 돌려주는 스케줄러를 붙였습니다. SM-2로 갈지 고민했는데 Anki도 넘어간 FSRS를 골랐어요. 파이썬 구현이 있어서 구현량이 오히려 적었고, 필수 의존성이 하나뿐이라 서버가 무거워지지도 않았습니다.
FSRS는 원래 사용자가 "쉬움/보통/어려움"을 눌러 주는 걸 전제합니다. 그런데 이건 객관식이라 맞았는지 틀렸는지를 앱이 이미 압니다. 그래서 정답이면 Good, 오답이면 Again으로 자동 매핑하고 버튼을 아예 없앴어요. 조절하고 싶은 사람을 위해 "어려웠음" 하나만 선택으로 남겼습니다.
로컬에서만 도는 물건으로 두기는 아까워서, 백엔드를 컨테이너 하나로 띄울 수 있게 정리했어요. 어디에 올릴지는 아직 안 정했지만, 정하면 바로 올릴 수 있는 상태까지는 만들어 뒀습니다.