@decencia/ch-cli 1.8.1 → 1.10.1
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/agent/2t-decencia-channel-issue-coder.md +5 -4
- package/agent/2t-decencia-channel-pr-merger.md +4 -4
- package/agent/2t-decencia-channel-terraformer.md +6 -3
- package/dist/commands/specs.d.ts.map +1 -1
- package/dist/commands/specs.js +36 -3
- package/dist/commands/specs.js.map +1 -1
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +20 -0
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/skill/2t-decencia-channel-change-manager/SKILL.md +21 -5
- package/skill/2t-decencia-channel-change-propagation-v2/SKILL.md +49 -10
- package/skill/2t-decencia-channel-cli-v2/SKILL.md +46 -25
- package/skill/2t-decencia-channel-db-schema-v2/SKILL.md +1 -1
- package/skill/2t-decencia-channel-github-issue/SKILL.md +1 -1
- package/skill/2t-decencia-channel-orchestrator/SKILL.md +1 -1
- package/skill/2t-decencia-channel-prd-v2/SKILL.md +13 -9
- package/skill/2t-decencia-channel-project-bootstrap/SKILL.md +3 -3
- package/skill/2t-decencia-channel-spec-v2/SKILL.md +123 -113
- package/skill/2t-decencia-channel-sprint-builder-v2/SKILL.md +9 -8
- package/skill/2t-decencia-channel-sprint-runner/SKILL.md +11 -10
- package/skill/2t-decencia-channel-sqa-v2/SKILL.md +15 -14
- package/skill/2t-decencia-channel-work-status-v2/SKILL.md +5 -6
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
name: 2t-decencia-channel-spec-v2
|
|
3
3
|
description: |
|
|
4
4
|
[2t][v2] 소통채널 기능명세(=Story) 작성/수정 표준.
|
|
5
|
-
Epic-Story
|
|
5
|
+
Epic-Story 구조에서 UI/Logic/DB 필드 각각의 작성 패턴, JSON 템플릿을 다룬다.
|
|
6
|
+
Story는 Task로 쪼개지 않는다 — 규모는 spec 단위 Story Point(`points`)로 매긴다.
|
|
6
7
|
Spec ID는 JIRA 스타일 사용자 지정(`LOGIN-001`) 또는 자동 생성 선택 가능 — §1.5.
|
|
7
8
|
작업 일지(workStatus)는 라이프사이클이 달라 [[2t-decencia-channel-work-status-v2]]로 분리.
|
|
8
9
|
Use when:
|
|
9
10
|
(1) spec(=Story)을 작성·수정할 때,
|
|
10
11
|
(2) UI 메타데이터·비즈니스 로직·DB 참조를 함께 다룰 때,
|
|
11
|
-
(3)
|
|
12
|
+
(3) Story 규모를 Story Point(`--points`)로 매길 때,
|
|
12
13
|
(4) 신규 spec ID를 `LOGIN-001` 같은 JIRA 스타일로 부여하고 싶을 때 (`ch specs create --id`).
|
|
13
|
-
version: 1.
|
|
14
|
+
version: 1.10.1
|
|
14
15
|
---
|
|
15
16
|
|
|
16
17
|
<!-- ch-version-gate -->
|
|
@@ -28,7 +29,7 @@ ch check
|
|
|
28
29
|
구버전 스킬·CLI 사용을 막기 위한 게이트다. 건너뛰지 말 것.
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
# 기능명세 —
|
|
32
|
+
# 기능명세 — Epic / Story 작성 표준
|
|
32
33
|
|
|
33
34
|
CLI 명령은 [[2t-decencia-channel-cli-v2]], DB 테이블 작성은 [[2t-decencia-channel-db-schema-v2]] 참조.
|
|
34
35
|
|
|
@@ -41,14 +42,16 @@ CLI 명령은 [[2t-decencia-channel-cli-v2]], DB 테이블 작성은 [[2t-decenc
|
|
|
41
42
|
| **Spec ID** | `spec.id` (string) | 식별자. **JIRA 스타일 사용자 지정 가능** (예: `LOGIN-001`). §1.5 |
|
|
42
43
|
| **Epic** | `spec.epic` (string) | 분류 라벨. 같은 에픽 spec끼리 자동 그룹핑 |
|
|
43
44
|
| **Story** | spec 자체 (1 spec = 1 story) | 명세 1건. CLI 명칭은 `specs` 그대로 |
|
|
44
|
-
| **
|
|
45
|
+
| **Story Point** | `spec.points` (number) | Story 규모 점수. Story를 Task로 쪼개지 않고 spec 단위로 매긴다. §3 |
|
|
45
46
|
| **UI** | `spec.ui` (object) | Figma·route·file·access·interactionMap |
|
|
46
|
-
| **Logic** | `spec.logic` (object) |
|
|
47
|
+
| **Logic** | `spec.logic` (object) | dataFlowScenarios·stateTransitions·businessRules |
|
|
47
48
|
| **DB** | `spec.dbTableRefs` (string[]) | db-tables 컬렉션의 테이블 ID 배열. 양방향 동기화 |
|
|
48
49
|
|
|
49
50
|
`spec.workStatus`(작업 일지)는 개발 진행 중에 누적되는 별개 라이프사이클 — [[2t-decencia-channel-work-status-v2]] 참조.
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
**Story는 Task로 쪼개지 않는다.** 규모는 spec 단위 Story Point(`points`)로 매긴다(§3). 진행률(%) 개념은 없다 — 완료 여부는 `spec.status`로 표현한다.
|
|
53
|
+
|
|
54
|
+
**완료 조건**: 별도 acceptanceCriteria 없음. **연관 SQA 통과 = 완료**. (`tasks`는 deprecated — 하위호환용으로만 남는다.)
|
|
52
55
|
|
|
53
56
|
---
|
|
54
57
|
|
|
@@ -56,12 +59,12 @@ CLI 명령은 [[2t-decencia-channel-cli-v2]], DB 테이블 작성은 [[2t-decenc
|
|
|
56
59
|
|
|
57
60
|
```bash
|
|
58
61
|
ch specs get <specId> --json > /tmp/spec.json # 1) 현재 상태 백업
|
|
59
|
-
# 편집 (
|
|
60
|
-
ch specs update <specId> --
|
|
61
|
-
ch specs get <specId> --json | jq '.
|
|
62
|
+
# 편집 (ui/logic JSON 통째 교체 위험)
|
|
63
|
+
ch specs update <specId> --logic /tmp/logic.json --no-version
|
|
64
|
+
ch specs get <specId> --json | jq '.logic' # 3) 검증
|
|
62
65
|
```
|
|
63
66
|
|
|
64
|
-
`--
|
|
67
|
+
`--ui` / `--logic` / `--work-status`는 **각 필드 자체를 통째로 교체**. 일부만 바꾸려면 반드시 전체 가져와서 편집 후 전송. (`--points`는 스칼라라 통째 교체 위험 없음 — 그 값만 바뀐다.)
|
|
65
68
|
|
|
66
69
|
---
|
|
67
70
|
|
|
@@ -71,11 +74,11 @@ ch specs get <specId> --json | jq '.tasks' # 3) 검증
|
|
|
71
74
|
|---|---|
|
|
72
75
|
| `content` | 개요 1~3줄 + 권한 요약. 짧게 유지 |
|
|
73
76
|
| `ui.*` | 화면 메타 (figma/route/file/access) + 인터랙션 맵 |
|
|
74
|
-
| `logic.
|
|
77
|
+
| `logic.dataFlowScenarios` | 시나리오별 데이터 흐름. 시나리오 → 순서 있는 단계 → 단계별 테이블 참조(refs) |
|
|
75
78
|
| `logic.stateTransitions` | 상태 머신 |
|
|
76
79
|
| `logic.businessRules` | 도메인 규칙 |
|
|
77
80
|
| `dbTableRefs[]` | 참조 테이블 ID (스키마 본문은 db-tables 문서에) |
|
|
78
|
-
| `
|
|
81
|
+
| `points` | Story 규모 점수 (Story Point). Story 단위로 매긴다 (§3) |
|
|
79
82
|
|
|
80
83
|
---
|
|
81
84
|
|
|
@@ -159,73 +162,40 @@ ch db-tables list --json
|
|
|
159
162
|
|
|
160
163
|
---
|
|
161
164
|
|
|
162
|
-
## 3.
|
|
163
|
-
|
|
164
|
-
### 3-1. tasks.json 구조
|
|
165
|
+
## 3. Story Point — spec 단위 규모
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
[
|
|
168
|
-
{
|
|
169
|
-
"id": "",
|
|
170
|
-
"title": "로그인 폼 UI 구현",
|
|
171
|
-
"done": false,
|
|
172
|
-
"assignee": "박준하",
|
|
173
|
-
"points": 5,
|
|
174
|
-
"description": "## 세부\n- React Hook Form + Yup\n- error UI 별도 컴포넌트\n- 참고: [Figma](https://...)"
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"id": "",
|
|
178
|
-
"title": "Firebase Auth 연결",
|
|
179
|
-
"done": false,
|
|
180
|
-
"points": 3,
|
|
181
|
-
"description": "- signInWithEmailAndPassword 사용\n- 5회 실패 시 잠금 로직은 별도 spec"
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
"id": "a1b2c3d4",
|
|
185
|
-
"title": "유효성 검증",
|
|
186
|
-
"done": true,
|
|
187
|
-
"points": 1,
|
|
188
|
-
"completedAt": "2026-05-29T08:00:00.000Z"
|
|
189
|
-
}
|
|
190
|
-
]
|
|
191
|
-
```
|
|
167
|
+
Story(=spec)를 Task로 쪼개지 않는다. Story 하나의 규모를 **Story Point 한 값**으로 매긴다. Sprint 용량 산정은 Σ spec.points로 한다([[2t-decencia-channel-sprint-builder-v2]]).
|
|
192
168
|
|
|
193
|
-
|
|
194
|
-
- `id` 비어있으면 UUID 부여
|
|
195
|
-
- `done: true && completedAt 없음` → 현재 ISO 부여
|
|
196
|
-
- `done: false` → completedAt 제거
|
|
197
|
-
- 전체 progress(%) 자동 재계산 (`Math.round(doneCount / total * 100)`)
|
|
169
|
+
### 3-1. 부여 방법
|
|
198
170
|
|
|
199
|
-
|
|
171
|
+
```bash
|
|
172
|
+
ch specs create --name "로그인 화면" --device web --domain user --type 인증 --points 5
|
|
173
|
+
ch specs update <specId> --points 8 --no-version
|
|
174
|
+
```
|
|
200
175
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
| "로그인 기능 구현" (points 13+) | "로그인 폼 UI 구현" (3~5p) | "input 태그 추가" (0p) |
|
|
176
|
+
- `--points <n>` — 0 이상의 숫자. 보통 피보나치(1/2/3/5/8/13)를 쓴다.
|
|
177
|
+
- 진행률(%)·완료율은 없다. 완료 여부는 `spec.status`로 표현한다.
|
|
204
178
|
|
|
205
|
-
-
|
|
206
|
-
- 13 이상이면 쪼개라.
|
|
207
|
-
- 1 이하면 description bullet으로 합쳐라.
|
|
179
|
+
### 3-2. points 부여 가이드 (피보나치)
|
|
208
180
|
|
|
209
|
-
|
|
181
|
+
Story 하나를 끝내는 데 드는 규모를 매긴다.
|
|
210
182
|
|
|
211
|
-
| points | 의미 | 예 |
|
|
183
|
+
| points | 의미 | 예 (Story 1건) |
|
|
212
184
|
|---|---|---|
|
|
213
|
-
| 1 | 거의 자명.
|
|
214
|
-
| 2 | 1일
|
|
215
|
-
| 3 | 1~2일. 신규
|
|
216
|
-
| 5 | 2~3일.
|
|
217
|
-
| 8 | 1주~. 큰 모듈, 모르는 영역 포함 | 결제
|
|
218
|
-
| 13 | 너무 큼 —
|
|
185
|
+
| 1 | 거의 자명. 반나절 이내 | 단순 텍스트/색상 변경 화면 |
|
|
186
|
+
| 2 | 1일 이내 | 기존 화면에 필드 1개 추가 |
|
|
187
|
+
| 3 | 1~2일. 신규 화면/엔드포인트 1개 | 로그인 화면 |
|
|
188
|
+
| 5 | 2~3일. UI + API + 상태 통합 | 회원가입 플로우 |
|
|
189
|
+
| 8 | 1주~. 큰 모듈, 모르는 영역 포함 | 결제 연동 화면 |
|
|
190
|
+
| 13 | 너무 큼 — **Story를 쪼개라** (spec 분리) | — |
|
|
219
191
|
|
|
220
|
-
### 3-
|
|
192
|
+
### 3-3. 너무 크면 Story를 나눈다
|
|
221
193
|
|
|
222
|
-
|
|
223
|
-
- 들어가야 할 것: 구체 산출물, 의존성, 참고 자료(Figma/문서 링크), 엣지케이스
|
|
224
|
-
- 들어가지 말 것: 작업 일지(→ [[work-status-v2]] 참조), 완료 보고(→ done + completedAt)
|
|
194
|
+
13 이상이면 한 Sprint에 못 끝낸다. Task로 쪼개는 게 아니라 **spec 자체를 여러 Story로 나눈다**(§9).
|
|
225
195
|
|
|
226
|
-
### 3-
|
|
196
|
+
### 3-4. tasks 필드는 deprecated
|
|
227
197
|
|
|
228
|
-
|
|
198
|
+
과거의 `spec.tasks[]`(체크리스트)는 deprecated다. 신규 spec에는 쓰지 않는다. `--tasks`는 하위호환으로 계속 통과되지만 사용 시 경고가 뜬다. 기존 spec의 tasks는 그대로 두거나, 규모가 필요하면 `--points`로 대체한다.
|
|
229
199
|
|
|
230
200
|
---
|
|
231
201
|
|
|
@@ -283,34 +253,67 @@ ch db-tables list --json
|
|
|
283
253
|
|
|
284
254
|
```json
|
|
285
255
|
{
|
|
286
|
-
"
|
|
256
|
+
"dataFlowScenarios": [],
|
|
287
257
|
"stateTransitions": "...",
|
|
288
258
|
"businessRules": "..."
|
|
289
259
|
}
|
|
290
260
|
```
|
|
291
261
|
|
|
292
|
-
|
|
262
|
+
`dataFlowScenarios`는 배열(아래 §5-2). `stateTransitions`·`businessRules`는 마크다운 문자열. 필요한 것만 채운다.
|
|
293
263
|
|
|
294
|
-
### 5-2.
|
|
264
|
+
### 5-2. dataFlowScenarios — 시나리오 → 순서 있는 단계 → 참조
|
|
295
265
|
|
|
296
|
-
|
|
266
|
+
데이터 흐름을 **시나리오 단위**로 적는다. 한 시나리오는 하나의 동작 경로다(예: "로그인 성공", "비밀번호 5회 실패로 잠금"). 시나리오 안에는 **순서 있는 단계(steps)**가 있고, 각 단계는 그 단계가 건드리는 테이블·컬럼을 `refs`로 가리킨다.
|
|
297
267
|
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"dataFlowScenarios": [
|
|
271
|
+
{
|
|
272
|
+
"name": "로그인 성공",
|
|
273
|
+
"description": "회원이 이메일과 비밀번호로 로그인에 성공하면 인증 토큰을 발급하고 마지막 로그인 시각을 갱신한다.",
|
|
274
|
+
"steps": [
|
|
275
|
+
{
|
|
276
|
+
"description": "클라이언트가 입력한 이메일과 비밀번호를 인증 서버로 전송한다."
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"description": "인증 서버가 자격 증명을 확인하고 ID 토큰을 발급해 httpOnly 쿠키에 저장한다.",
|
|
280
|
+
"refs": [
|
|
281
|
+
{ "tableId": "tbl_sessions", "direction": "WRITE", "note": "세션 레코드 생성" }
|
|
282
|
+
]
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"description": "인증에 성공하면 사용자 문서의 마지막 로그인 시각을 현재 시각으로 갱신한다.",
|
|
286
|
+
"refs": [
|
|
287
|
+
{ "tableId": "tbl_users", "field": "lastLoginAt", "direction": "WRITE", "note": "로그인 성공 시 갱신" }
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
]
|
|
291
|
+
}
|
|
292
|
+
]
|
|
293
|
+
}
|
|
306
294
|
```
|
|
307
295
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
296
|
+
#### 구조
|
|
297
|
+
|
|
298
|
+
| 필드 | 타입 | 의미 |
|
|
299
|
+
|---|---|---|
|
|
300
|
+
| `dataFlowScenarios[]` | 배열 | 시나리오 목록 |
|
|
301
|
+
| `…[].name` | 문자열(필수) | 시나리오 이름. 동작 경로를 짧게 가리킨다. 예: `로그인 성공` |
|
|
302
|
+
| `…[].description` | 문자열(선택) | 시나리오 전체를 요약한 완결 문장 1~2개 |
|
|
303
|
+
| `…[].steps[]` | 배열(필수) | **순서 있는** 단계. 배열 순서 = 실행 순서 |
|
|
304
|
+
| `…steps[].description` | 문자열(필수) | 그 단계에서 일어나는 일을 적은 완결 문장 |
|
|
305
|
+
| `…steps[].refs[]` | 배열(선택) | 이 단계가 읽거나 쓰는 테이블·컬럼 참조(§6-2-1) |
|
|
306
|
+
|
|
307
|
+
#### 작성 원칙 — 완결 문장으로
|
|
308
|
+
|
|
309
|
+
- `description`은 **6하원칙(누가·언제·어디서·무엇을·어떻게·왜)을 담은 완결 문장**으로 쓴다. 필드명이나 단어만 나열하지 않는다.
|
|
310
|
+
- 단, "누가", "어디에" 같은 **소제목·라벨은 달지 않는다**. 6하원칙은 문장 안에 자연스럽게 녹인다.
|
|
311
|
+
- ❌ 나쁜 예 (단어 나열): `이메일/비밀번호 → Firebase Auth → ID Token, users.lastLoginAt WRITE`
|
|
312
|
+
- ❌ 나쁜 예 (소제목): `누가: 회원 / 무엇을: 로그인 / 어디에: users 테이블`
|
|
313
|
+
- ⭕ 좋은 예 (완결 문장): `회원이 이메일과 비밀번호로 로그인하면, 인증 서버가 자격 증명을 확인한 뒤 마지막 로그인 시각을 갱신한다.`
|
|
314
|
+
- 한 단계 = 흐름의 한 매듭. 너무 잘게 쪼개지 말고, 데이터가 한 번 이동·변형하는 단위로 묶는다.
|
|
315
|
+
- 외부 API 호출도 한 단계로 적는다(예: "결제 서버에 승인을 요청한다"). 그 단계가 우리 테이블을 건드리면 `refs`로 표시한다.
|
|
316
|
+
- 🔒 컬럼은 **이름으로만** 가리킨다 — `type`/`nullable` 등 정의는 적지 않는다(§6-2 SSOT 규칙). 기계 추적 가능한 참조는 `refs`로 구조화한다(§6-2-1).
|
|
314
317
|
|
|
315
318
|
### 5-3. stateTransitions — 상태 머신 표
|
|
316
319
|
|
|
@@ -348,7 +351,7 @@ ch db-tables list --json
|
|
|
348
351
|
- 1 규칙 = 1 불릿
|
|
349
352
|
- 임계값·기간·조건을 구체 수치로
|
|
350
353
|
- 큰 규칙은 별도 spec 분리 가능
|
|
351
|
-
- 🔒 enum/상태값의 **허용값 집합 정의는 적지 않는다**(db-tables가 SSOT) — 그 값을 *이용한 규칙*만 적는다(§6-2). 규칙이
|
|
354
|
+
- 🔒 enum/상태값의 **허용값 집합 정의는 적지 않는다**(db-tables가 SSOT) — 그 값을 *이용한 규칙*만 적는다(§6-2). 규칙이 어떤 테이블·컬럼을 검사·갱신하는지는 그 규칙이 작동하는 시나리오의 단계 `refs`로 가리킨다(§5-2, §6-2-1). businessRules에는 별도 구조적 참조 필드를 두지 않는다.
|
|
352
355
|
|
|
353
356
|
---
|
|
354
357
|
|
|
@@ -364,7 +367,7 @@ ch db-tables list --json
|
|
|
364
367
|
|
|
365
368
|
| 위치 | 내용 |
|
|
366
369
|
|---|---|
|
|
367
|
-
| **spec** | "이 화면/기능이 어느 테이블의 어떤 컬럼을 R/W하는가" — `logic.
|
|
370
|
+
| **spec** | "이 화면/기능이 어느 테이블의 어떤 컬럼을 R/W하는가" — `logic.dataFlowScenarios`의 단계 `refs`로 **이름으로 참조만** |
|
|
368
371
|
| **db-tables** | 컬럼 정의, 인덱스, 보안 규칙, 역할 매트릭스 (스키마의 SSOT) |
|
|
369
372
|
|
|
370
373
|
spec.dbTableRefs는 **포인터만**. 스키마 본문은 [[2t-decencia-channel-db-schema-v2]] 참조.
|
|
@@ -376,28 +379,34 @@ spec.dbTableRefs는 **포인터만**. 스키마 본문은 [[2t-decencia-channel-
|
|
|
376
379
|
- enum/상태값의 **정의**(허용값 집합)는 db-tables. businessRules는 그 값을 이용한 **규칙**만 적는다. (예: ❌ "status는 draft|published|archived" / ⭕ "published 상태에서만 외부 노출")
|
|
377
380
|
- 같은 정보를 db-tables와 spec 양쪽에 쓰면 스키마 변경 시 반드시 어긋난다. 의심되면 정의는 지우고 `dbTableRefs` 링크로 대체.
|
|
378
381
|
|
|
379
|
-
### 6-2-1.
|
|
382
|
+
### 6-2-1. 단계별 구조적 참조 (`logic.dataFlowScenarios[].steps[].refs[]`)
|
|
380
383
|
|
|
381
|
-
|
|
384
|
+
각 단계가 읽거나 쓰는 테이블·컬럼을 **기계가 추적 가능하게** 가리키는 참조다. 시나리오의 단계 안에 둔다(§5-2).
|
|
382
385
|
|
|
383
386
|
```json
|
|
384
387
|
{
|
|
385
|
-
"
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
388
|
+
"dataFlowScenarios": [
|
|
389
|
+
{
|
|
390
|
+
"name": "로그인 성공",
|
|
391
|
+
"steps": [
|
|
392
|
+
{
|
|
393
|
+
"description": "인증에 성공하면 마지막 로그인 시각을 갱신한다.",
|
|
394
|
+
"refs": [
|
|
395
|
+
{ "tableId": "tbl_users", "field": "lastLoginAt", "direction": "WRITE", "note": "로그인 성공 시 갱신" },
|
|
396
|
+
{ "tableId": "tbl_sessions", "direction": "READ" }
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
]
|
|
400
|
+
}
|
|
393
401
|
]
|
|
394
402
|
}
|
|
395
403
|
```
|
|
396
404
|
|
|
397
|
-
- `tableId` **필수** — db-tables의 실제 id. `field` 선택(컬럼명). `direction` `READ|WRITE|READWRITE`
|
|
405
|
+
- `tableId` **필수** — db-tables의 실제 id. `field` 선택(컬럼명). `direction` 선택(`READ|WRITE|READWRITE`). `note` 선택.
|
|
398
406
|
- 서버가 **실존 검증**: 없는 tableId → 400, 컬럼 정의가 있는 테이블에 없는 field → 400(끊긴 참조 차단).
|
|
399
407
|
- CLI는 `--logic logic.json`으로 통째 전달(별도 플래그 없음). 웹은 spec 상세의 DB 섹션에서 칩+피커로 편집.
|
|
400
408
|
- **여전히 정의는 금지** — refs는 가리키기만 한다. type/nullable/enum 허용값 등은 db-tables.
|
|
409
|
+
- 레거시 spec의 `dataFlowRefs`/`businessRuleRefs`(logic 최상위 배열)는 하위호환으로 읽히지만, 신규·수정 시에는 해당 컬럼을 건드리는 **단계의 refs**로 옮긴다.
|
|
401
410
|
|
|
402
411
|
### 6-3. 신규 spec에서 신규 테이블이 필요한 경우 순서
|
|
403
412
|
|
|
@@ -436,22 +445,22 @@ spec 작성 시점이 아니라 **개발 진행 중에 누적**되는 일지(`sp
|
|
|
436
445
|
### 8-A. 화면 명세 (가장 흔함)
|
|
437
446
|
|
|
438
447
|
- `ui` 모든 필드 채움 (figmaNodeId/route/file/access/interactionMap)
|
|
439
|
-
- `logic.
|
|
440
|
-
- `
|
|
448
|
+
- `logic.dataFlowScenarios` 필수 (화면이 다루는 주요 동작 경로별 시나리오)
|
|
449
|
+
- `points` 화면 하나의 규모 (보통 3~8)
|
|
441
450
|
- `dbTableRefs` 화면이 R/W하는 테이블 전부
|
|
442
451
|
|
|
443
452
|
### 8-B. 기능 명세 (Cron · 배치 · 외부 연동)
|
|
444
453
|
|
|
445
454
|
- `ui` 통째 생략
|
|
446
|
-
- `logic.
|
|
455
|
+
- `logic.dataFlowScenarios` + `logic.businessRules` 필수
|
|
447
456
|
- `logic.stateTransitions` 작업 상태 머신
|
|
448
|
-
- `
|
|
457
|
+
- `points` 트리거·처리·에러처리를 포함한 규모
|
|
449
458
|
|
|
450
459
|
### 8-C. 공통 명세 (인증 · 알림 · 업로드)
|
|
451
460
|
|
|
452
461
|
- `ui` 생략 (모듈이라 화면 없음)
|
|
453
462
|
- `logic.businessRules` 중심 (정책·제약)
|
|
454
|
-
- `
|
|
463
|
+
- `points` 인터페이스 구현·통합까지 포함한 규모
|
|
455
464
|
- 다른 spec이 이걸 import한다는 점을 `note`에 명시
|
|
456
465
|
|
|
457
466
|
---
|
|
@@ -462,9 +471,8 @@ spec 작성 시점이 아니라 **개발 진행 중에 누적**되는 일지(`sp
|
|
|
462
471
|
|
|
463
472
|
| 지표 | 한계 | 조치 |
|
|
464
473
|
|---|---|---|
|
|
465
|
-
| `
|
|
466
|
-
|
|
|
467
|
-
| `logic.dataFlow` 표 행 수 | 15+ | 화면/기능이 다중일 가능성 → 분리 |
|
|
474
|
+
| `points` (Story Point) | 13+ | sprint 1회로 못 끝남 → spec 분리 |
|
|
475
|
+
| `logic.dataFlowScenarios` 시나리오 수 | 6+ | 화면/기능이 다중일 가능성 → 분리 |
|
|
468
476
|
| `ui.interactionMap` 줄 수 | 80+ | 화면이 너무 큼 → 분리 |
|
|
469
477
|
| 같은 spec에 화면 2개 이상 | 항상 분리 | 1 화면 = 1 spec |
|
|
470
478
|
|
|
@@ -472,11 +480,13 @@ spec 작성 시점이 아니라 **개발 진행 중에 누적**되는 일지(`sp
|
|
|
472
480
|
|
|
473
481
|
## 10. 흔한 함정
|
|
474
482
|
|
|
475
|
-
- `--
|
|
483
|
+
- `--ui/--logic` JSON 통째 교체 → 일부 수정도 **반드시 get 후 편집**. (`--points`는 스칼라라 안전.)
|
|
476
484
|
- `dbTableRefs`를 손으로 JSON에 넣어도 서버가 무시 (CLI `--db-tables` 또는 웹 picker만 사용).
|
|
477
|
-
-
|
|
478
|
-
-
|
|
485
|
+
- **Story를 Task로 쪼개려 하지 말 것.** 규모는 spec 단위 `--points`로 매기고, 너무 크면 spec 자체를 나눈다(§9).
|
|
486
|
+
- 시간축 진행 메모는 workStatus(별도 스킬)에 적는다.
|
|
487
|
+
- `tasks`는 deprecated. `--tasks`는 하위호환으로만 통과된다(사용 시 경고).
|
|
479
488
|
- **스키마 정의를 logic에 베껴 넣기** — 컬럼 type/nullable/index/보안규칙/enum 허용값은 db-tables에만. spec은 이름 참조 + `dbTableRefs` 링크만(§6-2).
|
|
489
|
+
- **dataFlow를 단어 나열로 적기** — 시나리오의 단계 `description`은 화살표·필드명 나열이 아니라 완결 문장으로(§5-2). "누가/어디에" 소제목도 달지 않는다.
|
|
480
490
|
|
|
481
491
|
---
|
|
482
492
|
|
|
@@ -487,10 +497,10 @@ spec 작성 시점이 아니라 **개발 진행 중에 누적**되는 일지(`sp
|
|
|
487
497
|
1. `ch specs meta --json` → 스키마 옵션 확인
|
|
488
498
|
2. 화면이 사용하는 테이블 정리 → 없으면 `ch db-tables create` 먼저
|
|
489
499
|
3. **Spec ID 결정** (§1.5) — JIRA 스타일(`EPIC-NNN`) 사용 시 다음 번호 결정. 자동 ID로 가도 됨
|
|
490
|
-
4. `
|
|
500
|
+
4. `points`(Story Point) 산정 — Story 하나의 규모 (§3, 보통 3~8)
|
|
491
501
|
5. `ui.json` 작성 (figmaNodeId/route/file/access/interactionMap)
|
|
492
|
-
6. `logic.json` 작성 (
|
|
493
|
-
7. `ch specs create [--id LOGIN-001] --name ... --epic ... --
|
|
502
|
+
6. `logic.json` 작성 (dataFlowScenarios 필수 — 시나리오→단계→refs, 나머지 해당 시)
|
|
503
|
+
7. `ch specs create [--id LOGIN-001] --name ... --epic ... --points 5 --ui ... --logic ... --db-tables tbl_a,tbl_b`
|
|
494
504
|
8. `ch specs get <id> --json`으로 결과 검증
|
|
495
505
|
9. SQA 항목은 [[2t-decencia-channel-sqa-v2]]에 따라 별도 등록
|
|
496
506
|
10. 개발 착수 후의 진행 일지는 [[2t-decencia-channel-work-status-v2]]에서 관리
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
name: 2t-decencia-channel-sprint-builder-v2
|
|
3
3
|
description: |
|
|
4
4
|
[2t][v2] 소통채널 Sprint 구성 가이드.
|
|
5
|
-
spec의 epic·
|
|
5
|
+
spec의 epic·points(Story Point)를 활용한 스프린트 산정과 자동 배치 원칙.
|
|
6
6
|
Use when:
|
|
7
7
|
(1) sprint를 구성할 때,
|
|
8
|
-
(2)
|
|
8
|
+
(2) Σ spec.points 기반 sprint 용량 산정이 필요할 때,
|
|
9
9
|
(3) Epic·도메인·의존성을 함께 고려해 spec을 sprint에 배분할 때.
|
|
10
|
-
version: 1.
|
|
10
|
+
version: 1.10.1
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
<!-- ch-version-gate -->
|
|
@@ -30,7 +30,7 @@ ch check
|
|
|
30
30
|
## 0. Read-before-Write
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
ch specs list --json > /tmp/specs.json # 모든 spec과
|
|
33
|
+
ch specs list --json > /tmp/specs.json # 모든 spec과 points 확보
|
|
34
34
|
ch sprints list --json > /tmp/sprints.json
|
|
35
35
|
# 분석 후
|
|
36
36
|
ch sprints create --name "Sprint 1" --start 2026-06-01 --end 2026-06-14 --specs <id1>,<id2>
|
|
@@ -39,8 +39,8 @@ ch sprints create --name "Sprint 1" --start 2026-06-01 --end 2026-06-14 --specs
|
|
|
39
39
|
## 1. 산정 절차
|
|
40
40
|
|
|
41
41
|
1. 모든 spec을 `ch specs list --json`로 수집.
|
|
42
|
-
2. 각 spec의 `epic`, `
|
|
43
|
-
3.
|
|
42
|
+
2. 각 spec의 `epic`, `points`(Story Point) 추출.
|
|
43
|
+
3. Sprint 용량 = **Σ spec.points**. spec 하나가 규모 단위이며 별도 하위 합산은 없다. `points` 미지정 spec은 산정 전에 [[2t-decencia-channel-spec-v2]] §3으로 부여한다(미지정은 0이 아니라 누락으로 본다).
|
|
44
44
|
4. Sprint 용량(예: 30 SP / 2주) 설정 후, 다음 순서로 채우기:
|
|
45
45
|
- **의존성** (PRD/spec.dbTableRefs 분석): DB 테이블 신규 생성 spec → 그걸 참조하는 spec 순.
|
|
46
46
|
- **Epic 단위 묶음**: 같은 Epic은 한 sprint에 몰아주는 게 컨텍스트 비용 ↓.
|
|
@@ -72,6 +72,7 @@ Sprint 1 (06-01 ~ 06-14, 용량 30 SP)
|
|
|
72
72
|
|
|
73
73
|
## 4. 흔한 함정
|
|
74
74
|
|
|
75
|
-
- points
|
|
76
|
-
- Sprint에
|
|
75
|
+
- `points` 미지정 spec이 많으면 산정 부정확 → spec마다 `--points` 부여(피보나치 1/2/3/5/8/13).
|
|
76
|
+
- Sprint에 담은 spec의 `points`를 바꾸면 sprint SP 합이 변동 — sprint 재산정 필요.
|
|
77
|
+
- Story를 Task로 쪼개 합산하지 않는다 — 규모는 spec 단위 `points` 하나다([[2t-decencia-channel-spec-v2]] §3).
|
|
77
78
|
- Sprint와 spec.workStatus는 별개. Sprint 진행 상황은 sprint 자체 status로, spec별 메모는 workStatus로.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: 2t-decencia-channel-sprint-runner
|
|
3
3
|
description: 특정 Sprint를 끝까지 실행(run)하는 오케스트레이터 스킬. Sprint의 spec을 시드로 이슈 목록을 분해·발행(github-issue)하고, GitHub milestone에 묶인 이슈를 상태별로 분류해 issue-coder(병렬)·pr-merger(직렬)로 전진시킨 뒤, 사람확인이 필요한 곳에서 멈춘다. 사람이 확인·체크 후 재호출하면 멱등하게 이어간다(반복 루프). "스프린트 돌려줘"·"sprint N 실행"·"이 스프린트 개발 진행해줘" 류 요청 시.
|
|
4
4
|
allowed-tools: Skill Agent Read Bash(ch:*) Bash(gh:*) Bash(git:*)
|
|
5
|
-
version: 1.
|
|
5
|
+
version: 1.10.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
<!-- ch-version-gate -->
|
|
@@ -55,7 +55,7 @@ ch check
|
|
|
55
55
|
|
|
56
56
|
## 브랜치와 worktree의 큰 그림
|
|
57
57
|
|
|
58
|
-
이 Sprint의 모든 이슈는 통합 브랜치 `sprint-<id>` 하나에 모인다. 원격의 이 브랜치가 정본이고, 어떤 이슈도 기본 브랜치로 곧장 머지하지 않는다. 모든 이슈가 모인 뒤에야 사람이 검토하고 한 번에 기본 브랜치로 머지한다.
|
|
58
|
+
이 Sprint의 모든 이슈는 통합 브랜치 `sprint-<id>` 하나에 모인다. 원격의 이 브랜치가 정본이고, 어떤 이슈도 기본 브랜치로 곧장 머지하지 않는다. 모든 이슈가 모인 뒤에야 사람이 검토하고 한 번에 기본 브랜치로 머지한다. 통합 결과를 테스트·검토할 때는 메인 폴더에서 `sprint-<id>`를 체크아웃해 본다(전용 worktree를 만들지 않는다). 이슈별 구현은 issue-coder가 각자 worktree에서 병렬로 하며, 그건 격리가 필요해 worktree로 둔다.
|
|
59
59
|
|
|
60
60
|
---
|
|
61
61
|
|
|
@@ -67,13 +67,14 @@ ch check
|
|
|
67
67
|
|
|
68
68
|
`ch sprints get <id>`로 이 Sprint에 묶인 spec 목록을 가져온다. 이건 출발점일 뿐이라 완전하지 않다. spec은 기획이라 인프라 구축 같은 실행 작업이 빠져 있으므로, spec에 없는 실행 작업을 사용자와 짧게 의논해 채운다. 모호하면 추측하지 말고 한 번 물어 확정한다. 결과물은 이 Sprint를 끝낼 완전한 할 일 목록이다.
|
|
69
69
|
|
|
70
|
-
### 2. 통합
|
|
70
|
+
### 2. 통합 브랜치를 만든다 (이슈 작업을 시작하기 전에 반드시 한다)
|
|
71
71
|
|
|
72
72
|
이 셋업을 끝내기 전에는 어떤 issue-coder도 띄우지 않는다. 건너뛰면 이슈가 기본 브랜치에서 갈라져 곧장 기본 브랜치로 향하는 PR이 생겨 통합이 깨진다.
|
|
73
73
|
|
|
74
74
|
- **milestone 확보**: `gh api repos/{owner}/{repo}/milestones`로 조회하고, 없으면 Sprint 이름(또는 `sprint-<id>`)으로 만든다.
|
|
75
75
|
- **통합 브랜치 `sprint-<id>` 확보**: 원격에 있으면 그대로 쓰고, 없으면 감지한 기본 브랜치에서 만들어 push한다. `BASE=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)`로 기본 브랜치를 구한 뒤 `git fetch origin "$BASE" && git branch sprint-<id> "origin/$BASE" && git push -u origin sprint-<id>`를 실행한다. 이후 모든 이슈 PR의 base가 된다.
|
|
76
|
-
|
|
76
|
+
|
|
77
|
+
통합 결과의 스모크 검사와 dev 서버, 사람 검토는 별도 worktree를 만들지 않고 메인 폴더(작업 디렉터리)에서 `sprint-<id>`를 체크아웃해서 한다. 메인 폴더의 기존 의존성과 env를 그대로 쓰므로 따로 설치할 필요가 없다.
|
|
77
78
|
|
|
78
79
|
### 3. 아직 이슈로 만들지 않은 할 일만 발행한다
|
|
79
80
|
|
|
@@ -108,9 +109,9 @@ ch check
|
|
|
108
109
|
|
|
109
110
|
green인 PR은 pr-merger에 하나씩 직렬로 위임한다. 한 번 머지하면 `sprint-<id>`가 바뀌므로 다음 PR을 다시 평가하고, 동시에 머지하지 않는다. issue-coder가 PR을 만들면 다음 회차에 `IN_PR`로 잡혀 머저로 넘어간다.
|
|
110
111
|
|
|
111
|
-
### 6. 통합
|
|
112
|
+
### 6. 메인 폴더를 최신 통합 상태로 맞추고, 사람에게 넘기기 전에 스모크 검사를 한 번 돌린다
|
|
112
113
|
|
|
113
|
-
|
|
114
|
+
통합 결과는 메인 폴더에서 `sprint-<id>`를 체크아웃해 확인한다. 메인 폴더에서 `git fetch origin sprint-<id>` 후 `git checkout sprint-<id> && git pull --ff-only origin sprint-<id>`로 로컬을 원격과 맞춘다. 메인 폴더는 사용자의 작업 공간이라 `git reset --hard`로 덮지 않는다. 커밋 안 된 변경이 있어 체크아웃이나 ff-pull이 막히면, 강제로 진행하지 말고 멈춰 사용자에게 알린다. **사람에게 확인이나 검토를 요청하기 직전에는 이 동기화를 반드시 한 번 더 해서, 그때까지 머지된 모든 변경이 반영되게 한다. 사람은 언제나 완전히 통합·동기화된 상태만 본다.**
|
|
114
115
|
|
|
115
116
|
스모크 검사는 머지마다 하지 않고, 이번 회차의 코딩·머지를 끝내고 사람에게 넘기기 직전에 한 번만 한다. 이 스킬은 git까지만 쓸 수 있어 빌드·dev 서버 실행은 Agent에 맡긴다. 검사는 빌드가 되는지, dev 서버가 뜨는지, 핵심 경로 한두 개가 도는지까지만 가볍게 보고 전체 기능을 다시 검증하지는 않는다. 실패하면 멈추고 어느 머지가 무엇을 깼는지 사람에게 보고한다.
|
|
116
117
|
|
|
@@ -120,7 +121,7 @@ green인 PR은 pr-merger에 하나씩 직렬로 위임한다. 한 번 머지하
|
|
|
120
121
|
|
|
121
122
|
### 8. 더 진행할 것이 없으면 멈추고 보고한다
|
|
122
123
|
|
|
123
|
-
더 전진시킬 것이 없으면 멈춘다. 보고하기 전에
|
|
124
|
+
더 전진시킬 것이 없으면 멈춘다. 보고하기 전에 메인 폴더를 `git fetch origin sprint-<id>` 후 `git checkout sprint-<id> && git pull --ff-only`로 최신 통합 상태에 맞춰(메인이 더티라 막히면 덮지 말고 멈춰 알린다), 사람이 보는 상태가 그때까지 머지된 전체와 일치하게 한다. 그다음 현황을 요약 보고한다. 완료(DONE) 개수, 사람 확인 대기(AWAIT_HUMAN) 이슈와 각각의 링크·미체크 항목, 막힌(블로커) 이슈와 그 이유(어느 이슈·PR인지)를 적는다. 그리고 사용자가 확인·피드백 후 같은 Sprint로 다시 부르면 이어서 진행한다고 안내한다.
|
|
124
125
|
|
|
125
126
|
### 9. 다시 불리면 이어서 진행한다 (멱등)
|
|
126
127
|
|
|
@@ -128,9 +129,9 @@ green인 PR은 pr-merger에 하나씩 직렬로 위임한다. 한 번 머지하
|
|
|
128
129
|
|
|
129
130
|
### 10. 모든 이슈가 모이면 사람이 검토하고 최종 머지한다 (사람 게이트)
|
|
130
131
|
|
|
131
|
-
모든 이슈가 `sprint-<id>`에 모이면, 먼저
|
|
132
|
+
모든 이슈가 `sprint-<id>`에 모이면, 먼저 메인 폴더를 `sprint-<id>`로 체크아웃하고 origin/sprint-<id>에 맞춰 모든 머지가 반영됐는지 확인한 뒤, dev 서버를 띄워 사용자가 통합 결과를 검토하게 한다. 최종 머지 전에 기본 브랜치를 `sprint-<id>`에 먼저 머지해 충돌을 미리 푼다. 검토 중 새 할 일이 나오면 별도 채널을 만들지 말고 해당 이슈의 체크리스트 note나 milestone 새 이슈로 흘린다.
|
|
132
133
|
|
|
133
|
-
어디로 머지할지는 사용자가 정해 직접 실행한다. 보통 기본 브랜치로 머지하고 이 머지가 곧 자동 배포로 이어지므로, 스킬은 특별한 지시가 없는 한 직접 누르지 않는다. 머지 뒤 `sprint-<id>`
|
|
134
|
+
어디로 머지할지는 사용자가 정해 직접 실행한다. 보통 기본 브랜치로 머지하고 이 머지가 곧 자동 배포로 이어지므로, 스킬은 특별한 지시가 없는 한 직접 누르지 않는다. 머지 뒤 `sprint-<id>` 브랜치를 정리하고 메인 폴더를 기본 브랜치로 되돌리며, 남은 이슈 worktree도 정리한다.
|
|
134
135
|
|
|
135
136
|
---
|
|
136
137
|
|
|
@@ -144,7 +145,7 @@ issue-coder는 독립 이슈를 각자 worktree에서 다루므로 병렬로 돌
|
|
|
144
145
|
- 이슈 close나 기본 브랜치 push는 하지 않는다. issue-coder는 PR까지만 하고, 이슈 close는 pr-merger가 조건부로(사람 확인 항목이 남으면 open 유지) 한다.
|
|
145
146
|
- 막혔을 때 무한히 시도하지 않는다. CI red·모호한 충돌·불분명한 요구 같은 블로커는 스스로 풀려 하지 말고 사람에게 넘긴다.
|
|
146
147
|
- 배포는 기본 브랜치 머지 시 GitHub Actions가 자동으로 한다. 스킬은 수동 배포를 하지 않고, 기본 브랜치로 올리는 최종 머지도 특별한 지시가 없는 한 사용자에게 맡긴다.
|
|
147
|
-
- 매 단계마다 지금 어느 worktree의 어느 브랜치에서 무엇을 하는지 사용자에게 먼저 알린다.
|
|
148
|
+
- 매 단계마다 지금 어디(메인 폴더인지 어느 이슈 worktree인지)의 어느 브랜치에서 무엇을 하는지 사용자에게 먼저 알린다. 메인 폴더는 통합 검토용으로 `sprint-<id>`를 오가고 이슈 worktree는 각자 이슈 브랜치를 쓰므로, 위치를 분명히 해야 사용자가 헷갈리지 않는다.
|
|
148
149
|
- 공통 함정도 지킨다. ch CLI 본문은 마크다운으로 쓰고 CRLF를 정제하며, spec 필드는 단수·복수를 함께 쓰고, `--json`이나 `specs get`이 윈도우에서 빈 출력이면 PowerShell `Out-File`로 우회한다(위임 대상이 이미 준수).
|
|
149
150
|
|
|
150
151
|
## 다른 컴포넌트와의 관계
|
|
@@ -7,12 +7,12 @@ description: |
|
|
|
7
7
|
Functional·Publishing·Frontend·Backend 카테고리를 한 묶음으로 제공하는 누적 라이브러리.
|
|
8
8
|
Use when:
|
|
9
9
|
(1) SQA 시트를 새로 작성하거나 항목을 보강할 때,
|
|
10
|
-
(2) spec.
|
|
10
|
+
(2) spec.ui/logic에서 도출한 검증 항목을 SQA 시트에 등록할 때,
|
|
11
11
|
(3) 보안/성능/접근성/호환성 비기능 TC를 시트에 채워야 할 때,
|
|
12
12
|
(4) 명세 영역별 완성형 TC 번들(퍼블리싱/프론트/백엔드 디센시아 운영 관점 포함)을 가져다 쓸 때,
|
|
13
13
|
(5) 새 명세 작업 중 반복 패턴을 발견해 영역별 번들을 보강할 때,
|
|
14
14
|
(6) Sprint 종료 전 spec별 SQA 통과 여부를 점검할 때.
|
|
15
|
-
version: 1.
|
|
15
|
+
version: 1.10.1
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
<!-- ch-version-gate -->
|
|
@@ -30,7 +30,7 @@ ch check
|
|
|
30
30
|
구버전 스킬·CLI 사용을 막기 위한 게이트다. 건너뛰지 말 것.
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
# SQA — spec
|
|
33
|
+
# SQA — spec 완료 판정 (SQA 통과 = 완료)
|
|
34
34
|
|
|
35
35
|
## 0. Read-before-Write
|
|
36
36
|
|
|
@@ -40,15 +40,16 @@ ch check
|
|
|
40
40
|
|
|
41
41
|
> **spec의 완료 조건 = 그 spec에 연결된 SQA 항목이 모두 통과**
|
|
42
42
|
|
|
43
|
-
별도 acceptanceCriteria 필드 없음. spec.
|
|
43
|
+
별도 acceptanceCriteria 필드 없음. **공식 완료는 SQA**가 판정한다 — spec에 연결된 SQA 항목이 모두 통과해야 spec.status를 완료로 올린다. spec 규모는 Story Point(`spec.points`)로 표현하고, 진행률(%)·Task 체크박스 개념은 없다.
|
|
44
44
|
|
|
45
|
-
## 2. spec
|
|
45
|
+
## 2. spec → SQA 항목 도출
|
|
46
46
|
|
|
47
|
-
spec.tasks
|
|
48
|
-
|
|
47
|
+
SQA 항목은 spec의 ui·logic(특히 logic.businessRules)에서 도출한다. Story는 Task로 쪼개지 않으므로(`tasks`는 deprecated) 검증 단위는 개별 task가 아니라 **spec이 정의한 동작·규칙**이다.
|
|
48
|
+
|
|
49
|
+
- 도출 입력: spec.ui(화면·상호작용), spec.logic(dataFlow·businessRules)
|
|
49
50
|
- SQA 항목: QA가 검증할 시나리오 (예: "잘못된 비밀번호 5회 시 잠금")
|
|
50
51
|
|
|
51
|
-
**1:N 관계**: 1
|
|
52
|
+
**1:N 관계**: spec 1개가 여러 SQA 항목을 유발한다. SQA 항목 작성 시 `relatedSpec`으로 spec에 연결해 추적한다.
|
|
52
53
|
|
|
53
54
|
## 3. 신규 SQA 작성 워크플로우
|
|
54
55
|
|
|
@@ -57,11 +58,11 @@ spec.tasks 작성 시 다음 패턴 권장:
|
|
|
57
58
|
# --date 생략 시 오늘로 자동 채움 (서버 DTO가 performDate 필수)
|
|
58
59
|
ch sqa create --name "Sprint 1 SQA" --date 2026-06-01
|
|
59
60
|
```
|
|
60
|
-
1. **spec
|
|
61
|
+
1. **spec의 ui·logic을 가져온다**:
|
|
61
62
|
```bash
|
|
62
|
-
ch specs get <specId> --json | jq '
|
|
63
|
+
ch specs get <specId> --json | jq '{ui, logic}'
|
|
63
64
|
```
|
|
64
|
-
2.
|
|
65
|
+
2. spec.ui(화면·상호작용)와 logic.businessRules를 참고하여 검증 항목 도출.
|
|
65
66
|
3. SQA 시트에 항목 추가 (§3.5 CLI 명령 사용).
|
|
66
67
|
4. 항목 작성 시 `relatedSpec`에 specId 명시(생략 시 미연결).
|
|
67
68
|
|
|
@@ -99,7 +100,7 @@ ch sqa reorder-items <sheetId> --file order.json # ["id1","id2",...] 또는 {
|
|
|
99
100
|
|
|
100
101
|
| 축 | 단위 | 출처 / 도출 방법 | 비고 |
|
|
101
102
|
|---|---|---|---|
|
|
102
|
-
| A. 명세별 기능 TC | spec 1개당 | spec.ui/logic
|
|
103
|
+
| A. 명세별 기능 TC | spec 1개당 | spec.ui/logic을 읽고 **§4.3 영역별 TC 번들 라이브러리**에서 해당 영역들을 골라 명세 맥락으로 구체화 | spec당 보통 5~15개 |
|
|
103
104
|
| B. 비기능 4축 표준 TC | 시트 1개당 묶음 | 표준(OWASP/Core Web Vitals/WCAG/호환성)을 그대로 등록 | **시트당 40개** (보안 12 + 성능 10 + 접근성 10 + 호환성 8) |
|
|
104
105
|
|
|
105
106
|
축 B는 spec 단위가 아니므로 `relatedSpec`을 비워두거나 "common"/"standard" 가상 specId로 일관 관리.
|
|
@@ -184,7 +185,7 @@ ch sqa reorder-items <sheetId> --file order.json # ["id1","id2",...] 또는 {
|
|
|
184
185
|
|
|
185
186
|
### 사용 절차
|
|
186
187
|
|
|
187
|
-
1. spec.ui/logic
|
|
188
|
+
1. spec.ui/logic을 읽어 그 spec이 속한 **명세 영역**을 1~N개 식별 (예: "지점 관리 화면" = 접근권한 + 목록 + 등록/수정 폼 + 삭제).
|
|
188
189
|
2. 각 영역 번들의 항목을 가져와 그 명세의 도메인 단어로 구체화. 추상 문구 그대로 박지 말 것.
|
|
189
190
|
- 추상: "Update시 모달창이나 수정 페이지로 데이터가 제대로 전달 되는가?"
|
|
190
191
|
- 명세별: "지점 수정 모달 진입 시 기존 지점명·지역·전화 필드가 prefill됨"
|
|
@@ -412,7 +413,7 @@ ch specs update <specId> --status 완료 --no-version
|
|
|
412
413
|
|
|
413
414
|
## 9. 흔한 함정
|
|
414
415
|
|
|
415
|
-
-
|
|
416
|
+
- 구현이 끝났다고 판단해도 연결된 SQA가 통과하기 전에는 spec.status를 완료로 바꾸지 않음.
|
|
416
417
|
- **명세별 E2E만 넣고 끝내지 말 것** — §4.3 번들에서 Publishing/Frontend/Backend 카테고리 누락, §4.2 비기능 4축 미등록이 가장 흔한 실수.
|
|
417
418
|
- §4.3 번들을 **별도 시트 묶음으로 등록**하지 말 것 — 각 명세의 A축 항목으로 풀어 써야 한다. 추상 문구 그대로 박아넣지 말 것.
|
|
418
419
|
- 항목 단위 CRUD(§3.5)는 **시트 템플릿**만 변경 — 진행 중 Run에는 반영 안 됨. Run 항목 결과는 `check`/`check-bulk`로.
|