Skip to content
Closed
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
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,65 @@ Use `/tasks` to create an actionable task list, then ask your agent to implement

For detailed step-by-step instructions, see our [comprehensive guide](./spec-driven.md).

## 🚀 FastAPI Server Usage

This project has been converted to a FastAPI web service. Here's how to run the server and use the API.

### 1. Installation

Ensure you have all the necessary dependencies installed:

```bash
pip install -r requirements.txt
```

### 2. Running the Server

You can run the server using `uvicorn`:

```bash
uvicorn src.main:app --reload
```

The server will be available at `http://localhost:8000`.

### 3. API Endpoints

All endpoints are available under the `/api/v1` prefix. You can access the interactive OpenAPI documentation at `http://localhost:8000/docs`.

#### Generate a Specification

- **Endpoint:** `POST /api/v1/spec/generate`
- **Description:** Creates a feature specification document from a user's description.
- **Example Request:**
```bash
curl -X POST "http://localhost:8000/api/v1/spec/generate" \
-H "Content-Type: application/json" \
-d '{"feature_description": "A new login system using email and password."}'
```

#### Generate an Implementation Plan

- **Endpoint:** `POST /api/v1/plan/generate`
- **Description:** Creates a technical implementation plan for a given feature.
- **Example Request:**
```bash
curl -X POST "http://localhost:8000/api/v1/plan/generate" \
-H "Content-Type: application/json" \
-d '{"feature_name": "New Login System"}'
```

#### Generate a Task List

- **Endpoint:** `POST /api/v1/tasks/generate`
- **Description:** Creates a list of development tasks for a given feature.
- **Example Request:**
```bash
curl -X POST "http://localhost:8000/api/v1/tasks/generate" \
-H "Content-Type: application/json" \
-d '{"feature_name": "New Login System"}'
```

## 📚 Core philosophy

Spec-Driven Development is a structured process that emphasizes:
Expand Down
91 changes: 91 additions & 0 deletions extracted_prompts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Extracted LLM Prompts

## From spec-template.md: For AI Generation

When creating this spec from a user prompt:
1. **Mark all ambiguities**: Use [NEEDS CLARIFICATION: specific question] for any assumption you'd need to make
2. **Don't guess**: If the prompt doesn't specify something (e.g., "login system" without auth method), mark it
3. **Think like a tester**: Every vague requirement should fail the "testable and unambiguous" checklist item
4. **Common underspecified areas**:
- User types and permissions
- Data retention/deletion policies
- Performance targets and scale
- Error handling behaviors
- Integration requirements
- Security/compliance needs

---

## From plan-template.md: Execution Flow (/plan command scope)

```
1. Load feature spec from Input path
→ If not found: ERROR "No feature spec at {path}"
2. Fill Technical Context (scan for NEEDS CLARIFICATION)
→ Detect Project Type from context (web=frontend+backend, mobile=app+api)
→ Set Structure Decision based on project type
3. Evaluate Constitution Check section below
→ If violations exist: Document in Complexity Tracking
→ If no justification possible: ERROR "Simplify approach first"
→ Update Progress Tracking: Initial Constitution Check
4. Execute Phase 0 → research.md
→ If NEEDS CLARIFICATION remain: ERROR "Resolve unknowns"
5. Execute Phase 1 → contracts, data-model.md, quickstart.md, agent-specific template file (e.g., `CLAUDE.md` for Claude Code, `.github/copilot-instructions.md` for GitHub Copilot, or `GEMINI.md` for Gemini CLI).
6. Re-evaluate Constitution Check section
→ If new violations: Refactor design, return to Phase 1
→ Update Progress Tracking: Post-Design Constitution Check
7. Plan Phase 2 → Describe task generation approach (DO NOT create tasks.md)
8. STOP - Ready for /tasks command
```

---

## From tasks-template.md: Execution Flow (main) & Task Generation Rules

### Execution Flow (main)
```
1. Load plan.md from feature directory
→ If not found: ERROR "No implementation plan found"
→ Extract: tech stack, libraries, structure
2. Load optional design documents:
→ data-model.md: Extract entities → model tasks
→ contracts/: Each file → contract test task
→ research.md: Extract decisions → setup tasks
3. Generate tasks by category:
→ Setup: project init, dependencies, linting
→ Tests: contract tests, integration tests
→ Core: models, services, CLI commands
→ Integration: DB, middleware, logging
→ Polish: unit tests, performance, docs
4. Apply task rules:
→ Different files = mark [P] for parallel
→ Same file = sequential (no [P])
→ Tests before implementation (TDD)
5. Number tasks sequentially (T001, T002...)
6. Generate dependency graph
7. Create parallel execution examples
8. Validate task completeness:
→ All contracts have tests?
→ All entities have models?
→ All endpoints implemented?
9. Return: SUCCESS (tasks ready for execution)
```

### Task Generation Rules
*Applied during main() execution*

1. **From Contracts**:
- Each contract file → contract test task [P]
- Each endpoint → implementation task

2. **From Data Model**:
- Each entity → model creation task [P]
- Relationships → service layer tasks

3. **From User Stories**:
- Each story → integration test [P]
- Quickstart scenarios → validation tasks

4. **Ordering**:
- Setup → Tests → Models → Services → Endpoints → Polish
- Dependencies block parallel execution
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fastapi
uvicorn[standard]
aiofiles
Empty file added src/__init__.py
Empty file.
Empty file added src/api/__init__.py
Empty file.
Empty file added src/api/endpoints/__init__.py
Empty file.
49 changes: 49 additions & 0 deletions src/api/endpoints/plans.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-

"""
구현 계획(Plan) 생성과 관련된 API 엔드포인트를 정의하는 파일.
"""

from fastapi import APIRouter, Depends
from src.models.documents import PlanGenerateRequest, ApiResponse
from src.services.document_generator import DocumentGeneratorService

# 'plans' 라우터를 생성합니다.
router = APIRouter(prefix="/plan", tags=["Plans"])

# 의존성 주입 함수는 재사용 가능하므로, 여기서는 간단하게 서비스 인스턴스를 생성합니다.
# 더 큰 애플리케이션에서는 공통 의존성 관리 파일을 만들 수 있습니다.
def get_doc_service() -> DocumentGeneratorService:
return DocumentGeneratorService()

@router.post("/generate", response_model=ApiResponse[str])
async def generate_plan(
request_body: PlanGenerateRequest,
doc_service: DocumentGeneratorService = Depends(get_doc_service)
):
"""
기능 이름을 받아 구현 계획(plan) 문서를 생성하는 API 엔드포인트.

Args:
request_body (PlanGenerateRequest): 기능 이름이 담긴 요청 본문.
doc_service (DocumentGeneratorService): 비즈니스 로직을 처리하는 서비스 인스턴스.

Returns:
ApiResponse[str]: 생성된 계획 문서의 내용을 담은 공통 응답 객체.
"""
try:
# 서비스의 create_plan 메서드를 호출하여 계획 문서를 생성합니다.
generated_plan = await doc_service.create_plan(
feature_name=request_body.feature_name
)
return ApiResponse(
success=True,
message="계획 문서가 성공적으로 생성되었습니다.",
data=generated_plan
)
except Exception as e:
return ApiResponse(
success=False,
message=f"오류가 발생했습니다: {e}",
data=None
)
74 changes: 74 additions & 0 deletions src/api/endpoints/specifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-

"""
사양(Specification) 생성과 관련된 API 엔드포인트를 정의하는 파일.
"""

# APIRouter는 엔드포인트들을 그룹화하는 데 사용됩니다.
from fastapi import APIRouter, Depends
# Pydantic 모델들을 가져옵니다. 데이터 유효성 검사 및 응답 구조 정의에 사용됩니다.
from src.models.documents import SpecGenerateRequest, ApiResponse
# 문서 생성 비즈니스 로직을 담고 있는 서비스 클래스를 가져옵니다.
from src.services.document_generator import DocumentGeneratorService

# 'specifications' 라우터를 생성합니다.
# prefix="/spec"는 이 라우터에 속한 모든 경로가 /spec으로 시작하도록 합니다.
# tags=["Specifications"]는 OpenAPI 문서에서 엔드포인트들을 'Specifications' 그룹으로 묶어줍니다.
router = APIRouter(prefix="/spec", tags=["Specifications"])

# 서비스 인스턴스를 생성하는 의존성 주입(Dependency Injection) 함수.
# 이 함수는 FastAPI가 엔드포인트 함수를 호출할 때마다
# DocumentGeneratorService의 새 인스턴스를 생성하여 제공합니다.
# 이를 통해 코드의 재사용성과 테스트 용이성이 향상됩니다.
def get_spec_service() -> DocumentGeneratorService:
"""
DocumentGeneratorService 인스턴스를 반환하는 의존성 함수.
"""
# 서비스 클래스의 인스턴스를 생성하여 반환합니다.
return DocumentGeneratorService()

@router.post("/generate", response_model=ApiResponse[str])
async def generate_specification(
# request_body는 SpecGenerateRequest 모델에 따라 유효성 검사를 거칩니다.
# 클라이언트가 보낸 JSON 본문이 이 모델의 구조와 일치해야 합니다.
request_body: SpecGenerateRequest,
# Depends(get_spec_service)는 get_spec_service 함수를 실행하고
# 그 반환값(DocumentGeneratorService 인스턴스)을 spec_service 매개변수에 주입합니다.
spec_service: DocumentGeneratorService = Depends(get_spec_service)
):
"""
사용자로부터 기능 설명을 받아 사양(specification) 문서를 생성하는 API 엔드포인트.

Args:
request_body (SpecGenerateRequest): 사용자가 제공한 기능 설명이 담긴 요청 본문.
spec_service (DocumentGeneratorService): 비즈니스 로직을 처리하는 서비스 인스턴스.
FastAPI의 의존성 주입에 의해 제공됩니다.

Returns:
ApiResponse[str]: 생성된 사양 문서의 내용을 담은 공통 응답 객체.
실패 시 에러 메시지를 포함할 수 있습니다.
"""
try:
# 주입된 서비스 인스턴스의 create_specification 메서드를 호출합니다.
# 요청 본문에서 받은 feature_description을 인자로 전달합니다.
# 비동기 함수이므로 await 키워드를 사용합니다.
generated_spec = await spec_service.create_specification(
feature_description=request_body.feature_description
)

# 성공적으로 문서가 생성되면, ApiResponse 모델에 맞춰 응답을 구성합니다.
# data 필드에 생성된 사양 문서 내용을 담아 반환합니다.
return ApiResponse(
success=True,
message="사양 문서가 성공적으로 생성되었습니다.",
data=generated_spec
)
except Exception as e:
# 서비스 로직에서 예외가 발생하면, 실패 응답을 구성합니다.
# success를 False로 설정하고, 예외 메시지를 message 필드에 담아 반환합니다.
# 실제 프로덕션 환경에서는 HTTP 500 에러를 반환하고 로그를 남기는 것이 더 좋습니다.
return ApiResponse(
success=False,
message=f"오류가 발생했습니다: {e}",
data=None
)
48 changes: 48 additions & 0 deletions src/api/endpoints/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-

"""
작업 목록(Tasks) 생성과 관련된 API 엔드포인트를 정의하는 파일.
"""

from fastapi import APIRouter, Depends
from src.models.documents import TasksGenerateRequest, ApiResponse
from src.services.document_generator import DocumentGeneratorService

# 'tasks' 라우터를 생성합니다.
router = APIRouter(prefix="/tasks", tags=["Tasks"])

# 의존성 주입 함수
def get_doc_service() -> DocumentGeneratorService:
return DocumentGeneratorService()

@router.post("/generate", response_model=ApiResponse[str])
async def generate_tasks(
request_body: TasksGenerateRequest,
doc_service: DocumentGeneratorService = Depends(get_doc_service)
):
"""
기능 이름을 받아 작업 목록(tasks) 문서를 생성하는 API 엔드포인트.

Args:
request_body (TasksGenerateRequest): 기능 이름이 담긴 요청 본문.
doc_service (DocumentGeneratorService): 비즈니스 로직을 처리하는 서비스 인스턴스.

Returns:
ApiResponse[str]: 생성된 작업 목록의 내용을 담은 공통 응답 객체.
"""
try:
# 서비스의 create_tasks 메서드를 호출하여 작업 목록을 생성합니다.
generated_tasks = await doc_service.create_tasks(
feature_name=request_body.feature_name
)
return ApiResponse(
success=True,
message="작업 목록이 성공적으로 생성되었습니다.",
data=generated_tasks
)
except Exception as e:
return ApiResponse(
success=False,
message=f"오류가 발생했습니다: {e}",
data=None
)
25 changes: 25 additions & 0 deletions src/api/router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-

"""
API 라우터를 통합하는 파일.
애플리케이션의 모든 엔드포인트 라우터들을 모아 FastAPI 앱에 등록할 수 있도록 합니다.
"""

# APIRouter 클래스를 가져옵니다.
from fastapi import APIRouter
# 사양(spec) 생성 관련 엔드포인트가 정의된 라우터를 가져옵니다.
from src.api.endpoints import specifications

# 최상위 API 라우터를 생성합니다.
# 이 라우터는 다른 모든 기능별 라우터들을 포함하게 됩니다.
api_router = APIRouter()

# specifications 라우터를 api_router에 포함시킵니다.
# 이렇게 하면 specifications.py에 정의된 모든 엔드포인트들이
# 이 api_router에 등록됩니다.
api_router.include_router(specifications.router)

# 여기에 나중에 plan, tasks 라우터도 추가될 예정입니다.
from src.api.endpoints import plans, tasks
api_router.include_router(plans.router)
api_router.include_router(tasks.router)
Empty file added src/core/__init__.py
Empty file.
Empty file added src/core/config.py
Empty file.
Loading