muno-claude-plugin 1.16.3 → 1.16.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/agents/story-reviewer.md +94 -78
- package/templates/skills/story-generator/SKILL.md +26 -11
- package/templates/skills/story-generator/reference/examples/bad-story.md +167 -0
- package/templates/skills/story-generator/reference/examples/good-story.md +48 -0
- package/templates/skills/story-generator/reference/principles.md +123 -56
- package/templates/skills/story-generator/reference/story-template.md +68 -98
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: story-reviewer
|
|
3
3
|
description: |
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Triggered after story-generator saves a Story file. Returns "OK" if story
|
|
4
|
+
Reviews User Story documents to ensure they follow Agile best practices.
|
|
5
|
+
Story should be a conversation starter (3 C's: Card, Conversation, Confirmation), NOT a detailed spec.
|
|
6
|
+
Triggered after story-generator saves a Story file. Returns "OK" if story follows Agile principles,
|
|
7
7
|
or specific feedback with severity (Critical/Major/Minor).
|
|
8
8
|
tools: Read, Glob, Grep
|
|
9
9
|
model: sonnet
|
|
@@ -17,62 +17,87 @@ ${{file:.claude/personas/sm.md}}
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## 핵심 철학
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- 문제 있을 때만 피드백 (심각도별)
|
|
25
|
-
- 직접 수정하지 않음
|
|
22
|
+
> "스토리는 소프트웨어 기능에 대한 **비공식적이고 일반적인 설명**으로, 최종 사용자 관점에서 작성됩니다."
|
|
23
|
+
> — Atlassian
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
**Story는 대화의 시작점이지 상세 스펙이 아닙니다.**
|
|
26
|
+
|
|
27
|
+
### 3 C's (Card, Conversation, Confirmation)
|
|
28
|
+
|
|
29
|
+
| C | 의미 | 검토 포인트 |
|
|
30
|
+
|---|------|------------|
|
|
31
|
+
| **Card** | 간결한 핵심 요구사항 | 20줄 이내로 표현 가능? |
|
|
32
|
+
| **Conversation** | 팀 대화 촉진 | 협의 여지가 있음? |
|
|
33
|
+
| **Confirmation** | 완료 조건 (AC) | 테스트 가능? |
|
|
28
34
|
|
|
29
35
|
---
|
|
30
36
|
|
|
31
|
-
## 검토
|
|
37
|
+
## 검토 기준
|
|
32
38
|
|
|
33
39
|
### 1. Story 구조 (필수 요소)
|
|
34
|
-
|
|
35
|
-
- [ ]
|
|
36
|
-
- [ ]
|
|
37
|
-
- [ ] Acceptance Criteria (
|
|
38
|
-
- [ ]
|
|
40
|
+
|
|
41
|
+
- [ ] Story ID와 Title
|
|
42
|
+
- [ ] User Story 문장 (As a / I want / so that)
|
|
43
|
+
- [ ] Acceptance Criteria (체크리스트 형식 권장)
|
|
44
|
+
- [ ] Notes (선택 - 협의 필요 사항)
|
|
39
45
|
|
|
40
46
|
### 2. INVEST 원칙
|
|
47
|
+
|
|
41
48
|
- [ ] **Independent**: 다른 미완료 Story 의존 없음
|
|
42
|
-
- [ ] **Negotiable**:
|
|
49
|
+
- [ ] **Negotiable**: 구현 방법이 열려있음 (과도한 세부사항 금지)
|
|
43
50
|
- [ ] **Valuable**: 사용자/비즈니스 가치 명확
|
|
44
|
-
- [ ] **Estimable**:
|
|
45
|
-
- [ ] **Small**:
|
|
46
|
-
- [ ] **Testable**: AC
|
|
51
|
+
- [ ] **Estimable**: 팀이 크기 추정 가능
|
|
52
|
+
- [ ] **Small**: 1 스프린트 내 완료 가능
|
|
53
|
+
- [ ] **Testable**: AC로 완료 여부 판단 가능
|
|
47
54
|
|
|
48
55
|
### 3. Acceptance Criteria 품질
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
- [ ]
|
|
53
|
-
- [ ]
|
|
54
|
-
- [ ]
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
|
|
57
|
+
**Good AC (체크리스트)**:
|
|
58
|
+
```markdown
|
|
59
|
+
- [ ] 유효한 이메일/비밀번호로 로그인 시 홈 화면 이동
|
|
60
|
+
- [ ] 잘못된 자격증명 시 에러 메시지 표시
|
|
61
|
+
- [ ] 로그인 상태 유지
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Bad AC (과도한 세부사항)**:
|
|
65
|
+
```gherkin
|
|
66
|
+
Scenario: 유효한 이메일과 비밀번호로 로그인
|
|
67
|
+
Given 등록된 이메일 "user@example.com"이 있다
|
|
68
|
+
When 이메일 필드에 "user@example.com"을 입력한다
|
|
69
|
+
And 비밀번호 필드에 올바른 비밀번호를 입력한다
|
|
70
|
+
Then JWT 토큰이 발급된다
|
|
71
|
+
And 토큰이 localStorage에 저장된다
|
|
72
|
+
And "환영합니다" 토스트가 3초간 표시된다
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 4. 과도한 세부사항 체크 (Red Flags)
|
|
76
|
+
|
|
77
|
+
스토리에 다음이 포함되면 **Major Issue**:
|
|
78
|
+
|
|
79
|
+
- [ ] 구현 기술 명시 (JWT, Redis, localStorage 등)
|
|
80
|
+
- [ ] UI 세부사항 (색상, 위치, 애니메이션 시간)
|
|
81
|
+
- [ ] API 스펙 (HTTP 메서드, 엔드포인트, 상태 코드)
|
|
82
|
+
- [ ] 데이터베이스 스키마
|
|
83
|
+
- [ ] Story Points / 추정 근거 (팀 플래닝에서 결정)
|
|
84
|
+
- [ ] 50줄 이상의 문서 길이
|
|
85
|
+
|
|
86
|
+
### 5. 가치 표현 체크
|
|
87
|
+
|
|
88
|
+
- [ ] "so that" 절이 동어반복이 아님
|
|
89
|
+
- [ ] 최종 사용자 관점의 가치 (개발자 관점 X)
|
|
90
|
+
- [ ] 비즈니스/사용자에게 의미있는 결과
|
|
66
91
|
|
|
67
92
|
---
|
|
68
93
|
|
|
69
94
|
## 심각도 정의
|
|
70
95
|
|
|
71
|
-
| 심각도 | 정의 |
|
|
96
|
+
| 심각도 | 정의 | 예시 |
|
|
72
97
|
|--------|------|------|
|
|
73
|
-
| **Critical** |
|
|
74
|
-
| **Major** |
|
|
75
|
-
| **Minor** | 개선하면
|
|
98
|
+
| **Critical** | 스토리의 본질 훼손 | User Story 문장 없음, 가치 불명확 |
|
|
99
|
+
| **Major** | 대화 촉진 방해 | 과도한 세부사항, 협상 불가능한 구조 |
|
|
100
|
+
| **Minor** | 개선하면 좋음 | 모호한 표현 일부, Notes 부재 |
|
|
76
101
|
|
|
77
102
|
**판정 기준:**
|
|
78
103
|
- FAIL: Critical 1개 이상 OR Major 3개 이상
|
|
@@ -81,29 +106,25 @@ ${{file:.claude/personas/sm.md}}
|
|
|
81
106
|
|
|
82
107
|
---
|
|
83
108
|
|
|
84
|
-
##
|
|
109
|
+
## 주요 Red Flags
|
|
85
110
|
|
|
86
|
-
###
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
```
|
|
111
|
+
### Critical (즉시 수정 필요)
|
|
112
|
+
- User Story 문장 없음
|
|
113
|
+
- AC 없음
|
|
114
|
+
- "so that" 동어반복 또는 가치 없음
|
|
115
|
+
- 사용자가 아닌 "개발자", "시스템" 관점
|
|
92
116
|
|
|
93
|
-
###
|
|
94
|
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
|
|
117
|
+
### Major (대화 촉진 방해)
|
|
118
|
+
- Given-When-Then이 100줄 이상
|
|
119
|
+
- 구현 기술 스택 명시
|
|
120
|
+
- UI 세부 디자인 포함
|
|
121
|
+
- Story Points 포함
|
|
122
|
+
- 추정 근거 표 포함
|
|
99
123
|
|
|
100
|
-
###
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
- 경계값 미정의
|
|
105
|
-
- 에러 시나리오 누락
|
|
106
|
-
- 단일 스프린트 불가능한 규모
|
|
124
|
+
### Minor (품질 개선)
|
|
125
|
+
- 모호한 표현 ("빠르게", "적절히")
|
|
126
|
+
- Notes 섹션 없음 (협의 사항 미명시)
|
|
127
|
+
- Epic 참조 누락
|
|
107
128
|
|
|
108
129
|
---
|
|
109
130
|
|
|
@@ -113,41 +134,36 @@ Then: "유효하지 않은 이메일 형식입니다" 에러 메시지가 표시
|
|
|
113
134
|
```
|
|
114
135
|
# Story 검토 완료 ✅
|
|
115
136
|
|
|
116
|
-
|
|
137
|
+
스토리가 애자일 원칙을 따르고 있습니다.
|
|
138
|
+
- 간결한 Card ✓
|
|
139
|
+
- 대화 촉진 가능 ✓
|
|
140
|
+
- AC로 완료 판단 가능 ✓
|
|
117
141
|
```
|
|
118
142
|
|
|
119
143
|
### 문제 발견 시
|
|
120
144
|
```
|
|
121
145
|
# Story 검토 피드백 - [FAIL/PASS with warnings]
|
|
122
146
|
|
|
123
|
-
## Critical Issues (
|
|
147
|
+
## Critical Issues (스토리 본질 훼손)
|
|
124
148
|
1. **[기준명]**: [문제] → [개선안]
|
|
125
149
|
|
|
126
|
-
## Major Issues (
|
|
150
|
+
## Major Issues (과도한 세부사항)
|
|
127
151
|
1. **[기준명]**: [문제] → [개선안]
|
|
128
152
|
|
|
129
153
|
## Minor Issues (품질 개선)
|
|
130
154
|
1. **[기준명]**: [문제] → [개선안]
|
|
131
|
-
```
|
|
132
155
|
|
|
133
156
|
---
|
|
134
157
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
**Story 파일 위치:**
|
|
138
|
-
`documents/epics/{epic-name}/stories/{story-id}-{name}/story.md`
|
|
139
|
-
|
|
140
|
-
**관련 파일:**
|
|
141
|
-
- Epic: `documents/epics/{epic-name}/epic.md`
|
|
142
|
-
- HLD/LLD: `documents/epics/{epic-name}/design/`
|
|
143
|
-
- PRD: `documents/prd/`
|
|
158
|
+
**참고**: Story는 대화의 시작점입니다. 구현 세부사항은 팀 대화에서 결정하세요.
|
|
159
|
+
```
|
|
144
160
|
|
|
145
161
|
---
|
|
146
162
|
|
|
147
163
|
## 원칙
|
|
148
164
|
|
|
149
|
-
1.
|
|
150
|
-
2.
|
|
151
|
-
3.
|
|
152
|
-
4.
|
|
153
|
-
5. **
|
|
165
|
+
1. **간결함 우선**: 스토리가 짧을수록 좋음
|
|
166
|
+
2. **과도한 세부사항 경고**: 너무 상세하면 Major Issue
|
|
167
|
+
3. **대화 촉진 관점**: 팀이 협의할 여지가 있는지 확인
|
|
168
|
+
4. **직접 수정 금지**: 피드백만, 수정은 story-generator 몫
|
|
169
|
+
5. **3 C's 기반**: Card-Conversation-Confirmation 균형 확인
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: story-generator
|
|
3
3
|
description: |
|
|
4
|
-
Creates User Stories
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
Creates User Stories - informal, general descriptions of software features from the end user's perspective.
|
|
5
|
+
Story is a conversation starter following the 3 C's (Card, Conversation, Confirmation), NOT a detailed spec.
|
|
6
|
+
|
|
7
|
+
Trigger when user requests:
|
|
8
|
+
- "create story", "write story", "add story", "story 생성", "스토리 만들어", "스토리 작성"
|
|
9
|
+
- "break down epic", "divide epic into stories", "Epic 분해", "Epic을 Story로"
|
|
10
|
+
- "user story 추출", "백로그 작성", "backlog item 생성"
|
|
11
|
+
- "story from PRD", "PRD에서 Story 도출"
|
|
12
|
+
|
|
13
|
+
Prerequisites: Epic document must exist. Never guesses - asks when info is insufficient.
|
|
8
14
|
allowed-tools: Read, Write, Edit, Glob, Grep, WebSearch, WebFetch
|
|
9
15
|
---
|
|
10
16
|
|
|
@@ -14,9 +20,17 @@ allowed-tools: Read, Write, Edit, Glob, Grep, WebSearch, WebFetch
|
|
|
14
20
|
|
|
15
21
|
## 개요
|
|
16
22
|
|
|
17
|
-
Story
|
|
23
|
+
**User Story란?**
|
|
24
|
+
|
|
25
|
+
> "스토리는 소프트웨어 기능에 대한 비공식적이고 일반적인 설명으로, 최종 사용자 관점에서 작성됩니다."
|
|
26
|
+
> — Atlassian
|
|
27
|
+
|
|
28
|
+
Story는 **최종 목표(end goal)**이지 기능 명세가 아닙니다. Story의 목적은 **대화를 시작하는 것**입니다.
|
|
18
29
|
|
|
19
|
-
|
|
30
|
+
**핵심 철학**:
|
|
31
|
+
- Story는 간결해야 합니다 (상세 스펙 X)
|
|
32
|
+
- Story는 협상 가능해야 합니다 (구현 방법은 팀이 결정)
|
|
33
|
+
- Story는 사용자에게 전달할 가치를 표현합니다
|
|
20
34
|
|
|
21
35
|
---
|
|
22
36
|
|
|
@@ -25,12 +39,13 @@ Story는 **사용자 관점의 기능 단위**입니다. 1 Sprint 내 완료 가
|
|
|
25
39
|
1. **Epic 확인**: Epic 문서 읽고 비즈니스 목표 파악
|
|
26
40
|
- Epic 없으면 진행 불가 → 사용자에게 질문
|
|
27
41
|
|
|
28
|
-
2. **Story 도출**: 사용자
|
|
29
|
-
-
|
|
30
|
-
-
|
|
42
|
+
2. **Story 도출**: 사용자 관점에서 가치 단위로 분해
|
|
43
|
+
- "사용자가 무엇을 할 수 있게 되는가?"
|
|
44
|
+
- 기술적 구현이 아닌 사용자 가치에 집중
|
|
31
45
|
|
|
32
|
-
3.
|
|
33
|
-
-
|
|
46
|
+
3. **간단한 AC 작성**: 완료 조건을 체크리스트로
|
|
47
|
+
- 과도한 세부사항 금지 (구현 제약 X)
|
|
48
|
+
- 팀이 대화할 수 있는 수준의 정보만
|
|
34
49
|
|
|
35
50
|
4. **검토 후 저장**
|
|
36
51
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Bad Story Example
|
|
2
|
+
|
|
3
|
+
피해야 할 User Story 패턴들입니다.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Bad Example 1: 과도한 세부사항 (스펙 문서가 됨)
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
---
|
|
11
|
+
id: STORY-001
|
|
12
|
+
title: 이메일로 로그인
|
|
13
|
+
epic: documents/epics/user-authentication/epic.md
|
|
14
|
+
status: todo
|
|
15
|
+
priority: must_have
|
|
16
|
+
story_points: 3
|
|
17
|
+
created_at: 2024-01-15
|
|
18
|
+
sprint: Sprint 5
|
|
19
|
+
assignee: dev-team
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# [STORY-001] 이메일로 로그인
|
|
23
|
+
|
|
24
|
+
## User Story
|
|
25
|
+
|
|
26
|
+
**AS A** 등록된 사용자
|
|
27
|
+
**I WANT** 이메일과 비밀번호로 로그인하고 싶다
|
|
28
|
+
**SO THAT** 내 계정의 개인화된 콘텐츠를 이용할 수 있다
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Acceptance Criteria
|
|
33
|
+
|
|
34
|
+
### 시나리오 1: 유효한 자격증명으로 로그인
|
|
35
|
+
|
|
36
|
+
```gherkin
|
|
37
|
+
Scenario: 유효한 이메일과 비밀번호로 로그인
|
|
38
|
+
Given 등록된 이메일 "user@example.com"이 있다
|
|
39
|
+
And 데이터베이스에 해당 사용자가 활성 상태로 존재한다
|
|
40
|
+
When 이메일 필드에 "user@example.com"을 입력한다
|
|
41
|
+
And 비밀번호 필드에 올바른 비밀번호를 입력한다
|
|
42
|
+
And "로그인" 버튼을 클릭한다
|
|
43
|
+
Then JWT 토큰이 발급된다
|
|
44
|
+
And 토큰이 localStorage에 저장된다
|
|
45
|
+
And 홈 화면 "/home"으로 리다이렉트된다
|
|
46
|
+
And 상단 네비게이션에 사용자 이름이 표시된다
|
|
47
|
+
And "환영합니다, {사용자명}님" 토스트가 3초간 표시된다
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 시나리오 2: 잘못된 비밀번호
|
|
51
|
+
|
|
52
|
+
```gherkin
|
|
53
|
+
Scenario: 잘못된 비밀번호 입력
|
|
54
|
+
Given 등록된 이메일 "user@example.com"이 있다
|
|
55
|
+
When 이메일 필드에 "user@example.com"을 입력한다
|
|
56
|
+
And 비밀번호 필드에 잘못된 비밀번호를 입력한다
|
|
57
|
+
And "로그인" 버튼을 클릭한다
|
|
58
|
+
Then HTTP 401 응답이 반환된다
|
|
59
|
+
And "이메일 또는 비밀번호가 올바르지 않습니다" 에러 메시지가 빨간색으로 표시된다
|
|
60
|
+
And 비밀번호 필드가 초기화된다
|
|
61
|
+
And 로그인 페이지에 남아있다
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 시나리오 3: 5회 연속 실패 시 계정 잠금
|
|
65
|
+
|
|
66
|
+
```gherkin
|
|
67
|
+
Scenario: 연속 로그인 실패로 계정 잠금
|
|
68
|
+
Given 4회 연속 잘못된 비밀번호로 시도했다
|
|
69
|
+
And Redis에 실패 카운터가 4로 저장되어 있다
|
|
70
|
+
When 5번째 잘못된 비밀번호로 시도한다
|
|
71
|
+
Then 계정 상태가 'LOCKED'로 변경된다
|
|
72
|
+
And "계정이 5분간 잠겼습니다. 5분 후 다시 시도해주세요." 메시지 표시
|
|
73
|
+
And 로그인 버튼이 disabled 상태로 변경
|
|
74
|
+
And 5분 타이머가 화면에 표시됨
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 의존성
|
|
80
|
+
|
|
81
|
+
### 선행 Story
|
|
82
|
+
- [ ] 없음
|
|
83
|
+
|
|
84
|
+
### 후행 Story
|
|
85
|
+
- [ ] STORY-002: 비밀번호 재설정 (이 Story 완료 후 진행)
|
|
86
|
+
- [ ] STORY-003: 소셜 로그인 연동
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 추정 근거
|
|
91
|
+
|
|
92
|
+
**Story Points**: 3
|
|
93
|
+
|
|
94
|
+
| 구성요소 | 복잡도 | Points |
|
|
95
|
+
|----------|--------|--------|
|
|
96
|
+
| 로그인 폼 UI | 단순 | 0.5 |
|
|
97
|
+
| API 연동 | 보통 | 1 |
|
|
98
|
+
| 세션/토큰 관리 | 보통 | 1 |
|
|
99
|
+
| 계정 잠금 로직 | 약간 복잡 | 0.5 |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 기술 스택
|
|
104
|
+
|
|
105
|
+
- Frontend: React + TypeScript
|
|
106
|
+
- API: REST POST /api/auth/login
|
|
107
|
+
- 인증: JWT (access token + refresh token)
|
|
108
|
+
- 저장소: localStorage (access), httpOnly cookie (refresh)
|
|
109
|
+
- 실패 카운터: Redis
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 문제점
|
|
115
|
+
|
|
116
|
+
1. **100줄 이상**: 스토리가 아니라 기술 스펙 문서
|
|
117
|
+
2. **Given-When-Then 강제**: BDD 테스트 시나리오를 AC로 사용
|
|
118
|
+
3. **구현 세부사항**: JWT, localStorage, Redis, HTTP 상태 코드 등
|
|
119
|
+
4. **UI 디테일**: 버튼 상태, 색상, 토스트 시간까지 명시
|
|
120
|
+
5. **추정 근거**: 이건 팀이 플래닝 때 하는 것
|
|
121
|
+
6. **기술 스택**: 스토리에 포함되면 안 됨
|
|
122
|
+
7. **협상 불가**: 팀이 결정할 여지가 없음
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Bad Example 2: 동어반복, 가치 없음
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
## User Story
|
|
130
|
+
|
|
131
|
+
**As a** 사용자
|
|
132
|
+
**I want** 로그인하고 싶다
|
|
133
|
+
**so that** 로그인할 수 있다
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**문제**: "so that"이 동어반복. 왜 로그인이 필요한지 가치가 없음.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Bad Example 3: 개발자 관점
|
|
141
|
+
|
|
142
|
+
```markdown
|
|
143
|
+
## User Story
|
|
144
|
+
|
|
145
|
+
**As a** 개발자
|
|
146
|
+
**I want** JWT 토큰을 localStorage에 저장하고 싶다
|
|
147
|
+
**so that** 인증 상태를 유지할 수 있다
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**문제**:
|
|
151
|
+
- 개발자는 사용자가 아님
|
|
152
|
+
- 구현 방법(How)을 명시
|
|
153
|
+
- 최종 사용자에게 전달되는 가치가 아님
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Bad Example 4: 모호한 표현
|
|
158
|
+
|
|
159
|
+
```markdown
|
|
160
|
+
## Acceptance Criteria
|
|
161
|
+
|
|
162
|
+
- [ ] 로그인이 빠르게 처리되어야 함
|
|
163
|
+
- [ ] 에러 메시지가 적절하게 표시되어야 함
|
|
164
|
+
- [ ] 보안이 잘 되어야 함
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**문제**: "빠르게", "적절하게", "잘" - 측정/테스트 불가능
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Good Story Example
|
|
2
|
+
|
|
3
|
+
실제 프로젝트에서 사용할 수 있는 올바른 User Story 예시입니다.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
```markdown
|
|
8
|
+
---
|
|
9
|
+
id: STORY-001
|
|
10
|
+
title: 이메일 로그인
|
|
11
|
+
epic: documents/epics/user-authentication/epic.md
|
|
12
|
+
status: ready
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# [STORY-001] 이메일 로그인
|
|
16
|
+
|
|
17
|
+
## User Story
|
|
18
|
+
|
|
19
|
+
**As a** 등록된 사용자
|
|
20
|
+
**I want** 이메일과 비밀번호로 로그인하고 싶다
|
|
21
|
+
**so that** 내 개인화된 콘텐츠와 주문 내역에 접근할 수 있다
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Acceptance Criteria
|
|
26
|
+
|
|
27
|
+
- [ ] 유효한 이메일/비밀번호로 로그인 시 홈 화면으로 이동
|
|
28
|
+
- [ ] 잘못된 자격증명 시 에러 메시지 표시
|
|
29
|
+
- [ ] 로그인 상태가 유지됨
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- 기존 소셜 로그인(Google, Kakao)과 공존해야 함
|
|
36
|
+
- 비밀번호 재설정은 STORY-002로 분리
|
|
37
|
+
- 보안팀과 세션 유지 시간 협의 필요
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 좋은 점
|
|
43
|
+
|
|
44
|
+
1. **간결함**: 전체 문서가 20줄 미만
|
|
45
|
+
2. **가치 명확**: "개인화된 콘텐츠와 주문 내역 접근" - 왜 필요한지 명확
|
|
46
|
+
3. **AC가 체크리스트**: 완료 여부 판단 가능
|
|
47
|
+
4. **Notes로 대화 유도**: 협의 필요 사항 명시
|
|
48
|
+
5. **구현 세부사항 없음**: JWT, localStorage 등 기술 결정은 팀에 위임
|
|
@@ -1,88 +1,155 @@
|
|
|
1
1
|
# Story Writing Principles
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## User Story란?
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
> 사용자 스토리는 소프트웨어 시스템 요구사항을 고객이나 최종 사용자의 관점에서 일상적 언어로 작성하여 개발팀에 컨텍스트를 제공하는 것입니다.
|
|
6
|
+
|
|
7
|
+
**핵심**: 스토리는 **상세 요구사항이 아니라 대화의 중심**입니다.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 3 C's: Card, Conversation, Confirmation
|
|
12
|
+
|
|
13
|
+
### Card (카드)
|
|
14
|
+
|
|
15
|
+
간결한 문장으로 핵심 요구사항을 적습니다:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
나는 {사용자 유형}으로서
|
|
19
|
+
{무엇을} 하고 싶다
|
|
20
|
+
왜냐하면 {이유/가치} 때문이다
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**예시**:
|
|
24
|
+
> "나는 웹사이트 방문객으로서, 신상품 목록을 볼 수 있다. 왜냐하면 최신 제품 정보를 빠르게 확인하고 싶기 때문이다."
|
|
25
|
+
|
|
26
|
+
### Conversation (대화)
|
|
27
|
+
|
|
28
|
+
- 개발팀, 디자이너, PO가 모여 스토리에 대해 깊이 있는 대화
|
|
29
|
+
- 이해를 공유하고 세부사항을 협의
|
|
30
|
+
- **카드는 대화의 시작점일 뿐**, 모든 것을 담을 필요 없음
|
|
31
|
+
|
|
32
|
+
### Confirmation (확인)
|
|
33
|
+
|
|
34
|
+
- 스토리가 "완료"되었다고 판단할 수 있는 조건
|
|
35
|
+
- **Acceptance Criteria (수용 기준)** 으로 정의
|
|
36
|
+
- 테스트 가능해야 함
|
|
9
37
|
|
|
10
38
|
---
|
|
11
39
|
|
|
12
40
|
## INVEST 원칙
|
|
13
41
|
|
|
14
|
-
| 원칙 | 질문 |
|
|
15
|
-
|
|
16
|
-
| **I**ndependent | 다른
|
|
17
|
-
| **N**egotiable |
|
|
18
|
-
| **V**aluable |
|
|
19
|
-
| **E**stimable | 팀이
|
|
20
|
-
| **S**mall | 1
|
|
21
|
-
| **T**estable | AC로
|
|
42
|
+
| 원칙 | 설명 | 체크 질문 |
|
|
43
|
+
|------|------|-----------|
|
|
44
|
+
| **I**ndependent | 독립적 | 다른 스토리 없이 개발 가능? |
|
|
45
|
+
| **N**egotiable | 협상 가능 | 구현 방법은 팀이 결정? |
|
|
46
|
+
| **V**aluable | 가치 중심 | 사용자/비즈니스에 가치 제공? |
|
|
47
|
+
| **E**stimable | 추정 가능 | 팀이 크기를 추정할 수 있음? |
|
|
48
|
+
| **S**mall | 작은 단위 | 1 스프린트 내 완료 가능? |
|
|
49
|
+
| **T**estable | 테스트 가능 | AC로 검증 가능? |
|
|
22
50
|
|
|
23
51
|
---
|
|
24
52
|
|
|
25
|
-
## Acceptance Criteria
|
|
53
|
+
## Acceptance Criteria 작성
|
|
54
|
+
|
|
55
|
+
### 기본: 체크리스트 형식 (권장)
|
|
26
56
|
|
|
27
|
-
|
|
57
|
+
```markdown
|
|
58
|
+
## Acceptance Criteria
|
|
59
|
+
|
|
60
|
+
- [ ] 로그인 성공 시 홈 화면으로 이동
|
|
61
|
+
- [ ] 잘못된 비밀번호 시 에러 메시지 표시
|
|
62
|
+
- [ ] 세션은 30분간 유지
|
|
63
|
+
```
|
|
28
64
|
|
|
29
|
-
|
|
30
|
-
2. **예외 케이스**: 에러 상황
|
|
31
|
-
3. **엣지 케이스**: 경계값, 보안
|
|
65
|
+
### 선택: Given-When-Then 형식
|
|
32
66
|
|
|
33
|
-
|
|
67
|
+
테스트 시나리오를 명확히 해야 할 때 선택적으로 사용:
|
|
34
68
|
|
|
35
69
|
```gherkin
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
When 올바른 비밀번호를 입력하고 로그인 클릭
|
|
40
|
-
Then 홈 화면으로 리다이렉트
|
|
41
|
-
And "환영합니다" 토스트 3초간 표시
|
|
42
|
-
|
|
43
|
-
# ❌ Bad - 모호, 측정 불가
|
|
44
|
-
- 로그인이 잘 되어야 함
|
|
45
|
-
- 에러 처리가 적절해야 함
|
|
70
|
+
Given 로그인 상태일 때
|
|
71
|
+
When '장바구니' 버튼을 클릭하면
|
|
72
|
+
Then 장바구니 페이지로 이동한다
|
|
46
73
|
```
|
|
47
74
|
|
|
75
|
+
**주의**: Given-When-Then은 테스트 케이스(TC) 단계에서 더 상세히 작성합니다.
|
|
76
|
+
스토리 AC에서는 **간결함 우선**.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 작성 팁
|
|
81
|
+
|
|
82
|
+
### Do
|
|
83
|
+
|
|
84
|
+
- 사용자 유형 명확히 정의 ('관리자', '방문객', '회원')
|
|
85
|
+
- '왜' 하는지에 집중 (기능 뒤의 목적)
|
|
86
|
+
- 대화의 시작점으로 활용
|
|
87
|
+
- 큰 스토리(Epic)는 작은 스토리로 분할
|
|
88
|
+
|
|
89
|
+
### Don't
|
|
90
|
+
|
|
91
|
+
- 처음부터 UI/UX 세부사항 정의
|
|
92
|
+
- 구현 방법(How) 명시
|
|
93
|
+
- 모호한 표현 ("빠르게", "적절히", "잘")
|
|
94
|
+
- 8 SP 초과 (분해 필요)
|
|
95
|
+
|
|
48
96
|
---
|
|
49
97
|
|
|
50
|
-
##
|
|
98
|
+
## Good vs Bad
|
|
51
99
|
|
|
52
100
|
```markdown
|
|
53
|
-
#
|
|
54
|
-
|
|
55
|
-
**
|
|
56
|
-
**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
101
|
+
# Good - 가치 중심, 간결
|
|
102
|
+
|
|
103
|
+
**As a** 등록된 사용자
|
|
104
|
+
**I want** 비밀번호를 재설정하고 싶다
|
|
105
|
+
**so that** 비밀번호를 잊어버려도 계정에 접근할 수 있다
|
|
106
|
+
|
|
107
|
+
## Acceptance Criteria
|
|
108
|
+
- [ ] 이메일로 재설정 링크 발송
|
|
109
|
+
- [ ] 링크는 24시간 유효
|
|
110
|
+
- [ ] 새 비밀번호로 로그인 가능
|
|
62
111
|
```
|
|
63
112
|
|
|
64
|
-
|
|
113
|
+
```markdown
|
|
114
|
+
# Bad - 동어반복, 가치 없음
|
|
65
115
|
|
|
66
|
-
|
|
116
|
+
**As a** 사용자
|
|
117
|
+
**I want** 비밀번호 재설정
|
|
118
|
+
**so that** 비밀번호를 재설정할 수 있다 ← 동어반복
|
|
119
|
+
```
|
|
67
120
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
121
|
+
```markdown
|
|
122
|
+
# Bad - 구현 세부사항 포함
|
|
123
|
+
|
|
124
|
+
**As a** 사용자
|
|
125
|
+
**I want** JWT 토큰을 localStorage에 저장 ← 구현 방법
|
|
126
|
+
**so that** 로그인 상태를 유지할 수 있다
|
|
127
|
+
```
|
|
74
128
|
|
|
75
129
|
---
|
|
76
130
|
|
|
77
|
-
## 기술
|
|
131
|
+
## 기술 부채를 가치로 표현하기
|
|
78
132
|
|
|
79
133
|
```markdown
|
|
80
|
-
#
|
|
81
|
-
**
|
|
82
|
-
**I
|
|
83
|
-
|
|
84
|
-
#
|
|
85
|
-
**
|
|
86
|
-
**I
|
|
87
|
-
**
|
|
134
|
+
# Bad - 개발자 관점, 가치 불명확
|
|
135
|
+
**As a** 개발자
|
|
136
|
+
**I want** 레거시 코드 리팩토링
|
|
137
|
+
|
|
138
|
+
# Good - 팀/비즈니스 가치 표현
|
|
139
|
+
**As a** 개발팀
|
|
140
|
+
**I want** 인증 모듈 코드 구조 개선
|
|
141
|
+
**so that** 신규 기능 추가 시간을 단축할 수 있다
|
|
88
142
|
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 스토리 분할 전략
|
|
147
|
+
|
|
148
|
+
큰 스토리(Epic)를 작은 스토리로 분할하는 방법:
|
|
149
|
+
|
|
150
|
+
1. **워크플로우 단계별**: 가입 → 로그인 → 프로필 수정
|
|
151
|
+
2. **사용자 유형별**: 관리자용, 일반 사용자용
|
|
152
|
+
3. **데이터 유형별**: 텍스트, 이미지, 동영상
|
|
153
|
+
4. **비즈니스 규칙별**: 정상 케이스, 예외 케이스
|
|
154
|
+
|
|
155
|
+
**1 스프린트 내 완료 가능한 크기로 유지!**
|
|
@@ -11,151 +11,121 @@
|
|
|
11
11
|
```markdown
|
|
12
12
|
---
|
|
13
13
|
id: STORY-XXX
|
|
14
|
-
title: [
|
|
14
|
+
title: [간결한 제목]
|
|
15
15
|
epic: documents/epics/{epic-name}/epic.md
|
|
16
|
-
status:
|
|
17
|
-
priority: must_have
|
|
18
|
-
story_points: 3
|
|
19
|
-
created_at: YYYY-MM-DD
|
|
16
|
+
status: draft | ready | in_progress | done
|
|
20
17
|
---
|
|
21
18
|
|
|
22
19
|
# [STORY-XXX] Story 제목
|
|
23
20
|
|
|
24
|
-
##
|
|
21
|
+
## User Story
|
|
25
22
|
|
|
26
|
-
**
|
|
27
|
-
**I
|
|
28
|
-
**
|
|
23
|
+
**As a** [사용자 유형]
|
|
24
|
+
**I want** [달성하고 싶은 것]
|
|
25
|
+
**so that** [얻고자 하는 가치/이유]
|
|
29
26
|
|
|
30
27
|
---
|
|
31
28
|
|
|
32
|
-
##
|
|
29
|
+
## Acceptance Criteria
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
스토리가 "완료"되었다고 판단할 수 있는 조건들:
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
When [사용자 행동]
|
|
40
|
-
Then [기대 결과]
|
|
41
|
-
```
|
|
33
|
+
- [ ] [조건 1]
|
|
34
|
+
- [ ] [조건 2]
|
|
35
|
+
- [ ] [조건 3]
|
|
42
36
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```gherkin
|
|
46
|
-
Scenario: [제목]
|
|
47
|
-
Given [전제 조건]
|
|
48
|
-
When [사용자 행동]
|
|
49
|
-
Then [기대 결과]
|
|
50
|
-
```
|
|
37
|
+
---
|
|
51
38
|
|
|
52
|
-
|
|
39
|
+
## Notes
|
|
53
40
|
|
|
54
|
-
|
|
55
|
-
Scenario: [제목]
|
|
56
|
-
Given [전제 조건]
|
|
57
|
-
When [사용자 행동]
|
|
58
|
-
Then [기대 결과]
|
|
41
|
+
팀과 논의가 필요한 사항, 제약 조건, 참고 정보 등 (선택 사항)
|
|
59
42
|
```
|
|
60
43
|
|
|
61
44
|
---
|
|
62
45
|
|
|
63
|
-
##
|
|
64
|
-
|
|
65
|
-
### 선행 Story
|
|
66
|
-
- [ ] 없음 / [STORY-XXX]: [이유]
|
|
46
|
+
## 핵심 포인트
|
|
67
47
|
|
|
68
|
-
|
|
69
|
-
|
|
48
|
+
1. **간결함 유지** - 스토리는 대화의 시작점이지 상세 스펙이 아님
|
|
49
|
+
2. **AC는 체크리스트** - 완료 여부를 판단할 수 있는 간단한 조건들
|
|
50
|
+
3. **구현 세부사항 금지** - "어떻게"가 아닌 "무엇을" 표현
|
|
51
|
+
4. **협상 가능** - 팀이 구현 방법을 결정할 여지를 남김
|
|
70
52
|
|
|
71
53
|
---
|
|
72
54
|
|
|
73
|
-
##
|
|
55
|
+
## Good vs Bad 예시
|
|
74
56
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
| Points | 복잡도 | 예시 |
|
|
78
|
-
|--------|--------|------|
|
|
79
|
-
| 1-2 | 단순 | CSS 수정, 필드 추가 |
|
|
80
|
-
| 3-5 | 보통 | API 엔드포인트, 폼 구현 |
|
|
81
|
-
| 8+ | 분해 필요 | 여러 컴포넌트 |
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## 예시
|
|
57
|
+
### Good Example
|
|
87
58
|
|
|
88
59
|
```markdown
|
|
89
60
|
---
|
|
90
61
|
id: STORY-001
|
|
91
|
-
title:
|
|
62
|
+
title: 이메일 로그인
|
|
92
63
|
epic: documents/epics/user-authentication/epic.md
|
|
93
|
-
status:
|
|
94
|
-
priority: must_have
|
|
95
|
-
story_points: 3
|
|
96
|
-
created_at: 2024-01-15
|
|
64
|
+
status: ready
|
|
97
65
|
---
|
|
98
66
|
|
|
99
|
-
# [STORY-001]
|
|
67
|
+
# [STORY-001] 이메일 로그인
|
|
100
68
|
|
|
101
|
-
##
|
|
69
|
+
## User Story
|
|
102
70
|
|
|
103
|
-
**
|
|
104
|
-
**I
|
|
105
|
-
**
|
|
71
|
+
**As a** 등록된 사용자
|
|
72
|
+
**I want** 이메일과 비밀번호로 로그인하고 싶다
|
|
73
|
+
**so that** 내 개인화된 콘텐츠에 접근할 수 있다
|
|
106
74
|
|
|
107
75
|
---
|
|
108
76
|
|
|
109
|
-
##
|
|
77
|
+
## Acceptance Criteria
|
|
110
78
|
|
|
111
|
-
|
|
79
|
+
- [ ] 유효한 이메일/비밀번호로 로그인하면 홈 화면으로 이동
|
|
80
|
+
- [ ] 잘못된 자격증명 시 에러 메시지 표시
|
|
81
|
+
- [ ] 로그인 후 세션 유지
|
|
112
82
|
|
|
113
|
-
|
|
114
|
-
Scenario: 유효한 이메일과 비밀번호로 로그인
|
|
115
|
-
Given 등록된 이메일 "user@example.com"이 있다
|
|
116
|
-
When 이메일과 올바른 비밀번호를 입력한다
|
|
117
|
-
And "로그인" 버튼을 클릭한다
|
|
118
|
-
Then 홈 화면으로 리다이렉트된다
|
|
119
|
-
And 상단에 사용자 이름이 표시된다
|
|
120
|
-
```
|
|
83
|
+
---
|
|
121
84
|
|
|
122
|
-
|
|
85
|
+
## Notes
|
|
123
86
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Given 등록된 이메일 "user@example.com"이 있다
|
|
127
|
-
When 잘못된 비밀번호를 입력한다
|
|
128
|
-
Then "이메일 또는 비밀번호가 올바르지 않습니다" 표시
|
|
129
|
-
And 로그인 페이지에 남아있다
|
|
87
|
+
- 기존 OAuth 로그인과 공존해야 함
|
|
88
|
+
- 비밀번호 재설정은 별도 스토리로 분리
|
|
130
89
|
```
|
|
131
90
|
|
|
132
|
-
###
|
|
91
|
+
### Bad Example (피해야 할 것)
|
|
133
92
|
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
Given 4회 연속 잘못된 비밀번호로 시도했다
|
|
137
|
-
When 5번째 잘못된 비밀번호로 시도한다
|
|
138
|
-
Then "계정이 5분간 잠겼습니다" 메시지 표시
|
|
139
|
-
And 로그인 버튼 비활성화
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
---
|
|
93
|
+
```markdown
|
|
94
|
+
# ❌ 너무 상세함 - 스토리가 아니라 스펙 문서가 됨
|
|
143
95
|
|
|
144
|
-
##
|
|
96
|
+
## Acceptance Criteria
|
|
145
97
|
|
|
146
|
-
|
|
147
|
-
|
|
98
|
+
```gherkin
|
|
99
|
+
Scenario: 유효한 이메일과 비밀번호로 로그인
|
|
100
|
+
Given 등록된 이메일 "user@example.com"이 있다
|
|
101
|
+
And 데이터베이스에 해당 사용자가 존재한다
|
|
102
|
+
When 이메일 필드에 "user@example.com"을 입력한다
|
|
103
|
+
And 비밀번호 필드에 올바른 비밀번호를 입력한다
|
|
104
|
+
And "로그인" 버튼을 클릭한다
|
|
105
|
+
Then JWT 토큰이 발급된다
|
|
106
|
+
And 토큰이 localStorage에 저장된다
|
|
107
|
+
And 홈 화면 "/home"으로 리다이렉트된다
|
|
108
|
+
And 상단 네비게이션에 사용자 이름이 표시된다
|
|
109
|
+
And "환영합니다" 토스트가 3초간 표시된다
|
|
110
|
+
```
|
|
148
111
|
|
|
149
|
-
|
|
150
|
-
-
|
|
112
|
+
## 문제점:
|
|
113
|
+
- Given-When-Then은 테스트 케이스 형식 (BDD)
|
|
114
|
+
- JWT, localStorage 등 구현 세부사항 포함
|
|
115
|
+
- UI 디테일까지 명시 → 팀의 창의성/협상 여지 없음
|
|
116
|
+
- 스토리 하나가 문서 수십 줄 → 대화 대신 문서 읽기
|
|
117
|
+
```
|
|
151
118
|
|
|
152
119
|
---
|
|
153
120
|
|
|
154
|
-
##
|
|
121
|
+
## 스토리 vs 테스트 케이스
|
|
155
122
|
|
|
156
|
-
|
|
123
|
+
| 구분 | User Story | Test Case |
|
|
124
|
+
|------|------------|-----------|
|
|
125
|
+
| 목적 | 대화 시작점 | 검증 시나리오 |
|
|
126
|
+
| 상세도 | 간략 | 상세 |
|
|
127
|
+
| 형식 | 자유 체크리스트 | Given-When-Then |
|
|
128
|
+
| 작성 시점 | 기획 단계 | 개발 직전/중 |
|
|
129
|
+
| 변경 | 협상 가능 | 구체적 기대값 |
|
|
157
130
|
|
|
158
|
-
-
|
|
159
|
-
- API 연동/세션 관리: 보통 (1 SP)
|
|
160
|
-
- 보안 처리 (계정 잠금): 약간 복잡 (1 SP)
|
|
161
|
-
```
|
|
131
|
+
**Given-When-Then은 TC(Test Case) 생성 단계에서 작성합니다.**
|