docs(following): 팔로잉 해제 확인 계획을 추가한다
This commit is contained in:
@@ -0,0 +1,358 @@
|
|||||||
|
# 팔로잉 해제 확인과 버튼 UI 구현 계획
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use `subagent-driven-development` or `executing-plans` to implement this plan task-by-task. 이 문서는 구현 계획이며, 현재 요청에서는 코드 구현을 수행하지 않는다.
|
||||||
|
|
||||||
|
**Goal:** 팔로잉 리스트와 크리에이터 채널에서 팔로우 해제 전 `V2ModalDialog` 확인을 거치고, 팔로잉 리스트의 팔로잉 중 버튼을 크리에이터 채널과 같은 원형 스타일로 맞춘다.
|
||||||
|
|
||||||
|
**Architecture:** 기존 `V2ModalDialog`와 기존 follow/unfollow delegate를 재사용한다. 팔로잉 리스트는 legacy 화면이지만 요청 동작을 위해 `FollowingCreatorActivity`, `FollowingCreatorAdapter`, `item_follower_list.xml`에만 최소 변경을 계획한다.
|
||||||
|
|
||||||
|
**Tech Stack:** Android Kotlin, XML layout/drawable/string resources, RxJava 기반 기존 ViewModel 흐름, `app/src/test` local/source tests.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
| 문서 항목 | 내용 |
|
||||||
|
|---|---|
|
||||||
|
| 상태 | 계획 작성 완료 |
|
||||||
|
| 작성일 | `2026-08-18` |
|
||||||
|
| 요구사항 기준 | `docs/20260818_팔로잉_해제_확인과_버튼_UI/prd.md` |
|
||||||
|
| API 기준 | 변경 없음 |
|
||||||
|
| 현재 Phase | 구현 대기 |
|
||||||
|
| 현재 활성 Goal | 없음 |
|
||||||
|
|
||||||
|
## 목표
|
||||||
|
|
||||||
|
사용자가 팔로잉 리스트 또는 크리에이터 채널에서 팔로우 해제를 시도하면 확인 Dialog를 본 뒤 명시적으로 확인한 경우에만 기존 팔로우 해제 프로세스가 실행된다.
|
||||||
|
|
||||||
|
## 현재 상태
|
||||||
|
|
||||||
|
| Phase | 상태 | 완료 Task | 활성/다음 Goal | 차단 또는 남은 조건 |
|
||||||
|
|---:|---|---:|---|---|
|
||||||
|
| 1 | 대기 | `0/3` | `P1-T1` | 코드 구현 승인 필요 |
|
||||||
|
| 2 | 대기 | `0/1` | `P2-T1` | Phase 1 완료 필요 |
|
||||||
|
| 3 | 대기 | `0/2` | `P3-T1` | Phase 2 완료 필요 |
|
||||||
|
| 4 | 대기 | `0/1` | `P4-T1` | Phase 2 완료 필요 |
|
||||||
|
| 5 | 대기 | `0/1` | `P5-GATE` | Phase 1~4 완료 필요 |
|
||||||
|
|
||||||
|
## 범위
|
||||||
|
|
||||||
|
### 포함
|
||||||
|
|
||||||
|
- 팔로잉 리스트 팔로잉 중 버튼의 icon/background/shape 변경 계획.
|
||||||
|
- 팔로잉 리스트 팔로잉 중 버튼의 Bottom Sheet route 제거 계획.
|
||||||
|
- 팔로잉 리스트와 크리에이터 채널의 팔로우 해제 확인 Dialog 적용 계획.
|
||||||
|
- 한국어, 일본어, 영어 string resource 추가 계획.
|
||||||
|
- `app/src/test` 기반 local/source test 계획.
|
||||||
|
|
||||||
|
### 제외
|
||||||
|
|
||||||
|
- 이 문서 작성 작업에서의 코드 구현.
|
||||||
|
- `CreatorFollowNotifyFragment` 자체 수정 또는 삭제.
|
||||||
|
- API, Repository, ViewModel 계약 변경.
|
||||||
|
- 신규 dependency 또는 공통 abstraction 추가.
|
||||||
|
- `app/src/androidTest`, `connectedDebugAndroidTest`, 기기·에뮬레이터 UI 조작, 스크린샷·시각 QA.
|
||||||
|
- 요청 범위 밖 레거시 리팩터링.
|
||||||
|
|
||||||
|
## 기술적 제약
|
||||||
|
|
||||||
|
- 기존 `V2ModalDialog` 생성자와 `show(screenWidth)` 패턴을 재사용한다.
|
||||||
|
- Dialog description은 string resource의 `%1$s`에 크리에이터 이름을 넣어 만든다.
|
||||||
|
- 팔로잉 리스트 legacy 파일 변경은 요청 동작에 필요한 최소 범위로 제한한다.
|
||||||
|
- 테스트는 source/local test로 route, resource 선택, callback 호출 여부를 검증한다.
|
||||||
|
- layout 크기, constraint, pixel-perfect 결과는 자동 테스트 대상으로 삼지 않는다.
|
||||||
|
|
||||||
|
## 파일 구조
|
||||||
|
|
||||||
|
| File | 계획된 역할 |
|
||||||
|
|---|---|
|
||||||
|
| `app/src/main/java/kr/co/vividnext/sodalive/following/FollowingCreatorActivity.kt` | 팔로잉 중 클릭 route를 Bottom Sheet에서 `V2ModalDialog` 확인 후 기존 unfollow 호출로 변경한다. |
|
||||||
|
| `app/src/main/java/kr/co/vividnext/sodalive/following/FollowingCreatorAdapter.kt` | 팔로잉 중 상태의 아이콘/배경 리소스 선택을 변경한다. |
|
||||||
|
| `app/src/main/res/layout/item_follower_list.xml` | 팔로잉 중 버튼에 원형 배경을 적용할 수 있는 구조를 최소 반영한다. |
|
||||||
|
| `app/src/main/res/drawable/bg_following_circle_gray_800.xml` | 팔로잉 리스트 팔로잉 중 버튼의 `gray_800` 원형 배경을 제공한다. |
|
||||||
|
| `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt` | 팔로잉 중 캡슐 클릭 시 즉시 unfollow하지 않고 Dialog 확인 후 기존 delegate를 호출한다. |
|
||||||
|
| `app/src/main/java/kr/co/vividnext/sodalive/v2/components/modal/V2ModalDialog.kt` | 수정하지 않고 재사용한다. 기존 API 한계가 증명될 때만 계획 갱신 후 수정한다. |
|
||||||
|
| `app/src/main/res/values/strings.xml` | 한국어 Dialog 문구를 추가한다. |
|
||||||
|
| `app/src/main/res/values-en/strings.xml` | 영어 Dialog 문구를 추가한다. |
|
||||||
|
| `app/src/main/res/values-ja/strings.xml` | 일본어 Dialog 문구를 추가한다. |
|
||||||
|
| `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorAdapterSourceTest.kt` | 팔로잉 중 버튼 리소스 계약을 검증한다. 없으면 생성한다. |
|
||||||
|
| `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorActivitySourceTest.kt` | 팔로잉 리스트 route 계약을 검증한다. 없으면 생성한다. |
|
||||||
|
| `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt` | 크리에이터 채널 즉시 unfollow 계약을 Dialog 확인 계약으로 갱신한다. |
|
||||||
|
| `app/src/test/java/kr/co/vividnext/sodalive/v2/components/modal/V2ModalDialogTest.kt` | Dialog callback, 버튼, description 회귀를 확인한다. |
|
||||||
|
| `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeViewModelTest.kt` | 기존 unfollow 성공/실패 흐름 회귀를 확인한다. |
|
||||||
|
|
||||||
|
## Phase 1. 테스트로 현재 동작 고정
|
||||||
|
|
||||||
|
**Phase 결과:** 기존 구현이 요청 동작과 다른 지점을 local/source test로 먼저 드러낸다.
|
||||||
|
|
||||||
|
**선행조건:** `prd.md`의 `UNFOLLOW-001~006` 확정.
|
||||||
|
|
||||||
|
**Phase 완료 조건:** `P1-T1`~`P1-T3` 완료, 각 RED 확인 기록 누적.
|
||||||
|
|
||||||
|
### 구현 항목
|
||||||
|
|
||||||
|
#### Task 1.1 팔로잉 리스트 버튼 표현 계약
|
||||||
|
|
||||||
|
**Goal 실행 `P1-T1`:** 팔로잉 리스트 팔로잉 중 버튼이 요청 리소스를 사용해야 함을 source/local test로 고정한다.
|
||||||
|
|
||||||
|
- **시작 조건:** `UNFOLLOW-001`, `UNFOLLOW-002` 확정.
|
||||||
|
- **완료 증거:** test가 기존 `btn_following_big`, `btn_following_no_alarm_big` 사용 때문에 실패한다.
|
||||||
|
- **범위 밖:** 실제 adapter/layout 구현 변경.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
|
||||||
|
- Create: `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorAdapterSourceTest.kt` if no equivalent exists
|
||||||
|
- Modify: equivalent existing following adapter source/local test if present
|
||||||
|
- Test: `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorAdapterSourceTest.kt`
|
||||||
|
|
||||||
|
- [ ] **RED:** `FollowingCreatorAdapter.kt`가 팔로잉 중 branch에서 `R.drawable.ic_new_following_white`와 `R.drawable.bg_creator_channel_following_capsule` 또는 동등한 `gray_800` 원형 배경을 참조하는지 검증하는 source/local test를 작성한다.
|
||||||
|
- [ ] **RED 확인:** `./gradlew :app:test --tests "kr.co.vividnext.sodalive.following.FollowingCreatorAdapterSourceTest"`를 실행해 현재 팔로잉 중 branch가 기존 이미지 리소스를 사용하므로 실패함을 확인한다.
|
||||||
|
- [ ] **GREEN:** 이 Task에서는 production 구현을 하지 않는다. 다음 구현 Task `P3-T1`에서 처리한다.
|
||||||
|
- [ ] **GREEN 확인:** `P3-T1` 완료 후 같은 focused test 성공을 기록한다.
|
||||||
|
- [ ] **REFACTOR:** test가 문자열 과검증이면 요청 리소스 계약만 남기고 이번 Task가 만든 중복만 정리한다.
|
||||||
|
|
||||||
|
#### Task 1.2 팔로잉 리스트 팔로우 해제 route 계약
|
||||||
|
|
||||||
|
**Goal 실행 `P1-T2`:** 팔로잉 리스트 팔로잉 중 클릭이 Bottom Sheet가 아니라 `V2ModalDialog`를 거쳐야 함을 source/local test로 고정한다.
|
||||||
|
|
||||||
|
- **시작 조건:** `UNFOLLOW-003`, `UNFOLLOW-004` 확정.
|
||||||
|
- **완료 증거:** test가 `CreatorFollowNotifyFragment` route 잔존과 Dialog 미사용 때문에 실패한다.
|
||||||
|
- **범위 밖:** 실제 Activity 구현 변경.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
|
||||||
|
- Create: `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorActivitySourceTest.kt` if no equivalent exists
|
||||||
|
- Modify: equivalent existing following activity source/local test if present
|
||||||
|
- Test: `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorActivitySourceTest.kt`
|
||||||
|
|
||||||
|
- [ ] **RED:** `FollowingCreatorActivity.kt`가 팔로잉 중 branch에서 `CreatorFollowNotifyFragment`를 생성하지 않고 `V2ModalDialog`를 생성하는지 검증한다.
|
||||||
|
- [ ] **RED:** 확인 callback 안에서만 `viewModel.follow(creatorId, follow = false, notify = false)`가 호출되는지 source/local test로 검증한다.
|
||||||
|
- [ ] **RED 확인:** `./gradlew :app:test --tests "kr.co.vividnext.sodalive.following.FollowingCreatorActivitySourceTest"`를 실행해 현재 Bottom Sheet route 때문에 실패함을 확인한다.
|
||||||
|
- [ ] **GREEN:** 이 Task에서는 production 구현을 하지 않는다. 다음 구현 Task `P3-T2`에서 처리한다.
|
||||||
|
- [ ] **GREEN 확인:** `P3-T2` 완료 후 같은 focused test 성공을 기록한다.
|
||||||
|
- [ ] **REFACTOR:** Dialog route와 unfollow callback 검증 외의 문자열 과검증은 제거한다.
|
||||||
|
|
||||||
|
#### Task 1.3 크리에이터 채널 팔로우 해제 확인 계약
|
||||||
|
|
||||||
|
**Goal 실행 `P1-T3`:** 크리에이터 채널 팔로잉 중 캡슐이 즉시 unfollow하지 않고 Dialog 확인을 거쳐야 함을 source/local test로 고정한다.
|
||||||
|
|
||||||
|
- **시작 조건:** `UNFOLLOW-005`, `UNFOLLOW-006` 확정.
|
||||||
|
- **완료 증거:** 기존 `onFollowCapsuleClicked()`가 즉시 `homeActionDelegate?.follow(false, false)`를 호출하므로 test가 실패한다.
|
||||||
|
- **범위 밖:** 실제 Activity 구현 변경.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
|
||||||
|
- Modify: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt`
|
||||||
|
- Test: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt`
|
||||||
|
|
||||||
|
- [ ] **RED:** `onFollowCapsuleClicked()`의 팔로잉 중 branch가 `V2ModalDialog`를 생성하고 description에 현재 header nickname을 전달하도록 기대값을 갱신한다.
|
||||||
|
- [ ] **RED:** `homeActionDelegate?.follow(follow = false, notify = false)` 호출이 Dialog confirm callback 안에만 있어야 함을 검증한다.
|
||||||
|
- [ ] **RED 확인:** `./gradlew :app:test --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"`를 실행해 현재 즉시 unfollow 구현 때문에 실패함을 확인한다.
|
||||||
|
- [ ] **GREEN:** 이 Task에서는 production 구현을 하지 않는다. 다음 구현 Task `P4-T1`에서 처리한다.
|
||||||
|
- [ ] **GREEN 확인:** `P4-T1` 완료 후 같은 focused test 성공을 기록한다.
|
||||||
|
- [ ] **REFACTOR:** 기존 title bar, owner, bell 동작 test가 깨지지 않도록 변경 범위를 팔로잉 해제 branch로 제한한다.
|
||||||
|
|
||||||
|
## Phase 2. 공통 Dialog 문구 리소스 추가
|
||||||
|
|
||||||
|
**Phase 결과:** 두 화면이 같은 string resource 계약으로 Dialog 문구를 사용할 수 있다.
|
||||||
|
|
||||||
|
**선행조건:** Phase 1 RED 확인 완료.
|
||||||
|
|
||||||
|
**Phase 완료 조건:** `P2-T1` 완료와 locale resource 검증 기록 누적.
|
||||||
|
|
||||||
|
### 구현 항목
|
||||||
|
|
||||||
|
#### Task 2.1 다국어 string resource 추가
|
||||||
|
|
||||||
|
**Goal 실행 `P2-T1`:** 팔로우 해제 확인 Dialog 문구를 한국어, 영어, 일본어 resource로 추가한다.
|
||||||
|
|
||||||
|
- **시작 조건:** `DEC-001` 한국어 문구 확정.
|
||||||
|
- **완료 증거:** 세 locale 파일 모두 같은 resource name과 `%1$s` placeholder를 가진다.
|
||||||
|
- **범위 밖:** Activity에서 resource를 소비하는 구현.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
|
||||||
|
- Modify: `app/src/main/res/values/strings.xml`
|
||||||
|
- Modify: `app/src/main/res/values-en/strings.xml`
|
||||||
|
- Modify: `app/src/main/res/values-ja/strings.xml`
|
||||||
|
- Test: `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorActivitySourceTest.kt` or equivalent resource/source test
|
||||||
|
|
||||||
|
- [ ] **RED:** 세 locale에 `creator_unfollow_confirm_title`, `creator_unfollow_confirm_desc`, `creator_unfollow_confirm_cancel`, `creator_unfollow_confirm_confirm`가 없어서 실패하는 source/local test를 작성한다.
|
||||||
|
- [ ] **RED 확인:** 관련 focused test를 실행해 resource 누락 실패를 확인한다.
|
||||||
|
- [ ] **GREEN:** 한국어 `팔로우 해제`, `팔로우를 해제할까요?\n%1$s의 소식을 받을 수 없어요.`, `취소`, `해제하기`를 추가한다.
|
||||||
|
- [ ] **GREEN:** 영어 `Unfollow`, `You’ll no longer receive updates from %1$s.\nDo you want to unfollow?`, `Cancel`, `Unfollow`를 추가한다.
|
||||||
|
- [ ] **GREEN:** 일본어 `フォロー解除`, `%1$sからの最新情報を受け取れなくなります。\nフォローを解除しますか?`, `キャンセル`, `解除する`를 추가한다.
|
||||||
|
- [ ] **GREEN 확인:** focused test를 다시 실행해 resource 계약 성공을 확인한다.
|
||||||
|
- [ ] **REFACTOR:** 중복 literal이 Activity에 남지 않도록 resource 소비 Task에서만 참조하도록 계획을 유지한다.
|
||||||
|
|
||||||
|
## Phase 3. 팔로잉 리스트 변경
|
||||||
|
|
||||||
|
**Phase 결과:** 팔로잉 리스트의 팔로잉 중 버튼 UI와 팔로우 해제 route가 요구사항과 일치한다.
|
||||||
|
|
||||||
|
**선행조건:** Phase 1, Phase 2 완료.
|
||||||
|
|
||||||
|
**Phase 완료 조건:** `P3-T1`, `P3-T2` 완료와 focused test 성공 기록 누적.
|
||||||
|
|
||||||
|
### 구현 항목
|
||||||
|
|
||||||
|
#### Task 3.1 팔로잉 중 버튼 UI 변경
|
||||||
|
|
||||||
|
**Goal 실행 `P3-T1`:** 팔로잉 리스트 팔로잉 중 버튼을 요청 아이콘과 원형 `gray_800` 배경으로 표시한다.
|
||||||
|
|
||||||
|
- **시작 조건:** `P1-T1`, `P2-T1` 완료.
|
||||||
|
- **완료 증거:** `P1-T1` focused test 성공.
|
||||||
|
- **범위 밖:** 팔로우 시작 버튼, 프로필 이미지, nickname layout 변경.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
|
||||||
|
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/following/FollowingCreatorAdapter.kt`
|
||||||
|
- Modify: `app/src/main/res/layout/item_follower_list.xml`
|
||||||
|
- Create: `app/src/main/res/drawable/bg_following_circle_gray_800.xml`
|
||||||
|
- Test: `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorAdapterSourceTest.kt`
|
||||||
|
|
||||||
|
- [ ] **RED:** `P1-T1` test 실패 상태를 확인한다.
|
||||||
|
- [ ] **RED 확인:** 실패 원인이 팔로잉 중 리소스 불일치임을 기록한다.
|
||||||
|
- [ ] **GREEN:** `item.isFollow` branch에서 `binding.ivFollow.setImageResource(R.drawable.ic_new_following_white)`를 사용하도록 최소 변경한다.
|
||||||
|
- [ ] **GREEN:** `ivFollow`에 `gray_800`과 `100dp` radius를 사용하는 `bg_following_circle_gray_800`을 적용하고, 팔로잉 중에만 `8dp` padding을 적용해 크리에이터 채널과 같은 `36dp` 원형 크기를 만든다.
|
||||||
|
- [ ] **GREEN 확인:** `./gradlew :app:test --tests "kr.co.vividnext.sodalive.following.FollowingCreatorAdapterSourceTest"` 성공을 확인한다.
|
||||||
|
- [ ] **REFACTOR:** 알림 on/off 분기에서 더 이상 다른 팔로잉 중 이미지를 쓰지 않도록 중복 branch만 정리한다.
|
||||||
|
|
||||||
|
#### Task 3.2 팔로잉 리스트 Bottom Sheet route 제거와 확인 Dialog 적용
|
||||||
|
|
||||||
|
**Goal 실행 `P3-T2`:** 팔로잉 리스트 팔로잉 중 클릭이 `V2ModalDialog` 확인 후에만 기존 unfollow를 실행한다.
|
||||||
|
|
||||||
|
- **시작 조건:** `P1-T2`, `P2-T1` 완료.
|
||||||
|
- **완료 증거:** `P1-T2` focused test 성공.
|
||||||
|
- **범위 밖:** 팔로우 시작 branch와 알림 설정 Bottom Sheet 자체 수정.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
|
||||||
|
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/following/FollowingCreatorActivity.kt`
|
||||||
|
- Test: `app/src/test/java/kr/co/vividnext/sodalive/following/FollowingCreatorActivitySourceTest.kt`
|
||||||
|
|
||||||
|
- [ ] **RED:** `P1-T2` test 실패 상태를 확인한다.
|
||||||
|
- [ ] **RED 확인:** 실패 원인이 `CreatorFollowNotifyFragment` route와 Dialog 미사용임을 기록한다.
|
||||||
|
- [ ] **GREEN:** `onClickFollow` callback이 Dialog description을 만들 수 있도록 클릭 대상의 creator name을 받을 수 있는 최소 경로를 정한다.
|
||||||
|
- [ ] **GREEN:** 팔로잉 중 branch에서 `CreatorFollowNotifyFragment` 생성과 `show()` 호출을 제거한다.
|
||||||
|
- [ ] **GREEN:** 팔로잉 중 branch에서 `V2ModalDialog(activity = this, layoutInflater = layoutInflater, title = getString(...), desc = getString(..., creatorName), confirmButtonTitle = getString(...), confirmButtonClick = { viewModel.follow(creatorId, follow = false, notify = false) }, cancelButtonTitle = getString(...))`를 생성해 `show(screenWidth)`로 표시한다.
|
||||||
|
- [ ] **GREEN 확인:** `./gradlew :app:test --tests "kr.co.vividnext.sodalive.following.FollowingCreatorActivitySourceTest"` 성공을 확인한다.
|
||||||
|
- [ ] **REFACTOR:** 사용하지 않게 된 import와 이번 변경이 만든 중복만 제거한다.
|
||||||
|
|
||||||
|
## Phase 4. 크리에이터 채널 변경
|
||||||
|
|
||||||
|
**Phase 결과:** 크리에이터 채널 팔로잉 중 캡슐이 확인 Dialog 없이 바로 팔로우 해제하지 않는다.
|
||||||
|
|
||||||
|
**선행조건:** Phase 1, Phase 2 완료.
|
||||||
|
|
||||||
|
**Phase 완료 조건:** `P4-T1` 완료와 focused test 성공 기록 누적.
|
||||||
|
|
||||||
|
### 구현 항목
|
||||||
|
|
||||||
|
#### Task 4.1 크리에이터 채널 팔로우 해제 확인 Dialog 적용
|
||||||
|
|
||||||
|
**Goal 실행 `P4-T1`:** `CreatorChannelActivity.onFollowCapsuleClicked()` 팔로잉 중 branch에서 Dialog 확인 후 기존 delegate를 호출한다.
|
||||||
|
|
||||||
|
- **시작 조건:** `P1-T3`, `P2-T1` 완료.
|
||||||
|
- **완료 증거:** `CreatorChannelActivitySourceTest` 성공.
|
||||||
|
- **범위 밖:** 팔로우 시작 branch, 알림 bell 토글, owner 상태 변경.
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
|
||||||
|
- Modify: `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivity.kt`
|
||||||
|
- Test: `app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelActivitySourceTest.kt`
|
||||||
|
|
||||||
|
- [ ] **RED:** `P1-T3` test 실패 상태를 확인한다.
|
||||||
|
- [ ] **RED 확인:** 실패 원인이 즉시 `homeActionDelegate?.follow(false, false)` 호출임을 기록한다.
|
||||||
|
- [ ] **GREEN:** `!header.isFollow` branch는 기존 즉시 follow 동작으로 유지한다.
|
||||||
|
- [ ] **GREEN:** `header.isFollow` branch에서 `V2ModalDialog`를 생성하고 `desc = getString(R.string.creator_unfollow_confirm_desc, header.nickname)`를 전달한다.
|
||||||
|
- [ ] **GREEN:** confirm callback 안으로 기존 `homeActionDelegate?.follow(follow = false, notify = false)`를 이동한다.
|
||||||
|
- [ ] **GREEN 확인:** `./gradlew :app:test --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"` 성공을 확인한다.
|
||||||
|
- [ ] **REFACTOR:** `showDeleteCreatorChannelCommunityPostDialog()`의 기존 `V2ModalDialog` 사용 패턴과 어긋나는 중복만 정리한다.
|
||||||
|
|
||||||
|
## Phase 5. 검증
|
||||||
|
|
||||||
|
**Phase 결과:** 요청 범위의 local/source test와 관련 회귀가 통과한다.
|
||||||
|
|
||||||
|
**선행조건:** Phase 1~4 완료.
|
||||||
|
|
||||||
|
**Phase 완료 조건:** `P5-GATE` 완료와 Verification Log 기록.
|
||||||
|
|
||||||
|
### 검증 방법
|
||||||
|
|
||||||
|
#### Phase 5 Gate
|
||||||
|
|
||||||
|
**Goal 실행 `P5-GATE`:** 팔로잉 리스트와 크리에이터 채널 팔로우 해제 확인 흐름을 최종 판정한다.
|
||||||
|
|
||||||
|
- **시작 조건:** 모든 구현 Task 완료.
|
||||||
|
- **완료 증거:** 아래 명령과 Expected 통과, Progress와 Verification Log 기록.
|
||||||
|
- **범위 밖:** 실패와 무관한 기능 수정, test 삭제·완화.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew :app:test --tests "kr.co.vividnext.sodalive.following.FollowingCreatorAdapterSourceTest"
|
||||||
|
./gradlew :app:test --tests "kr.co.vividnext.sodalive.following.FollowingCreatorActivitySourceTest"
|
||||||
|
./gradlew :app:test --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivitySourceTest"
|
||||||
|
./gradlew :app:test --tests "kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialogTest"
|
||||||
|
./gradlew :app:test --tests "kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelHomeViewModelTest"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected:** 모든 명령이 exit code 0으로 종료되고, 팔로잉 리스트 Bottom Sheet route 제거, 양 화면 `V2ModalDialog` 확인 후 unfollow, 다국어 resource 계약이 검증된다.
|
||||||
|
|
||||||
|
## 실행 순서와 의존성
|
||||||
|
|
||||||
|
| 순서 | Goal | 선행조건 | 병행 가능 | 차단 시 다음 행동 |
|
||||||
|
|---:|---|---|---|---|
|
||||||
|
| 1 | `P1-T1` | PRD 확정 | 예, `P1-T2`, `P1-T3`와 병행 가능 | test 대상 파일 재확인 |
|
||||||
|
| 2 | `P1-T2` | PRD 확정 | 예, `P1-T1`, `P1-T3`와 병행 가능 | following activity route 재확인 |
|
||||||
|
| 3 | `P1-T3` | PRD 확정 | 예, `P1-T1`, `P1-T2`와 병행 가능 | creator channel source test 재확인 |
|
||||||
|
| 4 | `P2-T1` | Phase 1 RED 확인 | 아니요 | resource name 충돌 확인 |
|
||||||
|
| 5 | `P3-T1` | `P1-T1`, `P2-T1` | 예, `P4-T1`과 병행 가능 | adapter/layout 책임 재확인 |
|
||||||
|
| 6 | `P3-T2` | `P1-T2`, `P2-T1` | 아니요 | creator name 전달 경로 재확인 |
|
||||||
|
| 7 | `P4-T1` | `P1-T3`, `P2-T1` | 예, `P3-T1`과 병행 가능 | currentHeader nickname 사용 가능성 재확인 |
|
||||||
|
| 8 | `P5-GATE` | Phase 3, Phase 4 완료 | 아니요 | 실패 소유 Task로 회귀 수정 Task 추가 |
|
||||||
|
|
||||||
|
```text
|
||||||
|
P1-T1 ┐
|
||||||
|
P1-T2 ├→ P2-T1 → P3-T1 → P3-T2 ┐
|
||||||
|
P1-T3 ┘ └→ P4-T1 ───────┴→ P5-GATE
|
||||||
|
```
|
||||||
|
|
||||||
|
## 변경 금지 항목
|
||||||
|
|
||||||
|
- 코드 구현 승인 없이 production/test 파일을 수정하지 않는다.
|
||||||
|
- `CreatorFollowNotifyFragment`를 삭제하거나 다른 화면의 사용처를 변경하지 않는다.
|
||||||
|
- API, DTO, Repository, ViewModel 계약을 근거 없이 변경하지 않는다.
|
||||||
|
- 신규 dependency 또는 단일 사용 abstraction을 추가하지 않는다.
|
||||||
|
- test를 삭제·skip·완화하지 않는다.
|
||||||
|
- 기존 완료 기록과 Decision Log를 삭제하거나 덮어쓰지 않는다.
|
||||||
|
|
||||||
|
## Progress
|
||||||
|
|
||||||
|
기존 기록을 삭제하거나 덮어쓰지 않고 실제 실행 결과를 차수별로 누적한다.
|
||||||
|
|
||||||
|
### 문서 작성 1차 실행 — 2026-08-18
|
||||||
|
|
||||||
|
- 상태: 완료
|
||||||
|
- 무엇을: PRD와 구현 계획 문서를 작성했다.
|
||||||
|
- 왜: 사용자 요청이 코드 구현 없이 문서 생성까지만 요구했기 때문이다.
|
||||||
|
- 어떻게:
|
||||||
|
- `docs/sample/sample-prd.md` 확인 — PRD 구조 기준 확인.
|
||||||
|
- `docs/sample/sample-plan-task.md` 확인 — 계획/TASK 구조 기준 확인.
|
||||||
|
- `codegraph`로 `FollowingCreatorActivity.kt`, `FollowingCreatorAdapter.kt`, `CreatorChannelActivity.kt`, `V2ModalDialog.kt` 관련 흐름 확인.
|
||||||
|
- 남은 항목: 코드 구현은 사용자 승인 전까지 대기.
|
||||||
|
- 다음 행동: 사용자가 구현을 요청하면 `P1-T1`부터 진행한다.
|
||||||
|
|
||||||
|
## Decision Log
|
||||||
|
|
||||||
|
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 Goal/문서 |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| `2026-08-18` | `DEC-001` | 확정 | 한국어 본문은 `팔로우를 해제할까요?\n%1$s의 소식을 받을 수 없어요.`를 사용한다. | 사용자 A안 선택 | `P2-T1` |
|
||||||
|
| `2026-08-18` | `DEC-002` | 확정 | 시각 보조 브라우저는 사용하지 않는다. | 사용자 응답 | 문서 작성 방식 |
|
||||||
|
| `2026-08-18` | `DEC-003` | 확정 | 현재 요청에서는 코드 구현을 하지 않는다. | 사용자 명시 요청 | 전체 계획 |
|
||||||
|
|
||||||
|
## 발견된 문제
|
||||||
|
|
||||||
|
| ID | 심각도 | 상태 | 발견 내용 | 영향 Goal | 처리 계획 |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 없음 | Low | 해결 | 문서 작성 중 구현 차단 이슈 없음 | 없음 | 없음 |
|
||||||
|
|
||||||
|
## Verification Log
|
||||||
|
|
||||||
|
- 2026-08-18: 문서 생성 작업만 수행했다. 사용자 요청에 따라 production/test 코드 구현과 Gradle test 실행은 수행하지 않았다.
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
# 팔로잉 해제 확인과 버튼 UI PRD
|
||||||
|
|
||||||
|
## 문서 정보
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|---|---|
|
||||||
|
| 문서 상태 | 구현 기준 확정 |
|
||||||
|
| 작성일 | `2026-08-18` |
|
||||||
|
| 최종 수정일 | `2026-08-18` |
|
||||||
|
| 대상 제품 | 팔로잉 리스트, 크리에이터 채널 팔로우/팔로잉 액션 |
|
||||||
|
| 작성자·결정권자 | 사용자 요청 기준 |
|
||||||
|
| 관련 API Contract | 변경 없음 |
|
||||||
|
| 관련 구현 계획 | `docs/20260818_팔로잉_해제_확인과_버튼_UI/plan-task.md` |
|
||||||
|
| 관련 review | 없음 |
|
||||||
|
|
||||||
|
## 1. Overview
|
||||||
|
|
||||||
|
팔로잉 리스트와 크리에이터 채널에서 팔로잉 해제 동작을 더 명확하고 안전하게 만든다. 팔로잉 리스트의 팔로잉 중 버튼은 크리에이터 채널의 팔로잉 중 버튼과 같은 원형 스타일을 사용하고, 팔로잉 해제 요청은 두 화면 모두 `V2ModalDialog` 확인 후에만 진행한다.
|
||||||
|
|
||||||
|
## 2. Problem Statement
|
||||||
|
|
||||||
|
현재 사용자는 다음 문제를 겪는다.
|
||||||
|
|
||||||
|
- 팔로잉 리스트의 팔로잉 중 버튼 UI가 크리에이터 채널의 팔로잉 중 상태와 다르다.
|
||||||
|
- 팔로잉 리스트에서 팔로잉 중 버튼을 누르면 `CreatorFollowNotifyFragment` Bottom Sheet 액션 메뉴가 표시된다.
|
||||||
|
- 크리에이터 채널에서는 팔로잉 중 버튼을 누르면 확인 없이 바로 팔로우 해제가 진행된다.
|
||||||
|
|
||||||
|
문제를 해결했다는 판단은 팔로잉 리스트와 크리에이터 채널 모두에서 팔로잉 해제 전 `V2ModalDialog`가 표시되고, 확인 버튼을 누른 경우에만 기존 팔로우 해제 API 흐름이 실행되는 것으로 한다.
|
||||||
|
|
||||||
|
## 3. Goals
|
||||||
|
|
||||||
|
### 3.1 제품 목표
|
||||||
|
|
||||||
|
- 팔로잉 리스트의 팔로잉 중 버튼을 `ic_new_following_white`, `gray_800`, 크리에이터 채널과 동일한 원형 스타일로 표시한다.
|
||||||
|
- 팔로잉 리스트의 팔로잉 중 버튼 터치 시 Bottom Sheet 액션 메뉴를 사용하지 않는다.
|
||||||
|
- 팔로잉 리스트와 크리에이터 채널 모두 팔로우 해제 전 한 번 더 확인한다.
|
||||||
|
- 취소 시 팔로우 상태와 알림 상태를 변경하지 않는다.
|
||||||
|
- 확인 시 기존 팔로우 해제 프로세스를 한 번만 실행한다.
|
||||||
|
|
||||||
|
### 3.2 UX 목표
|
||||||
|
|
||||||
|
- destructive action인 팔로우 해제의 영향을 Dialog 문구로 명확히 알린다.
|
||||||
|
- 한국어, 일본어, 영어에서 동일한 의미와 `%1$s` 크리에이터 이름 placeholder 계약을 유지한다.
|
||||||
|
- 팔로우 시작, 알림 토글, 기존 성공/실패 Toast 처리는 이번 변경으로 바꾸지 않는다.
|
||||||
|
|
||||||
|
## 4. Non-Goals
|
||||||
|
|
||||||
|
- 코드 구현은 이 문서 작성 작업의 범위가 아니다.
|
||||||
|
- `CreatorFollowNotifyFragment` 자체를 수정하거나 삭제하지 않는다.
|
||||||
|
- 팔로우/언팔로우 API, Repository, ViewModel 계약을 재설계하지 않는다.
|
||||||
|
- 신규 Dialog 컴포넌트, 신규 dependency, 공통 coordinator abstraction을 추가하지 않는다.
|
||||||
|
- 요청 범위 밖의 레거시 리팩터링을 하지 않는다.
|
||||||
|
- 사용자가 명시적으로 요청하지 않았으므로 `app/src/androidTest`, 기기·에뮬레이터 UI 조작, 스크린샷·시각 QA는 범위에서 제외한다.
|
||||||
|
|
||||||
|
## 5. Target Users and Permissions
|
||||||
|
|
||||||
|
| 사용자 | 목표 | 주요 작업 | 사용 환경 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 로그인 사용자 | 팔로잉 중인 크리에이터를 안전하게 해제 | 팔로잉 리스트 또는 크리에이터 채널에서 팔로우 해제 | Android 앱 |
|
||||||
|
|
||||||
|
권한과 인증 정책은 기존 팔로우/언팔로우 흐름을 그대로 따른다.
|
||||||
|
|
||||||
|
## 6. 핵심 사용자 흐름
|
||||||
|
|
||||||
|
1. 사용자가 팔로잉 리스트에서 팔로잉 중인 크리에이터의 액션 버튼을 누른다.
|
||||||
|
2. 앱은 `CreatorFollowNotifyFragment` Bottom Sheet를 표시하지 않고 `V2ModalDialog`를 표시한다.
|
||||||
|
3. 사용자가 `취소`를 누르면 Dialog만 닫히고 팔로우 해제 요청은 보내지 않는다.
|
||||||
|
4. 사용자가 `해제하기`를 누르면 기존 `viewModel.follow(creatorId, follow = false, notify = false)` 흐름으로 팔로우 해제를 진행한다.
|
||||||
|
5. 사용자가 크리에이터 채널에서 팔로잉 중 원형 캡슐을 누른다.
|
||||||
|
6. 앱은 `V2ModalDialog`를 표시한다.
|
||||||
|
7. 사용자가 확인하면 기존 `homeActionDelegate.follow(follow = false, notify = false)` 흐름으로 팔로우 해제를 진행한다.
|
||||||
|
|
||||||
|
## 7. 기능 요구사항
|
||||||
|
|
||||||
|
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `UNFOLLOW-001` | 확정 | 팔로잉 리스트의 팔로잉 중 버튼은 `ic_new_following_white`를 사용한다. | 팔로잉 중 branch가 기존 `btn_following_big`, `btn_following_no_alarm_big` 대신 요청 아이콘을 사용한다. | `P1-T1`, `P3-T1` |
|
||||||
|
| `UNFOLLOW-002` | 확정 | 팔로잉 리스트의 팔로잉 중 버튼은 `gray_800` 배경과 크리에이터 채널의 팔로잉 중과 동일한 원형 스타일을 사용한다. | `gray_800` 기반 원형 배경이 적용되고 unfollowed 상태는 기존 팔로우 버튼 정책을 유지한다. | `P1-T1`, `P3-T1` |
|
||||||
|
| `UNFOLLOW-003` | 확정 | 팔로잉 리스트에서 팔로잉 중 버튼 터치 시 Bottom Sheet 액션 메뉴를 표시하지 않는다. | `CreatorFollowNotifyFragment`를 통한 팔로잉 중 액션 메뉴 route가 제거된다. | `P1-T2`, `P3-T2` |
|
||||||
|
| `UNFOLLOW-004` | 확정 | 팔로잉 리스트에서 팔로우 해제 전 `V2ModalDialog`로 확인한다. | 취소는 side effect가 없고, 확인만 기존 unfollow 호출을 실행한다. | `P1-T2`, `P3-T2` |
|
||||||
|
| `UNFOLLOW-005` | 확정 | 크리에이터 채널에서 팔로우 해제 전 `V2ModalDialog`로 확인한다. | 팔로잉 중 캡슐 터치만 Dialog를 표시하고, 팔로우 시작 branch는 기존대로 즉시 실행한다. | `P1-T3`, `P4-T1` |
|
||||||
|
| `UNFOLLOW-006` | 확정 | Dialog 문구는 한국어, 일본어, 영어 string resource로 제공한다. | 모든 locale에서 title, description, cancel, confirm resource가 있고 description은 `%1$s`로 크리에이터 이름을 받는다. | `P2-T1` |
|
||||||
|
|
||||||
|
## 8. UI/UX Expectations
|
||||||
|
|
||||||
|
### 8.1 팔로잉 리스트 버튼
|
||||||
|
|
||||||
|
- 팔로잉 중: `ic_new_following_white`, `@color/gray_800`, 크리에이터 채널 팔로잉 중과 동일한 원형 스타일.
|
||||||
|
- 팔로우 전: 기존 팔로우 버튼 표시와 팔로우 시작 동작 유지.
|
||||||
|
- 알림 on/off에 따른 팔로잉 중 버튼 이미지 분기는 제거하거나 동일한 팔로잉 중 UI로 통합한다.
|
||||||
|
|
||||||
|
### 8.2 팔로우 해제 확인 Dialog
|
||||||
|
|
||||||
|
`V2ModalDialog`를 사용한다.
|
||||||
|
|
||||||
|
| Locale | Title | Description | Cancel | Confirm |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| Korean | `팔로우 해제` | `팔로우를 해제할까요?\n%1$s의 소식을 받을 수 없어요.` | `취소` | `해제하기` |
|
||||||
|
| Japanese | `フォロー解除` | `%1$sからの最新情報を受け取れなくなります。\nフォローを解除しますか?` | `キャンセル` | `解除する` |
|
||||||
|
| English | `Unfollow` | `You’ll no longer receive updates from %1$s.\nDo you want to unfollow?` | `Cancel` | `Unfollow` |
|
||||||
|
|
||||||
|
## 9. API 계약
|
||||||
|
|
||||||
|
API 계약 변경은 없다. 기존 팔로우/언팔로우 endpoint와 payload를 그대로 사용한다.
|
||||||
|
|
||||||
|
## 10. 보안과 데이터 취급
|
||||||
|
|
||||||
|
- 인증 토큰, API URL, 내부 오류 정보는 Dialog, Toast, 로그에 노출하지 않는다.
|
||||||
|
- Dialog description에는 화면에 이미 표시되는 크리에이터 이름만 삽입한다.
|
||||||
|
|
||||||
|
## 11. 성능과 품질 요구사항
|
||||||
|
|
||||||
|
- 신규 dependency를 추가하지 않는다.
|
||||||
|
- Dialog 확인 버튼 중복 터치는 기존 `V2ModalDialog`의 중복 클릭 방지 동작을 재사용한다.
|
||||||
|
- 테스트는 `app/src/test`의 local/source test로 제한한다.
|
||||||
|
- UI 변경 자동 테스트는 리소스 선택, route, callback 흐름만 검증하고 layout 크기·constraint·pixel은 직접 검증하지 않는다.
|
||||||
|
|
||||||
|
## 12. 성공 기준
|
||||||
|
|
||||||
|
### 12.1 기능 수용 기준
|
||||||
|
|
||||||
|
- [ ] 팔로잉 리스트 팔로잉 중 버튼이 요청 아이콘, 색상, 원형 스타일을 사용한다. (`UNFOLLOW-001`, `UNFOLLOW-002`)
|
||||||
|
- [ ] 팔로잉 리스트 팔로잉 중 버튼이 `CreatorFollowNotifyFragment`를 표시하지 않는다. (`UNFOLLOW-003`)
|
||||||
|
- [ ] 팔로잉 리스트 팔로우 해제는 `V2ModalDialog` 확인 후에만 실행된다. (`UNFOLLOW-004`)
|
||||||
|
- [ ] 크리에이터 채널 팔로우 해제는 `V2ModalDialog` 확인 후에만 실행된다. (`UNFOLLOW-005`)
|
||||||
|
- [ ] 한국어, 일본어, 영어 문구가 확정 문구와 일치한다. (`UNFOLLOW-006`)
|
||||||
|
|
||||||
|
### 12.2 추적성 완료 기준
|
||||||
|
|
||||||
|
- [ ] 모든 확정 요구사항이 `plan-task.md`의 Task와 연결된다.
|
||||||
|
- [ ] 구현 전 계획 문서가 먼저 준비된다.
|
||||||
|
- [ ] 코드 구현은 별도 사용자 승인 후 `plan-task.md`에 따라 진행한다.
|
||||||
|
|
||||||
|
## 13. Open Questions
|
||||||
|
|
||||||
|
| ID | 상태 | 결정 필요 사항 | 현재 권고 | 결정 주체 | 영향 Goal |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 없음 | 확정 | 없음 | 없음 | 사용자 | 없음 |
|
||||||
|
|
||||||
|
## 14. 요구사항 추적표
|
||||||
|
|
||||||
|
| 요구사항 범위 | API Contract | 계획 Phase | Goal | 자동 검증 | 수동 검증 |
|
||||||
|
|---|---|---:|---|---|---|
|
||||||
|
| `UNFOLLOW-001~002` | 변경 없음 | 1, 3 | `P1-T1`, `P3-T1` | `FollowingCreatorAdapterSourceTest` 또는 동등 source/local test | 범위 제외 |
|
||||||
|
| `UNFOLLOW-003~004` | 변경 없음 | 1, 3 | `P1-T2`, `P3-T2` | `FollowingCreatorActivitySourceTest` 또는 동등 source/local test | 범위 제외 |
|
||||||
|
| `UNFOLLOW-005` | 변경 없음 | 1, 4 | `P1-T3`, `P4-T1` | `CreatorChannelActivitySourceTest` | 범위 제외 |
|
||||||
|
| `UNFOLLOW-006` | 변경 없음 | 2 | `P2-T1` | string resource source/local test 또는 관련 source test | 범위 제외 |
|
||||||
|
|
||||||
|
## 15. Decision Log
|
||||||
|
|
||||||
|
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항·계약·Goal |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| `2026-08-18` | `DEC-001` | 확정 | 한국어 Dialog description은 `팔로우를 해제할까요?\n%1$s의 소식을 받을 수 없어요.`로 사용한다. | 사용자 인터뷰에서 A안 확정 | `UNFOLLOW-006`, `P2-T1` |
|
||||||
|
| `2026-08-18` | `DEC-002` | 확정 | 시각 보조 브라우저는 사용하지 않고 텍스트 기반 문서만 작성한다. | 사용자 응답 | 문서 작성 방식 |
|
||||||
|
| `2026-08-18` | `DEC-003` | 확정 | 이번 작업은 PRD와 구현 계획 문서 생성만 수행하고 코드 구현은 하지 않는다. | 사용자 명시 요청 | 전체 범위 |
|
||||||
|
|
||||||
|
## 16. 변경 관리
|
||||||
|
|
||||||
|
요구사항 변경 시 다음을 확인한다.
|
||||||
|
|
||||||
|
- [ ] Decision Log에 변경 이유와 날짜를 기록했다.
|
||||||
|
- [ ] 관련 요구사항 상태·본문·수용 기준을 갱신했다.
|
||||||
|
- [ ] `plan-task.md`의 범위·Files·체크박스·완료 증거를 코드 변경 전에 갱신했다.
|
||||||
|
- [ ] 기존 Progress·검증 기록을 삭제하거나 덮어쓰지 않았다.
|
||||||
Reference in New Issue
Block a user