test #426
@@ -349,7 +349,7 @@ data class HomeFollowingNewsInboxRecord(
|
|||||||
|
|
||||||
### Phase 1: 응답 DTO, 도메인 모델, Security 기본 골격
|
### Phase 1: 응답 DTO, 도메인 모델, Security 기본 골격
|
||||||
|
|
||||||
- [ ] **Task 1.1: 팔로잉 탭 응답 DTO와 domain model 추가**
|
- [x] **Task 1.1: 팔로잉 탭 응답 DTO와 domain model 추가**
|
||||||
- Files:
|
- Files:
|
||||||
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/following/dto/HomeFollowingTabResponse.kt`
|
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/following/dto/HomeFollowingTabResponse.kt`
|
||||||
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/domain/HomeFollowing.kt`
|
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/domain/HomeFollowing.kt`
|
||||||
@@ -362,7 +362,7 @@ data class HomeFollowingNewsInboxRecord(
|
|||||||
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
||||||
- REFACTOR: import, `JsonProperty`, nullable 필드 정리 후 `./gradlew --no-daemon ktlintCheck` 실행.
|
- REFACTOR: import, `JsonProperty`, nullable 필드 정리 후 `./gradlew --no-daemon ktlintCheck` 실행.
|
||||||
|
|
||||||
- [ ] **Task 1.2: Controller와 Security permitAll 추가**
|
- [x] **Task 1.2: Controller와 Security permitAll 추가**
|
||||||
- Files:
|
- Files:
|
||||||
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/following/adapter/in/web/HomeFollowingController.kt`
|
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/following/adapter/in/web/HomeFollowingController.kt`
|
||||||
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/following/application/HomeFollowingFacade.kt`
|
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/following/application/HomeFollowingFacade.kt`
|
||||||
@@ -377,7 +377,7 @@ data class HomeFollowingNewsInboxRecord(
|
|||||||
|
|
||||||
### Phase 2: 최근 소식 Inbox 저장소
|
### Phase 2: 최근 소식 Inbox 저장소
|
||||||
|
|
||||||
- [ ] **Task 2.1: Inbox Entity/JPA repository/DDL 정합성 구현**
|
- [x] **Task 2.1: Inbox Entity/JPA repository/DDL 정합성 구현**
|
||||||
- Files:
|
- Files:
|
||||||
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/adapter/out/persistence/HomeFollowingNewsInbox.kt`
|
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/adapter/out/persistence/HomeFollowingNewsInbox.kt`
|
||||||
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/adapter/out/persistence/HomeFollowingNewsInboxJpaRepository.kt`
|
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/adapter/out/persistence/HomeFollowingNewsInboxJpaRepository.kt`
|
||||||
@@ -390,7 +390,7 @@ data class HomeFollowingNewsInboxRecord(
|
|||||||
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
||||||
- REFACTOR: 컬럼명, enum 저장 방식, timestamp nullable 정책이 DDL과 맞는지 비교한다.
|
- REFACTOR: 컬럼명, enum 저장 방식, timestamp nullable 정책이 DDL과 맞는지 비교한다.
|
||||||
|
|
||||||
- [ ] **Task 2.2: Inbox persistence adapter 구현**
|
- [x] **Task 2.2: Inbox persistence adapter 구현**
|
||||||
- Files:
|
- Files:
|
||||||
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/port/out/HomeFollowingNewsInboxPort.kt`
|
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/port/out/HomeFollowingNewsInboxPort.kt`
|
||||||
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/adapter/out/persistence/HomeFollowingNewsInboxPersistenceAdapter.kt`
|
- Create: `src/main/kotlin/kr/co/vividnext/sodalive/v2/home/following/adapter/out/persistence/HomeFollowingNewsInboxPersistenceAdapter.kt`
|
||||||
@@ -398,9 +398,9 @@ data class HomeFollowingNewsInboxRecord(
|
|||||||
- RED: `insertIgnoreAll(records)`가 중복 source key를 예외 없이 무시하고 신규 row만 저장하는 테스트를 작성한다.
|
- RED: `insertIgnoreAll(records)`가 중복 source key를 예외 없이 무시하고 신규 row만 저장하는 테스트를 작성한다.
|
||||||
- RED: `findActiveFollowerIds(creatorId)`가 활성 팔로워만 반환하는 테스트를 작성한다.
|
- RED: `findActiveFollowerIds(creatorId)`가 활성 팔로워만 반환하는 테스트를 작성한다.
|
||||||
- 실패 확인: Task 2.1과 같은 단일 테스트 명령 실행, port/adapter 미구현 실패 확인.
|
- 실패 확인: Task 2.1과 같은 단일 테스트 명령 실행, port/adapter 미구현 실패 확인.
|
||||||
- GREEN: MySQL `INSERT IGNORE` 기반 bulk 저장으로 unique 충돌을 무시하는 idempotent 저장을 최소 구현한다.
|
- GREEN: JPA `saveAndFlush`와 unique 제약 기반 `DataIntegrityViolationException` 처리로 중복 source key를 예외 없이 무시하는 idempotent 저장을 최소 구현한다.
|
||||||
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
||||||
- REFACTOR: batch insert가 불필요하게 N+1 flush를 만들지 않도록 adapter 내부를 정리한다.
|
- REFACTOR: H2/MySQL dialect 분기 없이 단일 JPA 경로를 유지하고, 동시 적재 시 inserted count는 best-effort임을 검증 기록에 남긴다.
|
||||||
|
|
||||||
### Phase 3: 팔로잉 탭 조회 Repository/Service
|
### Phase 3: 팔로잉 탭 조회 Repository/Service
|
||||||
|
|
||||||
@@ -461,6 +461,15 @@ data class HomeFollowingNewsInboxRecord(
|
|||||||
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
||||||
- REFACTOR: `nowProvider: () -> LocalDateTime`을 주입해 테스트 시간을 고정한다.
|
- REFACTOR: `nowProvider: () -> LocalDateTime`을 주입해 테스트 시간을 고정한다.
|
||||||
|
|
||||||
|
- [ ] **Task 3.6: Inbox 중복 insert 충돌 통합 테스트 보강**
|
||||||
|
- Files:
|
||||||
|
- Modify: `src/test/kotlin/kr/co/vividnext/sodalive/v2/home/following/adapter/out/persistence/HomeFollowingNewsInboxPersistenceAdapterTest.kt`
|
||||||
|
- RED: 실제 `HomeFollowingNewsInboxJpaRepository`로 동일 `memberId/newsType/sourceKey` unique 충돌을 발생시킨 뒤, 같은 테스트 흐름에서 `insertIgnoreAll(records)` 또는 repository 조회가 예외 없이 동작하는 통합 테스트를 작성한다.
|
||||||
|
- 실패 확인: `./gradlew --no-daemon test --tests "kr.co.vividnext.sodalive.v2.home.following.adapter.out.persistence.HomeFollowingNewsInboxPersistenceAdapterTest"` 실행, 실제 DB 충돌 후 persistence context/transaction 상태 검증 실패를 확인한다.
|
||||||
|
- GREEN: 필요 시 adapter의 중복 충돌 처리에서 persistence context 정리 또는 트랜잭션 경계를 최소 보강한다.
|
||||||
|
- 통과 확인: 같은 단일 테스트 명령 실행, PASS 확인.
|
||||||
|
- REFACTOR: mock 기반 race 테스트와 통합 테스트의 책임을 분리해, mock은 분기 검증만 하고 통합 테스트는 실제 Hibernate 세션/트랜잭션 유효성을 검증하도록 정리한다.
|
||||||
|
|
||||||
### Phase 4: 최근 소식 Publish Service와 기존 이벤트 연결
|
### Phase 4: 최근 소식 Publish Service와 기존 이벤트 연결
|
||||||
|
|
||||||
- [ ] **Task 4.1: sourceKey 생성 정책 구현**
|
- [ ] **Task 4.1: sourceKey 생성 정책 구현**
|
||||||
@@ -588,4 +597,9 @@ data class HomeFollowingNewsInboxRecord(
|
|||||||
|
|
||||||
## 6. 검증 기록
|
## 6. 검증 기록
|
||||||
|
|
||||||
- 문서 작성 시점에는 구현 검증 기록 없음.
|
- 2026-06-25 Phase 1-2 구현 검증:
|
||||||
|
- `./gradlew --no-daemon test --tests "kr.co.vividnext.sodalive.v2.api.home.following.dto.HomeFollowingTabResponseTest"` 실행 결과 `BUILD SUCCESSFUL`.
|
||||||
|
- `./gradlew --no-daemon test --tests "kr.co.vividnext.sodalive.v2.api.home.following.adapter.in.web.HomeFollowingControllerTest"` 실행 결과 `BUILD SUCCESSFUL`.
|
||||||
|
- `./gradlew --no-daemon test --tests "kr.co.vividnext.sodalive.v2.home.following.adapter.out.persistence.HomeFollowingNewsInboxPersistenceAdapterTest"` 실행 결과 `BUILD SUCCESSFUL`.
|
||||||
|
- 병렬 Gradle 실행 중 `build/snapshot/kotlin/kaptGenerateStubsKotlin` 삭제 충돌이 1회 발생해 동일 명령을 순차 재실행했다.
|
||||||
|
- `insertIgnoreAll`은 H2/MySQL dialect 분기 없이 JPA `saveAndFlush`와 unique 제약 기반 중복 예외 재확인 단일 경로로 검증했다.
|
||||||
|
|||||||
Reference in New Issue
Block a user