# Claude / Fable Java Practice 목업 검토 검토일: 2026-09-08 대상: C:\PNP\Fable 목적: 실제 개발팀에 전달할 화면·업무 흐름·최소 기능 범위 검토 자료로서의 완성도 확인 ## 판단 화면과 정상적인 학습 흐름을 논의할 목업으로 사용할 수 있다. 단일 파일 편집기, 교육 자료, 제출 이력, 관리자 계정·콘텐츠·질문함이 실제로 연결되어 있다. 다만 게시본과 작업본, 문제 버전과 채점 fixture를 분리하지 않아 변경 시 잘못된 결과를 보여준다. 이 부분은 개발팀이 그대로 구현할 기준으로 삼기 전에 수정해야 한다. 원본 프로젝트 파일은 수정하지 않았다. 브라우저에서는 가상 계정 로그인, 페이지 이동, 수업·힌트, 예제 실행과 관리자 화면을 확인했다. 콘텐츠 변경·버전·새로고침 오류는 파일과 실제 브라우저 저장 데이터를 변경하지 않는 별도 Node VM의 메모리 저장소에서 재현했다. 제공된 검증 프로그램 `node tests/run-tests.js`는 **passed: 489, failed: 0**을 반환했다. 이 숫자는 검증 코드의 체크 개수이며, 489개의 독립적인 사용자 시나리오를 의미하지 않는다. 아래 변경·복구 시나리오는 이 검증이 놓치고 있다. ## 우선 수정 사항 ### 1. [P1] 게시된 문제의 초안 수정이 학습자에게 즉시 노출됨 - 위치: `C:\PNP\Fable\js\core\store.js:323` 및 `:327`, `:329`; `js\pages\admin-content.js:748`, `:850`; `js\pages\workspace.js:205`. - 재현: 게시된 Queue Ticket Countdown의 제목 또는 과제 본문 수정 → Save draft → Publish하지 않고 학습자 조회. - 결과: status는 published, version은 1인 채 수정한 제목과 본문이 노출된다. 빈 과제로 수정해 게시 검증에 실패해도 잘못된 내용은 이미 학습자 선택 결과에 포함된다. - 원인: 작업본과 게시본이 같은 객체이며 hasUnpublishedChanges는 표시용 플래그에 그친다. - 수정 방향: 관리자 작업본을 별도로 저장하고, Publish가 성공한 경우에만 새 게시 버전 스냅샷을 생성한다. 학습자는 배정 버전의 게시 스냅샷을 읽어야 한다. ### 2. [P2] 문제 변경 후 과거 코드 fixture가 새로운 결과를 만들어 냄 - 위치: `C:\PNP\Fable\js\adapters\grading.js:45`, `:167`, 특히 `:172`; `js\core\store.js:327`. - 재현: Queue Ticket Countdown의 공개 예제 예상 출력을 `Changed expected output`으로 바꾸고 v2 게시 → 기존 known passed code를 기본 모드로 채점. - 결과: 코드가 바뀌지 않았는데 Passed가 반환되고 actual과 expected가 모두 `Changed expected output`으로 표시된다. - 원인: fixture를 문제 버전/평가 명세에 묶지 않고 코드 문자열만 확인한다. 일부 통과 fixture는 현재 expected를 actual로 복사한다. - 수정 방향: 평가 관련 내용이 변경되면 기존 fixture를 무효화한다. 새 버전에 맞게 준비된 fixture가 없다면 Not evaluated를 반환하고, 명시적으로 선택한 데모 시나리오만 별도로 허용한다. - 의미: 실제 채점기를 요구하는 문제가 아니다. 모의 결과 자체가 준비된 코드/문제 버전과 일치해야 한다는 요구다. ### 3. [P2] 새 버전 재배정 뒤 화면마다 완료 여부가 다름 - 위치: `C:\PNP\Fable\js\pages\library.js:75`, `js\pages\workspace.js:266`, `js\core\store.js:661`. - 재현: Maria가 통과한 Print a Reference Label v1을 v2로 재게시 → 기존 경로를 Maria에게 다시 배정. - 결과: My Learning은 required 완료를 4에서 3으로 낮추고 해당 문제를 Attempted로 표시한다. Library와 Workspace는 여전히 Passed로 표시한다. - 원인: 경로 진도는 배정 버전을 검사하지만 Library/Workspace 상태 계산은 그 버전을 전달하지 않는다. - 수정 방향: 같은 배정 버전 기준의 공통 상태 선택 함수를 사용한다. 새 버전의 완료를 기존 버전 완료와 어떻게 취급할지도 명시적으로 합의한다. ### 4. [P2] 제출 중 새로고침하면 처리 상태가 영구적으로 남음 - 위치: `C:\PNP\Fable\js\core\store.js:92`; `js\adapters\grading.js:286`; `js\pages\workspace.js:952`. - 재현: Submit 직후 Queued/Compiling/Running 중 새로고침. - 결과: 저장된 진행 상태는 남지만 실행 타이머가 사라져 완료되지 않는다. 이력에서도 result가 없어 해당 제출에 대한 재시도를 제공하지 않는다. - 수정 방향: 초기화 시 중단된 데모 작업을 찾아 다시 진행하거나, 스냅샷을 보존한 System error로 전환하고 재시도를 제공한다. 학습자 오답으로 처리하면 안 된다. ## 추가 확인 사항 ### 5. 여러 탭이 서로의 데이터를 덮어쓸 수 있음 - 위치: `C:\PNP\Fable\js\core\store.js:48`–`:60` 및 초기화/저장 처리. - 재현: 같은 저장소를 읽은 A/B 두 탭에서 A가 질문을 저장한 뒤, 오래된 상태를 가진 B가 초안을 저장한다. - 결과: B의 전체 상태가 저장되면서 A의 새 질문이 사라진다. 별도 메모리 컨텍스트 두 개로 재현했다. - 수정 방향: storage 이벤트 또는 저장 전 최신 상태 확인을 적용한다. 같은 브라우저에서 학습자·관리자 탭을 나란히 검토하는 경우에 해당한다. 여러 PC의 공동 운영을 요구하는 지적이 아니다. ### 6. 문자열 과제의 숫자 허용 범위가 수업·정답과 다름 - 위치: `C:\PNP\Fable\js\data\exercises\ex-l2-01.js:336`, `:62`, `:191`, `:429`. - 과제: 마지막 네 문자는 명시적으로 0–9. - 정답·힌트: Character.isDigit를 사용하며, 수업과 관리자 노트는 다른 문자권의 숫자도 허용하는 방식과 ASCII 범위 검사를 모두 정답으로 인정한다고 설명한다. - 영향: `REF-١٢٣٤` 같은 입력에 두 방식이 다른 결과를 낸다. 평가에서 그 입력을 생략하는 것으로 계약의 모순이 해결되지는 않는다. - 수정 방향: 과제의 ASCII 요구를 유지한다면 정답·힌트도 명시적인 '0'–'9' 검사로 통일한다. ### 7. 관리자가 미답변 질문을 다시 열면 Answered로 표시함 - 위치: `C:\PNP\Fable\js\pages\admin-inbox.js:417`, `:613`; 비교: `js\pages\workspace.js:488`. - 재현 조건: 미답변 질문을 resolved로 만든 뒤 관리자 Reopen. - 결과: 답변 유무와 상관없이 answered가 설정되어 기본 Unanswered 필터에서 빠질 수 있다. 학습자 Reopen은 open을 설정한다. - 수정 방향: 실제 강사 답변 존재 여부에 따라 open/answered를 정하거나 이전 상태를 복원한다. 코드 분기 확인 사항이며 브라우저 데이터를 바꿔 재현하지는 않았다. ## 구현에서 확인한 강점 - 18개 원본 샘플 중 16개 게시, 2개 초안으로 실제 보유 콘텐츠를 정확히 표시한다. - 세 대표 문제는 구체적인 계약, 공개 예제, 충분한 수업 본문, PHP 비교, 단계별 힌트, 다양한 준비 코드와 질문을 갖췄다. - CodeMirror와 Java 모드가 로컬에 포함되어 있어 CDN 연결 없이 편집·구문 강조·괄호 처리·실행 취소를 검토할 수 있다. 대체 textarea 구현도 있다. - 검색/필터와 일부 탭·질문 맥락이 URL에 반영되어 특정 화면을 다시 열기 쉽다. - 기본 채점 모드는 코드 전체를 정규화해 fixture와 비교하고, 임의 코드를 단어 하나로 정답 처리하지 않는다. - Run examples는 정식 제출을 만들지 않고, 제출 소스는 이후 초안과 분리한다. 반복 통과와 이후 실패로 완료를 중복 집계하거나 지우지 않는 기본 규칙은 구현되어 있다. - 강사 답변과 제출 코멘트를 학습자에게 새 소식으로 표시하는 연결이 있다. - 데스크톱 화면의 핵심 Run/Submit 버튼은 확인한 1366×768 화면에서 접근 가능했다. 콘솔 오류·경고는 검토 시점에 확인되지 않았다. ## 검토 한계 - 모든 계정/콘텐츠 CRUD를 실제 브라우저에서 다시 실행하지는 않았다. 관련 오류는 공통 저장소 함수를 메모리 환경에서 검증했다. - 한 차례 최초 화면 진입 때 CodeMirror 줄 번호 영역이 코드 앞부분과 겹치는 현상을 관찰했다. 새로고침 후 사라졌고 일정한 재현 조건은 확정하지 못했으므로 확정 결함 목록에는 넣지 않았다. - UI 검토는 로컬 소스, 실제 화면과 [Web Interface Guidelines](https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md)를 참고했다. 실제 사용자 접근성 테스트 전체를 대신하지 않는다. - Java나 실제 AI를 실행하는 검증은 하지 않았다. 애초에 이번 범위는 정직한 시뮬레이션을 갖춘 프론트엔드 목업이다. ## 개발팀 실행 방법 `C:\PNP\Fable` 폴더 구조를 유지해서 전달한다. Node.js가 있는 환경에서 해당 폴더를 열고: ```text node serve.js ``` 브라우저에서 `http://127.0.0.1:8080`을 연다. 가상 학습자는 `maria / maria-demo`, 관리자는 `admin / admin-demo`이다. 다른 서비스가 8080을 사용하면 `node serve.js 8081`처럼 포트를 지정한다. 권장 전달 문구: 화면과 사용자 흐름을 합의하기 위한 인터랙티브 목업이며, 위 게시/버전/복구 오류는 수정 대상으로 남아 있다. Java/Spring 운영 코드나 검증 완료된 실제 채점기는 아니다.