Repository navigation
feat: 시뮬레이션 결과 화면 분리 — 새 라우트 /experience/simulation (#36) - #37
Merged
Merged
Conversation
| // 결과 화면(신규 라우트)이 이어받을 수 있게 program·result 스냅샷을 남긴다 — | ||
| // ExperienceView 는 라우트를 넘어가면 새로 마운트돼 이 mutation 상태를 잃는다. | ||
| writeSimulationResult({ program, result }); | ||
| router.push('/experience/simulation'); |
There was a problem hiding this comment.
🟠 MEDIUM · ERROR_HANDLING
결과 저장 실패에도 결과 라우트로 이동해 시뮬레이션 결과가 사라집니다
writeSimulationResult()는 sessionStorage 접근 거부나 용량 초과를 내부에서 삼키지만, 호출자는 성공 여부를 알 수 없고 항상 router.push()를 실행합니다. 이동한 결과 화면은 저장된 값이 없어 즉시 /experience로 되돌아가므로, 완료된 시뮬레이션 결과와 실패 이유가 사용자에게 전혀 표시되지 않습니다.
저장 함수가 성공 여부를 반환하게 하고 성공한 경우에만 이동하거나, 저장에 실패하면 현재 화면에서 결과를 표시하고 오류 안내를 제공해야 합니다.
| if (!store) return null; | ||
| try { | ||
| const raw = store.getItem(KEY); | ||
| return raw ? (JSON.parse(raw) as StoredSimulationResult) : null; |
There was a problem hiding this comment.
🟠 MEDIUM · DATA_INTEGRITY
JSON 구문만 유효하면 잘못된 저장 데이터도 결과 객체로 신뢰합니다
JSON.parse 결과를 구조 검증 없이 StoredSimulationResult로 단언합니다. JSON 자체는 유효하지만 program, stack, result 또는 숫자 필드가 빠진 값이면 읽기는 성공하고, 이후 program.stack, result.passed, totalDistanceM.toFixed() 접근 중 결과 페이지가 예외로 중단됩니다. 저장 데이터의 형태와 필수 필드를 검증하고 불일치 시 null로 처리해야 합니다.
Simulation "시뮬레이션 실행"이 페이지 필요:YES 로 바뀌어, 워크스페이스 안 텍스트 힌트 대신 전용 결과 화면(Figma Slide 6 실패·Slide 7 성공)을 새로 분리했다. - SimulationResult.failedAtIndex 추가: repeat 를 실제 실행 횟수만큼 펼친 순서 기준으로 안전 구역을 벗어난 지점(1-based) — evaluateProgram 이 계산 - views/experience/model: unrollExecutionSteps — 같은 펼치기 규칙을 클라이 언트에서 재사용해 "실행순서" 단계 목록을 만든다 - SimulationResultView: 결과 카드(성공/실패) + 실행순서(완료/문제 발생/ 대기) + 실행 블록(BlockStack 재사용) + 로봇 미리보기(배지·진행 바) - simulationResultStorage: ExperienceView ↔ 결과 화면 간 program·result 스냅샷을 sessionStorage 로 전달 (라우트 이동 시 리액트 state 소실 보완) - ExperienceView: 시뮬레이션 성공/실패 모두 결과 화면으로 이동, 결과 화면에서 돌아왔을 때(같은 program 이면) 통과 상태를 이어받아 RunReadyWorkspace 를 그대로 보여준다 - '블록 고치기'·'로봇 실행하기' 버튼은 모두 /experience 로 돌아간다 — 실제 실행 요청은 기존 RunReadyWorkspace 흐름 그대로 유지 테스트 인프라: next/navigation useRouter 를 테스트 전역에서 mock (기존 "invariant expected app router to be mounted" 회피) — shared/testing/routerMock.ts Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
wook10
force-pushed
the
feature/36-simulation-result
branch
from
September 16, 2026 14:11
6fbb605 to
9169605
Compare
inryeok-bot MEDIUM 2건:
1. ERROR_HANDLING — writeSimulationResult() 가 sessionStorage 저장 실패
(용량 초과·접근 거부 등)를 내부에서 삼키는데도 호출자는 항상 결과
화면으로 이동했다. 그 화면은 읽을 게 없어 곧장 /experience 로 돌아가
방금 끝난 시뮬레이션 결과가 안내 없이 사라졌다.
→ writeSimulationResult 가 성공 여부를 반환하고, 실패하면 이동하지
않는다(이 화면의 기존 인라인 안내로 계속 보여준다).
2. DATA_INTEGRITY — readSimulationResult() 가 JSON.parse 결과를 구조
검증 없이 StoredSimulationResult 로 단언했다. 필드가 빠지거나 타입이
어긋난 저장값도 그대로 신뢰해, 결과 화면이 program.stack 등에 접근
하다 예외로 죽을 수 있었다.
→ program 은 기존 isBlockProgramSnapshot 재사용, result 는 새
isSimulationResultShape 로 필드·타입을 확인하고, 하나라도 어긋나면
null 로 처리한다(localDraft 복원과 같은 방어 패턴).
테스트: simulationResultStorage.test.ts 신규(왕복·저장 실패·손상값 4종),
ExperienceView.test.tsx 에 저장 실패 시 이동하지 않고 인라인으로 계속
보여주는 통합 테스트 추가.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
개요
Closes #36
Simulation 기능명세서의 "시뮬레이션 실행"이
페이지 필요: YES로 바뀌어, 워크스페이스 안 텍스트 힌트 대신 Figma Slide 6(실패)·Slide 7(성공)의 전용 결과 화면을 새 라우트로 분리했다.기명서·Figma 대조표
/experience/simulation+SimulationResultView시뮬레이션 통과!(초록) / 실패:조금만 고치면 돼요!(빨강) + 안전 위반 메시지unrollExecutionSteps로 repeat 를 실제 실행 횟수만큼 펼치고, 서버가 계산한failedAtIndex기준으로 단계별 상태 표시BlockStack그대로 재사용(읽기 전용)/experience로 복귀 — 돌아간 화면에서 ExperienceView 가 남겨진 결과를 이어받아 BlockWorkspace/RunReadyWorkspace 중 맞는 쪽을 그대로 보여줌(기존 RunReadyWorkspace 흐름 유지)구현
features/simulation:SimulationResult.failedAtIndex추가.evaluateProgram이 repeat 를 실제 실행 횟수만큼 펼쳐(unroll) 안전 구역을 처음 벗어나는 위치를 계산views/experience/model/blockProgram.ts:unrollExecutionSteps— 서버와 같은 펼치기 규칙을 클라이언트에서 재사용해 실행순서 목록을 만든다(서버 응답은 인덱스 숫자만 주고, 목록 자체는 클라이언트가 이미 가진 program 으로 만든다 — 페이로드 최소화)views/experience/lib/simulationResultStorage.ts: ExperienceView ↔ 결과 화면 간 전달용 sessionStorage 스냅샷(program+result). ExperienceView 는 라우트를 넘어가면 새로 마운트돼 mutation state 를 잃기 때문에 필요views/experience/ui/SimulationResultView.tsx: 신규 컴포넌트views/experience/ui/ExperienceView.tsx: 시뮬레이션 성공/실패 모두 결과 화면으로 라우팅, 복귀 시 저장된 결과가 지금 program 과 일치하면(그 사이 편집 안 했으면) 통과 상태를 이어받음테스트
simulateProgram.test.ts:failedAtIndex계산 3건(안전 구역 위반 위치, 반복+개별 이동 합산 시 위치, 값 무효 시 undefined) + 통과 시 undefinedblockProgram.test.ts:unrollExecutionSteps3건(non-repeat 통과, repeat count 만큼 펼침, 펼친 단계가 원래 파라미터 보존)SimulationResultView.test.tsx: 신규 3건(저장된 결과 없으면 리다이렉트, 실패 화면 배지·상태·버튼, 성공 화면 배지·상태·버튼)ExperienceView.test.tsx: 신규 6건(결과 화면으로 이동 — 통과/실패 모두, 스냅샷 기록, 복귀 시 통과 이어받기, program 불일치 시 무시, 처음으로 시 기록도 함께 삭제)typecheck/lint/build/format:check클린참고
useRouter를 테스트에서 쓸 수 있게src/shared/testing/routerMock.ts+vitest.setup.ts전역 mock 추가(기존엔 App Router 컴포넌트를 렌더하는 테스트가 없어 필요 없었음)🤖 Generated with Claude Code