feat: Drama Studio 프로젝트 초기 구조 설정
- FastAPI 백엔드 (audio-studio-api) - Next.js 프론트엔드 (audio-studio-ui) - Qwen3-TTS 엔진 (audio-studio-tts) - MusicGen 서비스 (audio-studio-musicgen) - Docker Compose 개발/운영 환경 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
352
.claude/project-knowledge.md
Normal file
352
.claude/project-knowledge.md
Normal file
@ -0,0 +1,352 @@
|
||||
# Project Knowledge
|
||||
|
||||
이 문서는 프로젝트의 개발 표준 및 패턴을 정의합니다.
|
||||
Claude.ai Projects 또는 Claude Code에서 참조하여 일관된 코드를 작성하세요.
|
||||
|
||||
---
|
||||
|
||||
## 1. 프로젝트 개요
|
||||
|
||||
### 기술 스택
|
||||
- **Frontend**: Next.js 16 + React 19 + TypeScript + Tailwind CSS 4 + shadcn/ui
|
||||
- **Backend**: FastAPI + Python 3.11 + Pydantic v2
|
||||
- **Database**: MongoDB 7.0 (motor async driver) + Redis 7
|
||||
- **AI**: Claude API (Anthropic) + OpenAI API
|
||||
- **Containerization**: Docker + Docker Compose
|
||||
- **Repository**: Gitea (http://gitea.yakenator.io/yakenator/)
|
||||
|
||||
---
|
||||
|
||||
## 2. Docker 배포 규칙
|
||||
|
||||
### Dockerfile 패턴 (Python Worker)
|
||||
```dockerfile
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends git && rm -rf /var/lib/apt/lists/*
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY *.py .
|
||||
CMD ["python", "worker.py"]
|
||||
```
|
||||
|
||||
### docker-compose 서비스 패턴
|
||||
```yaml
|
||||
services:
|
||||
{서비스명}:
|
||||
build:
|
||||
context: ./repos/{서비스명}
|
||||
dockerfile: Dockerfile
|
||||
container_name: {프로젝트}-{서비스명}
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- MONGODB_URL=mongodb://${MONGO_USER}:${MONGO_PASSWORD}@mongodb:27017/
|
||||
- DB_NAME={데이터베이스명}
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- {프로젝트}-network
|
||||
```
|
||||
|
||||
### 네이밍 규칙
|
||||
- 컨테이너: `{프로젝트}-{서비스명}`
|
||||
- 볼륨: `{프로젝트}_{데이터유형}_data`
|
||||
- 네트워크: `{프로젝트}-network`
|
||||
|
||||
---
|
||||
|
||||
## 3. 한국어 개발 컨벤션
|
||||
|
||||
### Docstring
|
||||
```python
|
||||
async def get_data(self, name: str, context: List[str] = None) -> DataInfo:
|
||||
"""
|
||||
데이터 조회 (context 기반 후보 선택)
|
||||
|
||||
Args:
|
||||
name: 데이터 이름
|
||||
context: 컨텍스트 키워드
|
||||
|
||||
Returns:
|
||||
DataInfo 객체
|
||||
"""
|
||||
```
|
||||
|
||||
### 로깅 메시지 (한글 + 영문 혼용)
|
||||
```python
|
||||
logger.info(f"Found {len(items)} item(s) for '{name}'")
|
||||
logger.warning(f"Operation failed (non-critical): {e}")
|
||||
```
|
||||
|
||||
### 커밋 메시지
|
||||
```
|
||||
feat: 기능 설명
|
||||
|
||||
- 변경사항 1
|
||||
- 변경사항 2
|
||||
|
||||
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. FastAPI 패턴
|
||||
|
||||
### 앱 초기화
|
||||
```python
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
app = FastAPI(
|
||||
title="{서비스명} API",
|
||||
description="서비스 설명",
|
||||
version="1.0.0"
|
||||
)
|
||||
```
|
||||
|
||||
### Pydantic 모델
|
||||
```python
|
||||
class CreateRequest(BaseModel):
|
||||
name: str
|
||||
description: Optional[str] = ""
|
||||
data_type: Optional[str] = "default"
|
||||
```
|
||||
|
||||
### 엔드포인트
|
||||
```python
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
return {"status": "healthy", "timestamp": datetime.now().isoformat()}
|
||||
|
||||
@app.post("/create")
|
||||
async def create_item(request: CreateRequest):
|
||||
try:
|
||||
# 처리 로직
|
||||
return {"success": True, "data": result}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. React/Next.js 패턴
|
||||
|
||||
### 디렉토리 구조
|
||||
```
|
||||
src/
|
||||
├── app/ # Next.js App Router
|
||||
├── components/
|
||||
│ ├── ui/ # shadcn/ui 컴포넌트
|
||||
│ └── providers.tsx # Context Providers
|
||||
├── hooks/ # 커스텀 훅
|
||||
├── lib/utils.ts # cn() 등 유틸리티
|
||||
└── types/ # TypeScript 타입
|
||||
```
|
||||
|
||||
### cn() 유틸리티
|
||||
```typescript
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
```
|
||||
|
||||
### 폼 패턴 (react-hook-form + zod)
|
||||
```typescript
|
||||
const formSchema = z.object({
|
||||
title: z.string().min(1, "제목을 입력하세요"),
|
||||
content: z.string().min(10, "내용은 10자 이상"),
|
||||
})
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. MongoDB 패턴
|
||||
|
||||
### 연결 (motor async)
|
||||
```python
|
||||
from motor.motor_asyncio import AsyncIOMotorClient
|
||||
|
||||
client = AsyncIOMotorClient(os.getenv("MONGODB_URL"))
|
||||
db = client[os.getenv("DB_NAME")]
|
||||
```
|
||||
|
||||
### 인덱스 생성
|
||||
```python
|
||||
await collection.create_index("unique_field", unique=True, sparse=True)
|
||||
await collection.create_index("name")
|
||||
await collection.create_index("updated_at")
|
||||
```
|
||||
|
||||
### Upsert 패턴
|
||||
```python
|
||||
result = await collection.update_one(
|
||||
{"unique_field": data["unique_field"]},
|
||||
{
|
||||
"$set": update_doc,
|
||||
"$setOnInsert": {"created_at": datetime.now()}
|
||||
},
|
||||
upsert=True
|
||||
)
|
||||
```
|
||||
|
||||
### TTL 캐시
|
||||
```python
|
||||
CACHE_TTL_DAYS = 7
|
||||
|
||||
def _is_cache_fresh(self, cached_data: Dict) -> bool:
|
||||
updated_at = cached_data.get("updated_at")
|
||||
expiry_date = updated_at + timedelta(days=CACHE_TTL_DAYS)
|
||||
return datetime.now() < expiry_date
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. AI API 통합
|
||||
|
||||
### Claude API
|
||||
```python
|
||||
from anthropic import AsyncAnthropic
|
||||
|
||||
client = AsyncAnthropic(api_key=os.getenv("CLAUDE_API_KEY"))
|
||||
|
||||
response = await client.messages.create(
|
||||
model="claude-sonnet-4-20250514",
|
||||
max_tokens=8192,
|
||||
messages=[{"role": "user", "content": prompt}]
|
||||
)
|
||||
```
|
||||
|
||||
### 프롬프트 템플릿 (MongoDB 저장)
|
||||
```python
|
||||
async def _get_prompt_template(self) -> str:
|
||||
# 캐시 확인
|
||||
if self._cached_prompt and time.time() - self._prompt_cache_time < 300:
|
||||
return self._cached_prompt
|
||||
|
||||
# DB에서 조회
|
||||
custom_prompt = await self.db.prompts.find_one({"service": "{서비스명}"})
|
||||
return custom_prompt.get("content") if custom_prompt else self._default_prompt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 환경 변수
|
||||
|
||||
```bash
|
||||
# .env
|
||||
MONGO_USER=admin
|
||||
MONGO_PASSWORD={비밀번호}
|
||||
REDIS_URL=redis://redis:6379
|
||||
CLAUDE_API_KEY=sk-ant-...
|
||||
OPENAI_API_KEY=sk-...
|
||||
JWT_SECRET_KEY={시크릿키}
|
||||
DB_NAME={데이터베이스명}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 헬스체크
|
||||
|
||||
### FastAPI
|
||||
```python
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
return {"status": "healthy"}
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 데이터베이스 백업 정책
|
||||
|
||||
### 백업 규칙
|
||||
- **주기**: 하루에 한 번 (daily)
|
||||
- **보관 기간**: 최소 7일
|
||||
- **백업 위치**: 프로젝트 루트의 `./backups/` 디렉토리
|
||||
|
||||
### MongoDB 백업 명령어
|
||||
```bash
|
||||
BACKUP_NAME="mongodb_backup_$(date +%Y%m%d_%H%M%S)"
|
||||
docker exec {프로젝트}-mongodb mongodump \
|
||||
--uri="mongodb://{user}:{password}@localhost:27017" \
|
||||
--authenticationDatabase=admin \
|
||||
--out="/tmp/$BACKUP_NAME"
|
||||
docker cp {프로젝트}-mongodb:/tmp/$BACKUP_NAME ./backups/
|
||||
```
|
||||
|
||||
### 복원 명령어
|
||||
```bash
|
||||
docker cp ./backups/$BACKUP_NAME {프로젝트}-mongodb:/tmp/
|
||||
docker exec {프로젝트}-mongodb mongorestore \
|
||||
--uri="mongodb://{user}:{password}@localhost:27017" \
|
||||
--authenticationDatabase=admin \
|
||||
"/tmp/$BACKUP_NAME"
|
||||
```
|
||||
|
||||
### 자동화 (cron)
|
||||
```bash
|
||||
# crontab -e
|
||||
0 2 * * * /path/to/backup-script.sh # 매일 새벽 2시
|
||||
```
|
||||
|
||||
### 주의사항
|
||||
- 새 프로젝트 생성 시 반드시 백업 스크립트 설정
|
||||
- 백업 디렉토리는 .gitignore에 추가
|
||||
- 중요 데이터는 외부 스토리지에 추가 백업 권장
|
||||
|
||||
---
|
||||
|
||||
## 11. Gitea 리포지토리 관리
|
||||
|
||||
### 서버 정보
|
||||
- **URL**: http://gitea.yakenator.io
|
||||
- **사용자**: yakenator
|
||||
- **비밀번호**: asdfg23we
|
||||
|
||||
### 새 리포지토리 생성 (API)
|
||||
```bash
|
||||
curl -X POST "http://gitea.yakenator.io/api/v1/user/repos" \
|
||||
-H "Content-Type: application/json" \
|
||||
-u "yakenator:asdfg23we" \
|
||||
-d '{"name": "{repo-name}", "private": false}'
|
||||
```
|
||||
|
||||
### 새 프로젝트 초기화 및 푸시
|
||||
```bash
|
||||
# 1. Git 초기화
|
||||
git init
|
||||
|
||||
# 2. 첫 커밋
|
||||
git add -A
|
||||
git commit -m "Initial commit"
|
||||
|
||||
# 3. Gitea에 리포지토리 생성 (위 API 사용)
|
||||
|
||||
# 4. Remote 추가 및 푸시
|
||||
git remote add origin http://yakenator:asdfg23we@gitea.yakenator.io/yakenator/{repo-name}.git
|
||||
git branch -M main
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
이 문서를 Claude.ai Projects의 "Project Knowledge"에 추가하면 프로젝트 컨텍스트를 공유할 수 있습니다.
|
||||
Reference in New Issue
Block a user