Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 48 additions & 41 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
# Paxo — AI 에이전트 작업 규칙

> **작업 시작 전 반드시 `git pull`.** 규칙 문서가 자주 바뀐다.
> **작업 시작 전 반드시 `git pull`.**

Paxo는 화면 속 문제를 단축키로 캡처하면 AI가 정답과 해설을 알려주는 **macOS 메뉴바 앱**이다.
저장소 이름이 `iOS`지만 iOS 앱이 아니다. 배포 타깃은 macOS 14+.

이 파일은 저장소 전역 규칙이다. 하위 디렉토리에 더 구체적인 `AGENTS.md`가 있고,
에이전트는 트리에서 **가장 가까운 파일**을 읽는다.
본 문서는 저장소의 전역 규칙(Global Rule)을 정의한다.
하위 디렉터리에 위치한 AGENTS.md가 우선 적용되며, AI 에이전트는 작업 중인 위치에서 가장 가까운 규칙 파일을 참조해야 한다.

- `Paxo/AGENTS.md` — Swift 앱 코드 (밟기 쉬운 지뢰 모음)
- `proxy-vercel/AGENTS.md` — API 프록시 계약
- `Paxo/AGENTS.md` — Swift 앱 코드 컨벤션 및 주요 주의사항 (Anti-patterns)
- `proxy-vercel/AGENTS.md` — API 프록시 서버 스펙(Contract)

공통 문서:
공통 참조 문서:

- `docs/architecture.md` — 앱 ↔ 프록시 ↔ Gemini ↔ StoreKit 연결
- `docs/domain.md` — 기능 · 과금 용어
- `docs/decisions.md` — 팀 결정 기록 (날짜순)
- `docs/architecture.md` — 앱 ↔ 프록시 ↔ Gemini ↔ StoreKit 시스템 구성도
- `docs/domain.md` — 핵심 도메인 기능 및 과금 관련 용어 사전
- `docs/decisions.md` — 팀의 주요 기술적 결정 사항

## 셋업
## 1. 초기 설정 (Setup)

클론 직후 반드시 1회. **이 파일이 없으면 빌드가 실패한다.**
저장소 클론 직후 반드시 1회 실행해야 한다.

```sh
cp Config/Secrets.example.swift Paxo/Secrets.swift
```

`Paxo/Secrets.swift`는 gitignore 대상이다. 절대 커밋하지 않는다.
템플릿을 `Paxo/` 안에 복사본으로 남기면 `Secrets` 중복 선언으로 빌드가 깨진다.
- `Paxo/Secrets.swift`는 gitignore 대상이다. 절대 커밋하지 않는다.
- 템플릿 파일(Secrets.example.swift)을 Paxo/ 디렉터리 내부에 복사본으로 남겨둘 경우, Secrets 구조체 중복 선언(Duplicate declaration) 오류로 인해 빌드가 깨지므로 주의한다.

## 명령
## 2. 주요 명령어 (Commands)

빌드:

Expand All @@ -51,46 +51,53 @@ xcrun swift-format lint --recursive --strict Paxo PaxoTests
xcrun swift-format format --in-place --recursive Paxo PaxoTests
```

## 코드 스타일
## 3. 코드 스타일 및 컨벤션

- **식별자는 영어, 주석과 사용자 노출 문구는 한국어.** 예외 없다.
- 주석은 *왜*를 적는다. API를 재진술하지 않는다. 밀도는 코드 20줄당 1줄 정도.
- import는 알파벳순. `swift-format`의 `OrderedImports` 규칙으로 CI에서 강제된다.
- 접근 제어는 `private`만 명시하고 `internal`은 생략한다. `public`/`fileprivate`은 쓰지 않는다.
- 모든 참조 타입은 `final`.
- 강제 언래핑(`!`) 금지. 현재 코드베이스에 0개다.
- `print`/`os_log`/`Logger` 추가 금지. 로깅 인프라가 없고, 도입은 별도 논의 대상이다.
- 상태 없는 유틸리티는 case 없는 `enum` 네임스페이스로 만든다 (`Prompts`, `KeychainHelper`).
- 명명 규칙: 모든 식별자(변수, 함수, 클래스 등)는 영어로, 주석과 사용자 노출 UI 문구는 한국어로 작성한다. 예외는 허용하지 않는다.
- 주석: 코드의 '동작'을 그대로 설명하지 않고 '의도(Why)'를 작성한다. 주석 밀도는 코드 20줄당 1줄 내외로 유지한다.
- Import 정렬: 알파벳순으로 정렬한다. `swift-format`의 `OrderedImports` 규칙에 의해 CI 파이프라인에서 강제(Enforce)된다.
- 접근 제어자: private만 명시적으로 작성하고 `internal은` 생략한다. `public` 및 `fileprivate`은 사용하지 않는다.
- 참조 타입: 모든 참조 타입(Class)은 `final`로 선언한다.
- 안전성: 강제 언래핑(`!`)은 엄격히 금지한다.
- 로깅: `print`, `os_log`, `Logger` 등의 추가를 금지한다. 현재 로깅 인프라가 없으며, 시스템 도입은 추후 별도로 논의한다.
- 유틸리티 객체: 상태(State)를 가지지 않는 유틸리티 함수 묶음은 case가 없는 `enum` 네임스페이스를 활용해 구현한다. (예: `Prompts`, `KeychainHelper`)

## 중복을 만들지 않는다
## 4. 중복 코드 생성 방지 (DRY)

새 유틸리티나 헬퍼를 만들기 전에 **기존 것을 먼저 검색한다.**
비슷한 함수가 이미 있으면 새로 쓰지 말고 그것을 쓰거나 확장한다.
AI 생성 코드가 조용히 중복을 쌓는 것이 이 저장소의 가장 큰 품질 리스크다.
신규 유틸리티나 헬퍼 함수를 작성하기 전, 반드시 기존에 구현된 코드를 먼저 검색한다.
유사한 로직이 존재한다면 새로 작성하지 않고 기존 코드를 재사용하거나 확장한다. AI 에이전트가 코드베이스를 파악하지 못하고 조용히 중복 코드를 쌓아 올리는 것은 본 프로젝트의 가장 큰 품질 리스크다.

## 커밋과 PR
## 5. 브랜치 전략 및 PR 규칙

- 브랜치 접두사: `feat/`, `fix/`, `docs/`, `chore/`, `style/`, `test/`
- 커밋: Conventional Commits 접두사 + **한국어 제목** + `-` 불릿 본문
- **AI 사용 여부를 커밋에 표기하지 않는다.** 초안을 누가 썼든 커밋한 사람이 전적으로 책임진다
- 기능 브랜치는 `develop`에서 만들고 PR도 `develop`으로 보낸다 (Squash 머지). `main`은 릴리즈 PR만 받는다 (Merge 머지)
- `develop` · `main` 직접 푸시 금지. PR과 CI 통과가 필수다
- PR을 올리기 전에 빌드와 테스트를 **실제로 돌려서** 통과를 확인한다
- 브랜치 네이밍: `feat/`, `fix/`, `docs/`, `chore/`, `style/`, `test/` 접두사를 사용한다.
- 커밋 메시지: `Conventional Commits 접두사 + 한국어 요약 제목 + (필요시) '-' 불릿을 활용한 본문` 형태로 작성한다.
- 책임 소재: 커밋 메시지에 AI 사용 여부를 표기하지 않는다. 코드의 초안 작성자와 무관하게, 해당 코드를 커밋한 담당자가 결과물에 대한 모든 책임을 진다.
- 워크플로우: 기능 개발 브랜치는 `develop`에서 분기하며, PR 또한 `develop`을 타깃으로 생성한다 (Squash Merge). `main` 브랜치는 릴리스용 PR만 수용한다 (Regular Merge).
- 직접 푸시 금지: `develop` 및 `main` 브랜치에 대한 Direct Push를 금지한다. 반드시 PR 생성 후 CI를 통과해야 한다.
- 사전 검증: PR을 생성하기 전, 로컬 환경에서 직접 빌드 및 테스트를 실행하여 정상 동작을 확인해야 한다.

## 절대 하지 말 것
## 6. 엄격한 금지 사항 (Do Not's)

- `Paxo.xcodeproj/project.pbxproj`의 파일 목록 수동 편집 — `Paxo/`는 파일시스템 동기화 그룹이라 손댈 필요가 없다
- `Paxo/Secrets.swift` 커밋
- `docs/hansung/` 커밋 — 사업계획서와 신청서, 비공개다
- `docs/private/` 커밋 — 비공개 저장소 `paxo-app/internal`의 clone이다. 내용을 공개 저장소로 옮기지 않는다
- `node_modules/` 커밋

**이 저장소는 공개다.** 커밋 전에 시크릿이 섞였는지 확인한다.
- `Paxo.xcodeproj/project.pbxproj` 수동 편집 금지: `Paxo/` 디렉터리는 파일 시스템과 자동 동기화되도록 설정되어 있으므로 프로젝트 파일을 수동으로 수정할 필요가 없다.
- `Paxo/Secrets.swift` 커밋 금지.
- `docs/hansung/` 커밋 금지: 비공개 사업계획서 및 신청서가 포함되어 있다.
- `docs/private/` 커밋 금지: 사내 비공개 저장소(`paxo-app/internal`)의 서브모듈/클론본이다. 보안 내용을 퍼블릭 레포지토리로 유출하지 않는다.
- `node_modules/` 커밋 금지.

## 릴리스
> 주의: 현재 저장소는 퍼블릭(Public) 저장소다. 커밋 전 API 키, 토큰 등 시크릿 정보가 포함되지 않았는지 반드시 교차 검증한다.

전체 절차는 비공개 저장소 `paxo-app/internal`의 `app-store-submission.md`(로컬에선 `docs/private/`)에 있다. 제출 전 함정 3가지만 여기 적는다.
## 릴리스 체크리스트

1. `MARKETING_VERSION`이 아직 `0.1.0`이다 — 출시 빌드는 `1.0.0`
2. 공유 스킴의 StoreKit Configuration을 **None**으로 되돌려야 한다. 안 그러면 실제 결제가 동작하지 않는다
3. `DEVELOPMENT_TEAM = L3JLLU88WG`가 실제 배포 인증서의 팀과 일치하는지 확인한다
전체 배포 프로세스는 사내 비공개 저장소 문서(`docs/private/app-store-submission.md`)를 따른다. 배포 직전 가장 빈번하게 발생하는 3가지 크리티컬 이슈를 아래에 명시한다.

- 버전 확인: `MARKETING_VERSION`이 0.1.0 상태로 남아있는지 확인한다. 실제 출시 빌드는 1.0.0 (또는 그 이상)이어야 한다.

- StoreKit 설정 복구: 공유 스킴(Scheme)에 설정된 StoreKit Configuration을 반드시 None으로 원복해야 한다. 해당 설정이 남아있으면 프로덕션 환경에서 실제 결제가 동작하지 않는다.

- 인증서 팀 매칭: 프로젝트 세팅의 `DEVELOPMENT_TEAM = L3JLLU88WG` 값이 실제 배포용 App Store Connect 팀 ID와 정확히 일치하는지 확인한다.
22 changes: 11 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
@AGENTS.md

## Claude Code 전용
# Claude Code 전용 설정

위 `AGENTS.md`가 팀 공통 규칙이다. Codex도 같은 파일을 읽는다.
아래는 Claude Code에만 해당하는 내용이다.
상단의 AGENTS.md는 팀 공통 규칙이며, Codex 등 다른 AI 에이전트도 해당 파일을 동일하게 참조한다.
본 항목은 Claude Code 환경에만 추가로 적용되는 전용 규칙 및 기능이다.

### 스킬
## 1. 커스텀 스킬 (명령어)

- `/release-check` — App Store 제출 전 검사 항목을 순서대로 확인
- `/proxy-change` — 클라이언트와 프록시를 동시에 고쳐야 할 때의 절차
- `/weekly-report` — 커밋 기록으로 주간 보고서 초안 생성
- `/release-check` — App Store 배포 전 필수 점검 항목들을 순서대로 교차 검증한다.
- `/proxy-change` — 클라이언트 앱과 프록시 서버의 API 스펙(Contract)을 동시에 수정해야 할 경우, 준수해야 할 표준 절차를 실행한다.
- `/weekly-report` — 최근 커밋 기록을 바탕으로 주간 업무 보고서 초안을 자동 생성한다.

### 작업 방식
## 2. 작업 방식 (Workflow)

- 파일 3개 이상을 건드리거나 프록시 계약을 바꾸는 변경은 **플랜 모드로 시작한다.**
- 빌드를 실제로 돌리기 전에 "고쳤다"고 보고하지 않는다.
- 프롬프트 템플릿은 `docs/prompts/`에 있다. 잘 된 프롬프트는 개인 것이 아니라 여기 쌓는다.
- 플랜 모드(Plan Mode) 필수: 파일 3개 이상을 수정하거나 프록시 API 스펙을 변경하는 등 영향 범위가 큰 작업은, 코드를 작성하기 전 반드시 플랜 모드로 시작하여 작업 계획부터 수립한다.
- 섣부른 완료 보고 금지: 코드를 수정했더라도 실제로 로컬 빌드 및 테스트를 실행하여 정상 동작을 확인하기 전까지는 절대 작업이 완료되었다고 단언(보고)하지 않는다.
- 프롬프트 문서화: 기준 프롬프트 템플릿은 `docs/prompts/` 디렉터리에 관리된다. 유용하게 쓰인 프롬프트는 개인의 노하우로 남겨두지 않고, 반드시 해당 경로에 문서화하여 팀과 공유한다.
76 changes: 40 additions & 36 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,81 @@
# 기여 가이드
# 기여 가이드 (Contributing Guide)

AI 에이전트용 규칙은 [`AGENTS.md`](AGENTS.md)에 있다. 사람이 처음 합류할 때 필요한 것만 여기 적는다.
AI 에이전트 전용 규칙은 [`AGENTS.md`](AGENTS.md)를 참조한다. 본 문서는 팀에 새로 합류한 개발자가 초기 셋업 및 기여를 위해 알아야 할 필수 사항만 다룬다.

## 처음 한 번
## 1. 초기 셋업 (Initial Setup)

```sh
git clone https://github.com/paxo-app/iOS.git
cd iOS
cp Config/Secrets.example.swift Paxo/Secrets.swift # 없으면 빌드 실패
# 만든 파일의 appToken 에 팀에서 받은 토큰 값을 채운다 (비우면 AI 호출이 401)
open Paxo.xcodeproj
cp Config/Secrets.example.swift Paxo/Secrets.swift # 누락 시 빌드 실패
# 생성된 파일의 appToken 필드에 발급받은 팀 토큰 값을 입력한다 (비워둘 경우 AI 호출 401 에러)
open Paxo.
```

Xcode에서 Signing & Capabilities → Team을 본인 계정으로 바꾸고 Run.
첫 캡처 시 **화면 기록 권한**을 허용한 뒤 앱을 재실행해야 한다 (macOS TCC 특성).
1. Xcode의 **Signing & Capabilities → Team**을 본인 계정으로 변경한 후 앱을 실행(Run)한다.
2. macOS TCC(투명성, 동의 및 제어) 정책에 따라, 최초 캡처 시 '화면 기록 권한'을 허용한 후 **반드시 앱을 완전히 종료하고 재실행**해야 정상 동작한다.

⚠️ **프록시에는 이미 `APP_TOKEN` 검증이 켜져 있다.** `Paxo/Secrets.swift`의 `appToken`을
비워두면 빌드·실행은 되지만 AI 호출이 전부 401로 실패한다. 토큰 값은 팀에 요청한다.
팀 테스트용 토큰은 프로덕션과 분리된 `APP_TOKEN_PREV` 슬롯을 쓴다.
⚠️ **주의: 프록시 서버에는 이미 `APP_TOKEN` 검증이 활성화되어 있다.**
`Paxo/Secrets.swift` 내의 `appToken` 값을 비워두면 앱 빌드와 실행은 성공하지만, AI API 호출 시 전부 401(Unauthorized) 에러가 발생한다. 토큰 값은 팀 내 담당자에게 요청한다. (팀 내부 테스트용 토큰은 프로덕션과 분리된 `APP_TOKEN_PREV` 슬롯을 사용한다.)

팀원이라면 운영 규칙과 온보딩 문서가 있는 비공개 저장소도 받는다: `git clone https://github.com/paxo-app/internal.git docs/private` → `docs/private/README.md`부터 본다.
> **정식 팀원 온보딩**
> 정규 팀원인 경우 운영 규칙과 온보딩 문서가 포함된 사내 비공개 저장소도 클론해야 한다. 클론 후 `docs/private/README.md`를 최우선으로 확인한다.
> `git clone [https://github.com/paxo-app/internal.git](https://github.com/paxo-app/internal.git) docs/private`

## 작업 흐름
## 2. 작업 흐름 (Workflow)

```sh
git fetch origin
git switch -c feat/무엇을-한다 origin/develop
# 작업
git switch -c feat/feature-name origin/develop
# 코드 작업 진행
xcodebuild -project Paxo.xcodeproj -scheme Paxo -destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO test
xcrun swift-format lint --recursive --strict --configuration .swift-format Paxo PaxoTests
git push -u origin HEAD
gh pr create --base develop

```

`develop`과 `main`은 보호돼 있다. 직접 푸시할 수 없고 PR이 필요하다.
`develop` 및 `main` 브랜치는 보호(Protected)되어 있으므로 직접 푸시(Direct Push)가 불가하며 반드시 PR을 거쳐야 한다.

- **`develop`** — 기능 PR을 **Squash**로 머지한다. 리뷰어 승인은 필수가 아니므로 CI가 초록이면 본인이 머지한다. 단 과금 · 프록시 · 릴리즈 설정 파일을 건드리면 CODEOWNERS 승인이 필요하다
- **`main`** — 릴리즈 PR(develop → main)만 **Merge**로 머지한다. 승인 1명이 필요하다. Squash하면 다음 릴리즈 PR에 이미 나간 변경이 다시 뜬다
* **`develop`**: 신규 기능 PR은 **Squash and Merge** 방식으로 병합한다. 일반적인 변경 사항은 리뷰어 승인 없이 CI를 통과(Green)하면 작성자가 직접 머지할 수 있다. 단, **과금, 프록시, 릴리스 설정 파일 등 핵심(위험) 경로 수정 시에는 반드시 CODEOWNERS의 승인이 필요**하다.
* **`main`**: 릴리스 PR(`develop` → `main`)만 허용하며, **Create a merge commit (Regular Merge)** 방식으로 병합한다. 배포 전 리뷰어 최소 1명의 승인이 필수다. (Squash 병합 시 커밋 히스토리가 꼬여 다음 릴리스 PR에 이전 변경 사항이 중복 노출되므로 절대 금지한다.)

## 커밋
## 3. 커밋 메시지 컨벤션

Conventional Commits 접두사 + 한국어 제목.
`Conventional Commits` 표준 접두사 + **한국어 제목** 형태로 작성한다.

```
```text
feat: 캡처 영역을 마지막 선택으로 기억

- 재캡처 시 이전 영역을 기본값으로 제시
- 화면이 바뀌면 무시하고 전체 화면으로 폴백

```

**AI가 초안을 썼는지는 적지 않는다.** 커밋한 사람이 전적으로 책임진다.
자세한 내용은 [`docs/ai-usage-rules.md`](docs/ai-usage-rules.md).
**커밋 메시지에 AI 사용 여부나 초안 작성 내역을 표기하지 않는다.**
코드의 초안을 누가 작성했든, 이를 커밋(반영)한 담당자가 최종 결과물에 대한 모든 책임을 진다. 상세 원칙은 [`docs/ai-usage-rules.md`](docs/ai-usage-rules.md)를 참고한다.

## 자주 걸리는 것
## 4. 트러블슈팅 (Troubleshooting)

| 증상 | 원인 |
|---|---|
| `cannot find 'Secrets' in scope` | `Paxo/Secrets.swift`를 안 만들었다 |
| AI 호출이 401 | `Paxo/Secrets.swift`의 `appToken`이 비었거나 값이 틀렸다 |
| `Secrets` 중복 선언 | 템플릿을 `Paxo/` 안에 복사했다. `Config/`에 둬야 한다 |
| 캡처 시 권한 오류 반복 | 권한 허용 후 앱을 재실행해야 한다 |
| 결과 패널이 캡처 이미지에 찍힘 | `ScreenCapturer`의 PID 필터나 sleep을 건드렸다 |
| 뷰에서 런타임 크래시 | 주입받지 않는 `@EnvironmentObject`를 선언했다 — [`Paxo/AGENTS.md`](Paxo/AGENTS.md) 표 확인 |
| 증상 | 원인 및 해결 |
| --- | --- |
| `cannot find 'Secrets' in scope` | `Paxo/Secrets.swift` 파일이 생성되지 않음 |
| AI API 호출 시 401 에러 발생 | `Paxo/Secrets.swift` 내 `appToken` 값이 누락되었거나 불일치함 |
| `Secrets` 중복 선언 빌드 에러 | 템플릿 원본을 `Paxo/` 내부에 중복으로 복사함 (템플릿은 `Config/` 에 유지해야 함) |
| 캡처 시 화면 기록 권한 오류 반복 | 시스템 권한 허용 후 앱을 완전히 종료(Quit)하고 재실행하지 않음 |
| 캡처 이미지에 결과 패널이 찍힘 | `ScreenCapturer`의 PID 필터 로직이나 sleep 타이밍을 잘못 수정함 |
| 뷰 진입 시 런타임 크래시 발생 | 상위 뷰에서 주입하지 않은 `@EnvironmentObject`를 선언함. 상세 의존성은 [`Paxo/AGENTS.md`](Paxo/AGENTS.md) 표 참조 |

## 지표
## 5. 프로젝트 지표 (Metrics)

```sh
scripts/ax-metrics.sh 30

```

PR 리드타임과 CI 통과율을 집계한다. 체감이 아니라 숫자로 본다.
PR 리드 타임(Lead Time)과 CI 통과율 등 프로젝트 건전성을 집계한다. 팀의 퍼포먼스는 막연한 체감이 아닌 **실제 데이터(숫자)를 기반으로 평가하고 개선**한다.

## 라이선스
## 6. 라이선스 (License)

기여한 코드는 저장소의 [MIT 라이선스](LICENSE)를 따른다.
본 저장소에 기여한 모든 코드는 [MIT 라이선스](LICENSE) 정책을 따른다.
Loading
Loading