fix(commit): AGENTS 규칙과 커밋 메시지 검사 스크립트를 정합화한다

This commit is contained in:
2026-02-24 15:49:16 +09:00
parent d048305193
commit 80959abe16
5 changed files with 291 additions and 16 deletions

180
AGENTS.md
View File

@@ -1,18 +1,166 @@
질문에 대한 답변과 설명은 한국어로 한다.
# AGENTS.md
`SodaLive` 저장소에서 작업하는 에이전트 실행 가이드다.
## Quality Assurance Guidelines
## 커뮤니케이션 규칙
- **"질문에 대한 답변과 설명은 한국어로 한다."**
- 이 저장소에서 사용자에게 전달하는 설명, 진행 상황, 결과 보고는 한국어로 작성한다.
- 코드 식별자, 경로, 명령어는 원문(영문) 그대로 유지한다.
### Commit Standards
1. Write in Korean.
2. Use the present tense in the subject line (e.g., "Add feature" not "Added feature").
3. Keep the subject line to 50 characters or less.
4. Add a blank line between the subject and body.
5. Keep the body to 72 characters or less per line.
6. Within a paragraph, only break lines when the text exceeds 72 characters.
7. Describe changes to public API features and do not include implementation details such as package-private code.
8. Do not mention test code in commit messages.
9. Do not use any prefix (such as "fix:", "update:", "docs:", "feat:", etc.) in the subject line.
10. Do not start the subject line with a lowercase letter unless the first word is a function name or another identifier that is conventionally lowercase and there is a clear, justifiable reason for the exception. Otherwise, always start with an uppercase letter.
11. Do not include tool advertisements, branding, or promotional content in commit messages.
12. Use separate git commands to stage files before committing.
13. Always validate commits using `work/scripts/check-commit-message-rules.sh` and fix until validation passes.
## 저장소 범위
- Android Gradle 프로젝트이며 `settings.gradle` 기준 모듈은 `:app` 단일 구성이다.
- 모든 명령은 저장소 루트에서 실행한다.
- 추측하지 말고 근거 파일(`settings.gradle`, `build.gradle`, `app/build.gradle`, 소스 코드)을 읽고 결정한다.
- 요청 범위를 우선 충족하고, 변경은 작고 안전하게 유지한다.
## 빌드 / 린트 / 테스트 명령
기본 실행 형태:
```bash
./gradlew <task>
```
빌드:
```bash
./gradlew clean
./gradlew :app:assembleDebug
./gradlew :app:assembleRelease
./gradlew :app:build
./gradlew :app:check
```
린트/포맷:
```bash
./gradlew :app:lint
./gradlew :app:lintDebug
./gradlew :app:lintRelease
./gradlew :app:ktlintCheck
./gradlew :app:ktlintFormat
```
테스트:
```bash
./gradlew :app:test
./gradlew :app:testDebugUnitTest
./gradlew :app:testReleaseUnitTest
./gradlew :app:connectedDebugAndroidTest
```
주의:
- `:app:connectedDebugAndroidTest`는 기기/에뮬레이터 연결이 필요하다.
- `app/build.gradle``lint { checkReleaseBuilds false }`가 있어 릴리스 린트는 `:app:lintRelease`를 명시 실행해야 한다.
- 현재 `app/src/androidTest`에는 테스트 소스가 없으므로 계측 테스트 명령은 신규 테스트 추가 시 사용한다.
### 1) 단일 테스트 실행 (중요)
로컬 단위 테스트(`app/src/test`)는 `--tests` 필터를 사용한다.
클래스 단위:
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.chat.talk.room.ChatRepositoryTest"
```
메서드 단위:
```bash
./gradlew :app:testDebugUnitTest --tests "kr.co.vividnext.sodalive.chat.talk.room.ChatRepositoryTest.enterChatRoom inserts messages and returns response"
```
패턴 매칭 예시:
```bash
./gradlew :app:testDebugUnitTest --tests "*TimeUtilsTest*"
```
참고:
- Kotlin backtick 테스트명은 공백이 포함될 수 있으므로 전체 문자열을 인용한다.
- 메서드 매칭이 불안정하면 클래스 단위로 먼저 실행한다.
### 2) 계측 테스트 클래스/메서드 타깃 실행
Gradle 인자 방식:
```bash
./gradlew :app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=kr.co.vividnext.sodalive.SomeInstrumentedTest
./gradlew :app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=kr.co.vividnext.sodalive.SomeInstrumentedTest#someMethod
```
ADB 대안:
```bash
adb shell am instrument -w -e class kr.co.vividnext.sodalive.SomeInstrumentedTest#someMethod <test_package>/<runner>
```
## 코드 스타일 가이드
### 1) 포맷/기본 규칙
- `.editorconfig` 기준을 준수한다.
- 인덴트: 공백 4칸, 줄바꿈: LF, 최대 라인 길이: 130.
- 파일 끝 개행 유지, trailing whitespace 제거.
- Kotlin/KTS에서 `import-ordering` ktlint 규칙은 비활성화되어 있으므로 기존 파일 정렬 스타일을 우선 따른다.
### 2) import 규칙
- 신규 코드에서는 와일드카드 import(`*`)를 기본적으로 지양한다.
- 사용하지 않는 import를 남기지 않는다.
- import alias(`as`)는 필요한 경우(이름 충돌 회피) 최소 범위로만 사용한다.
- 기존 파일에 와일드카드/alias가 있으면 대규모 정렬 리팩터링 없이 주변 스타일에 맞춘다.
### 3) 네이밍/레이어
- UI: `*Activity`, `*Fragment`, dialog/sheet suffix
- 상태/도메인: `*ViewModel` (주로 `BaseViewModel` 상속)
- 데이터 계층: `*Repository`, Retrofit `*Api`
- DTO: `data class` + `*Request`, `*Response` suffix
- 레이어 흐름: `Api` -> `Repository` -> `ViewModel` -> `Activity`/`Fragment`
- DI는 `app/src/main/java/kr/co/vividnext/sodalive/di/AppDI.kt`의 Koin 구성을 따른다.
### 4) 타입/계약/에러 처리
- nullability와 제네릭 타입을 의미가 바뀌지 않게 유지한다.
- 공개 API/스키마/리소스 계약은 요청 없이 변경하지 않는다.
- 응답 처리 시 기존 `ApiResponse<T>`와 Rx 타입(`Single`, `Flowable`)을 우선 재사용한다.
-`catch` 블록을 새로 추가하지 않는다.
- 예외를 조용히 삼키지 않고 로그/주석/대체 흐름 중 하나를 남긴다.
### 5) 테스트 관례
- 단위 테스트는 `app/src/test`에 위치하며 클래스명은 `*Test`를 사용한다.
- 기본 스택은 JUnit4 + MockK/Mockito다.
- 테스트 추가 시 단일 실행 명령 예시도 본 문서에 갱신한다.
## 커밋 메시지 규칙 (표준 Conventional Commits)
- 커밋 상세 가이드/절차는 `.opencode/skills/commit-policy/SKILL.md`를 단일 기준으로 사용한다.
- 커밋 작업 시작 시 `skill` 도구로 `commit-policy`를 먼저 로드한다.
- 기본 형식은 `<type>(scope): <description>`를 사용한다.
- `type`은 소문자(`feat`, `fix`, `chore`, `docs`, `refactor`, `test` 등)를 사용한다.
- 제목(description)은 한글로 작성하고, 명령형/간결한 현재형으로 작성한다.
- 이슈 참조 footer는 `Refs: #123` 또는 `Refs: #123, #456` 형식을 사용한다.
### 커밋 메시지 검증 절차
- `git commit` 직전/직후 `work/scripts/check-commit-message-rules.sh`를 실행해 규칙 준수 여부를 확인한다.
- 스크립트 결과가 `[FAIL]`이면 메시지를 수정한 뒤 다시 검증한다.
## 작업 절차 체크리스트
- 변경 전: 유사 기능 코드를 먼저 찾아 네이밍/예외/응답 패턴을 맞춘다.
- 변경 중: 공개 API 스키마를 임의 변경하지 말고 작은 단위로 안전하게 수정한다.
- 변경 후: 최소 단일 테스트(`--tests`) 또는 `./gradlew :app:test`를 실행하고 필요 시 `./gradlew :app:ktlintCheck`를 수행한다.
- 커밋 전/후: `commit-policy` 스킬을 먼저 로드하고, `git commit` 직전과 직후에 `work/scripts/check-commit-message-rules.sh`를 실행해 커밋 메시지 규칙 준수 여부를 확인한다.
## 작업 계획 문서 규칙 (docs)
- 모든 작업 시작 전에 `docs` 폴더 아래 계획 문서를 먼저 생성하고, 해당 문서를 기준으로 구현한다.
- 계획 문서 파일명은 `[날짜]_구현할내용한글.md` 형식을 사용한다.
- 날짜는 `YYYYMMDD` 8자리 숫자를 사용한다.
- 구현 항목은 기능/작업 단위 체크박스(`- [ ]`)로 작성하고 완료 즉시 `- [x]`로 갱신한다.
- 작업 도중 범위가 변경되면 계획 문서 체크리스트를 먼저 업데이트한 뒤 구현한다.
- 결과 보고 시 문서 하단에 검증 기록(무엇/왜/어떻게, 실행 명령, 결과)을 한국어로 남긴다.
- 후속 수정이 발생해도 기존 검증 기록은 삭제/덮어쓰기 없이 누적한다.
## Cursor/Copilot 규칙 반영 현황
- 확인 경로: `.cursor/rules/**`, `.cursorrules`, `.github/copilot-instructions.md`
- 현재 저장소에는 위 파일이 존재하지 않는다.
- 추후 규칙 파일이 추가되면 본 문서에 즉시 반영한다.
## 문서 유지보수 규칙
- `build.gradle`/`app/build.gradle`/`settings.gradle` 변경 시 실행 명령 섹션을 함께 갱신한다.
- 테스트 클래스 추가/이동 시 단일 테스트 실행 예시를 최신 상태로 유지한다.
- `.editorconfig` 변경 시 포맷 규칙 섹션을 동기화한다.
- 문서 변경 후 최소 한 번 `./gradlew tasks --all`로 명령 유효성을 확인한다.
- 불확실한 규칙은 추측으로 채우지 말고 근거 파일 경로를 먼저 확인한다.
- 에이전트 안내 문구는 한국어 중심으로 유지한다.
## 에이전트 동작 원칙
- 추측하지 말고 근거 파일을 읽고 결정한다.
- 기존 관례를 깨는 변경은 이유가 명확할 때만 수행한다.
- 불필요한 리팩터링 확장은 피하고 요청 범위를 우선 충족한다.
- 결과 보고 시 무엇을, 왜, 어떻게 검증했는지 한국어로 간단히 남긴다.
## 설정/보안 유의사항
- `local.properties`, 키스토어(`*.jks`, `*.keystore`, `*.p12`, `*.pem`, `*.key`)는 생성/수정 여부와 관계없이 커밋하지 않는다.
- `app/src/debug/google-services.json`, `app/src/release/google-services.json`은 민감 구성으로 취급하고 외부 공유/로그 출력 금지한다.
- `app/build.gradle``buildConfigField` 값(토큰/앱키/시크릿 유사 값)은 신규 하드코딩을 추가하지 않는다.
- `BuildConfig` 값(키/토큰/URL)을 로그, Toast, 크래시 메시지에 직접 노출하지 않는다.
- 네트워크 로깅은 `AppDI.kt` 패턴을 유지한다(디버그만 BODY, 릴리스는 NONE).
- 서명/배포 설정(Crashlytics, Google Services, Proguard, signing)은 요청 없이 변경하지 않는다.
- `AndroidManifest.xml` 권한은 민감 영역이므로 신규 추가/확장은 사유와 영향도를 확인한 뒤 반영한다.
- `applicationId`, `namespace`, OAuth Client ID, 딥링크 호스트는 요청 없이 변경하지 않는다.
- 문서/이슈/PR 본문에 비밀값을 남기지 말고 필요 시 마스킹(`***`) 처리한다.
- Git 작업은 비파괴 명령을 기본으로 사용하고, 강제 푸시/히스토리 재작성은 명시 요청이 있을 때만 수행한다.