AI주도개발 통합시스템 v3.2.0 with Cursor Rules & Commands
현재 버전
Version
- v3.2.0
- 릴리스일: 2025-09-16
- 주요 변경: 인지과학 기반 최적화를 통한 논리 플로우 재구성
4_design/
01-database-design.md
경로 : .cursor/commands/4_design/01-database-design.md
# 데이터베이스 설계서 작성 프롬프트
## 역할 정의
당신은 경험 많은 **데이터베이스 설계 스페셜리스트**입니다. 요구사항 정의서와 기본 설계서를 바탕으로, **구현 가능**하고 **고품질**의 데이터베이스 설계서를 작성합니다. 설계에 필요한 정보가 부족하면 **반드시 질문**해 명확히 한 뒤 진행하세요.
## 설계 프로세스
### 1. 요구 분석 및 데이터 요구 추출
- 제공된 요구사항 정의서를 면밀히 분석
- 비즈니스 룰과 데이터 요구 추출
- 데이터 흐름과 라이프사이클 파악
- 기존 시스템과의 연동 요구 확인
### 2. 불명확 사항 식별 및 질의 프로세스
설계에 필요한 정보가 불명확할 경우, 아래 관점에서 **구체적으로 질문**합니다.
#### **필수 확인 항목**
- **데이터량 추정**
- 초기 데이터량
- 연간 데이터 증가율
- 피크 시 데이터량 예측
- **액세스 패턴**
- 읽기/쓰기 비율
- 동시 접속자 수 예상
- 자주 접근되는 데이터
- **성능 요구**
- 응답 시간 요구(SELECT/INSERT/UPDATE/DELETE)
- 처리량(Throughput) 요구
- 배치 처리의 시간 제한
- **가용성·신뢰성 요구**
- 가동률 요구(99.9%, 99.99% 등)
- 다운타임 허용도
- 재해 복구(BCP/DR) 요구
- **보안 요구**
- 데이터 암호화 필요 여부
- 접근제어 상세(역할/권한)
- 개인정보보호법/ISMS-P 등 컴플라이언스 대응
- 감사 로그 요구
- **외부 시스템 연동**
- 연동 대상 시스템 상세
- 동기화 빈도와 방식(실시간/배치)
- 데이터 포맷(예: JSON/CSV/Avro 등)
- **백업·복구 요구**
- 백업 주기
- 복구 시간 목표(RTO)
- 복구 시점 목표(RPO)
- **운영·유지보수 요구**
- 데이터 보존 기간
- 아카이브 정책
- 정기 점검(메인터넌스) 시간대
### 3. 설계 단계
#### **3.1 개념 데이터 모델**
- 엔터티 추출 및 정의
- 엔터티 간 관계 정의
- 개념 ERD 작성
- 비즈니스 룰 정리
#### **3.2 논리 데이터 모델**
- 정규화(1NF~3NF)
- 기본키/외래키 정의
- 데이터 무결성 제약 정의
- 논리 ERD 작성
#### **3.3 물리 데이터 모델**
- 테이블 설계
- 인덱스 설계
- 파티셔닝 설계
- 스토리지 설계
- 성능 튜닝 방침
## 산출물 구성
모든 불명확 사항이 해소된 후, 아래 구성으로 **Markdown 형식**의 데이터베이스 설계서를 작성합니다.
### 1. 시스템 개요
- 데이터베이스의 목적과 역할
- 전체 아키텍처 개요
- 기술 선정 이유
### 2. 개념 데이터 모델
- **엔터티 정의서**
- 엔터티명
- 개요·목적
- 주요 속성
- 비즈니스 룰
- **개념 ERD**
- **엔터티 관계 매트릭스**
### 3. 논리 데이터 모델
- **논리 테이블 정의**
- 테이블명(논리/물리)
- 목적·개요
- 컬럼 정의(논리명/물리명/타입/길이/NULL 허용/기본값)
- 기본키·외래키 정의
- 유니크·체크 제약
- **논리 ERD**
- **정규화 검증 결과**
### 4. 물리 데이터 모델
- **물리 테이블 정의**
- DDL 스크립트
- 인덱스 정의
- 파티션 정의
- 스토리지 파라미터
- **성능 설계**
- 인덱싱 전략
- 쿼리 최적화 방침
- 캐시 전략
- **용량 설계**
- 테이블 사이즈 추정
- 디스크 용량 계획
### 5. 데이터 딕셔너리
- **테이블 목록**
- **컬럼 상세 정의**
- **코드 값 정의**
- **도메인 정의**
### 6. 보안 설계
- **액세스 제어 설계**
- 사용자·롤 정의
- 권한 설계
- **데이터 암호화 설계**
- **감사 로그 설계**
### 7. 운영·유지보수 설계
- **백업 설계**
- 백업 방식
- 스케줄
- 보관 방법
- **모니터링 설계**
- 모니터링 항목
- 알림 임계치
- **메인터넌스 설계**
- 정기 메인터넌스 항목
- 데이터 아카이브 정책
### 8. 데이터 이관 설계(기존 시스템 존재 시)
- **이관 대상 데이터**
- **이관 방식**
- **데이터 변환 룰**
- **이관 일정**
### 9. 테스트 설계
- **단위 테스트 항목**
- **통합 테스트 항목**
- **성능 테스트 항목**
- **테스트 데이터 생성 방침**
## 중요한 유의사항
1. **협업적 접근**: 사용자와 협력하여 설계를 진행
2. **질문 원칙**: 불명확한 점은 끝까지 파고들어 명확히 하기 전까지 설계 진행 금지
3. **전문가 제안**: 질문 시 **최적 해법(추천안)**과 **근거**를 반드시 함께 제시
4. **구체성**: 선택지를 포함해 답변하기 쉬운 형식으로 질문
5. **구현 가능성**: 기술·운영 제약을 고려한 현실적 설계
6. **확장성**: 향후 확장을 고려한 유연한 스키마와 파티셔닝
7. **유지보수성**: 운영·보수 용이성을 고려한 설계
8. **보안**: 법·규제(개인정보보호법, ISMS-P 등) 충족
9. **성능**: 요구 성능을 만족하는 최적화된 설계
## 질문 방법
질문 시 아래 **구성**으로, 반드시 **전문가 추천안**을 함께 제시합니다.
### **질문 구성**
1. **현황 이해**: 요구에서 읽어낸 내용 확인
2. **추천안**: DB 설계 전문가로서의 최적 해법
3. **추천 이유**: 기술·업무 관점의 근거
4. **대안**: 다른 접근이 가능한 경우 선택지
5. **질문**: 최종 확인 사항
### **질문 예시(추천안 포함)**
**예시1: 데이터량 추정**
```
[현황 이해]요구서에 사용자 관리 기능이 필요한 것으로 보입니다.
[추천안]초기 사용자 1,000명, 연 20% 증가를 가정해 5년 후 약 2,500명을 기준으로 설계를 추천합니다.
[추천 이유]
- 일반적인 B2B 시스템 성장률 가정
- 인덱스 효율과 용량 계획의 균형
- 향후 수평 분할(샤딩) 고려 용이
[대안]보다 보수적으로 연 10% 증가 가정도 가능
[질문]실제 예상 사용자 수와 연 증가율은 어느 정도인가요?
```
**예시2: 성능 요구**
```
[현황 이해]검색 기능이 핵심 기능으로 제시되었습니다.
[추천안]검색 결과 표시 3초 이내, 목록 화면 1초 이내를 권장합니다.
[추천 이유]
- UX 관점에서 3초가 이탈률 분기점
- 복합 인덱스와 적절한 캐시로 현실적
- 시스템 전반 응답성 개선에 기여
[대안]1초 이내도 가능하지만 인프라 비용 상승
[질문]검색 기능의 응답 시간 목표가 정해져 있나요?
```
**예시3: 보안 요구**
```
[현황 이해]개인정보를 포함하는 시스템으로 보이나, 보안 요구가 명시되지 않았습니다.
[추천안]개인정보 필드(이름, 이메일 등)는 AES-256 암호화를 권장합니다.
[추천 이유]
- 개인정보보호법 및 ISMS-P 기술적 보호조치 정합
- 암호화 성능 오버헤드는 관리 가능
- 향후 규제 강화에도 대응 유연
[대안]해시만 적용하는 간이 방식도 가능하나, 복호화 필요 시 제약 존재
[질문]개인정보 보호 관련 구체 요건(법령·사내 규정)은 무엇인가요?
```
02-api-design.md
경로 : .cursor/commands/4_design/02-api-design.md
# API 명세서 작성 가이드라인
## 목적
본 문서는 프로젝트에서 **API 명세서의 작성 기준**과 **표준 포맷**을 제공합니다. 일관성 있는 API 명세서는 개발팀 커뮤니케이션을 매끄럽게 하고, 구현 품질을 높이며, 향후 유지보수를 쉽게 합니다.
## API 명세서의 기본 구성
API 명세서는 아래 구성 요소를 포함합니다:
1. **API 개요**
- API의 목적과 기능
- 대상 사용자
- 기술 스택
- 버전 정보
2. **엔드포인트 목록**
- 전체 엔드포인트 개요 테이블
- 필요 시 카테고리별 분류
3. **인증·인가**
- 인증 방식 상세(OAuth, API Key, JWT 등)
- 권한 레벨과 스코프
- 인증 오류 처리 방식
4. **엔드포인트 상세**
- 각 엔드포인트의 상세 사양
- 요청/응답 예시
5. **데이터 모델**
- 주요 데이터 구조 정의
- 데이터 타입과 제약 조건
6. **에러 핸들링**
- 에러 코드와 설명
- 에러 응답 포맷
7. **레이트 리밋(사용 제한)**
- API 이용 제한 사항
- 제한 초과 시 동작
8. **변경 이력**
- API 변경 기록
- 파괴적 변경(브레이킹 체인지) 경고
## 엔드포인트 사양 상세 포맷
각 엔드포인트는 아래 포맷으로 기술합니다:
```markdown
### 엔드포인트: {HTTP 메서드} {경로}
#### 개요
{엔드포인트에 대한 간결한 설명}
#### URL 파라미터
| 파라미터명 | 타입 | 필수 | 설명 |
|------------|------|--------|------------|
| {이름} | {타입} | Yes/No | {설명} |
#### 쿼리 파라미터
| 파라미터명 | 타입 | 필수 | 기본값 | 설명 |
|------------|------|--------|---------|------------|
| {이름} | {타입} | Yes/No | {기본값} | {설명} |
#### 요청 헤더
| 헤더명 | 필수 | 설명 |
|-----------|--------|------------|
| {이름} | Yes/No | {설명} |
#### 요청 바디
```json
{
"property1": "value1",
"property2": "value2"
}
```
| 프로퍼티 | 타입 | 필수 | 설명 |
|------------|------|--------|------------|
| {이름} | {타입} | Yes/No | {설명} |
#### 응답
##### 성공 응답: {HTTP 상태 코드}
```json
{
"property1": "value1",
"property2": "value2"
}
```
| 프로퍼티 | 타입 | 설명 |
|------------|------|------------|
| {이름} | {타입} | {설명} |
##### 에러 응답: {HTTP 상태 코드}
```json
{
"error": "error_code",
"message": "에러 메시지",
"details": {}
}
```
#### 주의사항
- {구현상의 주의점}
- {제한 사항 등}
#### 사용 예시
```bash
curl -X POST https://api.example.com/endpoint \
-H "Content-Type: application/json" \
-H "Authorization: Bearer token" \
-d '{"property": "value"}'
```
```
## API 명세서의 기술 규칙
### 1. 명확성과 간결성
- 각 엔드포인트의 목적을 명확히 기술할 것
- 설명은 간결하게, 전문 용어는 최초 등장 시 정의할 것
- 예시는 현실적이며 이해하기 쉽게 작성할 것
### 2. 일관성
- 네이밍 규칙은 일관성 유지(snake_case 또는 camelCase 중 하나로 통일)
- HTTP 상태 코드는 표준적 용례에 따를 것
- 데이터 타입 표기 방식 통일
### 3. 완전성
- 모든 입력 파라미터와 출력 데이터를 누락 없이 기술
- 제약 조건(최소/최대값, 길이 제한 등) 명시
- 에러 케이스와 대응 방안 기술
### 4. 정확성
- 실제 구현과 일치할 것
- 변경 발생 시, 명세서도 신속히 업데이트
- 리뷰 프로세스를 통해 오류를 제거
## API 문서 형식
### OpenAPI(Swagger) 형식
권장 형식은 **OpenAPI(Swagger)** 입니다. 아래 원칙을 따릅니다:
1. OpenAPI 3.0 이상 사용
2. YAML 또는 JSON으로 작성(**YAML 권장**)
3. `components` 재사용 적극 활용
4. 문서 생성 도구와 연계 가능한 형식 유지
예시:
```yaml
openapi: 3.0.0
info:
title: 샘플API
version: 1.0.0
description: API설명
paths:
/resource:
get:
summary: 리소스조회
description: 리소스 목록을 조회합니다
parameters:
# 파라미터 정의
responses:
'200':
description: 성공 응답
content:
application/json:
schema:
# 스키마 정의
```
## RESTful설계 원칙
API는 아래 RESTful 설계 원칙을 따르길 권장합니다:
1. **리소스 지향**
- URI는 리소스를 표현하며, 동사 대신 명사 사용
- 예: `/users` (좋음) vs `/getUsers` (지양)
2. **HTTP 메서드의 적절한 사용**
- GET: 리소스 조회(읽기 전용)
- POST: 신규 리소스 생성
- PUT: 리소스 전체 교체
- PATCH: 리소스 부분 업데이트
- DELETE: 리소스 삭제
3. **상태 코드의 적절한 사용**
- 2xx: 성공
- 3xx: 리다이렉트
- 4xx: 클라이언트 오류
- 5xx: 서버 오류
4. **버저닝**
- API에 버전 포함(URL 경로, 헤더, 쿼리 파라미터 중 택1)
- 예: `/api/v1/resources`
## API 명세서 관리 프로세스
### 1. 작성 프로세스
1. 요구정의 단계에서 API 명세 초기 드래프트 작성
2. 설계 리뷰를 수행하고 피드백 반영
3. 개발자와 합의 형성
4. 최종 명세서를 레포지토리에 저장
### 2. 변경(업데이트) 프로세스
1. API 변경 필요 시, 먼저 명세서 변경을 제안
2. 리뷰와 승인 절차 진행
3. 승인 후, 구현과 명세서 업데이트를 동시 진행
4. 버전 관리를 적절히 수행하고 변경 이력 기록
### 3. 공개 프로세스
1. 내부 개발자용 문서는 상시 접근 가능하도록 유지
2. 외부 파트너 공개가 필요한 경우, 공개용 발췌본 작성
3. 자동 생성 문서 사이트 활용(Swagger UI, Redoc 등)
## 도구와 템플릿
### 권장 도구
- **Swagger/OpenAPI Editor**: API 명세 작성·검증
- **Postman**: API 테스트 및 간이 문서화
- **Swagger UI**: 인터랙티브 문서 뷰어
- **Redoc**: 가독성 높은 문서 사이트 생성
### 표준 템플릿
프로젝트는 `docs/api` 디렉터리에 표준 템플릿을 둡니다:
- `template.yaml` - OpenAPI 명세 템플릿
- `examples/` - 요청/응답 예시 JSON 파일 모음
## 맺음말
본 가이드라인은 API 명세서의 품질 향상과 표준화를 목적으로 합니다. 프로젝트 진행에 따라 필요 시 본 가이드라인을 업데이트합니다.
새로운 베스트 프랙티스 도입과 팀의 경험을 반영해 지속적으로 개선해 나갑니다.
API 명세서는 단순한 문서가 아니라, 개발 프로세스의 핵심 구성 요소로서 고품질 API를 설계·구현하기 위한 기반입니다.
이 기준을 따름으로써 팀 전체의 생산성과 최종 산출물의 품질을 높이는 것을 목표로 합니다.
03-ui-prototype.md
경로 : .cursor/commands/4_design/03-ui-prototype.md
# UI 개념 설계 · 프로토타입 작성 프롬프트
## 개요
본 문서는 요구사항 정의서·ADR·데이터베이스 설계·API 명세를 바탕으로 화면 설계를 시작하고, **클라이언트와의 합의 형성**을 목적으로 **프로토타입(80% 품질)**을 제작하는 프로세스를 정의합니다. 프런트엔드(Next.js)와 백엔드(FastAPI)의 **모의(mock) 구현**을 포함합니다.
## 기본 방침
### 단계적 접근
1. **Phase 1: 요구 분석** — 기존 문서에서 UI 요구 추출
2. **Phase 2: 와이어프레임 설계** — 화면 구성의 개략 설계
3. **Phase 3: 프로토타입 구현** — 체험 가능한 형태로 구현(80% 품질)
- 3a. 프런트엔드 구현(Next.js + shadcn/ui)
- 3b. 백엔드 모의 구현(FastAPI)
- 3c. 통합 테스트·동작 확인
4. **Phase 4: 클라이언트 합의** — 프로토타입을 활용한 합의 형성
### 품질 레벨 정의
- **80% 품질**: 클라이언트 체험·합의에 필요한 수준
- 기본 기능 동작 확인 가능
- 시각적 완성도는 본 구현 수준
- 성능·보안은 경량(간이) 구현
- 실DB 대신 **모의 데이터** 사용
## 기술 스택
### 프런트엔드
```json
{
"framework": "Next.js 14+ (App Router)",
"ui_library": "shadcn/ui + Tailwind CSS",
"state_management": "React hooks (useState, useEffect)",
"data_fetching": "fetch API → FastAPI mock",
"styling": "Tailwind CSS + CSS Modules"
}
```
### 백엔드(모의 구현)
```json
{
"framework": "FastAPI",
"data_storage": "In-memory (dictionaries/lists)",
"authentication": "Simple JWT mock",
"validation": "Pydantic models",
"cors": "FastAPI CORS middleware"
}
```
### 개발 환경 요구
- **VSCode Live Server대응**: 즉시 실행·확인 가능
- **Hot Reload**: 프런트엔드·백엔드 모두 실시간 반영
- **반응형 대응**: 모바일·데스크톱 겸용
- **API통합**: 프런트엔드↔백엔드 연동 동작 확인
## 구현 프로세스
### Phase 1: 요구 분석
#### 1.1 기존 문서 분석
```markdown
## 분석 대상 문서
- doc01-requirements.mdc: 기능·비기능 요구
- doc02-adr.mdc: 아키텍처 결정 사항
- doc03-database.mdc: 데이터 구조·관계
- doc04-api-spec.mdc: API 명세·데이터 플로우
## 추출 항목
1. 사용자 롤·권한
2. 주요 기능·화면 전환
3. 데이터 표시·입력 항목
4. 업무 플로우·조작 절차
```
#### 1.2 UI 요구 정리
```markdown
## UI요구 매트릭스
| 기능 | 화면 | 입력 항목 | 표시 항목 | 권한 | 우선순위 |
|------|------|----------|----------|------|--------|
| 로그인 | login | email, password | 에러 메시지 | 전원 | 높음 |
| 대시보드 | dashboard | - | 통계 정보 | 인증됨 | 높음 |
```
### Phase 2: 와이어프레임 설계
#### 2.1 화면 구성 설계
```markdown
## 화면 목록·계층 구조
```
/
├── login (로그인 화면)
├── dashboard (대시보드)
│ ├── overview (개요)
│ ├── analytics (분석)
│ └── settings (설정)
└── [feature] (각 기능 화면)
├── list (목록)
├── detail (상세)
└── edit (편집)
```
## 레이아웃 패턴
1. **헤더 고정**: 내비게이션·사용자 정보
2. **사이드바**: 메인 내비게이션(데스크톱)
3. **메인 콘텐츠**: 각 화면의 주 콘텐츠
4. **푸터**: 보조 정보·링크
```
#### 2.2 컴포넌트 설계
```markdown
## 공통 컴포넌트
- Header: 사이트 공통 헤더
- Sidebar: 메인 내비게이션
- Button: 버튼(Primary, Secondary, Danger)
- Input: 폼 입력(Text, Email, Password, Select)
- Modal: 모달 다이얼로그
- Table: 데이터 테이블
- Card: 정보 카드 표시
## 화면별 컴포넌트
- LoginForm: 로그인 폼
- Dashboard: 대시보드 전체
- StatsCard: 통계 카드
```
### Phase 3: 프로토타입 구현
#### 3.1 프로젝트 초기화
##### 3.1.1 프런트엔드 초기화
```bash
# Next.js 프로젝트 생성
npx create-next-app@latest prototype-frontend --typescript --tailwind --eslint --app
# shadcn/ui 초기화
npx shadcn-ui@latest init
# 기본 컴포넌트 추가
npx shadcn-ui@latest add button input card table dialog toast
```
##### 3.1.2 백엔드 초기화
```bash
# FastAPI 프로젝트 생성
mkdir prototype-backend
cd prototype-backend
# 가상환경 생성·활성화
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 필요 패키지 설치
pip install fastapi uvicorn python-jose[cryptography] python-multipart pydantic-settings
pip freeze > requirements.txt
```
#### 3.2 디렉터리 구조
##### 3.2.1 프런트엔드 구조
```
prototype-frontend/
├── app/
│ ├── (auth)/
│ │ └── login/
│ ├── dashboard/
│ └── layout.tsx
├── components/
│ ├── ui/ (shadcn/ui)
│ ├── layout/
│ └── features/
├── lib/
│ ├── utils.ts
│ └── api.ts (FastAPI연동)
└── types/
└── index.ts
```
##### 3.2.2 백엔드 구조
```
prototype-backend/
├── app/
│ ├── __init__.py
│ ├── main.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── user.py
│ │ └── file.py
│ ├── routers/
│ │ ├── __init__.py
│ │ ├── auth.py
│ │ ├── users.py
│ │ └── files.py
│ ├── services/
│ │ ├── __init__.py
│ │ ├── auth_service.py
│ │ └── mock_data.py
│ └── core/
│ ├── __init__.py
│ ├── config.py
│ └── security.py
├── requirements.txt
└── run.py
```
#### 3.3 백엔드 모의 구현
##### 3.3.1 기본 설정·메인 엔트리
```python
# app/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.routers import auth, users, files
app = FastAPI(
title="Family Cloud System API (Mock)",
description="프로토타입용 Mock API",
version="0.1.0"
)
# CORS설정(개발용)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"], # Next.jsの개발 서버
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 라우터 등록
app.include_router(auth.router, prefix="/api/auth", tags=["인증"])
app.include_router(users.router, prefix="/api/users", tags=["사용자"])
app.include_router(files.router, prefix="/api/files", tags=["파일"])
@app.get("/")
async def root():
return {"message": "Family Cloud System API (Mock) - Running"}
@app.get("/health")
async def health_check():
return {"status": "healthy", "version": "0.1.0"}
```
##### 3.3.2 데이터 모델 정의
```python
# app/models/user.py
from pydantic import BaseModel, EmailStr
from typing import Optional, List
from datetime import datetime
class UserBase(BaseModel):
email: EmailStr
name: str
role: str = "user"
class UserCreate(UserBase):
password: str
class UserUpdate(BaseModel):
name: Optional[str] = None
email: Optional[EmailStr] = None
role: Optional[str] = None
class UserResponse(UserBase):
id: int
is_active: bool
created_at: datetime
updated_at: datetime
class UserLogin(BaseModel):
email: EmailStr
password: str
class Token(BaseModel):
access_token: str
token_type: str
user: UserResponse
# app/models/file.py
from pydantic import BaseModel
from typing import Optional, List
from datetime import datetime
class FileBase(BaseModel):
name: str
path: str
size: int
mime_type: str
class FileCreate(FileBase):
pass
class FileUpdate(BaseModel):
name: Optional[str] = None
class FileResponse(FileBase):
id: int
owner_id: int
is_shared: bool
created_at: datetime
updated_at: datetime
class FileListResponse(BaseModel):
files: List[FileResponse]
total: int
page: int
per_page: int
```
##### 3.3.3 모의(Mock) 데이터 서비스
```python
# app/services/mock_data.py
from datetime import datetime
from typing import Dict, List, Optional
from app.models.user import UserResponse
from app.models.file import FileResponse
class MockDataService:
def __init__(self):
self.users: Dict[int, dict] = {
1: {
"id": 1,
"email": "admin@example.com",
"name": "관리자",
"role": "admin",
"is_active": True,
"password": "admin123", # 실제로는 해시 저장
"created_at": datetime.now(),
"updated_at": datetime.now()
},
2: {
"id": 2,
"email": "user@example.com",
"name": "일반사용자",
"role": "user",
"is_active": True,
"password": "user123",
"created_at": datetime.now(),
"updated_at": datetime.now()
}
}
self.files: Dict[int, dict] = {
1: {
"id": 1,
"name": "가족사진.jpg",
"path": "/uploads/family_photo.jpg",
"size": 2048000,
"mime_type": "image/jpeg",
"owner_id": 1,
"is_shared": True,
"created_at": datetime.now(),
"updated_at": datetime.now()
},
2: {
"id": 2,
"name": "문서.pdf",
"path": "/uploads/document.pdf",
"size": 1024000,
"mime_type": "application/pdf",
"owner_id": 2,
"is_shared": False,
"created_at": datetime.now(),
"updated_at": datetime.now()
}
}
self.next_user_id = 3
self.next_file_id = 3
# 사용자 관련 메서드
def get_user_by_email(self, email: str) -> Optional[dict]:
for user in self.users.values():
if user["email"] == email:
return user
return None
def get_user_by_id(self, user_id: int) -> Optional[dict]:
return self.users.get(user_id)
def create_user(self, user_data: dict) -> dict:
user_id = self.next_user_id
self.next_user_id += 1
user = {
"id": user_id,
"created_at": datetime.now(),
"updated_at": datetime.now(),
**user_data
}
self.users[user_id] = user
return user
def get_all_users(self) -> List[dict]:
return list(self.users.values())
# 파일 관련 메서드
def get_files_by_user(self, user_id: int) -> List[dict]:
return [f for f in self.files.values() if f["owner_id"] == user_id]
def get_file_by_id(self, file_id: int) -> Optional[dict]:
return self.files.get(file_id)
def create_file(self, file_data: dict) -> dict:
file_id = self.next_file_id
self.next_file_id += 1
file = {
"id": file_id,
"created_at": datetime.now(),
"updated_at": datetime.now(),
**file_data
}
self.files[file_id] = file
return file
# 글로벌 인스턴스
mock_db = MockDataService()
```
##### 3.3.4 인증 서비스
```python
# app/core/security.py
from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from passlib.context import CryptContext
SECRET_KEY = "mock-secret-key-for-development-only"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def verify_password(plain_password: str, hashed_password: str) -> bool:
# 모의 구현에서는 간이 비교(본 구현에서는 해시 비교 필요)
return plain_password == hashed_password
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
def decode_access_token(token: str) -> Optional[dict]:
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except JWTError:
return None
# app/services/auth_service.py
from typing import Optional
from app.models.user import UserLogin, Token, UserResponse
from app.services.mock_data import mock_db
from app.core.security import verify_password, create_access_token
class AuthService:
def authenticate_user(self, login_data: UserLogin) -> Optional[dict]:
user = mock_db.get_user_by_email(login_data.email)
if not user:
return None
if not verify_password(login_data.password, user["password"]):
return None
return user
def create_token(self, user: dict) -> Token:
access_token = create_access_token(
data={"sub": user["email"], "user_id": user["id"]}
)
user_response = UserResponse(**{k: v for k, v in user.items() if k != "password"})
return Token(
access_token=access_token,
token_type="bearer",
user=user_response
)
auth_service = AuthService()
```
##### 3.3.5 API 라우터 구현
```python
# app/routers/auth.py
from fastapi import APIRouter, HTTPException, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from app.models.user import UserLogin, Token, UserResponse
from app.services.auth_service import auth_service
from app.services.mock_data import mock_db
from app.core.security import decode_access_token
router = APIRouter()
security = HTTPBearer()
@router.post("/login", response_model=Token)
async def login(login_data: UserLogin):
user = auth_service.authenticate_user(login_data)
if not user:
raise HTTPException(
status_code=401,
detail="이메일 또는 비밀번호가 올바르지 않습니다"
)
return auth_service.create_token(user)
@router.get("/me", response_model=UserResponse)
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
payload = decode_access_token(credentials.credentials)
if not payload:
raise HTTPException(status_code=401, detail="유효하지 않은 토큰입니다")
user = mock_db.get_user_by_id(payload.get("user_id"))
if not user:
raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다")
return UserResponse(**{k: v for k, v in user.items() if k != "password"})
# app/routers/users.py
from fastapi import APIRouter, HTTPException, Depends
from typing import List
from app.models.user import UserResponse, UserCreate
from app.services.mock_data import mock_db
router = APIRouter()
@router.get("/", response_model=List[UserResponse])
async def get_users():
users = mock_db.get_all_users()
return [UserResponse(**{k: v for k, v in user.items() if k != "password"}) for user in users]
@router.get("/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
user = mock_db.get_user_by_id(user_id)
if not user:
raise HTTPException(status_code=404, detail="사용자를 찾을 수 없습니다")
return UserResponse(**{k: v for k, v in user.items() if k != "password"})
@router.post("/", response_model=UserResponse)
async def create_user(user_data: UserCreate):
# 이메일 중복 체크
existing_user = mock_db.get_user_by_email(user_data.email)
if existing_user:
raise HTTPException(status_code=400, detail="해당 이메일은 이미 사용 중입니다")
user_dict = user_data.dict()
user = mock_db.create_user(user_dict)
return UserResponse(**{k: v for k, v in user.items() if k != "password"})
# app/routers/files.py
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
from typing import List
from app.models.file import FileResponse, FileListResponse, FileCreate
from app.services.mock_data import mock_db
router = APIRouter()
@router.get("/", response_model=FileListResponse)
async def get_files(page: int = 1, per_page: int = 10):
all_files = list(mock_db.files.values())
total = len(all_files)
start = (page - 1) * per_page
end = start + per_page
files = all_files[start:end]
return FileListResponse(
files=[FileResponse(**file) for file in files],
total=total,
page=page,
per_page=per_page
)
@router.get("/{file_id}", response_model=FileResponse)
async def get_file(file_id: int):
file = mock_db.get_file_by_id(file_id)
if not file:
raise HTTPException(status_code=404, detail="파일을 찾을 수 없습니다")
return FileResponse(**file)
@router.post("/upload", response_model=FileResponse)
async def upload_file(file: UploadFile = File(...), owner_id: int = 1):
# 모의 구현: 실제 파일 저장은 수행하지 않음
file_data = {
"name": file.filename,
"path": f"/uploads/{file.filename}",
"size": file.size or 0,
"mime_type": file.content_type or "application/octet-stream",
"owner_id": owner_id,
"is_shared": False
}
created_file = mock_db.create_file(file_data)
return FileResponse(**created_file)
```
##### 3.3.6 서버 기동 설정
```python
# run.py
import uvicorn
from app.main import app
if __name__ == "__main__":
uvicorn.run(
"app.main:app",
host="0.0.0.0",
port=8000,
reload=True,
log_level="info"
)
```
#### 3.4 프런트엔드 구현(API 연동)
##### 3.4.1 API 연동 설정
```typescript
// lib/api.ts
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
class APIClient {
private baseURL: string;
private token: string | null = null;
constructor(baseURL: string) {
this.baseURL = baseURL;
}
setToken(token: string) {
this.token = token;
}
private async request(
endpoint: string,
options: RequestInit = {}
): Promise {
const url = `${this.baseURL}${endpoint}`;
const headers = {
'Content-Type': 'application/json',
...options.headers,
};
if (this.token) {
headers.Authorization = `Bearer ${this.token}`;
}
const response = await fetch(url, {
...options,
headers,
});
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.detail || `HTTP ${response.status}`);
}
return response.json();
}
// 인증 관련
async login(email: string, password: string) {
const response = await this.request<{
access_token: string;
token_type: string;
user: any;
}>('/api/auth/login', {
method: 'POST',
body: JSON.stringify({ email, password }),
});
this.setToken(response.access_token);
return response;
}
async getCurrentUser() {
return this.request('/api/auth/me');
}
// 사용자 관련
async getUsers() {
return this.request('/api/users/');
}
async getUser(userId: number) {
return this.request(`/api/users/${userId}`);
}
async createUser(userData: any) {
return this.request('/api/users/', {
method: 'POST',
body: JSON.stringify(userData),
});
}
// 파일 관련
async getFiles(page = 1, perPage = 10) {
return this.request<{
files: any[];
total: number;
page: number;
per_page: number;
}>(`/api/files/?page=${page}&per_page=${perPage}`);
}
async uploadFile(file: File, ownerId = 1) {
const formData = new FormData();
formData.append('file', file);
formData.append('owner_id', ownerId.toString());
const headers: Record = {};
if (this.token) {
headers.Authorization = `Bearer ${this.token}`;
}
const response = await fetch(`${this.baseURL}/api/files/upload`, {
method: 'POST',
headers,
body: formData,
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.status}`);
}
return response.json();
}
}
export const apiClient = new APIClient(API_BASE_URL);
// React hooks for API integration
export async function fetchUsers() {
return apiClient.getUsers();
}
export async function loginUser(email: string, password: string) {
return apiClient.login(email, password);
}
export async function fetchFiles(page = 1, perPage = 10) {
return apiClient.getFiles(page, perPage);
}
```
##### 3.4.2 인증 훅 업데이트
```tsx
// hooks/useAuth.ts
import { useState, useEffect } from 'react';
import { apiClient } from '@/lib/api';
interface User {
id: number;
email: string;
name: string;
role: string;
}
export function useAuth() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// 로컬 스토리지에서 토큰 복원
const token = localStorage.getItem('auth_token');
if (token) {
apiClient.setToken(token);
getCurrentUser();
} else {
setLoading(false);
}
}, []);
const getCurrentUser = async () => {
try {
const userData = await apiClient.getCurrentUser();
setUser(userData);
} catch (err) {
console.error('Failed to get current user:', err);
localStorage.removeItem('auth_token');
} finally {
setLoading(false);
}
};
const login = async (email: string, password: string) => {
setLoading(true);
setError(null);
try {
const response = await apiClient.login(email, password);
localStorage.setItem('auth_token', response.access_token);
setUser(response.user);
return response;
} catch (err) {
const errorMessage = err instanceof Error ? err.message : '로그인에 실패했습니다';
setError(errorMessage);
throw err;
} finally {
setLoading(false);
}
};
const logout = () => {
localStorage.removeItem('auth_token');
apiClient.setToken('');
setUser(null);
};
return { user, login, logout, loading, error };
}
```
##### 3.4.3 파일 관리 훅
```tsx
// hooks/useFiles.ts
import { useState, useEffect } from 'react';
import { apiClient } from '@/lib/api';
interface FileItem {
id: number;
name: string;
size: number;
mime_type: string;
created_at: string;
is_shared: boolean;
}
export function useFiles() {
const [files, setFiles] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchFiles = async (page = 1, perPage = 10) => {
setLoading(true);
setError(null);
try {
const response = await apiClient.getFiles(page, perPage);
setFiles(response.files);
return response;
} catch (err) {
const errorMessage = err instanceof Error ? err.message : '파일 조회에 실패했습니다';
setError(errorMessage);
throw err;
} finally {
setLoading(false);
}
};
const uploadFile = async (file: File) => {
setLoading(true);
setError(null);
try {
const response = await apiClient.uploadFile(file);
// 파일 목록 재조회
await fetchFiles();
return response;
} catch (err) {
const errorMessage = err instanceof Error ? err.message : '파일 업로드에 실패했습니다';
setError(errorMessage);
throw err;
} finally {
setLoading(false);
}
};
return { files, fetchFiles, uploadFile, loading, error };
}
```
#### 3.5 통합 개발·테스트
##### 3.5.1 개발 서버 기동 절차
```bash
# 백엔드 기동(터미널1)
cd prototype-backend
source venv/bin/activate # Windows: venv\Scripts\activate
python run.py
# 프런트엔드 기동(터미널2)
cd prototype-frontend
npm run dev
```
##### 3.5.2 동작 확인 테스트
```markdown
## 기본 동작 테스트 절차
### 1. API 연결 확인
- http://localhost:8000 에서 FastAPI 기동 확인
- http://localhost:8000/docs 에서 Swagger UI 확인
### 2. 인증 플로우 확인
- 프런트엔드에서 로그인 실행
- 토큰 획득·저장 확인
- 인증 필요한 API 접근 확인
### 3. 데이터 조작 확인
- 사용자 목록 조회
- 파일 목록 조회
- 파일 업로드(Mock)
### 4. 에러 핸들링 확인
- 무효한 인증정보로 로그인 시도
- 존재하지 않는 리소스 접근
- 네트워크 에러 발생 시 동작
```
##### 3.5.3 통합 테스트용 컴포넌트
```tsx
// components/test/APITestPanel.tsx
'use client';
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { useAuth } from '@/hooks/useAuth';
import { useFiles } from '@/hooks/useFiles';
export function APITestPanel() {
const { user, login, logout, loading: authLoading } = useAuth();
const { files, fetchFiles, uploadFile, loading: filesLoading } = useFiles();
const [email, setEmail] = useState('admin@example.com');
const [password, setPassword] = useState('admin123');
const handleLogin = async () => {
try {
await login(email, password);
} catch (error) {
console.error('Login failed:', error);
}
};
const handleFetchFiles = async () => {
try {
await fetchFiles();
} catch (error) {
console.error('Fetch files failed:', error);
}
};
return (
API통합 테스트
{!user ? (
setEmail(e.target.value)}
/>
setPassword(e.target.value)}
/>
) : (
로그인됨: {user.name} ({user.email})
)}
{files.length > 0 && (
파일 목록:
{files.map((file) => (
-
{file.name} ({file.size} bytes)
))}
)}
);
}
```
#### 3.6 VSCode Live Server 대응
##### 3.6.1 개발 환경 설정
```json
// package.json (프론트엔드)
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test:api": "next dev & python ../prototype-backend/run.py"
}
}
```
##### 3.6.2 환경 변수 설정
```bash
# .env.local (프론트엔드)
NEXT_PUBLIC_API_URL=http://localhost:8000
```
### Phase 4: 클라이언트 합의
#### 4.1 데모 환경 준비
```markdown
## 데모 실행 절차
1. 백엔드 서버 기동: `cd prototype-backend && python run.py`
2. 프런트엔드 서버 기동: `cd prototype-frontend && npm run dev`
3. http://localhost:3000 에서 프런트엔드 접속
4. http://localhost:8000/docs 에서 API 스펙 확인(Swagger UI)
5. 주요 화면·기능을 순차 데모
## 데모 시나리오
1. 로그인 화면에서 인증 플로우(실제 API 연동)
2. 대시보드 정보 확인(실시간 데이터 조회)
3. 각 기능 화면의 조작 체험(CRUD)
4. 반응형 대응 확인
5. 에러 핸들링 동작 확인
## 기술 데모 포인트
- 프런트엔드↔백엔드 연동 동작
- 실시간 데이터 갱신
- 인증·인가 플로우
- 파일 업로드 기능
- 에러 핸들링·사용성
```
#### 4.2 피드백 수집
```markdown
## 피드백 항목
- [ ] 화면 레이아웃·디자인
- [ ] 조작 플로우·유저빌리티
- [ ] 표시 항목·정보의 과부족
- [ ] 반응형 대응
- [ ] API 연동·데이터 플로우
- [ ] 퍼포먼스·응답 속도
- [ ] 에러 핸들링·메시지
- [ ] 추가 요구·변경점
## 기술적 합의 사항
- 프런트엔드·백엔드 분리 아키텍처
- API 스펙·데이터 모델
- 인증·인가 방식
- 파일 관리 방식
- 에러 핸들링 방침
## 합의 사항 기록
- 승인된 화면·기능
- 승인된 API 스펙
- 수정이 필요한 항목
- 추가 요구 사항
- 다음 단계 인수인계 사항
```
## 산출물·인수인계
### Phase 3 완료 시 산출물
1. **동작하는 프로토타입**: Next.js + shadcn/ui + FastAPI
2. **화면 설계서**: 와이어프레임·컴포넌트 스펙
3. **API 사양서**: FastAPI 자동 생성 문서 + 구현
4. **기술 사양서**: 사용 기술·구현 방침
5. **데모 환경**: 프론트엔드·백엔드 통합 환경
### doc06으로의 인수인계 사항
1. **합의된 화면 스펙**: 클라이언트 승인 설계
2. **합의된 API 스펙**: 동작 확인된 API 설계
3. **프로토타입 코드**: 80% 품질 구현(프론트엔드·백엔드)
4. **기술 스택**: 확정된 기술 선택
5. **개선 요구**: 본 구현에서 다룰 품질 향상 항목
## 주의사항
### 품질 수준 명확화
- **80% 품질**: 체험·합의 형성에 충분
- **퍼포먼스**: 기본 동작 확인 수준
- **보안**: 개발 환경 기준의 간이 구현
- **데이터 영속성**: In-memory 구현(재기동 시 리셋)
- **에러 핸들링**: 주요 케이스 위주 대응
### 클라이언트 커뮤니케이션
- 프로토타입의 포지셔닝 사전 설명
- 본 구현과의 품질 차이에 대한 합의
- 프론트엔드·백엔드 통합 데모 실시
- 피드백 수집·기록 철저
- 다음 단계에 대한 기대치 명확화
### 개발 효율 고려
- Mock 구현으로 빠른 개발·테스트
- 실 DB 없이 프로토타입 동작
- 클라이언트 체험에 필요한 기능 집중
- 본 구현 전환을 고려한 설계
---
## Stagewise 통합 개발환경 기동
프로토타입 개발 효율을 높이기 위해 Stagewise 통합 개발환경 사용을 권장합니다.
### Setup Toolbar기동 방법
아래 커맨드로 Stagewise Setup Toolbar를 기동해, 화면상에서 직관적으로 수정·조정을 수행할 수 있습니다:
```json
{
"key": "",
"command": "stagewise.setupToolbar"
}
```
### Setup Toolbar 활용 방법
1. **화면 레이아웃 조정**: 드래그&드롭으로 컴포넌트 배치 변경
2. **스타일 조정**: 실시간으로 CSS 프로퍼티 수정
3. **컴포넌트 추가**: UI 라이브러리에서 직접 추가
4. **반응형 확인**: 다양한 디바이스 크기로 즉시 확인
5. **API 연동 테스트**: 백엔드 연동 동작을 실시간 확인
### 추천 워크플로우
1. **Setup Toolbar 기동**: 위 JSON 커맨드 실행
2. **베이스 레이아웃 구성**: 주요 화면을 시각적으로 배치
3. **컴포넌트 조정**: UI 컴포넌트 상세 설정
4. **API 통합 확인**: 프론트엔드↔백엔드 연동 동작 검증
5. **반응형 조정**: 모바일·데스크톱 최적화
### Stagewise를 사용할 이유
- **시각적 개발**: 코드 수정 없이 화면에서 조정 가능
- **실시간 반영**: 변경 사항 즉시 반영
- **효율적 프로토타이핑**: 빠른 화면 설계·수정
- **클라이언트 합의 촉진**: 시각적 확인으로 원활한 합의
- **품질 향상**: UI 일관성과 사용성 개선
이 통합환경을 활용하면 프로토타입 품질과 개발 효율이 크게 개선됩니다.
프로토타입 개발 시작 시, 반드시 Stagewise Setup Toolbar를 기동해 주세요.
04-detailed-design.md
경로 : .cursor/commands/4_design/04-detailed-design.md
# 상세 설계서 작성 프롬프트
당신은 숙련된 소프트웨어 엔지니어이자 상세 설계서 작성 전문가입니다. 다만, 설계에 필요한 정보가 부족한 경우에는 반드시 질문을 통해 명확히 한 뒤 진행하세요. 상세 설계서를 작성하기 위한 절차는 다음과 같습니다.
1. 설계서 요구사항 분석과 불명확점 식별
- 제공된 설계서를 면밀히 분석하고, 모호한 부분·세부정보 부족·모순점을 식별
- 각 기능 요구사항 구현에 필요한 세부가 충분히 기술되어 있는지 확인
- 기술적 실현 가능성과 잠재적 과제를 평가
2. 질문 프로세스
- 불명확한 점이 있으면 구체적인 질문을 사용자에게 제시
- 질문은 구체적으로, 선택지를 제시하는 등 답변하기 쉬운 형식으로 구성
- 모든 의문점이 해소될 때까지 상세 설계로 진행하지 않음
- 필요 시 복수 회의 질문을 수행
- 특히 아래 항목이 불명확한 경우 반드시 질문:
* 기능의 정확한 동작 조건
* 데이터 플로우와 시스템 간 연계 상세
* 에러 처리의 구체적 방침
* 성능 요구사항과 제약 조건
* 보안 요구사항의 구체적 구현 방법
* UI/UX의 상세 동작
3. 상세 설계서 구성(모든 불명확점 해소 후, Markdown 형식으로 작성)
- 시스템 개요: 시스템 목적과 전체 아키텍처 설명
- 컴포넌트 설계: 각 컴포넌트의 상세(속성, 메서드, 관계)
- 4+1c 뷰
- 논리 뷰: Markdown 파일 내에서 Mermaid를 사용한 컴포넌트 다이어그램 등으로 **반드시 시각화**
- 개발 뷰: 주로 텍스트로 기술. **프로젝트 루트 디렉터리 기준의 상세 디렉터리 구조를 텍스트 트리(tree) 형식으로 반드시 기술**(예: `tree` 명령 출력 형식). 추가로 주요 라이브러리, 개발 도구, 코드 스타일도 기술. Mermaid 시각화는 필수 아님.
- 프로세스 뷰: Markdown 파일 내에서 Mermaid 시퀀스 다이어그램 등으로 **반드시 시각화**
- 물리 뷰: Markdown 파일 내에서 Mermaid 배포(Deployment) 다이어그램 등으로 **반드시 시각화**. 주의: 복잡한 물리 뷰(특히 graph TD)에서 중첩 서브그래프는 렌더러에 따라 문법 오류가 발생하기 쉬움. 오류 발생 시 서브그래프 사용을 피하고 더 평평한 구조로 그리거나 도식을 단순화할 것.
- 유스케이스 뷰: 주요 유스케이스에 대해 Mermaid 유스케이스 다이어그램으로 시각화 권장(복잡하지 않다면 텍스트 기술도 가능)
- 데이터 모델: 데이터베이스 스키마 상세 정의
- API 설계: 전체 API 엔드포인트 상세 사양
- 사용자 인터페이스 설계: UI/UX 상세와 동작 플로우
- 보안 설계: 인증, 인가, 데이터 보호의 구현 상세
- 에러 처리: 시스템 전반의 에러 처리 전략
4. 상세 설계서를 기반으로 한 사용자 인터페이스 작성
- 사용자 인터페이스 묘사(HTML, CSS 사용)
- 작성한 UI 묘사(HTML/CSS 스케치)를 제시하고, 사용자에게 “이 UI 이미지로 괜찮으신가요?”와 같이 확인을 요청
5. 각 섹션에서 명확히 할 사항
- 구현 상세: 구체적 코드 구조, 함수, 변수 등
- 의존관계: 컴포넌트 간 관계와 상호작용
- 엣지 케이스 처리
- 성능 고려사항
6. 구체적 코드 예시
- 중요한 컴포넌트와 복잡 로직의 구현 샘플
- 데이터 모델 스키마 정의
- API 구현 예시
- 사용자 인터페이스 구현 예시
7. 테스트 전략과 배포 고려사항
중요: 사용자의 지시나 설계서 내용이 모호한 경우, 주저하지 말고 질문하세요.
명확해지기 전에는 상세 설계를 작성하면 안 됩니다. 사용자의 이해를 돕기 위해서도, 적극적으로 질문을 던지세요.
질문은 가능한 한 구체적으로 하고, 답변을 이끌어내기 쉬운 형식으로 구성하세요.
05-design-review.md
경로 : .cursor/commands/4_design/05-design-review.md
# 설계 리뷰 절차 프롬프트
당신은 상세 설계에 대해 사용자의 이해도를 점검하는 서포터입니다. 아래 가이드라인을 따라 대응하세요.
1. 사용자가 제시한 요구사항과 상세 설계에서 **핵심 포인트**와 **중요 요소**를 식별하세요.
2. 식별한 중요 포인트에 대해 **질문을 제시**하여 사용자의 이해도를 측정하세요. 질문은 **포괄적**이어야 하며, 상세 설계의 다양한 측면을 다루도록 **최소 3문항 이상** 준비하세요. 한 문제로 끝내지 마세요.
3. 사용자의 답변이 부정확하거나 불완전한 경우:
- 어떤 부분이 잘못되었는지 **명확히 지적**
- 그 생각이 **부적절한 이유**를 설명
- 올바른 상세 설계의 사고방식과 **도출 과정**을 단계적으로 해설
- **도식(예: 간단한 다이어그램)**이나 **비유**로 복잡한 개념을 쉽게 설명
4. 사용자의 답변이 정확한 경우:
- 그 이해를 **긍정**하고, 더 깊은 관점이나 **관련 고려사항**을 추가로 제공
5. 항상 **교육적 태도**를 유지하여, 사용자가 설계의 배경에 있는 **이유와 원칙**을 이해하도록 지원하세요.
6. 질문은 **구체적·명확**하게 하며, 모호한 질문은 피하세요.
7. 상세 설계의 **잠재적 리스크**와 **대안**도 논의하고, 설계 결정의 **근거**에 대한 이해를 심화하도록 유도하세요.
8. 사용자의 이해 수준에 맞춰 설명의 **상세도**를 조절하고, 전문 용어는 필요 시 **간단히 정의**하세요.
9. 설계 프로세스 각 단계의 **결정 포인트**를 강조하고, 왜 그 선택이 최적이었는지 **설명할 수 있도록** 이끌어 주세요.
10. 질문은 반드시 다음 범주를 포함해야 합니다:
- 설계의 **주요 콘셉트와 원칙**에 관한 질문
- **기술적 구현 상세**에 관한 질문
- **엣지 케이스/예외 처리**에 관한 질문
- **성능/확장성**에 관한 질문
- **보안/데이터 무결성**에 관한 질문(해당되는 경우)
11. 논의 마지막에는 **이해도 종합**과 **다음 단계 제안**을 제시하세요.
이 서포터의 역질문에 답할 수 있다면 **실행(구현) 단계**로 진행해도 좋습니다.
**모든 질문에 적절히 답변한 경우에만** 구현 페이즈로의 전환을 승인하세요.