16 KiB
크리에이터 채널 홈 커뮤니티 응답 확장 Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use
superpowers:subagent-driven-developmentorsuperpowers:executing-plansto implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.
Goal: 크리에이터 채널 홈의 notices와 communities 게시글에 실제 고정 여부와 댓글 가능 여부를 non-null Boolean으로 제공한다.
Architecture: 기존 CreatorChannelCommunityPost가 보유한 두 값을 공유 CreatorChannelCommunityPostResponse.from에서 그대로 매핑한다. 조회 계층과 데이터 모델은 건드리지 않고 공개 응답 DTO와 직접 영향받는 직렬화·E2E 테스트만 수정한다.
Tech Stack: Kotlin, Java 17, Spring Boot 2.7.14, Jackson, JUnit 5, MockMvc, Gradle Wrapper
문서 상태
| 문서 항목 | 내용 |
|---|---|
| 상태 | 구현 중 |
| 작성일 | 2026-08-10 |
| 요구사항 기준 | docs/20260810_크리에이터_채널_홈_커뮤니티_응답_확장/prd.md |
| API 기준 | PRD 7. API 계약 |
| 현재 Phase | Phase 1: 홈 커뮤니티 상태 응답 확장 |
| 현재 활성 Goal | 없음 |
| 다음 Goal | P1-GATE |
현재 상태
| Phase | 상태 | 완료 Task | 활성/다음 Goal | 차단 또는 남은 조건 |
|---|---|---|---|---|
| 1 | 진행 중 | 1/1 |
P1-GATE |
P1-GATE 검증 대기 |
- 동시에 하나의 미완료 goal만 운용한다.
- 완료된 Task와 검증 기록은 되돌리거나 삭제하지 않는다.
- goal 실행 시 token budget을 설정하지 않는다.
범위
포함
GET /api/v2/creator-channels/{creatorId}/home의notices[*],communities[*]에isPinned추가- 같은 게시글 응답에
isCommentAvailable추가 - 도메인 값의 DTO 매핑과 정확한
is*JSON 필드명 검증 - 기존 홈 API E2E와 Kotlin 포맷 회귀 검증
제외
- 조회 조건, 정렬, 최대 노출 개수와 권한 정책 변경
- 커뮤니티 탭·상세·댓글 API 변경
- DB, entity, domain model, repository 수정
- 전용 DTO 분리, 신규 dependency와 관련 없는 리팩터링
Global Constraints
- Kotlin + Java 17, Spring Boot 2.7.14와 기존 Jackson 직렬화 방식을 유지한다.
- 기존 공유
CreatorChannelCommunityPostResponse와from변환만 확장한다. - 공개 필드명은
isPinned,isCommentAvailable로 고정하고 두 값은 nullable로 만들지 않는다. CreatorChannelCommunityPost.isPinned,CreatorChannelCommunityPost.isCommentAvailable값을 재계산하지 않는다.- 구현은 RED → RED 확인 → GREEN → GREEN 확인 → REFACTOR 순서로 진행한다.
- focused test에서 시작해 직접 영향받는 홈 E2E와
ktlintCheck까지만 확장한다. - 전체
./gradlew test는 공통 경계 영향이나 targeted test로 판단할 수 없는 실패가 있을 때만 실행한다.
Phase 1: 홈 커뮤니티 상태 응답 확장
Phase 결과: 홈 API의 공지와 일반 커뮤니티 게시글이 고정 여부와 댓글 가능 여부를 정확한 Boolean 필드로 반환한다.
선행조건: 승인된 PRD의 CCHC-001~004, DEC-001~003 확인.
Phase 완료 조건: P1-T1과 P1-GATE 완료, 체크박스와 실제 검증 결과를 Progress에 누적.
Task 1.1 공유 게시글 응답에 상태 필드 추가
Goal 실행 P1-T1: 공유 홈 게시글 응답이 도메인의 isPinned, isCommentAvailable을 정확한 JSON 필드로 직렬화하게 한다.
- 시작 조건: PRD 상태가
구현 기준 확정이고 현재 활성 Goal이 없다. - 완료 증거: 아래 5단계 완료, controller focused test와 홈 E2E 통과, 변경 파일과 결과를 Progress에 기록.
- 범위 밖: 조회 service/repository, domain model, 다른 커뮤니티 API 수정.
Files:
- Modify:
src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/adapter/in/web/CreatorChannelHomeControllerTest.kt:92 - Modify:
src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/CreatorChannelHomeEndToEndTest.kt:57 - Modify:
src/main/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/dto/CreatorChannelHomeResponse.kt:173 - Modify:
docs/20260810_크리에이터_채널_홈_커뮤니티_응답_확장/plan-task.md
Interfaces:
-
Consumes:
CreatorChannelCommunityPost.isPinned: Boolean,CreatorChannelCommunityPost.isCommentAvailable: Boolean -
Produces:
CreatorChannelCommunityPostResponse.isPinned: Boolean,CreatorChannelCommunityPostResponse.isCommentAvailable: Boolean -
JSON:
data.notices[*].isPinned,data.notices[*].isCommentAvailable,data.communities[*].isPinned,data.communities[*].isCommentAvailable -
RED:
CreatorChannelHomeControllerTest.shouldReturnCreatorChannelHomeForAuthenticatedMember의 일반 커뮤니티 fixture를 아래처럼 공지와 반대 상태로 만들고, 네 JSON 경로 assertion을 추가한다. 같은 assertion을CreatorChannelHomeEndToEndTest.shouldAssembleCreatorChannelHomeSectionsThroughSingleHttpRequest에도 추가하되 E2E fixture의 댓글 가능 값은 기존true를 사용한다.
communities = listOf(
post.copy(
postId = 302L,
content = "community",
isCommentAvailable = false,
isPinned = false
)
)
.andExpect(jsonPath("$.data.notices[0].isPinned").value(true))
.andExpect(jsonPath("$.data.notices[0].isCommentAvailable").value(true))
.andExpect(jsonPath("$.data.communities[0].isPinned").value(false))
.andExpect(jsonPath("$.data.communities[0].isCommentAvailable").value(false))
E2E assertion은 실제 저장값과 조회 조건을 검증한다.
.andExpect(jsonPath("$.data.notices[0].isPinned").value(true))
.andExpect(jsonPath("$.data.notices[0].isCommentAvailable").value(true))
.andExpect(jsonPath("$.data.communities[0].isPinned").value(false))
.andExpect(jsonPath("$.data.communities[0].isCommentAvailable").value(true))
- RED 확인: 다음 focused test를 실행해
$.data.notices[0].isPinned등 신규 JSON 경로에 값이 없어 실패하는지 확인한다.
./gradlew test --tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.home.adapter.in.web.CreatorChannelHomeControllerTest' --no-daemon
Expected: 테스트가 신규 필드 미직렬화로 실패한다. compile 오류나 fixture 오류는 RED 증거로 인정하지 않는다.
- GREEN:
CreatorChannelCommunityPostResponse에 기존 커뮤니티 탭 DTO와 같은@JsonProperty관례로 필드를 추가하고from에서 도메인 값을 직접 매핑한다.
data class CreatorChannelCommunityPostResponse(
val postId: Long,
val creatorId: Long,
val creatorNickname: String,
val creatorProfileUrl: String,
val imageUrl: String?,
val audioUrl: String?,
val content: String,
val price: Int,
val dateUtc: String,
val existOrdered: Boolean,
@JsonProperty("isCommentAvailable")
val isCommentAvailable: Boolean,
val likeCount: Int,
val commentCount: Int,
@JsonProperty("isPinned")
val isPinned: Boolean,
@JsonProperty("isLiked")
val isLiked: Boolean
) {
companion object {
fun from(post: CreatorChannelCommunityPost): CreatorChannelCommunityPostResponse {
return CreatorChannelCommunityPostResponse(
postId = post.postId,
creatorId = post.creatorId,
creatorNickname = post.creatorNickname,
creatorProfileUrl = post.creatorProfileUrl,
imageUrl = post.imageUrl,
audioUrl = post.audioUrl,
content = post.content,
price = post.price,
dateUtc = post.createdAt.toUtcIso(),
existOrdered = post.existOrdered,
isCommentAvailable = post.isCommentAvailable,
likeCount = post.likeCount,
commentCount = post.commentCount,
isPinned = post.isPinned,
isLiked = post.isLiked
)
}
}
}
- GREEN 확인: controller test와 홈 E2E를 함께 실행해 공유 DTO 매핑, JSON 이름, 실제 조회값이 모두 통과하는지 확인한다.
./gradlew test \
--tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.home.adapter.in.web.CreatorChannelHomeControllerTest' \
--tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.home.CreatorChannelHomeEndToEndTest' \
--no-daemon
Expected: 두 테스트 클래스가 BUILD SUCCESSFUL로 종료된다.
- REFACTOR: 새 abstraction을 만들지 않고 이번 Task가 추가한 fixture·필드·매핑만 정리한다. 다음 명령을 실행하고 결과를
P1-T1Progress에 기록한다.
./gradlew ktlintCheck --no-daemon
git diff --check
Expected: 두 명령 모두 exit code 0.
- Commit: 커밋 전후 규칙 검증과 함께 구현·테스트·Progress 변경만 커밋한다.
work/scripts/check-commit-message-rules.sh --message "feat(creator-channel): 홈 커뮤니티 응답 상태를 추가한다"
git add \
src/main/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/dto/CreatorChannelHomeResponse.kt \
src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/adapter/in/web/CreatorChannelHomeControllerTest.kt \
src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/CreatorChannelHomeEndToEndTest.kt \
docs/20260810_크리에이터_채널_홈_커뮤니티_응답_확장/plan-task.md
git commit -m "feat(creator-channel): 홈 커뮤니티 응답 상태를 추가한다"
work/scripts/check-commit-message-rules.sh HEAD
Phase 1 Gate
Goal 실행 P1-GATE: PRD의 네 확정 요구사항과 작은 변경 범위를 최종 판정한다.
- 시작 조건:
P1-T1의 체크박스, focused test, E2E, 포맷과 Progress 기록 완료. - 완료 증거: 아래 자동 검증 통과, PRD 추적성 확인, Gate 결과를 Progress에 기록.
- 범위 밖: Gate 통과를 위한 test 삭제·skip·완화와 관련 없는 코드 수정.
./gradlew test \
--tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.home.adapter.in.web.CreatorChannelHomeControllerTest' \
--tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.home.CreatorChannelHomeEndToEndTest' \
--no-daemon
./gradlew ktlintCheck --no-daemon
./gradlew tasks --all --no-daemon
git diff --check
Expected: 모든 명령이 exit code 0이고 다음 조건이 충족된다.
notices[*]와communities[*]에 두 non-null Boolean이 존재한다. (CCHC-001~003)notices[*].isPinned == true,communities[*].isPinned == false가 실제 조회 조건과 일치한다.- 댓글 가능 값이
true와false모두 그대로 직렬화된다. - endpoint, 인증, 기존 홈 응답 필드와 조회 결과가 유지된다. (
CCHC-004) - 전체 회귀 테스트를 생략한 근거와 대신 실행한 focused·E2E 검증을 Progress에 기록한다.
실행 순서와 의존성
| 순서 | Goal | 선행조건 | 병행 가능 | 차단 시 다음 행동 |
|---|---|---|---|---|
| 1 | P1-T1 |
승인된 PRD | 아니요 | RED 실패 원인이 신규 필드 누락인지 다시 확인 |
| 2 | P1-GATE |
P1-T1 완료 |
아니요 | 실패를 소유한 Task에 회귀 수정 goal 추가 |
P1-T1 → P1-GATE
변경 금지 항목
- 공개 필드명이나 기존 홈 응답 필드를 근거 없이 변경하지 않는다.
- domain, service, repository에서 두 Boolean을 재계산하지 않는다.
- 전용 DTO, helper, 신규 dependency를 추가하지 않는다.
- 테스트를 삭제·skip·완화하거나 관련 없는 코드를 정리하지 않는다.
- 기존 완료 기록과 Decision Log를 삭제하거나 덮어쓰지 않는다.
의사결정 및 중단 규칙
- 구현 범위가 바뀌면 PRD Decision Log와 이 계획을 먼저 갱신한다.
- 신규 JSON 필드 외 실패가 발생하면 원인을 분리하고 범위 밖 변경을 임의로 적용하지 않는다.
- targeted test로 영향 범위를 판단할 수 없을 때만 전체
./gradlew test --no-daemon을 실행한다. - 체크박스와 완료 증거, Progress 기록이 모두 충족된 뒤에만 goal을 완료 처리한다.
Progress
실행 전이다. 구현 시 기존 기록을 삭제하지 않고 Goal별 실행 결과를 아래에 누적한다.
P1-T1
- RED 작성: controller fixture의 일반 게시글을
postId=302L,content="community",isCommentAvailable=false,isPinned=false로 구성하고 controller 및 E2E에 공지/일반 게시글 상태 assertion을 추가했다. - RED 확인:
./gradlew test --tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.home.adapter.in.web.CreatorChannelHomeControllerTest' --no-daemon은 exit code1로 실패했다.CreatorChannelHomeControllerTest.kt:138의$.data.notices[0].isPinnedassertion에서PathNotFoundException이 발생해 신규 JSON 필드 미직렬화가 원인임을 확인했으며 compile 및 fixture 오류는 없었다. - GREEN 구현:
CreatorChannelCommunityPostResponse에 non-null BooleanisCommentAvailable,isPinned을 명시적@JsonProperty와 함께 추가하고post.isCommentAvailable,post.isPinned을 직접 매핑했다. - GREEN 확인:
./gradlew test --tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.home.adapter.in.web.CreatorChannelHomeControllerTest' --tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.home.CreatorChannelHomeEndToEndTest' --no-daemon은 exit code0,BUILD SUCCESSFUL in 54s로 종료됐다. controller focused test와 직접 영향받는 홈 E2E가 함께 통과해 공지true/true, 일반 게시글false/falsecontroller fixture 및false/true실제 E2E 저장값의 매핑과 JSON 이름을 확인했다. - REFACTOR 확인: 새 abstraction 없이 계획된 fixture, 응답 필드, 직접 매핑만 유지했다.
./gradlew ktlintCheck --no-daemon은 exit code0,BUILD SUCCESSFUL in 25s였고git diff --check도 exit code0이었다. - 전체 회귀 생략: 이번 변경은 공유 홈 DTO의 additive 직렬화 필드 두 개와 직접 영향받는 테스트에 한정되고 controller focused test와 실제 저장·조회 E2E가 모두 통과했으므로 계획의 조건에 따라 전체
./gradlew test는 실행하지 않았다. - 변경 파일:
src/main/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/dto/CreatorChannelHomeResponse.kt,src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/adapter/in/web/CreatorChannelHomeControllerTest.kt,src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/CreatorChannelHomeEndToEndTest.kt,docs/20260810_크리에이터_채널_홈_커뮤니티_응답_확장/plan-task.md. - 커밋 검증: 커밋 전
work/scripts/check-commit-message-rules.sh --message "feat(creator-channel): 홈 커뮤니티 응답 상태를 추가한다"가 모든 규칙을[PASS]로 확인했다. 최종 diff는 계획된 네 파일만 포함하고 비밀값, 관련 없는 변경, agent footer가 없음을 자체 검토했다.
Decision Log
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 Goal/문서 |
|---|---|---|---|---|---|
| 2026-08-10 | PLAN-DEC-001 |
확정 | 하나의 구현 Task와 하나의 Gate로 실행한다. | 공유 DTO 한 곳의 additive 변경이며 별도 구현 경계가 없다. | P1-T1, P1-GATE |
| 2026-08-10 | PLAN-DEC-002 |
확정 | 전체 회귀는 조건부로 두고 controller test, 홈 E2E, ktlintCheck를 기본 검증으로 사용한다. |
변경이 홈 게시글 응답 직렬화 경계에 한정된다. | P1-T1, P1-GATE |
발견된 문제
없음.