161 lines
8.8 KiB
Markdown
161 lines
8.8 KiB
Markdown
# AGENTS.md
|
|
`SodaLive` 저장소에서 작업하는 에이전트 실행 가이드다.
|
|
|
|
## 커뮤니케이션 규칙
|
|
- **"질문에 대한 답변과 설명은 한국어로 한다."**
|
|
- 사용자에게 전달하는 설명, 진행 상황, 결과 보고는 한국어로 작성한다.
|
|
- 코드 식별자, 파일 경로, 명령어는 원문(영문) 그대로 유지한다.
|
|
|
|
## 저장소 범위
|
|
- 앱 소스: `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 키 변경 시 빌드 설정과 런타임 초기화 지점을 함께 검토한다.
|