docs(commit-policy): 커밋 정책 스킬과 검증 절차를 정비한다

This commit is contained in:
Yu Sung
2026-02-25 14:58:12 +09:00
parent b796f6d9c5
commit aaffd08cb5
6 changed files with 299 additions and 17 deletions

1
.gitignore vendored
View File

@@ -279,6 +279,5 @@ xcuserdata
.kiro/
.junie/
docs/
# End of https://www.toptal.com/developers/gitignore/api/macos,xcode,appcode,swift,swiftpackagemanager,swiftpm,fastlane,cocoapods

View File

@@ -0,0 +1,21 @@
---
description: commit-policy 스킬을 로드해 커밋 메시지 생성과 전후 검증을 수행한다
agent: build
subtask: true
---
작업 목표:
현재 변경사항을 안전하게 커밋한다.
필수 시작 단계:
1. `skill` 도구로 `commit-policy` 스킬을 먼저 로드한다.
- `skill({ name: "commit-policy" })`
실행 단계:
1. 로드한 `commit-policy` 스킬의 Hard Requirements와 Execution Flow를 그대로 수행한다.
2. `AGENTS.md`의 최소 정책(형식/한글 description/검증 스크립트)을 항상 만족한다.
3. `$ARGUMENTS`가 있으면 scope 또는 description 의도에 반영하되, 스킬 규칙과 형식을 깨지 않는다.
4. 마지막에 실행 명령과 pre-check/post-check PASS/FAIL 핵심 결과를 간단히 보고한다.
추가 사용자 의도:
$ARGUMENTS

View File

@@ -0,0 +1,46 @@
---
name: commit-policy
description: Apply this skill for any git commit task in this repository. It enforces commit message format and validation flow defined in AGENTS.md and work/scripts/check-commit-message-rules.sh, including pre-commit and post-commit verification.
---
# Commit Policy Skill
Use this workflow whenever the task includes creating a commit.
## Required References
- `@AGENTS.md`
- `@work/scripts/check-commit-message-rules.sh`
## Hard Requirements
1. Use commit subject format: `<type>(scope): <description>`.
2. `type` must be lowercase (for example `feat`, `fix`, `chore`, `docs`, `refactor`, `test`).
3. `description` must include Korean text and stay concise in imperative present tone.
4. Optional footer must use `Refs: #123` or `Refs: #123, #456` format.
5. Never commit secret files (`.env`, key/token/secret credential files).
6. Never bypass hooks with `--no-verify`.
## Execution Flow
1. Inspect context with:
- `git status`
- `git diff --cached`
- `git diff`
- `git log -5 --oneline`
2. Stage commit target files only. Exclude suspicious secret-bearing files.
3. Draft commit message from the change intent (focus on why, not only what).
4. Run pre-commit validation with the full draft message:
- `./work/scripts/check-commit-message-rules.sh --message "<full message>"`
5. If validation fails, revise message and re-run until PASS.
6. Commit using the validated message.
7. Run post-commit validation:
- `./work/scripts/check-commit-message-rules.sh`
8. Report executed commands and PASS/FAIL summary.
## Output Checklist
- Final commit subject.
- Whether pre-check passed.
- Whether post-check passed.
- Any excluded files and reason.

174
AGENTS.md
View File

@@ -1,18 +1,160 @@
질문에 대한 답변과 설명은 한국어로 한다.
# 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.
## 저장소 범위
- 앱 소스: `SodaLive/Sources/**`
- 프로젝트/스킴: `SodaLive.xcodeproj`, `SodaLive.xcworkspace`
- 의존성 설정: `Podfile`, `Podfile.lock`
- 운영 스크립트: `work/scripts/**`
- 생성/외부 결과물: `Pods/**`, `generated/**`, `build/**`
- 작업 계획 문서: `docs/**`
### 수정 우선순위
- 기능 변경은 `SodaLive/Sources/**`에서 해결한다.
- 프로젝트 설정 변경은 필요한 경우에만 수행한다.
- `Pods/**`, `generated/**`는 직접 수정하지 않는다.
- `build/**`는 빌드 산출물로 간주하며 수정 대상이 아니다.
## 빌드/테스트/검증 명령
아래 명령은 현재 저장소에서 확인된 공식 진입점이다.
### 1) 의존성 설치
- `pod install`
- 근거: `Podfile`에 CocoaPods 타깃(`SodaLive`, `SodaLive-dev`) 정의.
### 2) 스킴/타깃 확인
- `xcodebuild -workspace "SodaLive.xcworkspace" -list`
- 근거: 공유 스킴 `SodaLive`, `SodaLive-dev` 존재.
### 3) 빌드
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`
### 4) 테스트(전체)
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test`
### 5) 단일 테스트 실행
- 일반 형식(테스트 타깃이 있는 경우):
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -only-testing:"SodaLiveTests/TestClass/testMethod" test`
- **현재 주의사항**:
- `SodaLive.xcodeproj/project.pbxproj` 기준으로 앱 타깃 중심 구성이고 테스트 번들 타깃이 확인되지 않는다.
- 따라서 현재 상태에서는 단일 테스트 지정이 실질적으로 동작하지 않을 수 있다.
### 6) 린트/포맷
- 저장소에 공식 `swiftlint`/`swiftformat` 실행 스크립트는 확인되지 않았다.
- `generated/*.generated.swift``swiftlint:disable all` 주석은 존재하나, 이는 생성 코드 보호 목적이다.
- 린트 도구를 도입/추가하면 본 문서 명령 섹션을 즉시 갱신한다.
## 코드 스타일 가이드
### 아키텍처/레이어
- 기본 흐름은 `View -> ViewModel -> Repository -> Api(TargetType)`를 따른다.
- API는 `enum ...Api: TargetType`, 저장소는 `final class ...Repository` 형태를 우선 사용한다.
- 상태 모델은 `struct`/`enum` 중심으로 두고, 화면 상태는 `ObservableObject`에서 관리한다.
### 임포트 규칙
- 시스템 프레임워크(`Foundation`, `SwiftUI`, `Combine`)를 먼저 배치한다.
- 서드파티(`Moya`, `CombineMoya`, SDK들)는 이후 배치한다.
- import 그룹 사이에는 한 줄 공백으로 의미 단위를 분리한다.
### 포맷/구조
- 들여쓰기는 4칸 스페이스를 사용한다.
- 프로퍼티 선언, 비즈니스 로직, 헬퍼 메서드는 공백 줄로 구획한다.
- 클로저 체인은 줄바꿈해 가독성을 유지한다.
### 타입/상태 관리
- ViewModel은 `final class ...: ObservableObject` 패턴을 우선한다.
- View가 소유하는 객체는 `@StateObject`, 외부 주입 객체는 `@ObservedObject`를 사용한다.
- 네트워크 반환은 `AnyPublisher<Response, MoyaError>` 패턴을 기본으로 따른다.
### 네이밍 규칙
- 타입명은 PascalCase (`HomeViewModel`, `UserRepository`, `UserApi`).
- 변수/함수는 camelCase (`errorMessage`, `getMemberInfo`).
- 역할을 이름에 반영한다 (`*View`, `*ViewModel`, `*Repository`, `*Api`, `*Request`, `*Response`).
### 비동기/Combine 규칙
- 비동기 처리는 Combine의 `sink`, `receiveValue`, `.store(in: &subscription)` 패턴을 따른다.
- `sink` 완료 블록에서 `.failure`를 반드시 처리한다.
- 클로저 캡처는 상황에 맞게 `[weak self]` 또는 `[unowned self]`를 선택한다.
### 에러 처리 규칙
- 사용자 노출 오류는 `errorMessage`와 팝업 플래그(`isShowPopup`)로 일관되게 처리한다.
- JSON 파싱은 `do/catch + JSONDecoder` 패턴을 따른다.
- **신규 코드에서 빈 `catch`는 금지**하고, 최소한 로깅 또는 명시적 무시 사유를 남긴다.
### 로깅 규칙
- 디버그 로그는 `DEBUG_LOG`, 오류 로그는 `ERROR_LOG`를 사용한다.
- `print`는 임시 디버깅 목적 외 신규 코드에서 지양한다.
### 네트워크/헤더 규칙
- 공통 Moya 플러그인(`AuthPlugin`, `AcceptLanguagePlugin`) 흐름을 유지한다.
- 언어 헤더는 `LanguageHeaderProvider.current`를 기준으로 사용한다.
### 문자열/다국어
- 신규 사용자 노출 문자열은 가능하면 `I18n` 경로를 우선 사용한다.
- 다국어 기능 수정 시 `Settings/Language` 모듈과 `Accept-Language` 헤더 흐름을 함께 점검한다.
### 주석/문서화
- 자명한 코드에는 주석을 남기지 않는다.
- 복잡한 분기, 외부 제약, 부작용이 있는 로직에만 주석을 추가한다.
## Cursor/Copilot 규칙 반영
- 아래 파일 존재 여부를 확인해 AGENTS와 함께 유지한다.
- `.cursor/rules/**`
- `.cursorrules`
- `.github/copilot-instructions.md`
- 현재 저장소에서는 위 파일들이 확인되지 않았다.
- 추후 파일이 추가되면 AGENTS.md에 요약 규칙을 동기화한다.
- 충돌 우선순위 기본값:
- 범위가 더 구체적인 규칙이 우선한다(경로 특화 > 저장소 전역).
- Cursor: `.cursor/rules/**` > `.cursorrules` > `AGENTS.md`
- Copilot: `.github/instructions/**`(존재 시) > `.github/copilot-instructions.md` > `AGENTS.md`
## 커밋 메시지 규칙 (표준 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 스키마를 임의 변경하지 말고 작은 단위로 안전하게 수정한다.
- 변경 후: 영향 범위 파일에 대해 빌드/테스트/로그/다국어 키를 점검한다.
- 커밋 직후: `commit-policy` 스킬을 로드하고 메시지 검증 스크립트를 실행한다.
## 작업 계획 문서 규칙 (docs)
- 모든 작업 시작 전에 `docs` 폴더 아래 계획 문서를 먼저 생성하고, 해당 문서를 기준으로 구현한다.
- 계획 문서 파일명은 `[날짜]_구현할내용한글.md` 형식을 사용한다.
- 날짜는 `YYYYMMDD` 8자리 숫자를 사용한다.
- 구현 항목은 기능/작업 단위 체크박스(`- [ ]`)로 작성하고 완료 즉시 `- [x]`로 갱신한다.
- 작업 도중 범위가 변경되면 계획 문서 체크리스트를 먼저 업데이트한 뒤 구현한다.
- 결과 보고 시 문서 하단에 검증 기록(무엇/왜/어떻게, 실행 명령, 결과)을 한국어로 남긴다.
- 후속 수정이 발생해도 기존 검증 기록은 삭제/덮어쓰기 없이 누적한다.
## 문서 유지보수 규칙
- 불확실한 규칙은 추측으로 채우지 말고 근거 파일 경로를 먼저 확인한다.
- 에이전트 안내 문구는 한국어 중심으로 유지한다.
- 명령/경로/타깃명이 바뀌면 본 문서를 즉시 업데이트한다.
## 에이전트 동작 원칙
- 추측하지 말고 근거 파일을 읽고 결정한다.
- 기존 관례를 깨는 변경은 이유가 명확할 때만 수행한다.
- 불필요한 리팩터링 확장은 피하고 요청 범위를 우선 충족한다.
- 결과 보고 시 무엇을, 왜, 어떻게 검증했는지 한국어로 간단히 남긴다.
## 설정/보안 유의사항
- 토큰/키/개인정보를 코드/로그/문서에 하드코딩하지 않는다.
- 인증 관련 헤더/토큰 처리 로직(`AuthPlugin`, `UserDefaultsKey.token`) 수정 시 회귀 위험을 함께 점검한다.
- 외부 SDK 키 변경 시 빌드 설정과 런타임 초기화 지점을 함께 검토한다.

View File

@@ -0,0 +1,53 @@
# 20260225 AGENTS 가이드 보강
## 작업 목표
- 저장소 실행/검증 명령을 근거 기반으로 정리한다.
- 코드 스타일 가이드를 실제 코드 관례 기반으로 정리한다.
- Cursor/Copilot 규칙 파일 존재 시 AGENTS.md에 반영한다.
## 체크리스트
- [x] 저장소 빌드/린트/테스트 명령 근거 수집
- [x] 단일 테스트 실행 명령(가능한 범위) 정리
- [x] 코드 스타일 관례(임포트/포맷/타입/네이밍/에러처리) 추출
- [x] Cursor/Copilot 규칙 파일 반영
- [x] `AGENTS.md`를 약 150줄 내외로 보강
- [x] 검증 로그 추가
## 검증 기록
- 2026-02-25: 작업 시작. 근거 파일 탐색 진행 중.
- 2026-02-25:
- 무엇: 빌드/테스트/의존성 명령 근거를 확인했다.
- 왜: AGENTS.md에 실행 가능한 공식 명령만 기재하기 위해서다.
- 어떻게:
- `xcodebuild -workspace "SodaLive.xcworkspace" -list`
- `read Podfile`
- `read SodaLive.xcodeproj/xcshareddata/xcschemes/SodaLive.xcscheme`
- `read SodaLive.xcodeproj/xcshareddata/xcschemes/SodaLive-dev.xcscheme`
- `grep project.pbxproj "PBXNativeTarget|Tests|SWIFT_VERSION|IPHONEOS_DEPLOYMENT_TARGET"`
- 결과: 스킴 `SodaLive`, `SodaLive-dev`를 확인했고, 테스트 번들 타깃 부재로 단일 테스트 실행은 제한될 수 있음을 문서화했다.
- 2026-02-25:
- 무엇: 코드 스타일 규칙(임포트/아키텍처/타입/네이밍/에러처리/로깅/비동기)을 추출했다.
- 왜: 에이전트가 기존 관례를 깨지 않고 수정하도록 하기 위해서다.
- 어떻게:
- `read SodaLive/Sources/User/UserApi.swift`
- `read SodaLive/Sources/User/UserRepository.swift`
- `read SodaLive/Sources/User/Login/LoginViewModel.swift`
- `read SodaLive/Sources/Extensions/MoyaProviderExtension.swift`
- `read SodaLive/Sources/Utils/Log.swift`
- `ast_grep_search "do { $$$ } catch { $$$ }"`
- 결과: `View -> ViewModel -> Repository -> Api` 레이어와 `DEBUG_LOG/ERROR_LOG`, `sink + .store(in:)` 패턴을 AGENTS.md에 반영했다.
- 2026-02-25:
- 무엇: Cursor/Copilot 규칙 파일 존재 여부를 점검했다.
- 왜: 요청사항(룰 파일 반영)을 누락 없이 처리하기 위해서다.
- 어떻게:
- `glob .cursor/rules/**/*`
- `glob .cursorrules`
- `glob .github/copilot-instructions.md`
- 결과: 현재 저장소에는 해당 파일이 없어, AGENTS.md에 "미존재/추후 동기화" 정책을 기재했다.
- 2026-02-25:
- 무엇: AGENTS.md 최종 라인 수와 섹션 충족 여부를 확인했다.
- 왜: 요청 조건(약 150줄, 빈 섹션 채우기) 충족 검증을 위해서다.
- 어떻게:
- `read AGENTS.md`
- `wc -l AGENTS.md`
- 결과: 총 160줄로 확인되었고, 기존 빈 섹션(저장소 범위/코드 스타일)을 포함해 전 섹션을 채웠다.

View File

@@ -0,0 +1,21 @@
- [x] `check-commit-message-rules.sh`의 인자 지원 방식 확인
- [x] `AGENTS.md` 커밋 메시지 검증 절차를 커밋 후 검증 전용으로 수정
- [x] 변경 내용 검증 및 결과 기록
## 검증 기록
- 2026-02-25: 작업 시작
- 무엇/왜/어떻게: 커밋 전 `--message` 검증 가능 여부를 스크립트 소스 기준으로 확인.
- 실행 명령: `read work/scripts/check-commit-message-rules.sh`
- 결과: 사용법이 `[commit-hash]`만 정의되어 있어 커밋 전 메시지 직접 검증은 미지원.
- 실행 명령: `./work/scripts/check-commit-message-rules.sh --message`
- 결과: `git log`에서 `fatal: 알 수 없는 인자: --message`가 발생해도 스크립트는 성공으로 끝나므로 사전 검증 용도로 사용할 수 없음.
- 2026-02-25: AGENTS 문구 정정
- 무엇/왜/어떻게: 스크립트 실제 동작과 문서 지침을 일치시키기 위해 커밋 검증 시점을 사후 전용으로 수정.
- 실행 명령: `apply_patch AGENTS.md`
- 결과: `git commit` 직전/직후 안내를 `git commit` 직후 안내로 변경하고, 체크리스트의 `커밋 전/후``커밋 직후`로 정정.
- 2026-02-25: 변경 검증
- 무엇/왜/어떻게: 문구가 완전히 전환되었는지와 문서 진단 오류 유무를 확인.
- 실행 명령: `grep "직전/직후|커밋 전/후|--message" AGENTS.md`, `lsp_diagnostics AGENTS.md`, `lsp_diagnostics docs/20260225_커밋메시지사후검증전환.md`
- 결과: AGENTS.md에서 구문 미검출(No matches), 두 파일 모두 진단 오류 없음(No diagnostics found).