Skill: Design API
목적
도메인의 API 명세를 작성하고 입출력과 처리 흐름 정의
철학: "추상적 설계 말고, 정확한 명세"
입력
- 도메인 이름 (예: "users")
- Phase 2 결과 (SESSION.md의 도메인 정의)
- Phase 3 결과 (domain-model.md)
출력
ai-context/domain-books/{domain}/api-spec.md
- API 목록 + Request/Response + 수도코드 (복잡한 로직만)
작동 방식
1. API 목록 추출
SESSION.md와 domain-model.md의 생명주기(생성/수정/삭제)와 비즈니스 룰을 읽고 필요한 API를 도출한다:
domain-model.md → users 도메인:
생성: 회원가입
조회: 프로필 조회
수정: 프로필 수정
삭제: 회원 탈퇴 (Cascade → 복잡도 "보통")
2. 복잡도 판단
각 API가 수도코드가 필요한지 판단한다:
| 복잡도 |
판단 기준 |
수도코드 |
| 단순 |
단순 CRUD, 검증만 있음 |
❌ 불필요 |
| 보통 |
Cascade, 다단계 검증, 조건부 로직 |
✅ 필요 |
| 복잡 |
상태 전이, 복잡한 계산, 외부 호출 |
✅ 필수 |
3. Request/Response 작성
domain-model.md의 용어와 제약 조건을 그대로 활용해 필드 테이블을 작성한다.
- 필드명: camelCase
- 타입: 한글 (문자열, 숫자, 불린, 날짜시간, 배열, 객체)
- 오류 메시지: 반드시 한글
4. 수도코드 작성 (복잡한 로직만)
단계별 번호와 들여쓰기로 처리 흐름을 자연어로 표현한다.
api-spec.md 구조
# {domain} API 명세
> 생성일: {오늘 날짜}
> Phase: 4 (API Designer)
> 상태: ✅ 완료
---
## API 목록
| 번호 | API 이름 | 설명 | 복잡도 |
|------|----------|------|--------|
| 1 | 회원가입 | 새 사용자 생성 | 단순 |
| 2 | 프로필 조회 | 사용자 정보 조회 | 단순 |
| 3 | 프로필 수정 | 사용자 정보 변경 | 단순 |
| 4 | 회원 탈퇴 | 사용자 삭제 (Cascade) | 보통 |
---
## 1. 회원가입
### Request (요청)
| 필드명 | 타입 | 필수 | 설명 | 예시 | 검증 규칙 |
|--------|------|------|------|------|-----------|
| email | 문자열 | O | 로그인용 이메일 주소 | user@example.com | 이메일 형식, 중복 불가, 최대 255자 |
| displayName | 문자열 | O | 사용자 닉네임 | 여행러버 | 최소 1자, 최대 50자 |
| profileImage | 문자열 | X | 프로필 사진 URL | https://example.com/photo.jpg | URL 형식 |
| preferredLanguage | 문자열 | X | 선호 언어 | ko | 'ko' 또는 'en' (기본값: 'en') |
### Response (응답)
#### 성공 (200)
| 필드명 | 타입 | 설명 | 예시 |
|--------|------|------|------|
| id | 문자열 | 생성된 사용자 ID | u_123abc |
| email | 문자열 | 이메일 주소 | user@example.com |
| displayName | 문자열 | 표시 이름 | 여행러버 |
| profileImage | 문자열 | 프로필 사진 URL | https://example.com/photo.jpg |
| preferredLanguage | 문자열 | 선호 언어 | ko |
| createdAt | 날짜시간 | 가입 시각 | 2026-01-28T10:30:00Z |
#### 오류
| 상태 | 조건 | 메시지 | 필드 예시 |
|------|------|--------|-----------|
| 409 | 이메일 중복 | 이미 가입된 이메일입니다 | {"email": "user@example.com"} |
| 400 | 필드 검증 실패 | 이메일 형식이 올바르지 않습니다 | {"email": "invalid-email"} |
| 400 | 필수 필드 누락 | 필수 필드가 누락되었습니다 | {"displayName": null} |
| 400 | 언어 코드 오류 | 지원하지 않는 언어입니다 | {"preferredLanguage": "fr"} |
---
## 4. 회원 탈퇴
### Request (요청)
| 필드명 | 타입 | 필수 | 설명 | 예시 | 검증 규칙 |
|--------|------|------|------|------|-----------|
| userId | 문자열 | O | 삭제할 사용자 ID | u_123abc | - |
### Response (응답)
#### 성공 (200)
| 필드명 | 타입 | 설명 | 예시 |
|--------|------|------|------|
| message | 문자열 | 완료 메시지 | 회원 탈퇴가 완료되었습니다 |
| deletedCount | 숫자 | 삭제된 연관 데이터 수 | 15 |
#### 오류
| 상태 | 조건 | 메시지 | 필드 예시 |
|------|------|--------|-----------|
| 404 | 사용자 없음 | 존재하지 않는 사용자입니다 | {"userId": "u_999"} |
| 403 | 권한 없음 | 본인만 탈퇴할 수 있습니다 | {"userId": "u_123abc"} |
### 수도코드
\`\`\`
1. userId로 사용자를 조회한다
- 없으면 404 오류 반환
2. 요청자가 본인인지 확인한다
- 본인이 아니면 403 오류 반환
3. 연결된 모든 데이터를 조회한다
- 번역 기록 목록
- 미션 진행 기록 목록
4. 연결 데이터를 모두 삭제한다
- 번역 기록 삭제 (Cascade)
- 미션 진행 기록 삭제 (Cascade)
- 삭제된 개수를 기록
5. 사용자 엔티티를 삭제한다
6. 삭제 완료 메시지와 개수를 반환한다
\`\`\`
작성 원칙
Request 필드 설명
| 항목 |
내용 |
| 필드명 |
camelCase (예: displayName) |
| 타입 |
한글 (문자열, 숫자, 불린, 날짜시간, 배열, 객체) |
| 필수 |
O/X |
| 설명 |
구체적 역할 설명 |
| 예시 |
실제 사용 가능한 값 |
| 검증 규칙 |
모든 제약 조건 나열 |
Response 필드 설명
| 항목 |
내용 |
| 필드명 |
camelCase |
| 타입 |
한글 |
| 설명 |
필드 역할 설명 |
| 예시 |
실제 반환 값 예시 |
오류 응답 설명
| 항목 |
내용 |
| 상태 |
숫자 코드 (200, 400, 404 등) |
| 조건 |
오류 발생 조건 |
| 메시지 |
한글 사용자 메시지 |
| 필드 예시 |
오류 관련 필드와 값 |
복잡도 판단 기준
단순 (수도코드 불필요)
- 단순 CRUD (생성, 조회, 수정, 삭제)
- 검증만 있는 경우
- 직접적인 데이터 반환
예시: 회원가입, 프로필 조회, 프로필 수정
보통 (수도코드 필요)
- Cascade 처리
- 다단계 검증
- 조건부 로직 (if/else)
- 여러 엔티티 조회/수정
예시: 회원 탈퇴 (연결 데이터 삭제), 주문 생성 (재고 확인 + 차감)
복잡 (수도코드 필수)
- 상태 전이 (FSM)
- 복잡한 계산 로직
- 외부 API 호출 + 후처리
- 트랜잭션 관리
예시: 결제 처리 (검증 → 결제 → 재고 차감 → 알림), 미션 진행 (상태 전이)
수도코드 작성 가이드
구조
1. [액션 1]
- [세부사항 1-1]
- [세부사항 1-2]
2. [액션 2]
- [조건] 확인
- 맞으면: [처리 A]
- 아니면: [처리 B]
3. [결과 반환]
조건문
1. X를 확인한다
- 맞으면: Y를 한다
- 아니면: Z 오류 반환
반복문
1. 모든 A 목록을 조회한다
2. 각 A마다:
- B를 처리한다
- C를 기록한다
3. 처리된 개수를 반환한다
외부 호출
1. X 서비스에 Y를 요청한다
- 성공하면: 결과를 저장
- 실패하면: Z 오류 반환
2. 저장된 결과로 A를 처리한다
타입 표현
기본 타입
| 영어 |
한글 |
| string |
문자열 |
| number |
숫자 |
| boolean |
불린 |
| datetime |
날짜시간 |
| array |
배열 |
| object |
객체 |
복합 타입
| 필드명 | 타입 | 설명 |
|--------|------|------|
| tags | 문자열 배열 | 관심 태그 목록 |
| address | 주소 객체 | 주소 정보 |
객체 타입은 별도 정의:
### 주소 객체
| 필드명 | 타입 | 필수 | 설명 |
|--------|------|------|------|
| street | 문자열 | O | 도로명 |
| city | 문자열 | O | 도시 |
| zipCode | 문자열 | O | 우편번호 |
기술 용어 금지 목록
아래 용어가 없는지 확인한다:
| 금지 영역 |
키워드 |
대체 표현 |
| 프로토콜 |
HTTP, REST, GraphQL, GET, POST, PUT, PATCH, DELETE |
사용 목적으로 설명 |
| 인증 |
JWT, OAuth, Bearer, Token |
"인증 정보" |
| 형식 |
JSON, XML, YAML |
"응답" |
| 상태 코드 영어명 |
OK, Created, Bad Request, Forbidden |
숫자만 (예: "성공 (200)") |
한글 메시지 필수
✅ 좋은 메시지
- "이미 가입된 이메일입니다"
- "필수 필드가 누락되었습니다"
- "본인만 수정할 수 있습니다"
- "회원 탈퇴가 완료되었습니다"
❌ 나쁜 메시지
- "Email already exists"
- "Invalid request"
- "Forbidden"
- "Success"
검증 체크리스트
api-spec.md 작성 완료 후:
1---2name: design-api3description: domain-model.md를 기반으로 API 명세를 작성한다. 각 API마다 Request/Response 필드 테이블과 오류 응답을 정의하고, 복잡한 로직(Cascade·상태전이·다단계 검증)에만 수도코드를 추가한다. 기술 용어(HTTP, REST, JWT 등) 금지.4---56# Skill: Design API78## 목적910도메인의 **API 명세**를 작성하고 입출력과 처리 흐름 정의1112**철학**: "추상적 설계 말고, 정확한 명세"1314---1516## 입력1718- 도메인 이름 (예: "users")19- Phase 2 결과 (SESSION.md의 도메인 정의)20- Phase 3 결과 (domain-model.md)2122---2324## 출력2526- `ai-context/domain-books/{domain}/api-spec.md`27- API 목록 + Request/Response + 수도코드 (복잡한 로직만)2829---3031## 작동 방식3233### 1. API 목록 추출3435SESSION.md와 domain-model.md의 생명주기(생성/수정/삭제)와 비즈니스 룰을 읽고 필요한 API를 도출한다:3637```38domain-model.md → users 도메인:39 생성: 회원가입40 조회: 프로필 조회41 수정: 프로필 수정42 삭제: 회원 탈퇴 (Cascade → 복잡도 "보통")43```4445### 2. 복잡도 판단4647각 API가 수도코드가 필요한지 판단한다:4849| 복잡도 | 판단 기준 | 수도코드 |50|-------|---------|--------|51| 단순 | 단순 CRUD, 검증만 있음 | ❌ 불필요 |52| 보통 | Cascade, 다단계 검증, 조건부 로직 | ✅ 필요 |53| 복잡 | 상태 전이, 복잡한 계산, 외부 호출 | ✅ 필수 |5455### 3. Request/Response 작성5657domain-model.md의 용어와 제약 조건을 그대로 활용해 필드 테이블을 작성한다.58- 필드명: camelCase59- 타입: 한글 (문자열, 숫자, 불린, 날짜시간, 배열, 객체)60- 오류 메시지: 반드시 한글6162### 4. 수도코드 작성 (복잡한 로직만)6364단계별 번호와 들여쓰기로 처리 흐름을 자연어로 표현한다.6566---6768## api-spec.md 구조6970```markdown71# {domain} API 명세7273> 생성일: {오늘 날짜}74> Phase: 4 (API Designer)75> 상태: ✅ 완료7677---7879## API 목록8081| 번호 | API 이름 | 설명 | 복잡도 |82|------|----------|------|--------|83| 1 | 회원가입 | 새 사용자 생성 | 단순 |84| 2 | 프로필 조회 | 사용자 정보 조회 | 단순 |85| 3 | 프로필 수정 | 사용자 정보 변경 | 단순 |86| 4 | 회원 탈퇴 | 사용자 삭제 (Cascade) | 보통 |8788---8990## 1. 회원가입9192### Request (요청)9394| 필드명 | 타입 | 필수 | 설명 | 예시 | 검증 규칙 |95|--------|------|------|------|------|-----------|96| email | 문자열 | O | 로그인용 이메일 주소 | user@example.com | 이메일 형식, 중복 불가, 최대 255자 |97| displayName | 문자열 | O | 사용자 닉네임 | 여행러버 | 최소 1자, 최대 50자 |98| profileImage | 문자열 | X | 프로필 사진 URL | https://example.com/photo.jpg | URL 형식 |99| preferredLanguage | 문자열 | X | 선호 언어 | ko | 'ko' 또는 'en' (기본값: 'en') |100101### Response (응답)102103#### 성공 (200)104105| 필드명 | 타입 | 설명 | 예시 |106|--------|------|------|------|107| id | 문자열 | 생성된 사용자 ID | u_123abc |108| email | 문자열 | 이메일 주소 | user@example.com |109| displayName | 문자열 | 표시 이름 | 여행러버 |110| profileImage | 문자열 | 프로필 사진 URL | https://example.com/photo.jpg |111| preferredLanguage | 문자열 | 선호 언어 | ko |112| createdAt | 날짜시간 | 가입 시각 | 2026-01-28T10:30:00Z |113114#### 오류115116| 상태 | 조건 | 메시지 | 필드 예시 |117|------|------|--------|-----------|118| 409 | 이메일 중복 | 이미 가입된 이메일입니다 | {"email": "user@example.com"} |119| 400 | 필드 검증 실패 | 이메일 형식이 올바르지 않습니다 | {"email": "invalid-email"} |120| 400 | 필수 필드 누락 | 필수 필드가 누락되었습니다 | {"displayName": null} |121| 400 | 언어 코드 오류 | 지원하지 않는 언어입니다 | {"preferredLanguage": "fr"} |122123---124125## 4. 회원 탈퇴126127### Request (요청)128129| 필드명 | 타입 | 필수 | 설명 | 예시 | 검증 규칙 |130|--------|------|------|------|------|-----------|131| userId | 문자열 | O | 삭제할 사용자 ID | u_123abc | - |132133### Response (응답)134135#### 성공 (200)136137| 필드명 | 타입 | 설명 | 예시 |138|--------|------|------|------|139| message | 문자열 | 완료 메시지 | 회원 탈퇴가 완료되었습니다 |140| deletedCount | 숫자 | 삭제된 연관 데이터 수 | 15 |141142#### 오류143144| 상태 | 조건 | 메시지 | 필드 예시 |145|------|------|--------|-----------|146| 404 | 사용자 없음 | 존재하지 않는 사용자입니다 | {"userId": "u_999"} |147| 403 | 권한 없음 | 본인만 탈퇴할 수 있습니다 | {"userId": "u_123abc"} |148149### 수도코드150151\`\`\`1521. userId로 사용자를 조회한다153 - 없으면 404 오류 반환1541552. 요청자가 본인인지 확인한다156 - 본인이 아니면 403 오류 반환1571583. 연결된 모든 데이터를 조회한다159 - 번역 기록 목록160 - 미션 진행 기록 목록1611624. 연결 데이터를 모두 삭제한다163 - 번역 기록 삭제 (Cascade)164 - 미션 진행 기록 삭제 (Cascade)165 - 삭제된 개수를 기록1661675. 사용자 엔티티를 삭제한다1681696. 삭제 완료 메시지와 개수를 반환한다170\`\`\`171```172173---174175## 작성 원칙176177### Request 필드 설명178179| 항목 | 내용 |180|------|------|181| **필드명** | camelCase (예: displayName) |182| **타입** | 한글 (문자열, 숫자, 불린, 날짜시간, 배열, 객체) |183| **필수** | O/X |184| **설명** | 구체적 역할 설명 |185| **예시** | 실제 사용 가능한 값 |186| **검증 규칙** | 모든 제약 조건 나열 |187188### Response 필드 설명189190| 항목 | 내용 |191|------|------|192| **필드명** | camelCase |193| **타입** | 한글 |194| **설명** | 필드 역할 설명 |195| **예시** | 실제 반환 값 예시 |196197### 오류 응답 설명198199| 항목 | 내용 |200|------|------|201| **상태** | 숫자 코드 (200, 400, 404 등) |202| **조건** | 오류 발생 조건 |203| **메시지** | **한글** 사용자 메시지 |204| **필드 예시** | 오류 관련 필드와 값 |205206---207208## 복잡도 판단 기준209210### 단순 (수도코드 불필요)211212- 단순 CRUD (생성, 조회, 수정, 삭제)213- 검증만 있는 경우214- 직접적인 데이터 반환215216**예시**: 회원가입, 프로필 조회, 프로필 수정217218### 보통 (수도코드 필요)219220- Cascade 처리221- 다단계 검증222- 조건부 로직 (if/else)223- 여러 엔티티 조회/수정224225**예시**: 회원 탈퇴 (연결 데이터 삭제), 주문 생성 (재고 확인 + 차감)226227### 복잡 (수도코드 필수)228229- 상태 전이 (FSM)230- 복잡한 계산 로직231- 외부 API 호출 + 후처리232- 트랜잭션 관리233234**예시**: 결제 처리 (검증 → 결제 → 재고 차감 → 알림), 미션 진행 (상태 전이)235236---237238## 수도코드 작성 가이드239240### 구조241242```2431. [액션 1]244 - [세부사항 1-1]245 - [세부사항 1-2]2462472. [액션 2]248 - [조건] 확인249 - 맞으면: [처리 A]250 - 아니면: [처리 B]2512523. [결과 반환]253```254255### 조건문256257```2581. X를 확인한다259 - 맞으면: Y를 한다260 - 아니면: Z 오류 반환261```262263### 반복문264265```2661. 모든 A 목록을 조회한다2672682. 각 A마다:269 - B를 처리한다270 - C를 기록한다2712723. 처리된 개수를 반환한다273```274275### 외부 호출276277```2781. X 서비스에 Y를 요청한다279 - 성공하면: 결과를 저장280 - 실패하면: Z 오류 반환2812822. 저장된 결과로 A를 처리한다283```284285---286287## 타입 표현288289### 기본 타입290291| 영어 | 한글 |292|------|------|293| string | 문자열 |294| number | 숫자 |295| boolean | 불린 |296| datetime | 날짜시간 |297| array | 배열 |298| object | 객체 |299300### 복합 타입301302```markdown303| 필드명 | 타입 | 설명 |304|--------|------|------|305| tags | 문자열 배열 | 관심 태그 목록 |306| address | 주소 객체 | 주소 정보 |307```308309**객체 타입은 별도 정의**:310311```markdown312### 주소 객체313314| 필드명 | 타입 | 필수 | 설명 |315|--------|------|------|------|316| street | 문자열 | O | 도로명 |317| city | 문자열 | O | 도시 |318| zipCode | 문자열 | O | 우편번호 |319```320321---322323## 기술 용어 금지 목록324325아래 용어가 없는지 확인한다:326327| 금지 영역 | 키워드 | 대체 표현 |328|---------|-------|---------|329| 프로토콜 | HTTP, REST, GraphQL, GET, POST, PUT, PATCH, DELETE | 사용 목적으로 설명 |330| 인증 | JWT, OAuth, Bearer, Token | "인증 정보" |331| 형식 | JSON, XML, YAML | "응답" |332| 상태 코드 영어명 | OK, Created, Bad Request, Forbidden | 숫자만 (예: "성공 (200)") |333334---335336## 한글 메시지 필수337338### ✅ 좋은 메시지339340- "이미 가입된 이메일입니다"341- "필수 필드가 누락되었습니다"342- "본인만 수정할 수 있습니다"343- "회원 탈퇴가 완료되었습니다"344345### ❌ 나쁜 메시지346347- "Email already exists"348- "Invalid request"349- "Forbidden"350- "Success"351352---353354## 검증 체크리스트355356api-spec.md 작성 완료 후:357358- [ ] API 목록 테이블 있음359- [ ] 각 API마다 Request/Response 있음360- [ ] Request에 검증 규칙 명시361- [ ] Response에 성공/오류 모두 포함362- [ ] 오류 메시지가 모두 한글363- [ ] 복잡한 로직에 수도코드 있음364- [ ] 단순 CRUD에는 수도코드 없음365- [ ] 기술 용어 (HTTP, REST, JWT 등) 0개366- [ ] 타입 표현이 한글 ("문자열", "숫자" 등)