개념
이 가이드는 OpenSpec의 핵심 개념과 그것들이 어떻게 결합되는지 설명합니다. 실제 사용법은 시작하기와 워크플로를 참조하세요.
철학
OpenSpec은 네 가지 원칙을 중심으로 구축되었습니다:
유연하게, 경직되게 아님 — 단계별 게이트 없음, 의미 있는 작업 수행
반복적으로, 폭포수식 아님 — 구축하면서 배우고, 진행하면서 다듬기
간단하게, 복잡하게 아님 — 가벼운 설정, 최소한의 의식
기존 코드 기반 우선 — 신규 개발뿐 아니라 기존 코드베이스에서도 작동왜 이러한 원칙이 중요한가
유연하게, 경직되게 아님. 전통적인 사양 시스템은 단계에 고정시킵니다: 먼저 계획하고, 그 다음 구현하고, 마지막으로 완료합니다. OpenSpec은 더 유연합니다 — 작업에 의미 있는 순서대로 산출물을 생성할 수 있습니다.
반복적으로, 폭포수식 아님. 요구사항은 변합니다. 이해는 깊어집니다. 처음에는 좋은 접근법처럼 보였던 것이 코드베이스를 살펴본 후에는 맞지 않을 수 있습니다. OpenSpec은 이러한 현실을 수용합니다.
간단하게, 복잡하게 아님. 일부 사양 프레임워크는 광범위한 설정, 고정된 형식 또는 무거운 프로세스를 요구합니다. OpenSpec은 방해하지 않습니다. 몇 초 만에 초기화하고, 즉시 작업을 시작하며, 필요한 경우에만 사용자 정의합니다.
기존 코드 기반 우선. 대부분의 소프트웨어 작업은 처음부터 구축하는 것이 아니라 기존 시스템을 수정하는 것입니다. OpenSpec의 델타 기반 접근법은 새로운 시스템을 설명하는 것뿐만 아니라 기존 동작에 대한 변경 사항을 명세하기 쉽게 만듭니다.
전체 개요
OpenSpec는 작업을 두 가지 주요 영역으로 구성합니다:
┌────────────────────────────────────────────────────────────────────┐
│ openspec/ │
│ │
│ ┌─────────────────────┐ ┌───────────────────────────────┐ │
│ │ specs/ │ │ changes/ │ │
│ │ │ │ │ │
│ │ 진실의 원본 │◄─────│ 제안된 수정 사항 │ │
│ │ 시스템이 현재 │ merge│ 각 변경사항 = 하나의 폴더 │ │
│ │ 작동하는 방식 │ │ 산출물 + 델타 포함 │ │
│ │ │ │ │ │
│ └─────────────────────┘ └───────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘**스펙(Specs)**은 진실의 원본입니다 — 시스템이 현재 어떻게 동작하는지를 기술합니다.
**변경사항(Changes)**은 제안된 수정 사항입니다 — 준비가 될 때까지 별도의 폴더에 존재합니다.
이 분리가 핵심입니다. 충돌 없이 여러 변경사항을 병렬로 작업할 수 있습니다. 메인 스펙에 영향을 주기 전에 변경사항을 검토할 수 있습니다. 그리고 변경사항을 보관할 때, 그 델타가 진실의 원본에 깔끔하게 병합됩니다.
스펙
스펙은 구조화된 요구사항과 시나리오를 사용하여 시스템의 동작을 기술합니다.
구조
openspec/specs/
├── auth/
│ └── spec.md # 인증 동작
├── payments/
│ └── spec.md # 결제 처리
├── notifications/
│ └── spec.md # 알림 시스템
└── ui/
└── spec.md # UI 동작 및 테마스펙은 도메인별로 구성합니다 — 시스템에 의미 있는 논리적 그룹입니다. 일반적인 패턴:
- 기능 영역별:
auth/,payments/,search/ - 구성 요소별:
api/,frontend/,workers/ - 경계 컨텍스트별:
ordering/,fulfillment/,inventory/
스펙 형식
스펙은 요구사항을 포함하며, 각 요구사항은 시나리오를 가집니다:
markdown
# 인증 스펙
## 목적
애플리케이션의 인증 및 세션 관리.
## 요구사항
### 요구사항: 사용자 인증
시스템은 로그인 성공 시 JWT 토큰을 발급해야 합니다.
#### 시나리오: 유효한 자격 증명
- GIVEN 유효한 자격 증명을 가진 사용자
- WHEN 사용자가 로그인 양식을 제출하면
- THEN JWT 토큰이 반환되고
- AND 사용자가 대시보드로 리디렉션됩니다
#### 시나리오: 유효하지 않은 자격 증명
- GIVEN 유효하지 않은 자격 증명
- WHEN 사용자가 로그인 양식을 제출하면
- THEN 오류 메시지가 표시되고
- AND 토큰이 발급되지 않습니다
### 요구사항: 세션 만료
시스템은 30분간 비활성 시 세션을 만료시켜야 합니다.
#### 시나리오: 유휴 시간 초과
- GIVEN 인증된 세션
- WHEN 30분간 활동 없이 시간이 지나면
- THEN 세션이 무효화되고
- AND 사용자는 재인증해야 합니다핵심 요소:
| 요소 | 목적 |
|---|---|
## Purpose | 이 스펙의 도메인에 대한 고수준 설명 |
### Requirement: | 시스템이 가져야 하는 특정 동작 |
#### Scenario: | 요구사항이 작동하는 구체적인 예시 |
| SHALL/MUST/SHOULD | 요구사항 강도를 나타내는 RFC 2119 키워드 |
스펙을 이렇게 구조화하는 이유
요구사항은 "무엇(what)"입니다 — 구현을 지정하지 않고 시스템이 해야 할 일을 명시합니다.
시나리오는 "언제(when)"입니다 — 검증할 수 있는 구체적인 예시를 제공합니다. 좋은 시나리오:
- 테스트 가능합니다 (자동화된 테스트를 작성할 수 있습니다)
- 정상 경계와 엣지 케이스를 모두 다룹니다
- Given/When/Then 또는 유사한 구조화된 형식을 사용합니다
RFC 2119 키워드 (SHALL, MUST, SHOULD, MAY)는 의도를 전달합니다:
- MUST/SHALL — 절대적인 요구사항
- SHOULD — 권장되지만 예외가 있음
- MAY — 선택 사항
스펙이란 무엇이며 (또는 무엇이 아닌지)
스펙은 구현 계획이 아닌 동작 계약입니다.
좋은 스펙 내용:
- 사용자나 하위 시스템이 의존하는 관찰 가능한 동작
- 입력, 출력 및 오류 조건
- 외부 제약 조건 (보안, 개인정보 보호, 신뢰성, 호환성)
- 테스트하거나 명시적으로 검증할 수 있는 시나리오
스펙에서 피해야 할 것:
- 내부 클래스/함수 이름
- 라이브러리 또는 프레임워크 선택
- 단계별 구현 세부 사항
- 상세한 실행 계획 (이것은
design.md또는tasks.md에 속함)
빠른 테스트:
- 구현이 외부에 보이는 동작을 변경하지 않고 변경될 수 있다면, 아마도 스펙에 속하지 않을 것입니다.
가볍게 유지하기: 점진적 엄밀함
OpenSpec는 관료주의를 피하는 것을 목표로 합니다. 변경사항을 검증 가능하게 만들면서 가장 가벼운 수준을 사용합니다.
라이트 스펙 (기본값):
- 짧은 동작 우선 요구사항
- 명확한 범위 및 비목적
- 몇 가지 구체적인 검수 항목
풀 스펙 (더 높은 위험을 위해):
- 팀 간 또는 저장소 간 변경사항
- API/계약 변경, 마이그레이션, 보안/개인정보 보호 문제
- 모호성이 비용이 많이 드는 재작업을 초래할 가능성이 높은 변경사항
대부분의 변경사항은 라이트 모드로 유지해야 합니다.
인간 + 에이전트 협업
많은 팀에서 인간이 탐색하고 에이전트가 산출물을 작성합니다. 의도된 루프는 다음과 같습니다:
- 인간이 의도, 컨텍스트 및 제약 조건을 제공합니다.
- 에이전트는 이를 동작 우선 요구사항과 시나리오로 변환합니다.
- 에이전트는 구현 세부 사항을
design.md와tasks.md에 유지하며,spec.md에는 유지하지 않습니다. - 검증은 구현 전에 구조와 명확성을 확인합니다.
이렇게 하면 스펙은 인간에게 읽기 쉽고 에이전트에게는 일관성을 유지합니다.
변경사항
변경사항은 시스템에 대한 제안된 수정 사항으로, 이해하고 구현하는 데 필요한 모든 것이 포함된 폴더로 패키징됩니다.
변경사항 구조
openspec/changes/add-dark-mode/
├── proposal.md # 이유와 내용
├── design.md # 방법 (기술적 접근 방식)
├── tasks.md # 구현 체크리스트
├── .openspec.yaml # 변경사항 메타데이터 (선택 사항)
└── specs/ # 델타 스펙
└── ui/
└── spec.md # ui/spec.md에서 변경되는 내용각 변경사항은 자체 포함되어 있습니다. 다음을 포함합니다:
- 산출물 — 의도, 설계 및 작업을 담은 문서
- 델타 스펙 — 추가, 수정 또는 삭제되는 내용에 대한 사양
- 메타데이터 — 이 특정 변경사항에 대한 선택적 구성
변경사항이 폴더인 이유
변경사항을 폴더로 패키징하면 여러 가지 이점이 있습니다:
모든 것이 한 곳에. 제안서, 설계, 작업 및 스펙이 한 곳에 있습니다. 다른 위치를 뒤질 필요가 없습니다.
병렬 작업. 여러 변경사항이 동시에 존재할 수 있으며 충돌하지 않습니다.
fix-auth-bug도 진행 중인 동안add-dark-mode를 작업할 수 있습니다.깔끔한 기록. 보관 시 변경사항은 전체 컨텍스트가 보존된 채
changes/archive/로 이동합니다. 무엇이 변경되었는지뿐만 아니라 왜 변경되었는지도 돌아보며 이해할 수 있습니다.검토 용이. 변경사항 폴더는 검토하기 쉽습니다 — 폴더를 열고, 제안서를 읽고, 설계를 확인하고, 스펙 델타를 봅니다.
산출물
산출물은 작업을 안내하는 변경사항 내의 문서입니다.
산출물 흐름
proposal ──────► specs ──────► design ──────► tasks ──────► implement
│ │ │ │
why what how steps
+ scope changes approach to take산출물은 서로 쌓아 올립니다. 각 산출물은 다음 산출물에 대한 컨텍스트를 제공합니다.
산출물 유형
제안서 (proposal.md)
제안서는 의도, 범위 및 접근 방식을 고수준으로 포착합니다.
markdown
# 제안서: 다크 모드 추가
## 의도
사용자들이 야간 사용 시 눈의 피로를 줄이고 시스템 환경설정에 맞추기 위해 다크 모드 옵션을 요청했습니다.
## 범위
범위 내:
- 설정에서 테마 토글
- 시스템 환경설정 감지
- localStorage에 환경설정 저장
범위 외:
- 사용자 정의 색상 테마 (향후 작업)
- 페이지별 테마 재정의
## 접근 방식
상태 관리를 위한 React 컨텍스트와 함께 테마에 CSS 사용자 정의 속성을 사용합니다. 첫 로드 시 시스템 환경설정을 감지하고 수동 재정의를 허용합니다.제안서를 업데이트해야 할 때:
- 범위 변경 (축소 또는 확대)
- 의도가 명확해짐 (문제에 대한 더 나은 이해)
- 접근 방식이 근본적으로 변경됨
스펙 (specs/의 델타 스펙)
델타 스펙은 현재 스펙 대비 변경되는 내용을 기술합니다. 아래의 델트 스펙을 참조하세요.
설계 (design.md)
설계는 기술적 접근 방식과 아키텍처 결정을 포착합니다.
markdown
# 설계: 다크 모드 추가
## 기술적 접근 방식
prop drilling을 피하기 위해 React Context를 통해 테마 상태를 관리합니다.
CSS 사용자 정의 속성을 사용하여 클래스 토글 없이 런타임 전환을 가능하게 합니다.
## 아키텍처 결정
### 결정: Context over Redux
테마 상태에 React Context를 사용하는 이유:
- 단순한 이진 상태 (라이트/다크)
- 복잡한 상태 전환 없음
- Redux 의존성 추가를 피함
### 결정: CSS Custom Properties
CSS-in-JS 대신 CSS 변수를 사용하는 이유:
- 기존 스타일시트와 호환
- 런타임 오버헤드 없음
- 브라우저 네이티브 솔루션
## 데이터 흐름
```
ThemeProvider (context)
│
▼
ThemeToggle ◄──► localStorage
│
▼
CSS Variables (applied to :root)
```
## 파일 변경
- `src/contexts/ThemeContext.tsx` (새 파일)
- `src/components/ThemeToggle.tsx` (새 파일)
- `src/styles/globals.css` (수정됨)
**설계를 업데이트해야 하는 시점:**
- 구현 과정에서 접근 방식이 작동하지 않는 것으로 밝혀질 때
- 더 나은 해결책이 발견될 때
- 의존성이나 제약 조건이 변경될 때
#### 작업 (`tasks.md`)
작업은 **구현 체크리스트**입니다 — 체크박스가 있는 구체적인 단계입니다.
```markdown
# 작업
## 1. 테마 인프라
- [ ] 1.1 라이트/다크 상태를 가진 ThemeContext 생성
- [ ] 1.2 색상을 위한 CSS 사용자 정의 속성 추가
- [ ] 1.3 localStorage 지속성 구현
- [ ] 1.4 시스템 선호도 감지 추가
## 2. UI 컴포넌트
- [ ] 2.1 ThemeToggle 컴포넌트 생성
- [ ] 2.2 설정 페이지에 토글 추가
- [ ] 2.3 빠른 토글을 포함하도록 Header 업데이트
## 3. 스타일링
- [ ] 3.1 다크 테마 색상 팔레트 정의
- [ ] 3.2 CSS 변수를 사용하도록 컴포넌트 업데이트
- [ ] 3.3 접근성을 위한 대비 비율 테스트
```
**작업 모범 사례:**
- 제목 아래에 관련 작업을 그룹화
- 계층적 번호 매기기(1.1, 1.2 등) 사용
- 작업을 한 세션에 완료할 수 있을 만큼 작게 유지
- 완료된 작업에 체크 표시
## 델타 스펙
델타 스펙은 OpenSpec이 기존 개발 환경에서 작동하게 만드는 핵심 개념입니다. 전체 스펙을 다시 명시하는 대신 **변경되는 내용**을 설명합니다.
### 형식
```markdown
# 인증에 대한 델타
## 추가된 요구사항
### 요구사항: 2단계 인증
시스템은 TOTP 기반 2단계 인증을 지원해야 합니다.
#### 시나리오: 2FA 등록
- 2FA가 활성화되지 않은 사용자가 있을 때
- 사용자가 설정에서 2FA를 활성화할 때
- 인증기 앱 설정을 위한 QR 코드가 표시됩니다
- 그리고 사용자는 활성화 전에 코드로 인증해야 합니다
#### 시나리오: 2FA 로그인
- 2FA가 활성화된 사용자가 있을 때
- 사용자가 유효한 자격 증명을 제출할 때
- OTP 인증이 표시됩니다
- 그리고 유효한 OTP 후에만 로그인이 완료됩니다
## 수정된 요구사항
### 요구사항: 세션 만료
시스템은 비활성 상태 15분 후에 세션을 만료해야 합니다.
(이전: 30분)
#### 시나리오: 유휴 시간 초과
- 인증된 세션이 있을 때
- 활동 없이 15분이 경과할 때
- 세션이 무효화됩니다
## 제거된 요구사항
### 요구사항: 로그인 상태 유지
(2FA를 위해 폐기됨. 사용자는 각 세션에서 다시 인증해야 합니다.)
```
### 델타 섹션
| 섹션 | 의미 | 보관 시 처리 |
|---------|---------|------------------------|
| `## 추가된 요구사항` | 새로운 동작 | 메인 스펙에 추가 |
| `## 수정된 요구사항` | 변경된 동작 | 기존 요구사항 대체 |
| `## 제거된 요구사항` | 폐기된 동작 | 메인 스펙에서 삭제 |
### 왜 전체 스펙 대신 델타를 사용하는가
**명확성.** 델타는 정확히 무엇이 변경되는지를 보여줍니다. 전체 스펙을 읽으면 현재 버전과의 차이를 마음속으로 비교해야 합니다.
**충돌 회피.** 두 변경 사항이 다른 요구사항을 수정하는 한 동일한 스펙 파일을 건드려도 충돌하지 않습니다.
**검토 효율성.** 검토자는 변경 사항을 보고, 변경되지 않은 맥락은 보지 않습니다. 중요한 것에 집중합니다.
**기존 개발 환경에 적합.** 대부분의 작업은 기존 동작을 수정합니다. 델타는 수정 사항을 부수적인 것이 아닌 1급 시민으로 만듭니다.
## 스키마
스키마는 워크플로우를 위한 산출물 유형과 그 의존성을 정의합니다.
### 스키마 작동 방식
```yaml
# openspec/schemas/spec-driven/schema.yaml
name: spec-driven
artifacts:
- id: proposal
generates: proposal.md
requires: [] # 의존성 없음, 먼저 생성 가능
- id: specs
generates: specs/**/*.md
requires: [proposal] # 생성 전에 proposal 필요
- id: design
generates: design.md
requires: [proposal] # specs와 병렬로 생성 가능
- id: tasks
generates: tasks.md
requires: [specs, design] # 먼저 specs와 design 모두 필요
```
**산출물은 의존성 그래프를 형성합니다:**
```
proposal
(루트 노드)
│
┌─────────────┴─────────────┐
│ │
▼ ▼
specs design
(필요: (필요:
proposal) proposal)
│ │
└─────────────┬─────────────┘
│
▼
tasks
(필요:
specs, design)
```
**의존성은 게이트가 아닌 활성화 요소입니다.** 다음에 반드시 만들어야 하는 것이 아니라 만들 수 있는 것을 보여줍니다. 필요하지 않으면 design을 건너뛸 수 있습니다. specs는 design 전후에 만들 수 있습니다 — 둘 다 proposal에만 의존합니다.
### 내장 스키마
**spec-driven** (기본값)
스펙 기반 개발을 위한 표준 워크플로우:
```
proposal → specs → design → tasks → implement
```
적합한 경우: 구현 전에 스펙에 동의하고 싶은 대부분의 기능 작업.
### 사용자 정의 스키마
팀의 워크플로우를 위한 사용자 정의 스키마를 만드세요:
```bash
# 처음부터 만들기
openspec schema init research-first
# 또는 기존 스키마를 포크하기
openspec schema fork spec-driven research-first
```
**사용자 정의 스키마 예시:**
```yaml
# openspec/schemas/research-first/schema.yaml
name: research-first
artifacts:
- id: research
generates: research.md
requires: [] # 먼저 연구 수행
- id: proposal
generates: proposal.md
requires: [research] # 연구에 의해 정보를 얻은 제안
- id: tasks
generates: tasks.md
requires: [proposal] # specs/design을 건너뛰고 바로 작업으로
```
사용자 정의 스키마 생성 및 사용에 대한 전체 세부 정보는 [사용자 정의](customization.md)를 참조하세요.
## 보관
보관은 델타 스펙을 메인 스펙에 병합하고 변경 사항을 기록으로 보존하여 변경을 완료합니다.
### 보관 시 수행되는 작업
```
보관 전:
openspec/
├── specs/
│ └── auth/
│ └── spec.md ◄────────────────┐
└── changes/ │
└── add-2fa/ │
├── proposal.md │
├── design.md │ 병합
├── tasks.md │
└── specs/ │
└── auth/ │
└── spec.md ─────────┘
보관 후:
openspec/
├── specs/
│ └── auth/
│ └── spec.md # 이제 2FA 요구사항 포함
└── changes/
└── archive/
└── 2025-01-24-add-2fa/ # 기록을 위해 보존
├── proposal.md
├── design.md
├── tasks.md
└── specs/
└── auth/
└── spec.md
```
### 보관 프로세스
1. **델타 병합.** 각 델타 스펙 섹션(추가/수정/제거)이 해당 메인 스펙에 적용됩니다.
2. **보관으로 이동.** 변경 폴더가 날짜 접두사와 함께 `changes/archive/`로 이동하여 연대순으로 정렬됩니다.
3. **맥락 보존.** 모든 산출물은 보관소에서 온전하게 유지됩니다. 변경 사항이 왜 만들어졌는지 이해하기 위해 항상 돌아볼 수 있습니다.
### 보관이 중요한 이유
**깨끗한 상태.** 활성 변경 사항(`changes/`)은 진행 중인 작업만 보여줍니다. 완료된 작업은 자리를 비워줍니다.
**감사 추적.** 보관소는 모든 변경 사항의 전체 맥락을 보존합니다 — 무엇이 변경되었는지뿐만 아니라, 왜 변경되었는지를 설명하는 제안, 어떻게 변경되었는지를 설명하는 design, 수행된 작업을 보여주는 tasks까지.
**스펙 진화.** 변경 사항이 보관됨에 따라 스펙은 자연스럽게 성장합니다. 각 보관은 델타를 병합하여 시간이 지남에 따라 포괄적인 스펙을 구축합니다.
## 전체 흐름
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ OPENSPEC 흐름 │
│ │
│ ┌────────────────┐ │
│ │ 1. 변경 시작 │ /opsx:propose (코어) 또는 /opsx:new (확장) │
│ │ │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 2. 산출물 │ /opsx:ff 또는 /opsx:continue (확장 워크플로우) │
│ │ 생성 │ proposal → specs → design → tasks 생성 │
│ │ │ (스키마 의존성에 기반) │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 3. 작업 │ /opsx:apply │
│ │ 구현 │ 작업을 수행하고 체크 표시 │
│ │ │◄──── 배우는 대로 산출물 업데이트 │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 4. 작업 │ /opsx:verify (선택 사항) │
│ │ 검증 │ 구현이 스펙과 일치하는지 확인 │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ ┌──────────────────────────────────────────────┐ │
│ │ 5. 변경 │────►│ 델타 스펙이 메인 스펙으로 병합됨 │ │
│ │ 보관 │ │ 변경 폴더가 archive/로 이동됨 │ │
│ └────────────────┘ │ 스펙이 이제 업데이트된 진실의 원천이 됨 │ │
│ └──────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```
**선순환:**
1. 스펙은 현재 동작을 설명
2. 변경 사항은 수정 사항을 제안(델타로)
3. 구현은 변경 사항을 실현
4. 보관은 델타를 스펙으로 병합
5. 스펙은 이제 새로운 동작을 설명
6. 다음 변경 사항은 업데이트된 스펙을 기반으로 구축
## 용어집
| 용어 | 정의 |
|------|------|
| **아티팩트** | 변경 사항(제안, 설계, 작업 또는 델타 스펙) 내의 문서 |
| **보관** | 변경 사항을 완료하고 그 델타를 메인 스펙에 병합하는 프로세스 |
| **변경 사항** | 시스템에 대한 수정 제안으로, 아티팩트가 포함된 폴더로 패키징됨 |
| **델타 스펙** | 현재 스펙 대비 변경 사항(추가/수정/제거)을 설명하는 스펙 |
| **도메인** | 스펙의 논리적 그룹 (예: `auth/`, `payments/`) |
| **요구 사항** | 시스템이 반드시 가져야 하는 특정 동작 |
| **시나리오** | 요구 사항의 구체적인 예시로, 일반적으로 Given/When/Then 형식 |
| **스키마** | 아티팩트 유형과 그 의존성에 대한 정의 |
| **스펙** | 요구 사항과 시나리오를 포함하여 시스템 동작을 설명하는 명세 |
| **진실의 원본** | 현재 합의된 동작을 포함하는 `openspec/specs/` 디렉토리 |
## 다음 단계
- [시작하기](getting-started.md) - 실용적인 첫 단계
- [워크플로](workflows.md) - 일반적인 패턴과 각각의 사용 시점
- [명령어](commands.md) - 전체 명령어 참조
- [사용자 정의](customization.md) - 사용자 정의 스키마 생성 및 프로젝트 구성