|
26 | 26 | ### 금지/비권장 이름 |
27 | 27 | - `pages` 사용 금지 |
28 | 28 | - 기존 `pages`는 점진적으로 `screens`로 이동한다. |
29 | | -- `viewmodels` 사용 금지 |
30 | | - - Riverpod `Notifier`, `AsyncNotifier`, `Provider`는 모두 `providers` 아래에 둔다. |
31 | | -- `states` 디렉터리 사용 금지 |
32 | | - - UI 상태 타입은 `models` 아래에 둔다. |
| 29 | +- 신규 코드는 `providers` / `models`를 쓴다. |
| 30 | + - 기존 `viewmodels` / `states` 디렉터리는 그대로 두고, 그 안의 코드를 수정할 때 |
| 31 | + 한 파일씩 옮긴다. 이름만 바꾸는 일괄 리네임은 하지 않는다. |
| 32 | + |
| 33 | +## 상태를 어디에 둘까 |
| 34 | + |
| 35 | +디렉터리 이름보다 이 질문이 먼저다. Riverpod의 `Notifier`가 곧 ViewModel이므로 |
| 36 | +"MVVM을 쓸까"가 아니라 **"이 상태가 위젯보다 오래 사는가"**로 판단한다. |
| 37 | + |
| 38 | +### 1. Provider(= ViewModel)에 둔다 |
| 39 | +- 화면을 벗어나도 유지돼야 하거나, 둘 이상이 읽는 상태 |
| 40 | +- 서버 호출·비동기 로딩·에러·폼 검증이 붙는 상태 |
| 41 | +- 예: `authProvider`, `signupProvider`, `mapScreenProvider`, `settingsProvider` |
| 42 | + |
| 43 | +### 2. `setState`로 둔다 |
| 44 | +- 위젯 하나만 읽고 쓰고, 위젯이 사라지면 같이 사라지는 상태 |
| 45 | +- 바텀시트 안의 선택값, 토글 진행 중 플래그, 펼침/접힘 같은 것 |
| 46 | +- provider로 올리면 `autoDispose.family` + 식별용 키가 따라붙는다. |
| 47 | + 그건 `setState`를 어렵게 재구현한 것이다. |
| 48 | +- 부모가 새 값을 내려줄 때 따라가야 하면 `didUpdateWidget`에서 명시적으로 반영한다. |
| 49 | + |
| 50 | +### 3. 만들지 않는다 |
| 51 | +- 다른 provider의 메서드를 그대로 호출만 하는 ViewModel은 두지 않는다. |
| 52 | +- 위젯에서 `ref.read(대상provider.notifier)`를 직접 부른다. |
33 | 53 |
|
34 | 54 | ## 파일 규칙 |
35 | 55 |
|
@@ -103,6 +123,62 @@ feature/ |
103 | 123 | - `provider`로 통일한다. `viewmodel`은 더 이상 추가하지 않는다. |
104 | 124 | - `model`로 통일한다. `state` 전용 디렉터리는 더 이상 추가하지 않는다. |
105 | 125 | - pass-through `usecase`는 더 이상 기본값이 아니다. |
| 126 | +- 저장소/서비스도 마찬가지다. 인터페이스와 구현이 1:1이고 구현이 전달만 하면 |
| 127 | + 중간 계층 없이 `datasource` 또는 유틸을 직접 쓴다. |
| 128 | + 플랫폼 API를 감싸 테스트에서 갈아끼워야 하는 경우(`PermissionService`)만 예외다. |
| 129 | + |
| 130 | +## 정리 대상 (2026-08-19 기준) |
| 131 | + |
| 132 | +규칙에 맞지 않지만 아직 옮기지 않은 것들. 수정이 닿을 때 함께 정리한다. |
| 133 | + |
| 134 | +| 위치 | 내용 | |
| 135 | +| --- | --- | |
| 136 | +| `features/*/presentation/viewmodels/` | 디렉터리 11개. 안의 provider 이름은 이미 대부분 `xxxProvider`라 파일 위치만 남았다. | |
| 137 | +| `features/auth/verification/presentation/states/` | `models/`로 이동 | |
| 138 | +| `features/map/shared/presentation/widgets/` | 15개. 실제로 공용인 것만 남기고 나머지는 소유 하위 feature로 | |
| 139 | +| `features/map/routes/` | 다른 feature와 맞춰 `presentation/routes/`로 | |
| 140 | +| `features/home/domain/enums/student_role_enum.dart` | `home`의 유일한 파일인데 실사용처는 `member`/`outing`. `core/enums/`로 | |
| 141 | +| `features/auth/email_verification/data/models/request/email_verification/` | 경로에 feature 이름이 두 번 들어간다 | |
| 142 | + |
| 143 | +## Git 네이밍 |
| 144 | + |
| 145 | +### 브랜치 |
| 146 | +`<타입>/#<이슈번호>-<영문 설명>` |
| 147 | + |
| 148 | +| 타입 | 용도 | |
| 149 | +| --- | --- | |
| 150 | +| `feature` | 기능 추가 | |
| 151 | +| `fix` | 버그 수정 | |
| 152 | +| `refactor` | 동작 변경 없는 구조 정리 | |
| 153 | +| `perf` | 성능 개선 | |
| 154 | +| `release` | 배포 준비 (`release/v1.4.2` 처럼 이슈번호 없이) | |
| 155 | + |
| 156 | +- 타입은 브랜치가 하는 일에 맞춘다. 리팩터링에 `feature`를 붙이지 않는다. |
| 157 | +- 설명은 영문 kebab-case. 예: `refactor/#108-dead-code-cleanup` |
| 158 | + |
| 159 | +### 커밋 |
| 160 | +`:gitmoji: :: <한글 설명>` |
| 161 | + |
| 162 | +- gitmoji는 콜론 형식(`:sparkles:`)으로 쓴다. 유니코드 이모지(`✨`)를 섞지 않는다. |
| 163 | +- 이슈 참조가 필요하면 설명 끝에 `(#126)`. |
| 164 | + |
| 165 | +| gitmoji | 용도 | |
| 166 | +| --- | --- | |
| 167 | +| `:sparkles:` | 기능 추가 | |
| 168 | +| `:bug:` | 버그 수정 | |
| 169 | +| `:recycle:` | 리팩터링 | |
| 170 | +| `:zap:` | 성능 개선 | |
| 171 | +| `:memo:` | 문서 | |
| 172 | +| `:green_heart:` | CI | |
| 173 | +| `:bookmark:` | 버전업 | |
| 174 | + |
| 175 | +### PR 제목 |
| 176 | +`🔀 :: (#<이슈번호>) - <한글 설명>` |
| 177 | + |
| 178 | +- PR 제목의 이모지는 변경 성격과 무관하게 항상 `🔀`다. 커밋과 달리 유니코드 이모지를 쓴다. |
| 179 | +- 배포 PR만 이슈번호 대신 버전을 쓴다. 예: `🔀 :: v1.4.4 - 핫플레이스 조회 기준 기간 1일로 변경` |
| 180 | +- base는 `develop`. `main`으로 직접 열지 않는다. |
| 181 | +- 본문은 `.github/PULL_REQUEST_TEMPLATE.md`를 채우고, 관련 이슈에 `Closes #N`을 남긴다. |
106 | 182 |
|
107 | 183 | ## 예외 |
108 | 184 | - 외부 라이브러리/코드 생성기 제약이 있는 경우 |
|
0 commit comments