# 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` 패턴을 기본으로 따른다. ### 네이밍 규칙 - 타입명은 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`를 먼저 로드한다. - 기본 형식은 `(scope): `를 사용한다. - `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 키 변경 시 빌드 설정과 런타임 초기화 지점을 함께 검토한다.