Files
appkit/.claude/commands/appkit.design.md
rupy1014 f4b14fddf5 Initial commit
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 07:07:35 +09:00

786 lines
16 KiB
Markdown

# appkit.design
**개발 준비 - API, ERD, 기술 스펙 설계**
---
## Overview
**This is Step 7 of the logical thinking 7-step workflow**:
```
논리적 사고 7단계:
1. /appkit.new → 아이디어 스케치 (어떤 서비스인지?)
2. /appkit.spec → 기능 구체화 (뭐가 필요할까? 누가 쓸까?)
3. /appkit.customer → 고객 스토리 (고객의 하루, 고민, 해결)
4. /appkit.sales → 세일즈 랜딩 구성 (어떻게 설득할까?)
5. /appkit.mvp → MVP 범위 정하기 (최소한으로 검증하려면?)
6. /appkit.merge → 기획 정돈 (흩어진 기획 통합)
7. /appkit.design → 개발 준비 (API, ERD, 기술 스펙) ← YOU ARE HERE
```
## Purpose
merge에서 정돈된 기획을 기반으로, 실제 개발에 필요한 **기술 스펙**을 생성합니다.
기획 레벨(merge)과 구현 레벨(개발) 사이의 다리 역할을 합니다.
**핵심 질문**: "개발자에게 뭘 전달해야 하나? 어떻게 만들까?"
---
## When to Use
- `/appkit.merge`로 기획을 정돈한 후 (Step 6 완료 후)
- 개발 시작 직전
- 기술 스펙이 필요할 때
- ERD, API 설계가 필요할 때
---
## Usage
```bash
/appkit.design
/appkit.design "persona 도메인 집중"
/appkit.design "API 우선"
```
---
## What I'll Do
### 1. 소스 문서 읽기
**읽을 파일들**:
- `docs/appkit/merge/concept-map.md` (통합 컨셉)
- `docs/appkit/merge/consolidated-specs.md` (통합 스펙)
- `docs/appkit/merge/journey-feature-map.md` (기능 매핑)
- `docs/appkit/mvp-scope.md` (MVP 범위)
### 2. 데이터 엔티티 설계 (ERD)
**Output**: `docs/appkit/design/entities.md`
```markdown
# Data Entity Design (ERD)
*생성 기준: concept-map.md, consolidated-specs.md*
*생성일: 2025-11-20*
---
## Entity Relationship Diagram
```mermaid
erDiagram
Persona ||--o{ Content : generates
Content ||--|| Post : becomes
Schedule ||--o{ Post : manages
Persona {
int id PK
string name
int age
string personality
string tone
string language
json style_rules
datetime created_at
}
Content {
int id PK
int persona_id FK
string topic
string image_url
text caption
json hashtags
enum status
datetime generated_at
}
Post {
int id PK
int content_id FK
string platform
datetime scheduled_at
datetime posted_at
enum status
}
Schedule {
int id PK
time execution_time
bool is_active
json target_personas
}
```
```
---
## Entity Details
### Entity: Persona
**Purpose**: 캐릭터별 페르소나 정보 저장
**Table Name**: `personas`
**Fields**:
| Field | Type | Constraints | Description |
|-------|------|-------------|-------------|
| id | INT | PK, AUTO_INCREMENT | 페르소나 고유 ID |
| name | VARCHAR(100) | NOT NULL | 캐릭터 이름 |
| age | INT | NOT NULL | 캐릭터 나이 |
| personality | TEXT | NOT NULL | 성격 설명 |
| tone | VARCHAR(50) | NOT NULL | 말투 (밝은/전문가/친근한) |
| language | VARCHAR(10) | NOT NULL | 언어 (ko/en/ja) |
| style_rules | JSON | NULL | 스타일 규칙 (이모티콘, 반말/존댓말) |
| created_at | DATETIME | NOT NULL, DEFAULT NOW() | 생성 시간 |
**Relationships**:
- `Persona.id` → `Content.persona_id` (1:N)
**Business Rules**:
- 한 페르소나는 여러 콘텐츠 생성 가능
- 페르소나 삭제 시 생성된 콘텐츠는 보존 (FK: RESTRICT)
**Sample Data**:
```json
{
"id": 1,
"name": "밝은 20대 여성",
"age": 25,
"personality": "긍정적이고 친근한 성격",
"tone": "밝은",
"language": "ko",
"style_rules": {
"emoji_frequency": "high",
"formality": "casual",
"hashtag_style": "trendy"
},
"created_at": "2025-01-01T10:00:00Z"
}
```
---
### Entity: Content
**Purpose**: AI가 생성한 콘텐츠 저장
**Table Name**: `contents`
**Fields**:
| Field | Type | Constraints | Description |
|-------|------|-------------|-------------|
| id | INT | PK, AUTO_INCREMENT | 콘텐츠 고유 ID |
| persona_id | INT | FK → personas.id, NOT NULL | 생성한 페르소나 |
| topic | VARCHAR(200) | NOT NULL | 주제 |
| image_url | VARCHAR(500) | NOT NULL | 이미지 URL (Midjourney) |
| caption | TEXT | NOT NULL | 캡션 (GPT 생성) |
| hashtags | JSON | NULL | 해시태그 배열 |
| status | ENUM | NOT NULL | draft, approved, posted |
| generated_at | DATETIME | NOT NULL, DEFAULT NOW() | 생성 시간 |
**Enums**:
- `status`: `draft` (생성됨), `approved` (검토 완료), `posted` (포스팅됨)
**Relationships**:
- `Content.persona_id``Persona.id` (N:1)
- `Content.id``Post.content_id` (1:1)
**Business Rules**:
- 하나의 콘텐츠는 하나의 포스트로 변환
- 캡션 길이: 최소 50자, 최대 2200자 (Instagram 제한)
---
### Entity: Post
**Purpose**: 실제 포스팅 기록
**Table Name**: `posts`
**Fields**:
| Field | Type | Constraints | Description |
|-------|------|-------------|-------------|
| id | INT | PK, AUTO_INCREMENT | 포스트 고유 ID |
| content_id | INT | FK → contents.id, UK, NOT NULL | 연결된 콘텐츠 |
| platform | VARCHAR(50) | NOT NULL | instagram, twitter, etc |
| scheduled_at | DATETIME | NOT NULL | 예약 시간 |
| posted_at | DATETIME | NULL | 실제 포스팅 시간 |
| status | ENUM | NOT NULL | pending, posted, failed |
**Enums**:
- `status`: `pending` (대기), `posted` (완료), `failed` (실패)
**Relationships**:
- `Post.content_id``Content.id` (1:1)
**Business Rules**:
- 하나의 콘텐츠는 하나의 포스트
- 포스팅 실패 시 재시도 로직 필요
---
## Summary
- **Total Entities**: 4 (Persona, Content, Post, Schedule)
- **Total Relationships**: 3 (1:N, 1:1)
- **Foreign Keys**: 3
**Entity Dependencies** (구현 순서):
1. **No dependencies**: Persona, Schedule (먼저 구현)
2. **Depends on 1**: Content (needs Persona)
3. **Depends on 2**: Post (needs Content)
```
### 3. API 엔드포인트 설계
**Output**: `docs/appkit/design/apis.md`
```markdown
# API Endpoint Design
*생성 기준: entities.md, consolidated-specs.md*
*API Style: RESTful*
*Base URL: `/api/v1`*
---
## 1. Persona APIs
### 1.1 Create Persona
**Endpoint**: `POST /personas`
**Description**: 새로운 페르소나 생성
**Request Body**:
```json
{
"name": "밝은 20대 여성",
"age": 25,
"personality": "긍정적이고 친근한 성격",
"tone": "밝은",
"language": "ko",
"style_rules": {
"emoji_frequency": "high",
"formality": "casual"
}
}
```
**Success Response** (201 Created):
```json
{
"persona": {
"id": 1,
"name": "밝은 20대 여성",
"age": 25,
"tone": "밝은",
"created_at": "2025-01-01T10:00:00Z"
}
}
```
**Error Responses**:
- 400 Bad Request: Validation failed
**Related Spec**: 001-persona/spec.md
**Related Entity**: Persona
---
### 1.2 List Personas
**Endpoint**: `GET /personas`
**Description**: 모든 페르소나 조회
**Success Response** (200 OK):
```json
{
"personas": [
{
"id": 1,
"name": "밝은 20대 여성",
"age": 25,
"tone": "밝은"
},
{
"id": 2,
"name": "전문가 30대 남성",
"age": 32,
"tone": "전문가"
}
],
"total": 2
}
```
---
## 2. Content APIs
### 2.1 Generate Content
**Endpoint**: `POST /contents/generate`
**Description**: AI로 콘텐츠 자동 생성
**Request Body**:
```json
{
"persona_id": 1,
"topic": "오늘의 운동 루틴",
"auto_post": false
}
```
**Success Response** (201 Created):
```json
{
"content": {
"id": 101,
"persona_id": 1,
"topic": "오늘의 운동 루틴",
"image_url": "https://midjourney.com/...",
"caption": "오늘도 열심히 운동했어요! 💪...",
"hashtags": ["운동", "헬스", "루틴"],
"status": "draft",
"generated_at": "2025-01-01T07:00:00Z"
}
}
```
**Business Logic**:
1. persona_id로 페르소나 정보 조회
2. Midjourney API 호출 (이미지 생성)
3. GPT API 호출 (캡션 생성, 페르소나 톤 반영)
4. 생성된 콘텐츠 DB 저장 (status: draft)
5. auto_post = true면 자동 포스팅 예약
**Error Responses**:
- 404 Not Found: Persona not found
- 502 Bad Gateway: Midjourney/GPT API 실패
- 503 Service Unavailable: API rate limit 초과
**Related Spec**: 002-content/spec.md
**Related Entity**: Content, Persona
---
### 2.2 List Contents
**Endpoint**: `GET /contents`
**Query Parameters**:
```
?persona_id=1 // Filter by persona
&status=draft // Filter by status
&date=2025-01-01 // Filter by generation date
&limit=20
&page=1
```
**Success Response** (200 OK):
```json
{
"contents": [
{
"id": 101,
"persona_id": 1,
"topic": "오늘의 운동 루틴",
"image_url": "https://...",
"status": "draft",
"generated_at": "2025-01-01T07:00:00Z"
}
],
"pagination": {
"total": 45,
"page": 1,
"limit": 20
}
}
```
---
## 3. Schedule APIs
### 3.1 Create Schedule
**Endpoint**: `POST /schedules`
**Description**: 자동 생성 스케줄 등록
**Request Body**:
```json
{
"execution_time": "07:00",
"target_personas": [1, 2, 3],
"is_active": true
}
```
**Success Response** (201 Created):
```json
{
"schedule": {
"id": 1,
"execution_time": "07:00",
"target_personas": [1, 2, 3],
"is_active": true
}
}
```
**Business Logic**:
- Cron job 생성 (매일 07:00 실행)
- 실행 시 target_personas의 각 페르소나로 콘텐츠 생성
- 생성 후 자동 포스팅
**Related Spec**: 003-schedule/spec.md
**Related Entity**: Schedule
---
## 4. Post APIs
### 4.1 Create Post
**Endpoint**: `POST /posts`
**Description**: 콘텐츠를 포스팅으로 예약
**Request Body**:
```json
{
"content_id": 101,
"platform": "instagram",
"scheduled_at": "2025-01-01T12:00:00Z"
}
```
**Success Response** (201 Created):
```json
{
"post": {
"id": 201,
"content_id": 101,
"platform": "instagram",
"scheduled_at": "2025-01-01T12:00:00Z",
"status": "pending"
}
}
```
**Business Logic**:
1. content_id로 콘텐츠 조회
2. 포스트 생성 (status: pending)
3. scheduled_at 시간에 Instagram API 호출
4. 성공 시 status = posted, 실패 시 status = failed
**Related Spec**: 003-schedule/spec.md (포스팅)
**Related Entity**: Post, Content
---
## API Summary
| Domain | Endpoints | Description |
|--------|-----------|-------------|
| Persona | 3 (create, list, update) | 페르소나 관리 |
| Content | 2 (generate, list) | 콘텐츠 생성 |
| Schedule | 2 (create, list) | 스케줄 관리 |
| Post | 2 (create, list) | 포스팅 관리 |
**Total Endpoints**: 9
---
## Error Response Format
**Standard Error Response**:
```json
{
"error": {
"code": "API_RATE_LIMIT",
"message": "Midjourney API rate limit exceeded",
"details": {
"limit": 50,
"current": 51,
"reset_at": "2025-01-01T08:00:00Z"
}
}
}
```
**Error Codes**:
- `VALIDATION_ERROR`: 입력 검증 실패
- `API_RATE_LIMIT`: API 제한 초과
- `GENERATION_FAILED`: 콘텐츠 생성 실패
- `NOT_FOUND`: 리소스 없음
```
### 4. 기술 정책 정의
**Output**: `docs/appkit/design/tech-policies.md`
```markdown
# Technical Policies
*기술 구현 관련 정책*
---
## API Rate Limiting
### Midjourney API
- **Limit**: 시간당 50회
- **동시 처리**: 최대 3개
- **초과 시**: 429 에러, 다음 시간까지 대기
- **Queue**: FIFO 방식
### OpenAI GPT-4 API
- **Limit**: 분당 60회
- **토큰**: 일 500,000 제한
- **초과 시**: 429 에러
- **Retry**: Exponential backoff (1s, 2s, 4s)
### Instagram Graph API
- **Limit**: 하루 200개 포스트
- **시간당**: 25회
- **초과 시**: 403 에러
**구현 방안**:
- Rate Limiter 모듈 구현
- 우선순위 큐 시스템
- API 호출 로그 기록
---
## Error Handling
### 재시도 정책
**API 실패**:
- 재시도 횟수: 3회
- 방식: Exponential backoff
- 대기 시간: 1s, 2s, 4s
**생성 실패**:
- 재시도 횟수: 2회
- 방식: 즉시 재시도
- 실패 시: 에러 로그 기록, 알림
**품질 불량**:
- 판단 기준: 이미지 해상도 < 1080x1080
- 처리: 자동 재생성 (1회)
### 로깅
**로그 종류**:
- `error.log`: 모든 에러
- `api-calls.log`: API 호출 기록
- `generation.log`: 콘텐츠 생성 기록
**로그 레벨**:
- ERROR: 시스템 오류
- WARN: API 제한 근접
- INFO: 정상 실행
---
## Content Safety
### 브랜드 안전성
- 성인 콘텐츠: GPT moderation API로 자동 차단
- 폭력/혐오: 필터 적용
- 저작권: 학습 데이터 외 참조 금지
### 품질 검증
- 이미지: 최소 1080x1080
- 캡션: 최소 50자, 최대 2200자
- 해시태그: 5-30개
---
## Data Management
### 저장 위치
- 페르소나: Database (personas table)
- 콘텐츠: Database (contents table)
- 이미지: S3 (Midjourney URL 저장)
- 로그: `logs/` directory
### 백업
- DB 백업: 일 1회 (자정)
- S3 백업: 자동 (versioning)
- 로그 보존: 90일
```
### 5. 화면-API 매핑
**Output**: `docs/appkit/design/screen-api-map.md`
```markdown
# Screen to API Mapping
*UI 화면과 API 호출 매핑*
---
## Flow: 콘텐츠 자동 생성
### Screen 1: 페르소나 설정
**User Actions**:
- 페르소나 목록 조회
- 새 페르소나 생성
**API Calls**:
```
1. GET /personas
→ Returns: 페르소나 리스트
2. (On create) POST /personas
→ Returns: 생성된 페르소나
```
---
### Screen 2: 스케줄 설정
**User Actions**:
- 스케줄 등록
- 실행 시간 설정
- 대상 페르소나 선택
**API Calls**:
```
1. GET /personas
→ Returns: 선택 가능한 페르소나
2. (On save) POST /schedules
→ Returns: 생성된 스케줄
```
---
### Screen 3: 콘텐츠 확인
**User Actions**:
- 생성된 콘텐츠 조회
- 승인/거부
**API Calls**:
```
1. GET /contents?status=draft
→ Returns: Draft 콘텐츠 목록
2. (On approve) PATCH /contents/{id}
→ Body: { "status": "approved" }
→ Returns: 업데이트된 콘텐츠
```
---
## Complete Sequence Diagram
```mermaid
sequenceDiagram
actor User
participant UI
participant API
participant Midjourney
participant GPT
participant Instagram
User->>UI: 스케줄 등록
UI->>API: POST /schedules
API-->>UI: Schedule created
Note over API: 매일 07:00 Cron 실행
API->>API: GET /personas (target)
loop Each Persona
API->>Midjourney: Generate Image
Midjourney-->>API: Image URL
API->>GPT: Generate Caption
GPT-->>API: Caption Text
API->>API: Save Content (draft)
end
User->>UI: 콘텐츠 확인
UI->>API: GET /contents?status=draft
API-->>UI: Content List
User->>UI: 승인
UI->>API: PATCH /contents/{id}
API->>Instagram: Post Content
Instagram-->>API: Success
API-->>UI: Posted
```
```
---
## Output Files
### 생성될 파일들:
```
docs/appkit/design/
├── entities.md # ERD 및 데이터 모델
├── apis.md # API 엔드포인트 설계
├── tech-policies.md # 기술 정책
└── screen-api-map.md # 화면-API 매핑
```
---
## Integration Points
### 다른 명령어와의 연계:
- **From `/appkit.merge`**: concept-map.md 사용
- **To 개발팀**: 설계 문서 전달
- **To `/appkit.verify`**: 설계 완성도 체크 (향후)
---
## Key Principles
### 설계 원칙:
1. **Planning only, no code**: 설계 문서만 생성, 코드 작성 안 함
2. **Entity-first approach**: 데이터 모델부터 설계
3. **API follows entity**: API는 엔티티 관계에서 도출
4. **Traceability**: 모든 설계는 spec과 연결
---
## Next Steps
### 이 명령어 실행 후:
**📍 7단계 완료!**
- 기획부터 설계까지 모든 문서 완성
- 개발팀에게 전달 가능
- MVP Phase 0 개발 시작
---
## Version
- **Version**: 1.0.0
- **Created**: 2025-11-20
- **Philosophy**: "설계는 기획과 구현 사이의 다리"