[AWS SAA-C03] 덤프 PDF를 PC·모바일 연동 문제풀이 앱으로 만들기 (Claude Cowork 활용)
1. 배경
AWS SAA-C03 준비를 하면서 덤프 PDF(V29.35, 880문항)를 보고 있는데, 몇 가지가 불편했습니다.
- PDF 한 페이지에 문제가 2~3개씩 이어져 있어서 지금 보는 문제가 어디서 끝나는지 눈으로 찾아야 함
- 정답과 해설이 보기 바로 아래 붙어 있어서, 생각하기도 전에 정답이 눈에 들어옴
- 어디까지 봤는지 기록이 안 남아서 매번 페이지 번호를 기억해야 함
- 출퇴근 길에 폰으로 이어서 보고 싶은데 PDF 뷰어로는 사실상 불가능
그래서 “문제 하나씩 보고, 내가 고른 뒤에 정답·해설을 확인하고, 중간에 끄더라도 PC와 폰 어디서든 이어서 풀 수 있는” 웹 앱을 만들기로 했습니다. 코드는 Claude Cowork에게 맡기고, 저는 요구사항 정의와 검증만 했습니다.
2. 요구사항 정리
| 구분 | 내용 |
|---|---|
| 문제 표시 | 한 화면에 한 문제, 이전/다음 이동 |
| 정답 확인 | 보기를 고른 뒤 정답 확인 → 정오답 표시, 그 다음에 해설 열람 |
| 다중 선택 | “Select TWO/THREE” 문항은 여러 개 고른 뒤 확인 |
| 진행 기록 | 현재 위치·풀이 결과·북마크가 계정 단위로 저장, 다른 기기에서 이어서 |
| 언어 | 영문 덤프 기본, 같은 문항의 한글판으로 전환 가능 |
| 모바일 | 폰 브라우저에서 바로 열고, 홈 화면에 추가해 앱처럼 사용 |
| AI 해설 | 덤프 해설이 부족한 문항은 AI에게 해설을 요청 |
3. 전체 구조
덤프 PDF (EN / KR)
│ pdftotext -layout
▼
텍스트 파일 ──(Python 파서)──▶ questions.json (880문항, EN+KR 병합)
│
▼
index.html (단일 파일, 순수 JS, 라이브러리 없음)
│
▼
claude.ai Artifact 호스팅 (비공개 URL, 로그인 필요)
├─ db : 문항별 진행 상황 (계정별 비공개 저장소)
└─ sample : "AI 질문" 탭에서 Claude 호출
서버 코드는 한 줄도 없습니다. 문제 표시·정답 판정·필터 같은 로직은 전부 브라우저에서 돌고, 서버가 관여하는 건 “진행 상황 저장”과 “AI 질문” 두 가지뿐입니다.
4. PDF 파싱
4-1. 텍스트 추출
pdftotext -layout로 뽑으면 아래처럼 규칙적인 구조가 나옵니다. 영문판은 NO.1, 한글판은 QUESTION NO: 1 형식으로 번호 패턴만 다르고 문항 번호는 동일했습니다.
NO.1 A company maintains a data lake in an Amazon S3 bucket. ...
Which solution will meet these requirements in the MOST scalable way?
A. Create an IAM role and IAM policy for each vendor. ...
B. ...
C. ...
D. ...
Answer: C
Explanation:
Amazon S3 Access Grants is designed to provide fine-grained ...
4-2. 파서 핵심 로직
페이지마다 반복되는 머리글(“IT Certification Guaranteed, The Easy Way!”)과 페이지 번호(숫자만 있는 줄)를 먼저 걷어내고, 상태 머신으로 문제 → 보기 → Answer → Explanation을 나눴습니다.
# 페이지 머리글·페이지 번호 제거
if 'IT Certification Guaranteed' in t: continue
if re.fullmatch(r'\d{1,4}', t): continue
# 문항 시작: EN은 ^NO\.(\d+), KR은 ^QUESTION NO:\s*(\d+)
# 보기 시작: ^([A-H])\.\s+
# 정답: ^Answer:\s*(.*) → 'A, C' / 'AC' 모두 글자만 추출
# 해설: Explanation: 이후 다음 문항 전까지
PDF 줄바꿈 때문에 한 문장이 여러 줄로 잘려 있으므로, 같은 보기/문단에 속한 줄은 공백으로 다시 이어 붙였습니다. 빈 줄은 문단 구분으로 유지했습니다.
4-3. 검증 결과
EN/KR 두 파일을 각각 파싱한 뒤 문항 번호로 병합하면서 자동 검증을 걸었습니다.
- 문항 수: EN 880 / KR 880, 누락 0
- 보기 수 불일치(EN↔︎KR): 0건
- 정답 불일치(EN↔︎KR): 0건
- 정답이 비어 있는 문항: 0건
- 해설이 없는 문항: 21건 (앱에서 “해설 없음”으로 표시)
- 다중 정답 문항: 2개 선택 61건, 3개 선택 17건
PDF 추출 과정에서 생긴 company ' s 같은 아포스트로피 공백도 일괄 정리했습니다.
5. 앱 기능
문제 풀이 흐름
- 보기를 클릭하면 즉시 채점 (단일 정답). 다중 정답은 여러 개 고른 뒤 「정답 확인」
- 정답 보기는 초록, 내가 고른 오답은 빨강으로 표시
- 「해설 보기」를 누르면 「덤프 해설」 / 「AI 질문」 탭이 열림
- 「다시 풀기」로 기록을 지우고 재도전

문제 카드 — A를 골라 오답, 정답 C는 초록으로 표시 NO.1에서 A를 골랐다가 틀린 화면. 내가 고른 오답은 빨강, 정답은 초록으로 표시되고 상단에 진행률·정답률·오답 수가 바로 갱신된다.
진행 관리
- 상단에 진행률 바, 푼 문항 수, 정답률, 오답 수, 북마크 수
- 「목록」에서 880문항을 격자로 보고 전체 / 오답만 / 안 푼 문제 / 북마크 필터로 바로 이동
- 중간에 닫았다가 다시 열면 마지막 문항부터 이어서 시작

문항 목록 — 880문항 격자와 필터 「목록」 화면. 전체 / 오답만 / 안 푼 문제 / 북마크 필터로 걸러서 번호를 누르면 바로 이동한다. 풀이 결과에 따라 칸 색이 바뀐다.
편의 기능
EN/KR버튼으로 같은 문항의 한글판 전환- 키보드:
←→이동,A~F보기 선택,Enter확인,E해설,B북마크 - 모바일: 좌우 스와이프로 이전/다음
6. PC ↔︎ 모바일 진행 상황 동기화
처음엔 localStorage만 쓰려 했는데, 그러면 기기마다 기록이 따로 놉니다. claude.ai 아티팩트에는 페이지별로 작은 문서 저장소(db)를 붙일 수 있고, data/users/<내 ID>/ 아래 경로는 계정 소유자만 읽고 쓸 수 있어서 여기에 진행 상황을 한 문서로 저장했습니다.
// 진행 문서 하나에 전부 저장 (880문항 기준 수십 KB)
docRef = db.doc('data/users/' + uid + '/progress');
// { cur: 123, a: { "12": {c:["A"], ok:true, t:...}, ... }, m: {북마크}, u: updatedAt }
동작 방식은 이렇습니다.
- 페이지를 열면
localStorage캐시로 즉시 렌더링 (대기 없음) - 서버 문서를 읽어 와서 문항별 타임스탬프 기준으로 병합
- 문제를 풀 때마다 약 1초 디바운스 후 서버에 저장 (한 번에 한 쓰기)
onSnapshot으로 다른 기기의 변경을 구독 → 폰에서 풀고 PC로 돌아오면 자동 반영
상단에 “계정에 저장됨” / “이 기기에만 저장됨” 상태를 표시해서, 서버 저장이 실패해도 알 수 있게 했습니다.
7. AI 질문 탭
덤프 해설이 없는 문항이 21개 있고, 있는 해설도 왜 다른 보기가 틀렸는지는 잘 안 적혀 있습니다. 그래서 「AI 질문」 탭에서 문항·보기·덤프 정답을 함께 보내 한국어 해설을 받도록 했습니다. 아티팩트의 sample 기능을 쓰면 페이지 안에서 Claude를 호출할 수 있습니다.
const sample = await claude.use('sample');
const { text } = await sample(
[{ role: 'user', content: 튜터_지시문 }, ...대화_turns],
{ cache: false, signal: ctl.signal, onText: ({ text }) => render(text) }
);
지시문에는 답변 구성을 고정해 두었습니다: 문제의 핵심 조건 → 정답 이유 → 오답별 이유 → 기억할 포인트. 그리고 “덤프 정답이 AWS 문서 기준으로 의심스러우면 그 점을 밝혀라”를 넣었습니다. 덤프 정답이 항상 맞는 건 아니라서요.

AI 질문 탭 — 문항 해설 답변 NO.1에 “문제 해설이랑 답이 C인 이유 설명좀해줘”라고 물은 결과. 핵심 조건 → 정답 이유 → 오답별 이유 → 기억할 포인트 순으로 답하고, 이 문항은 덤프 해설의 로깅 근거가 약하다는 점까지 짚어 주었다.
답변은 문항별로 data/users/<ID>/progress/ai/<문항번호> 문서에 저장되어, 한 번 받은 해설은 다른 기기에서도 다시 호출 없이 보입니다. 추가 질문(“C는 왜 안 되나요?”)은 같은 문항 대화에 이어집니다.
주의할 점은 AI 호출이 내 Claude 계정 사용량을 소모하고, 처음 한 번 “이 페이지가 Claude를 사용하도록 허용” 창이 뜬다는 것입니다.
8. 모바일 설치
별도 앱 스토어 설치는 없고, 폰 브라우저에서 URL을 연 뒤 홈 화면에 추가하면 됩니다.
- Android Chrome:
⋮→ 「홈 화면에 추가」 - PC Chrome:
⋮→ 「저장 및 공유」 → 「페이지를 앱으로 설치」
조건은 그 브라우저에서 claude.ai에 로그인되어 있을 것. 페이지가 비공개라 로그인 없이는 열리지 않습니다.
9. 한계와 아쉬운 점
- 로그인 의존: claude.ai 세션이 풀리면 다시 로그인해야 합니다. 세션 유지 기간은 플랫폼 정책이라 페이지 쪽에서 조정할 수 없습니다.
- 오프라인 불가: 호스팅 페이지라 네트워크가 없으면 열리지 않습니다. 필요하면 문항 데이터를 내장한 단일 HTML 파일 버전(로그인 불필요, 기기별 저장)을 따로 두는 방법이 있습니다.
- 덤프 정답의 신뢰성: 앱은 덤프에 적힌 정답을 그대로 채점 기준으로 씁니다. AI 해설과 덤프 정답이 갈리면 AWS 공식 문서로 확인해야 합니다.
- 이미지 문항 없음: 이번 PDF에는 그림이 포함된 문항이 없어서(
pdfimages -list결과 0건) 텍스트 파싱만으로 충분했습니다. 그림 문항이 있는 덤프라면 별도 처리가 필요합니다.
10. 정리
- PDF → 텍스트 → JSON 파싱은 정규식 상태 머신으로 충분했고, EN/KR 교차 검증으로 파싱 오류를 0건으로 확인
- 단일 HTML + 아티팩트 호스팅만으로 서버 없이 계정 단위 진행 동기화와 AI 해설까지 구현
- 작업 시간은 요구사항 정리부터 게시까지 약 20분, 코드 작성은 전부 Claude Cowork
덤프 PDF 자체는 저작권 문제가 있으니 공유하지 않고, 파서와 앱 구조만 공개합니다.