You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
우주 탐험 도메인을 신규 구현. 행성(planet) → 지역(region) 2단계 트리를 연료로 해금하며, 이전 행성을 클리어해야 다음 행성을 해금할 수 있는 진행 게이트를 포함. 시드 데이터는 프론트(Flutter) 게스트 시드와 1:1로 일치시켜 게스트/회원 모드 간 정합성 확보. 구현 검증 중 Flyway가 실제로는 한 번도 실행되지 않던 잠복 인프라 버그를 발견·수정.
실제 dev DB에 Flyway migrate 실행으로 시드 적용 검증: exploration_nodes planet=8, region=30(38노드), 행성 순서 earth, mercury, venus, mars, jupiter, saturn, uranus, neptune 확인
🔄 코드 리뷰(CodeRabbit) 반영
PR #42 자동 리뷰 12건을 점검·triage하여 실제 결함만 수정(커밋 a24577a).
🔴 무료 지역(requiredFuel=0)으로 인한 행성 클리어 영구 불가 — 수정
문제: getRegions는 requiredFuel==0 지역(예: korea)을 암묵 해금/클리어로 취급하나, getPlanets의 진행도 집계와 isPlanetCleared는 진행도 레코드가 있는 지역만 카운트. 무료 지역은 진행도 레코드가 절대 생성되지 않으므로(해금 시 ALREADY_UNLOCKED), 무료 지역을 가진 지구가 영원히 클리어되지 않음 → 수성 해금이 영구 차단(PREREQUISITE_NOT_CLEARED). 게임 진행 불가
수정: clearedByParent 집계와 isPlanetCleared 모두 requiredFuel == 0 || unlocked.contains(id)로 보정 → getRegions와 일관되게 무료 지역을 클리어로 인정
테스트 보강: unlockPlanet_success에서 무료 지역을 진행도 맵에 넣어 결함을 가리던 픽스처를, 진행도 없이도 클리어 인정되는 실제 상태로 교정
반박/유지 (리뷰 도구가 맥락 미보유)
해금 응답 201 제안: 프론트 계약이 200 OK로 고정 → 200 유지
커밋 #27 포맷 지적: 짧은 이슈 태그(#27)는 사용자 명시 선호 → 유지
plan 문서 커밋 단계 지적: 승인된 워크플로우 절차 기술일 뿐 → 유지
보류 (별도 처리 권장)
unlockedAt 타임존: LocalDateTime.now()를 UTC로 직렬화 → JVM TZ가 UTC 아니면 오프셋 가능. 단, fuel/timer/todo 등 프로젝트 전체 공통 컨벤션이라 탐험만 고치면 불일치. 서버 TZ를 UTC로 고정하는 전역 개선으로 별도 처리 권장
문서 정리
spec/plan의 로컬 절대경로 → 레포 상대경로
exploration-frontend-requirements.md §8.2 비교표에 "구버전 스냅샷, 본 PR에서 해소" 주석 추가
📌 참고사항
게스트(로컬)와 회원(서버)은 완전히 분리. 게스트→회원 마이그레이션은 범위 밖
동기화 Tier 2(Server-Validated): 해금은 온라인 필수, 서버에서 잔량 확인·차감·해금 원자 처리
API 스펙 문서(docs/api-specs/05_exploration.md)를 구현에 맞춰 갱신(prerequisiteId, PREREQUISITE_NOT_CLEARED, 시드 값/아이콘 규칙)
서버 직접 실행: SPRING_PROFILES_ACTIVE=dev ./gradlew :SS-Web:bootRun
Activity
EM-H20 commentedon Apr 22, 2026
Guide by SUH-LAB
브랜치
커밋 메시지
탐험 도메인 구현 : feat : 탐험 ErrorCode 5종 + INSUFFICIENT_FUEL 응답 보강 #27
탐험 도메인 구현 : feat : NodeType enum + Converter 추가 #27
탐험 도메인 구현 : feat : ExplorationNode 마스터 엔티티 추가 #27
탐험 도메인 구현 : feat : UserExploration 진행 엔티티 추가 #27
탐험 도메인 구현 : feat : Exploration Repository 2종 + 테스트 #27
탐험 도메인 구현 : test : ErrorResponse @JsonInclude 직렬화 검증 추가 #27
탐험 도메인 구현 : feat : Exploration DTO 6종 추가 #27
탐험 도메인 구현 : feat : ExplorationService 목록 조회 2종 #27
탐험 도메인 구현 : feat : 지역 해금 로직 + 잔량 pre-check + 자동 클리어 #27
탐험 도메인 구현 : feat : 행성 해금 로직 + 선행 클리어 게이트 #27
탐험 도메인 구현 : test : 해금 서비스 에러 경로에 ErrorCode 검증 추가 #27
탐험 도메인 구현 : feat : ExplorationController 4 엔드포인트 + 테스트 #27
탐험 도메인 구현 : chore : exploration 테이블 + 시드 38노드 마이그레이션 #27
탐험 도메인 구현 : docs : 05_exploration 스펙 frontend 계약 정합 갱신 #27
docs : 구현 문서 #27
탐험 도메인 구현 : fix : 무료 지역(requiredFuel=0) 행성 클리어 누락 수정 + 진행도 일관성 #27
Merge pull request #42 from SpaceStudyShip/20260422_#27_행성_지역_해금_도메인_구현
EM-H20 commentedon May 29, 2026
행성/지역 해금(탐험) 도메인 구현 (#27)
📌 작업 개요
우주 탐험 도메인을 신규 구현. 행성(planet) → 지역(region) 2단계 트리를 연료로 해금하며, 이전 행성을 클리어해야 다음 행성을 해금할 수 있는 진행 게이트를 포함. 시드 데이터는 프론트(Flutter) 게스트 시드와 1:1로 일치시켜 게스트/회원 모드 간 정합성 확보. 구현 검증 중 Flyway가 실제로는 한 번도 실행되지 않던 잠복 인프라 버그를 발견·수정.
🎯 구현 목표
docs/api-specs/exploration-frontend-requirements.md) 충족✅ 구현 내용
API 엔드포인트 (SS-Web)
SS-Web/.../controller/exploration/ExplorationController.java/api/explorations하위 4개 엔드포인트GET /planets— 행성 목록 + 유저 해금/클리어/진행도GET /planets/{planetId}/regions— 행성 하위 지역 목록 + 해금 상태POST /regions/{regionId}/unlock— 지역 해금POST /planets/{planetId}/unlock— 행성 해금마스터/진행 엔티티 (SS-Study)
study/exploration/entity/ExplorationNode.java,UserExploration.javaExplorationNode: 행성/지역 공통 마스터(시드 전용, 읽기 전용).nodeType,prerequisiteNodeId(선행 행성),requiredFuel,mapX/Y등UserExploration: 유저별 해금 상태. 행이 존재하면 해금됨을 의미.UNIQUE(user_id, node_id)로 중복 해금 방지해금/조회 로직 (SS-Study)
study/exploration/service/ExplorationService.javaclearedChildren/totalChildren/progressRatio)를 저장하지 않고 조회 시 파생 계산requiredFuel == 0인 노드(지구, 대한민국)는 행 없이도 암묵적으로 해금 처리REGION_NOT_FOUND/PLANET_LOCKED/ALREADY_UNLOCKED검증 → 연료 잔량 pre-check →FuelService.consume→ 해금 행 저장 → (지역) 상위 행성 자동 클리어 판정PREREQUISITE_NOT_CLEARED@Transactional로 두어FuelService.consume와 동일 트랜잭션에 묶음 → 연료 차감/거래내역/해금이 원자적DTO (SS-Study)
study/exploration/dto/—PlanetResponse,RegionResponse,ProgressDto,UnlockedNodeDto,RegionUnlockResponse,PlanetUnlockResponse(record)nodeType는 소문자(planet/region) 직렬화, 행성 응답에prerequisiteId·progress포함, 해금 응답에currentFuel포함(프론트가 fuel 별도 조회 불필요)에러 처리 + INSUFFICIENT_FUEL 응답 보강 (SS-Common)
common/exception/ErrorCode.java,ErrorResponse.java,InsufficientFuelException.java,GlobalExceptionHandler.javaPLANET_NOT_FOUND,REGION_NOT_FOUND,ALREADY_UNLOCKED,PLANET_LOCKED,PREREQUISITE_NOT_CLEARED)ErrorResponse에 nullablerequiredFuel/currentFuel추가 +@JsonInclude(NON_NULL)→ 연료 부족 시에만 해당 필드 노출, 기존 에러 응답 형식은 불변시드 데이터 (마이그레이션)
SS-Web/.../db/migration/V0_0_42__add_exploration.sqlexploration_nodes,user_exploration_progress테이블 + 시드 38노드(행성 8 + 지역 30)exploration_seed_data.dart)와 id/아이콘/연료/정렬을 row-by-row로 동일하게 맞춰 게스트/회원 코드·렌더링 재사용🔧 주요 변경사항 상세
Flyway 미실행 인프라 버그 수정 (중요)
구현 후
GET /planets가 빈 배열을 반환하는 현상 발생. 원인 추적 결과:exploration_nodes테이블은 있으나 0행,flyway_schema_history테이블 자체가 부재 → Flyway가 한 번도 실행된 적 없음flyway-core는 클래스패스에 있으나, Spring Boot 4가 autoconfiguration을 기술별 모듈로 분리하면서 Flyway 연동 모듈(spring-boot-flyway)이 누락됨. Boot 3에선flyway-core만으로 자동 실행됐으나 Boot 4에선 이 모듈이 있어야FlywayMigrationInitializer가 작동ddl-auto=update가 생성, 마이그레이션 5개는 모두 무력 상태였음(다른 도메인은 시드가 없어 표면화되지 않음)수정:
SS-Common/build.gradle—org.springframework.boot:spring-boot-flyway의존성 추가SS-Web/.../application.yml—baseline-version: 0추가baseline-on-migrate의 기본 baseline(버전 1)이0.0.x마이그레이션을 "이미 적용됨"으로 스킵하는 문제 방지. 0으로 두어 0.0.31~0.0.42 전부 적용되게 함특이사항:
CREATE TABLE IF NOT EXISTS로 건너뛰므로, 마이그레이션에 정의된 CHECK/FK 제약이 그 테이블엔 안 붙어 있을 수 있음(Hibernate-우선 설정의 기존 특성, 시드 동작엔 영향 없음)IF NOT EXISTS/ON CONFLICT DO NOTHING이라 기존 데이터에 안전기본 해금 / 진행 게이트
requiredFuel == 0노드는 진행 행 없이 암묵 해금 → 지구/대한민국이 시작 시점부터 열림📦 의존성 변경
org.springframework.boot:spring-boot-flyway추가 (Spring Boot 4 Flyway autoconfiguration 모듈)🧪 테스트 및 검증
SS-Common/SS-Study/SS-Web전체 테스트 통과 확인exploration_nodesplanet=8, region=30(38노드), 행성 순서earth, mercury, venus, mars, jupiter, saturn, uranus, neptune확인🔄 코드 리뷰(CodeRabbit) 반영
PR #42 자동 리뷰 12건을 점검·triage하여 실제 결함만 수정(커밋
a24577a).🔴 무료 지역(requiredFuel=0)으로 인한 행성 클리어 영구 불가 — 수정
getRegions는requiredFuel==0지역(예:korea)을 암묵 해금/클리어로 취급하나,getPlanets의 진행도 집계와isPlanetCleared는 진행도 레코드가 있는 지역만 카운트. 무료 지역은 진행도 레코드가 절대 생성되지 않으므로(해금 시ALREADY_UNLOCKED), 무료 지역을 가진 지구가 영원히 클리어되지 않음 → 수성 해금이 영구 차단(PREREQUISITE_NOT_CLEARED). 게임 진행 불가study/exploration/service/ExplorationService.javaclearedByParent집계와isPlanetCleared모두requiredFuel == 0 || unlocked.contains(id)로 보정 →getRegions와 일관되게 무료 지역을 클리어로 인정unlockPlanet_success에서 무료 지역을 진행도 맵에 넣어 결함을 가리던 픽스처를, 진행도 없이도 클리어 인정되는 실제 상태로 교정반박/유지 (리뷰 도구가 맥락 미보유)
#27포맷 지적: 짧은 이슈 태그(#27)는 사용자 명시 선호 → 유지보류 (별도 처리 권장)
unlockedAt타임존:LocalDateTime.now()를 UTC로 직렬화 → JVM TZ가 UTC 아니면 오프셋 가능. 단, fuel/timer/todo 등 프로젝트 전체 공통 컨벤션이라 탐험만 고치면 불일치. 서버 TZ를 UTC로 고정하는 전역 개선으로 별도 처리 권장문서 정리
exploration-frontend-requirements.md§8.2 비교표에 "구버전 스냅샷, 본 PR에서 해소" 주석 추가📌 참고사항
docs/api-specs/05_exploration.md)를 구현에 맞춰 갱신(prerequisiteId, PREREQUISITE_NOT_CLEARED, 시드 값/아이콘 규칙)SPRING_PROFILES_ACTIVE=dev ./gradlew :SS-Web:bootRun