@decencia/ch-cli 1.30.0 → 1.31.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.
Files changed (45) hide show
  1. package/agent/2t-decencia-channel-issue-coder.md +1 -1
  2. package/agent/2t-decencia-channel-pr-merger.md +1 -1
  3. package/agent/2t-decencia-channel-terraformer.md +1 -1
  4. package/dist/commands/policies.d.ts +12 -0
  5. package/dist/commands/policies.d.ts.map +1 -0
  6. package/dist/commands/policies.js +302 -0
  7. package/dist/commands/policies.js.map +1 -0
  8. package/dist/commands/screens.d.ts.map +1 -1
  9. package/dist/commands/screens.js +103 -23
  10. package/dist/commands/screens.js.map +1 -1
  11. package/dist/commands/specs.d.ts +15 -0
  12. package/dist/commands/specs.d.ts.map +1 -1
  13. package/dist/commands/specs.js +117 -10
  14. package/dist/commands/specs.js.map +1 -1
  15. package/dist/commands/sprints.d.ts +16 -0
  16. package/dist/commands/sprints.d.ts.map +1 -1
  17. package/dist/commands/sprints.js +152 -4
  18. package/dist/commands/sprints.js.map +1 -1
  19. package/dist/commands/sqa.d.ts +23 -0
  20. package/dist/commands/sqa.d.ts.map +1 -1
  21. package/dist/commands/sqa.js +252 -6
  22. package/dist/commands/sqa.js.map +1 -1
  23. package/dist/commands/userflows.d.ts +11 -0
  24. package/dist/commands/userflows.d.ts.map +1 -0
  25. package/dist/commands/userflows.js +275 -0
  26. package/dist/commands/userflows.js.map +1 -0
  27. package/dist/index.js +4 -0
  28. package/dist/index.js.map +1 -1
  29. package/package.json +1 -1
  30. package/skill/2t-decencia-channel-change-manager/SKILL.md +1 -1
  31. package/skill/2t-decencia-channel-change-propagation-v2/SKILL.md +11 -7
  32. package/skill/2t-decencia-channel-cli-v2/SKILL.md +48 -20
  33. package/skill/2t-decencia-channel-db-schema-v2/SKILL.md +4 -4
  34. package/skill/2t-decencia-channel-github-issue/SKILL.md +1 -1
  35. package/skill/2t-decencia-channel-orchestrator/SKILL.md +1 -1
  36. package/skill/2t-decencia-channel-policy-v2/SKILL.md +115 -0
  37. package/skill/2t-decencia-channel-prd-v2/SKILL.md +37 -12
  38. package/skill/2t-decencia-channel-project-bootstrap/SKILL.md +50 -38
  39. package/skill/2t-decencia-channel-screen-v2/SKILL.md +137 -0
  40. package/skill/2t-decencia-channel-spec-v2/SKILL.md +290 -443
  41. package/skill/2t-decencia-channel-sprint-builder-v2/SKILL.md +11 -3
  42. package/skill/2t-decencia-channel-sprint-runner/SKILL.md +1 -1
  43. package/skill/2t-decencia-channel-sqa-v2/SKILL.md +126 -21
  44. package/skill/2t-decencia-channel-userflow-v2/SKILL.md +126 -0
  45. package/skill/2t-decencia-channel-work-status-v2/SKILL.md +3 -3
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseUserflowOrder = parseUserflowOrder;
4
+ exports.registerUserflowsCommand = registerUserflowsCommand;
5
+ const client_1 = require("../client");
6
+ const output_1 = require("../output");
7
+ const utils_1 = require("../utils");
8
+ /**
9
+ * ch userflows — 유저플로우(분기 있는 사용자 여정의 Mermaid 문서) 관리 명령.
10
+ *
11
+ * ch-api의 /userflows REST(이슈 #216)를 호출한다. 명령 계약의 SSOT는 스킬
12
+ * `2t-decencia-channel-userflow-v2` §5이며, `ch screens` 선례를 그대로 따른다.
13
+ *
14
+ * 지키는 계약 두 가지:
15
+ * - 출력(PLAT-003): `--json`(기계 모드)이면 stdout은 순수 JSON 문서 하나뿐이고
16
+ * 사람용 메시지는 stderr로 나간다. 빈 목록도 stdout에는 `[]`로 나간다.
17
+ * - 종료코드: HTTP 4xx/5xx는 client의 응답 인터셉터가 exitCode를 세우지만, 서버에
18
+ * 닿기 전 로컬 입력 오류(파일 없음·--order 비숫자·수정 필드 0개)는 아무도
19
+ * 세워주지 않는다. 그래서 공용 failInput()(output.ts)으로 직접 exitCode=1을 세운다.
20
+ *
21
+ * Mermaid 문법은 CLI도 서버도 검증하지 않는다 — 문자열로 실어 보낼 뿐이다
22
+ * (렌더러 버전마다 유효 문법이 갈려서, 파서를 들고 있으면 그 버전이 곧 저장 가능한
23
+ * 문법의 상한이 된다). 렌더 실패는 웹 뷰어가 안내한다.
24
+ */
25
+ /** create/update의 help 하단에 붙는 --file 안내. */
26
+ const FILE_HELP = `
27
+ --file <경로> — Mermaid 코드 파일 (.mmd):
28
+ ch userflows create --name "로그인·계정 복구" --file ./login-flow.mmd
29
+ cat login-flow.mmd | ch userflows create --name "로그인·계정 복구" --file -
30
+
31
+ BOM·CRLF는 자동 정제되어 LF로 전송된다 (PowerShell Out-File 호환).
32
+ "-"를 주면 stdin에서 읽는다. 플래그 없이 stdin을 넘겨다보지는 않는다 —
33
+ 에이전트·CI 셸에서 fd0가 '열린 채 EOF가 오지 않는 파이프'인 경우가 흔해서,
34
+ 암묵적 stdin 읽기는 "ch userflows update <id> --order 3" 같은 평범한 호출을
35
+ 무한 대기시킨다.
36
+
37
+ 수정은 Read-before-Write:
38
+ Mermaid는 통째 교체다(부분 병합 없음). 고칠 때는 먼저
39
+ 'ch userflows get <flowId> --json'으로 현재 코드를 받아 편집한 뒤 전체를 넘긴다.
40
+ `;
41
+ /**
42
+ * `--order` 값을 숫자로 파싱한다. 문자열을 그대로 서버에 실어 보내면 400으로
43
+ * 되돌아오므로 요청 전에 CLI가 거른다 (screens의 parseScreenOrder 선례).
44
+ *
45
+ * screens에서 import하지 않고 여기 둔다 — 커맨드 모듈끼리 헬퍼를 주고받으면
46
+ * 리소스 하나의 규칙 변경이 다른 리소스로 새어 나간다.
47
+ */
48
+ function parseUserflowOrder(value, label = '--order') {
49
+ const trimmed = String(value).trim();
50
+ const n = Number(trimmed);
51
+ if (trimmed === '' || !Number.isFinite(n)) {
52
+ throw new Error(`${label}: 숫자를 지정하세요 (예: 3). 받은 값: "${value}"`);
53
+ }
54
+ return n;
55
+ }
56
+ /**
57
+ * Mermaid 코드를 해석한다. `--file -`이면 stdin, 그 외에는 파일에서 읽는다.
58
+ * 어느 경로든 BOM 제거 + CRLF→LF 정규화(readContentFile/readContentStdin).
59
+ *
60
+ * 인라인 플래그(`--mermaid "<코드>"`)는 두지 않는다. 플로우차트는 여러 줄이라
61
+ * 셸 인용부호를 타고 넘어오다 줄바꿈이 뭉개진다 — 파일이 정본이다.
62
+ */
63
+ function resolveMermaid(file) {
64
+ if (file === '-') {
65
+ const piped = (0, utils_1.readContentStdin)();
66
+ if (piped === null) {
67
+ throw new Error('--file -: stdin에서 읽을 내용이 없습니다. Mermaid 코드를 파이프로 넘기거나 --file <경로>를 쓰세요.');
68
+ }
69
+ return requireNonEmptyMermaid(piped, '--file -');
70
+ }
71
+ return requireNonEmptyMermaid((0, utils_1.readContentFile)(file, '--file'), '--file');
72
+ }
73
+ /**
74
+ * 빈 Mermaid를 요청 전에 거른다. 서버도 400으로 막지만(CreateUserflowDto), 여기서
75
+ * 걸러야 "저장됐겠거니" 하고 넘어가지 않는다. PowerShell `Out-File`이 개행만 흘려
76
+ * 넣은 .mmd가 실제로 이 모양이라 흔하다.
77
+ */
78
+ function requireNonEmptyMermaid(mermaid, label) {
79
+ if (mermaid.trim() === '') {
80
+ throw new Error(`${label}: Mermaid 코드가 비어 있습니다.`);
81
+ }
82
+ return mermaid;
83
+ }
84
+ /**
85
+ * 플래그를 요청 바디로 변환한다. 지정된 플래그만 담으므로 update에서 그대로 PATCH
86
+ * 바디가 되고, 미지정 필드는 서버가 보존한다.
87
+ *
88
+ * 입력 오류(파일 없음·본문 비었음·--order 비숫자)는 throw한다 — 호출부가
89
+ * failInput으로 받아 종료코드를 세운다.
90
+ */
91
+ function buildUserflowBody(options) {
92
+ const body = {};
93
+ if (options.name !== undefined)
94
+ body.name = options.name;
95
+ // 빈 문자열 판정은 `!== undefined`로 한다. falsy 체크를 쓰면 `--description ""`
96
+ // (설명 지우기)가 무시된다.
97
+ if (options.description !== undefined)
98
+ body.description = options.description;
99
+ if (options.file !== undefined)
100
+ body.mermaid = resolveMermaid(options.file);
101
+ if (options.order !== undefined) {
102
+ body.order = parseUserflowOrder(options.order, '--order');
103
+ }
104
+ return body;
105
+ }
106
+ /** 기계 모드(=stdout이 순수 JSON이어야 하는 모드)인지. */
107
+ function isMachineOutput(globalOpts) {
108
+ return !!(globalOpts.json || globalOpts.csv || globalOpts.quiet);
109
+ }
110
+ // ── 서브커맨드 ────────────────────────────────────────────────────────────
111
+ function registerUserflowsList(userflows, program) {
112
+ userflows
113
+ .command('list')
114
+ .description('유저플로우 목록 조회 (order 오름차순, order 없는 플로우는 뒤)')
115
+ .action(async () => {
116
+ const globalOpts = program.opts();
117
+ try {
118
+ const client = (0, client_1.createClient)({ projectId: globalOpts.project });
119
+ const { data } = await client.get('/userflows');
120
+ const items = Array.isArray(data) ? data : data?.data ?? [];
121
+ // 기계 모드 분기를 빈값 안내(printInfo)보다 앞에 둔다. 빈 결과도 stdout에
122
+ // `[]`로 나가야 하고, 사람용 안내문이 stdout(JSON)을 오염시키면 안 된다
123
+ // (PLAT-003, 이슈 #50 — db-tables에서 겪은 회귀).
124
+ if (isMachineOutput(globalOpts)) {
125
+ (0, output_1.formatOutput)(items, globalOpts);
126
+ return;
127
+ }
128
+ if (!items.length) {
129
+ (0, output_1.printInfo)('등록된 유저플로우가 없습니다.');
130
+ return;
131
+ }
132
+ // 표는 스킬 §5대로 order | id | name 세 컬럼이다. Mermaid 본문은 목록에
133
+ // 싣지 않는다 — 한 장이 수십 줄이라 표가 읽히지 않는다(get으로 본다).
134
+ (0, output_1.printTable)(['order', 'id', 'name'], items.map((f) => [
135
+ f?.order === undefined || f?.order === null ? '' : String(f.order),
136
+ String(f?.id ?? ''),
137
+ String(f?.name ?? ''),
138
+ ]));
139
+ }
140
+ catch (error) {
141
+ // 오류 출력·종료코드는 client 인터셉터가 처리했다.
142
+ }
143
+ });
144
+ }
145
+ function registerUserflowsGet(userflows, program) {
146
+ // 로컬 --json은 두지 않는다. commander가 부모(program)의 전역 옵션을 서브커맨드
147
+ // 뒤에서도 해석하므로 `ch userflows get <id> --json`이 그대로 동작한다.
148
+ userflows
149
+ .command('get <flowId>')
150
+ .description('유저플로우 상세 조회 (Mermaid 코드 포함 — 수정 전 Read-before-Write)')
151
+ .action(async (flowId) => {
152
+ const globalOpts = program.opts();
153
+ try {
154
+ const client = (0, client_1.createClient)({ projectId: globalOpts.project });
155
+ const { data } = await client.get(`/userflows/${flowId}`);
156
+ (0, output_1.formatOutput)(data, globalOpts);
157
+ }
158
+ catch (error) {
159
+ // Error already handled
160
+ }
161
+ });
162
+ }
163
+ function registerUserflowsCreate(userflows, program) {
164
+ userflows
165
+ .command('create')
166
+ .description('유저플로우 생성 (한 장 = 한 여정)')
167
+ .requiredOption('--name <name>', '여정 이름 (필수)')
168
+ // --file을 requiredOption으로 둔다. mermaid는 서버 필수 필드라 없으면 400인데,
169
+ // 왕복 한 번 없이 여기서 걸러야 종료코드 계약("로컬 입력 오류는 요청 없이 exit≠0")이 선다.
170
+ .requiredOption('--file <path>', 'Mermaid 코드 파일 (.mmd, "-"이면 stdin) (필수)')
171
+ .option('--description <text>', '한 줄 설명 (이 여정이 무엇을 보여주는지)')
172
+ .option('--order <n>', '목록 정렬 순서 (숫자)')
173
+ .addHelpText('after', FILE_HELP)
174
+ .action(async (options) => {
175
+ const globalOpts = program.opts();
176
+ try {
177
+ // 파일을 먼저 읽고 dry-run을 판정한다 — 깨진 파일이 --dry-run에서 통과하면
178
+ // 정작 실행할 때 실패한다 (sqa add-scenario와 같은 순서).
179
+ let body;
180
+ try {
181
+ body = buildUserflowBody(options);
182
+ }
183
+ catch (e) {
184
+ (0, output_1.failInput)(e?.message ?? String(e));
185
+ return;
186
+ }
187
+ if (globalOpts.dryRun) {
188
+ (0, output_1.printInfo)(`[DRY-RUN] 유저플로우 "${options.name}" 생성 요청`);
189
+ return;
190
+ }
191
+ const client = (0, client_1.createClient)({ projectId: globalOpts.project });
192
+ const { data } = await client.post('/userflows', body);
193
+ (0, output_1.formatOutput)(data, globalOpts);
194
+ (0, output_1.printSuccess)('유저플로우가 생성되었습니다.');
195
+ }
196
+ catch (error) {
197
+ // Error already handled
198
+ }
199
+ });
200
+ }
201
+ function registerUserflowsUpdate(userflows, program) {
202
+ userflows
203
+ .command('update <flowId>')
204
+ .description('유저플로우 부분 업데이트 (지정한 플래그만 변경)')
205
+ .option('--name <name>', '여정 이름')
206
+ .option('--file <path>', 'Mermaid 코드 파일 (.mmd, "-"이면 stdin) — 통째 교체')
207
+ .option('--description <text>', '한 줄 설명 ("" 이면 지움)')
208
+ .option('--order <n>', '목록 정렬 순서 (숫자)')
209
+ .addHelpText('after', FILE_HELP)
210
+ .action(async (flowId, options) => {
211
+ const globalOpts = program.opts();
212
+ try {
213
+ // 파일 읽기·입력 검증을 dry-run 판정보다 먼저 — create와 같은 이유.
214
+ let body;
215
+ try {
216
+ body = buildUserflowBody(options);
217
+ }
218
+ catch (e) {
219
+ (0, output_1.failInput)(e?.message ?? String(e));
220
+ return;
221
+ }
222
+ if (Object.keys(body).length === 0) {
223
+ (0, output_1.failInput)('수정할 필드를 지정하세요.');
224
+ return;
225
+ }
226
+ if (globalOpts.dryRun) {
227
+ (0, output_1.printInfo)(`[DRY-RUN] 유저플로우 "${flowId}" 수정 요청`);
228
+ return;
229
+ }
230
+ const client = (0, client_1.createClient)({ projectId: globalOpts.project });
231
+ const { data } = await client.patch(`/userflows/${flowId}`, body);
232
+ (0, output_1.formatOutput)(data, globalOpts);
233
+ (0, output_1.printSuccess)('유저플로우가 수정되었습니다.');
234
+ }
235
+ catch (error) {
236
+ // Error already handled
237
+ }
238
+ });
239
+ }
240
+ function registerUserflowsDelete(userflows, program) {
241
+ userflows
242
+ .command('delete <flowId>')
243
+ .description('유저플로우 삭제')
244
+ .action(async (flowId) => {
245
+ const globalOpts = program.opts();
246
+ try {
247
+ if (globalOpts.dryRun) {
248
+ (0, output_1.printInfo)(`[DRY-RUN] 유저플로우 "${flowId}" 삭제 요청`);
249
+ return;
250
+ }
251
+ const client = (0, client_1.createClient)({ projectId: globalOpts.project });
252
+ const { data } = await client.delete(`/userflows/${flowId}`);
253
+ // 기계 모드에서는 서버 응답을 stdout에 순수 JSON으로 남겨 JSON.parse가 되게 한다.
254
+ // 사람용(표) 모드에서는 성공 한 줄이면 충분하다.
255
+ if (isMachineOutput(globalOpts)) {
256
+ (0, output_1.formatOutput)(data, globalOpts);
257
+ }
258
+ (0, output_1.printSuccess)('유저플로우가 삭제되었습니다.');
259
+ }
260
+ catch (error) {
261
+ // Error already handled
262
+ }
263
+ });
264
+ }
265
+ function registerUserflowsCommand(program) {
266
+ const userflows = program
267
+ .command('userflows')
268
+ .description('유저플로우 관리 — 분기 있는 사용자 여정의 Mermaid 문서 (/userflows)');
269
+ registerUserflowsList(userflows, program);
270
+ registerUserflowsGet(userflows, program);
271
+ registerUserflowsCreate(userflows, program);
272
+ registerUserflowsUpdate(userflows, program);
273
+ registerUserflowsDelete(userflows, program);
274
+ }
275
+ //# sourceMappingURL=userflows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userflows.js","sourceRoot":"","sources":["../../src/commands/userflows.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -53,6 +53,8 @@ const prd_1 = require("./commands/prd");
53
53
  const db_schema_1 = require("./commands/db-schema");
54
54
  const db_tables_1 = require("./commands/db-tables");
55
55
  const screens_1 = require("./commands/screens");
56
+ const userflows_1 = require("./commands/userflows");
57
+ const policies_1 = require("./commands/policies");
56
58
  const backup_1 = require("./commands/backup");
57
59
  const handoff_1 = require("./commands/handoff");
58
60
  const notifications_1 = require("./commands/notifications");
@@ -112,6 +114,8 @@ program.hook('preAction', (thisCommand) => {
112
114
  (0, db_schema_1.registerDbSchemaCommand)(program);
113
115
  (0, db_tables_1.registerDbTablesCommand)(program);
114
116
  (0, screens_1.registerScreensCommand)(program);
117
+ (0, userflows_1.registerUserflowsCommand)(program);
118
+ (0, policies_1.registerPoliciesCommand)(program);
115
119
  (0, backup_1.registerBackupCommand)(program);
116
120
  (0, handoff_1.registerHandoffCommand)(program);
117
121
  (0, notifications_1.registerNotificationsCommand)(program);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decencia/ch-cli",
3
- "version": "1.30.0",
3
+ "version": "1.31.1",
4
4
  "description": "Decencia Communication Channel CLI",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-change-manager
3
3
  description: 기존 소통채널 프로젝트의 기능 추가/수정을 사용자와 대화로 명확화 → 전파 스킬로 연관 PRD/spec/DB/SQA 일괄 갱신 → 변경으로 생긴 새 할일을 GitHub 이슈로 발행하는 오케스트레이터 스킬. (1)대화로 변경 내용 확정 → (2)[게이트] 영향 범위 확인 후 전파 적용 → (3)[게이트] 할일 목록 확인 후 이슈 발행. "이 기능 바꿀래"·"기획 수정"·"이거 추가해줘(기존 프로젝트)" 류 요청 시.
4
4
  allowed-tools: Bash(ch:*) Bash(git:*) Bash(gh:*) Read Write
5
- version: 1.30.0
5
+ version: 1.31.1
6
6
  ---
7
7
 
8
8
  <!-- ch-version-gate -->
@@ -10,7 +10,7 @@ description: |
10
10
  (3) 명세·DB·SQA가 서로 어긋나 있는 의심이 들 때 (정합성 점검),
11
11
  (4) PRD 갱신 후 하위 spec/db/SQA로 변경분을 흘려보내야 할 때,
12
12
  (5) Sprint 진행 중 도메인 규칙·스키마가 흔들렸을 때 연쇄 갱신이 필요할 때.
13
- version: 1.30.0
13
+ version: 1.31.1
14
14
  ---
15
15
 
16
16
  <!-- ch-version-gate -->
@@ -134,14 +134,18 @@ ch check
134
134
  | D | **spec 의 비즈니스 규칙(logic)** 변경 | `spec.logic` | 의존 spec, SQA(정상/비정상 TC), db-tables(검증 규칙·trigger), PRD 도메인 규칙 절 |
135
135
  | E | **권한/역할 정책** 변경 | 영향 spec.logic, db-tables.securityRules | 모든 영향 spec의 SQA(접근권한 TC), db-schema 보안 일관성 절, PRD 권한 절 |
136
136
  | F | **Story Point(points) 변경** | `spec.points` | Sprint 용량 산정, workStatus |
137
- | G | **Epic 명/범위 변경** | `spec.epic`, PRD Epic 절 | 모든 같은 Epic 산하 spec 재태깅, Sprint 묶음 |
137
+ | G | **Epic 명/범위 변경** | `spec.epic`, PRD 기능 요구사항 카테고리 절 | 모든 같은 Epic 산하 spec 재태깅, Sprint 묶음 |
138
138
  | H | **PRD 본문 변경** | `prd` | 그 PRD에서 파생된 spec, db-schema, SQA 시트 — **전수 리뷰 트리거** |
139
139
 
140
+ > **스토리 명세 프로젝트**(`storySpecsEnabled=true` — [[2t-decencia-channel-spec-v2]] §0)에서는 이렇게 읽는다:
141
+ > C(UI 변경) = 화면 연결(`ui.screenRefs`)·화면(screens) 변경. interactionMap 등 UI 상세는 없다.
142
+ > D(logic 변경) = 스토리문장(`story`)·사전 조건(`preconditions`)·로직 플로우(`dataFlowScenarios`)·비즈니스 규칙 변경. stateTransitions는 없다.
143
+
140
144
  사용자 발화 → 진앙 매핑 예시:
141
145
  - "users 테이블에 last_login_at 추가" → **A**
142
146
  - "회원 등급에 VIP 추가, 권한도 더 줘야 함" → **E** (+ D)
143
147
  - "로그인 화면에 SNS 로그인 버튼 추가" → **C** (+ E if 권한)
144
- - "이 spec의 규모(Story Point)를 다시 매김" → **F** (규모가 너무 크면 spec 자체를 여러 Story로 분리 — [[2t-decencia-channel-spec-v2]] §9)
148
+ - "이 spec의 규모(Story Point)를 다시 매김" → **F** (규모가 너무 크면 spec 자체를 여러 Story로 분리 — [[2t-decencia-channel-spec-v2]] §2·§14)
145
149
 
146
150
  ---
147
151
 
@@ -153,7 +157,7 @@ ch check
153
157
 
154
158
  ```bash
155
159
  # 모든 spec과 dbTableRefs/relatedSpecIds
156
- ch specs list --json --per-page 200 > /tmp/specs.json
160
+ ch specs list --json --per-page 100 > /tmp/specs.json
157
161
 
158
162
  # 모든 db-table
159
163
  ch db-tables list --json > /tmp/tables.json
@@ -313,7 +317,7 @@ ch prd get --json | jq -r '.content' | grep -niE "데이터 모델|컬럼|nullab
313
317
  - **B (새 테이블)**: 1 → 2(인벤토리/ERD, 테이블 단위) → 3(dbTableRefs) → 4 → 6. **5(PRD) 스킵** (새 *기능*이면 그건 C/H로 별도)
314
318
  - **C (UI만 변경)**: 1·2 스킵하고 3 → 4 → 5 → 6
315
319
  - **E (권한)**: 1(securityRules) + 3(logic) 거의 동시 → 2 → 4 → 5(권한 *정책* 절 — 기능이므로 PRD 가능) → 6
316
- - **G (Epic 변경)**: 3(spec.epic 재태깅) → 5(PRD Epic ) → 6
320
+ - **G (Epic 변경)**: 3(spec.epic 재태깅) → 5(PRD 기능 요구사항 카테고리) → 6
317
321
  - **H (PRD 변경)**: 5(PRD) → 영향 재조사 → 1~4 순차 → 6
318
322
 
319
323
  ---
@@ -378,7 +382,7 @@ ch specs update <specId> --work-status /tmp/ws.md --no-version
378
382
  ### 6.1 spec ↔ db-table 양방향 일치
379
383
 
380
384
  ```bash
381
- ch specs list --json --per-page 200 | jq -r '.data[] | "spec\t" + .id + "\t" + ((.dbTableRefs // []) | join(","))' > /tmp/spec_refs.tsv
385
+ ch specs list --json --per-page 100 | jq -r '.data[] | "spec\t" + .id + "\t" + ((.dbTableRefs // []) | join(","))' > /tmp/spec_refs.tsv
382
386
  ch db-tables list --json | jq -r '.data[] | "table\t" + .id + "\t" + ((.relatedSpecIds // []) | join(","))' > /tmp/table_refs.tsv
383
387
 
384
388
  # spec.dbTableRefs에는 있는데 table.relatedSpecIds에 누락된 경우 → 불일치
@@ -489,7 +493,7 @@ jq -r '.data[] | select((.logic // "" | tostring) | test("nullable|timestamp\\b|
489
493
  3) ch specs update — 영향 spec.epic 일괄 재태깅
490
494
  (스크립트: for s in $(jq -r ... ); do ch specs update $s --epic <new>; done)
491
495
  4) (SQA는 대개 무영향. Epic 단위 필터링하는 사용처가 있다면 시트 분리 검토)
492
- 5) PRD Epic
496
+ 5) PRD 기능 요구사항 카테고리
493
497
  6) Sprint — Epic 단위 묶음 사용 중이라면 sprint 재구성 검토
494
498
  7) workStatus
495
499
  ```
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-cli-v2
3
3
  description: |
4
4
  [2t][v2] 소통채널 CLI(`ch`, npm @decencia/ch-cli) 가이드.
5
- Epic-Story 체계(규모=Story Point)와 db-tables·screens 리소스, --work-status, --id, --points 플래그를 망라한다.
5
+ Epic-Story 체계(규모=Story Point)와 db-tables·screens 리소스, 스토리 명세 플래그(--story·--preconditions), --work-status, --id, --points 등을 망라한다.
6
6
  Use when:
7
7
  (1) spec/db-table/화면(screen)을 CLI로 다룰 때,
8
8
  (2) spec 규모를 Story Point(`--points`)로 매길 때,
@@ -10,7 +10,7 @@ description: |
10
10
  (4) ch screens 명령(list/get/create/update/delete/migrate)으로 화면을 다루거나 레거시 프로젝트를 화면 모드로 이관할 때,
11
11
  (5) spec의 화면 연결을 CLI로 걸거나 풀 때 (`ch specs screen-refs`),
12
12
  (6) Spec ID를 JIRA 스타일(`LOGIN-001`)로 직접 지정할 때 (`ch specs create --id`).
13
- version: 1.30.0
13
+ version: 1.31.1
14
14
  ---
15
15
 
16
16
  <!-- ch-version-gate -->
@@ -42,32 +42,52 @@ ch specs update <specId> --logic /tmp/logic.json # 3) 수정 적용
42
42
 
43
43
  ## 1. spec 명령
44
44
 
45
+ 프로젝트 모드에 따라 쓰는 플래그가 다르다 ([[2t-decencia-channel-spec-v2]] §0).
46
+
47
+ **스토리 명세 모드** (`storySpecsEnabled=true` — 신규 프로젝트 기본):
48
+
49
+ ```bash
50
+ # 생성 (사용자 지정 Spec ID = Epic 도메인 코드 prefix 권장)
51
+ # ID 패턴: ^[A-Za-z][A-Za-z0-9_]*-[A-Za-z0-9]+$ (MaxLength 60), 충돌 시 409
52
+ ch specs create --id AUTH-001 \
53
+ --name "로그인" \
54
+ --device web,app --domain 회원 --permission 비회원 \
55
+ --epic AUTH \
56
+ --points 5 \
57
+ --story "회원은 이메일과 비밀번호로 로그인해서, 재인증 없이 자신의 프로젝트에 바로 접근하고 싶다." \
58
+ --preconditions ./preconditions.md \
59
+ --logic ./logic.json \
60
+ --db-tables tbl_users,tbl_sessions
61
+
62
+ # 수정: 지정한 플래그만 PATCH. --no-version 시 버전 기록 생략.
63
+ ch specs update <specId> --story "..." --no-version
64
+ ch specs update <specId> --preconditions ./preconditions.md --no-version
65
+ ch specs update <specId> --points 8 --no-version
66
+ ```
67
+
68
+ - `--story "<줄글>"` — 스토리문장(As a/I want/So that). 스칼라라 그 값만 바뀐다.
69
+ - `--preconditions <텍스트|파일경로>` — 사전 조건 마크다운.
70
+ - `--domain`은 쉼표로 **복수** 지정 (`--domain 회원,관리자`).
71
+ - `--type`(기능유형)·`--content`는 스토리 명세 모드에서 쓰지 않는다 (레거시 전용).
72
+ - `--ui`는 생성 시 보통 생략한다 — 화면설계서는 spec보다 나중(작성 순서 ④)이라, 화면을 만든 뒤 `ch specs screen-refs`로 연결한다(§1 화면 연결).
73
+
74
+ **레거시 모드** (`storySpecsEnabled` 미설정·false — 기존 프로젝트):
75
+
45
76
  ```bash
46
- # 생성 (자동 ID)
47
77
  ch specs create \
48
78
  --name "로그인" \
49
79
  --device web,app --domain user --type 인증 --permission 비회원 \
50
80
  --content "이메일/비밀번호 로그인" \
51
- --epic 인증 \
52
- --points 5 \
53
- --ui ./ui.json \
54
- --logic ./logic.json \
81
+ --epic 인증 --points 5 \
82
+ --ui ./ui.json --logic ./logic.json \
55
83
  --db-tables tbl_users,tbl_sessions \
56
84
  --work-status ./work-status.md
57
85
 
58
- # 생성 (사용자 지정 Spec ID, JIRA 스타일 — ch-cli 1.3.5+ / ch-api b029f88+)
59
- # 패턴: ^[A-Za-z][A-Za-z0-9_]*-[A-Za-z0-9]+$ (MaxLength 60)
60
- # 충돌 시 409, 패턴 위반 시 400
61
- ch specs create --id LOGIN-001 \
62
- --name "로그인" --device web --domain user --type 인증 --epic 인증
63
-
64
- # 수정: 지정한 플래그만 PATCH. --no-version 시 버전 기록 생략.
65
86
  ch specs update <specId> --epic 인증 --no-version
66
- ch specs update <specId> --points 8 --no-version
67
87
  ch specs update <specId> --work-status ./status.md
68
88
  ```
69
89
 
70
- > `--id`의 자세한 네이밍 규칙·예외·자동 다음 번호 산정 스크립트는 [[2t-decencia-channel-spec-v2]] §1.5 참조.
90
+ > `--id`의 자세한 네이밍 규칙·예외·자동 다음 번호 산정 스크립트는 [[2t-decencia-channel-spec-v2]] §4 참조.
71
91
 
72
92
  ### Story Point (`--points`)
73
93
 
@@ -79,7 +99,7 @@ ch specs update <specId> --points 8 --no-version
79
99
  ```
80
100
 
81
101
  - `--points <n>` — 0 이상의 숫자(보통 피보나치 1/2/3/5/8/13). 진행률(%)·완료율은 없다 — 완료 여부는 `status`로.
82
- - Sprint 용량 = Σ spec.points ([[2t-decencia-channel-sprint-builder-v2]]). 규모 산정 가이드는 [[2t-decencia-channel-spec-v2]] §3.
102
+ - Sprint 용량 = Σ spec.points ([[2t-decencia-channel-sprint-builder-v2]]). 규모 산정 가이드는 [[2t-decencia-channel-spec-v2]] §11.
83
103
 
84
104
  ### Task JSON (`--tasks`) — [deprecated]
85
105
 
@@ -107,7 +127,13 @@ ch specs update <specId> --points 8 --no-version
107
127
 
108
128
  ### UI JSON (`--ui`)
109
129
 
110
- **화면 모드** (`screensEnabled=true`) — spec.ui 소유 4필드만 쓴다.
130
+ **스토리 명세 모드** (`storySpecsEnabled=true`) — `screenRefs`만 쓴다. interactionMap·primaryActions·keyInformation은 스토리 명세에 없다.
131
+
132
+ ```json
133
+ { "screenRefs": ["SCR-LOGIN"] }
134
+ ```
135
+
136
+ **레거시 + 화면 모드** (`screensEnabled=true`) — spec.ui 소유 4필드만 쓴다.
111
137
 
112
138
  ```json
113
139
  {
@@ -161,7 +187,8 @@ ch specs update <specId> --points 8 --no-version
161
187
  ```
162
188
 
163
189
  - `dataFlowScenarios[]`=시나리오, 각 시나리오의 `steps[]`=순서 있는 단계, 각 단계의 `refs[]`=**db-tables의 tableId(+선택 field)를 가리키는 구조적 참조**(SSOT — 스키마 정의는 db-tables에만). 서버가 실존 검증: 없는 tableId/컬럼이면 400. `direction`은 `READ|WRITE|READWRITE`.
164
- - 단계 `description`은 필드명 나열이 아니라 **완결 문장**으로 — [[2t-decencia-channel-spec-v2]] §5.
190
+ - `stateTransitions`(화면 상태 전이)는 **레거시 전용**이다. 스토리 명세 모드에서는 쓰지 않는다. 스토리 명세의 흐름은 로직 플로우 하나다(정상/예외 구분 없음 실패 경로는 분기로) — [[2t-decencia-channel-spec-v2]] §7.
191
+ - 단계 `description`은 필드명 나열이 아니라 **완결 문장**으로 — [[2t-decencia-channel-spec-v2]] §7.
165
192
  - 하위호환: 레거시 `dataFlow`(문자열)/`dataFlowRefs[]`/`businessRuleRefs[]`도 그대로 수용된다(점진 마이그레이션). SQA 항목도 동일 취지로 `--db-tables`(쉼표 구분)를 가진다 — [[2t-decencia-channel-sqa-v2]].
166
193
 
167
194
  ### dbTableRefs (`--db-tables`)
@@ -248,6 +275,7 @@ ch db-tables delete <tableId> # 참조 spec의 dbTableRefs도
248
275
  ## 3. screens 명령 (화면)
249
276
 
250
277
  화면(Screen)은 화면 정의의 SSOT다. `ch_projects.screensEnabled=true`인 프로젝트에서 쓴다.
278
+ **무엇을 적어야 하는지**(필수 기재항목 6종·디스크립션 작성규칙·예외상태 4종)는 [[2t-decencia-channel-screen-v2]]가 정본이다.
251
279
 
252
280
  ```bash
253
281
  ch screens list # 표 출력: order | id | name | route | epic | states | specs
@@ -281,7 +309,7 @@ ch screens migrate --rollback # 화면 모드만 끄기 (화
281
309
  ch screens migrate --rollback --force # 되돌아갈 route가 없어도 강행 (기본은 서버가 409로 거절)
282
310
  ```
283
311
 
284
- - `--id`는 JIRA 스타일(`SCR-001`). 패턴 `^[A-Za-z][A-Za-z0-9_]*-[A-Za-z0-9]+$`, 중복 시 409.
312
+ - `--id`는 슬러그 스타일(`SCR-001`, `STORE-ORDER-DETAIL` 같은 다중 세그먼트 허용). 패턴 `^[A-Za-z][A-Za-z0-9_]*(-[A-Za-z0-9_]+)+$`, 중복 시 409. (spec ID 패턴과 다르다 — 화면만 완화됐다.)
285
313
  - 화면 소유 필드다. spec.ui가 아니라 여기에 적는다.
286
314
  - `--figma-node-id <id>` — 이 화면의 Figma 노드 ID(`123:456`). Figma URL의 `?node-id=` 값에서 `-`를 `:`로 바꾼 값이다.
287
315
  - `--page-file <path>` — 이 화면의 **페이지 진입 파일** 경로 하나(예: `src/app/store/[code]/page.tsx`). 하위 컴포넌트는 적지 않는다.
@@ -8,7 +8,7 @@ description: |
8
8
  (2) DB 테이블 단위로 컬럼·인덱스·보안규칙을 등록·수정할 때,
9
9
  (3) 새 테이블을 추가하면서 전체 인벤토리도 함께 업데이트할 때,
10
10
  (4) spec.dbTableRefs와 양방향 동기화가 필요한 작업 시.
11
- version: 1.30.0
11
+ version: 1.31.1
12
12
  ---
13
13
 
14
14
  <!-- ch-version-gate -->
@@ -277,7 +277,7 @@ description 활용 권장:
277
277
 
278
278
  ### 5-4. state-machines.json — 엔티티 상태머신
279
279
 
280
- 엔티티가 **저장되는 상태 컬럼**을 가지면(주문 `status`, 배포 `phase` 등) 그 생애주기를 여기에 정의한다. 화면의 휘발성 UI 전이(idle/loading 등)는 여기 말고 spec.logic.stateTransitions에 적는다[[2t-decencia-channel-spec-v2]] §5-3.
280
+ 엔티티가 **저장되는 상태 컬럼**을 가지면(주문 `status`, 배포 `phase` 등) 그 생애주기를 여기에 정의한다. 화면의 휘발성 UI 전이(idle/loading 등)는 여기 적지 않는다 — 화면(screens)의 `states`에, 레거시 프로젝트는 spec.logic.stateTransitions에 적는다([[2t-decencia-channel-spec-v2]] §L-3).
281
281
 
282
282
  `StateMachine[]` — 한 테이블에 상태머신 여러 개 가능(컬럼별).
283
283
 
@@ -327,7 +327,7 @@ description 활용 권장:
327
327
 
328
328
  #### spec dataFlow와의 상호참조 (`columnRef` ↔ `toState`)
329
329
 
330
- spec은 이 상태머신을 **`columnRef`로 잇는다**. spec의 dataFlow ref에서 `field`가 이 머신의 `columnRef`와 같으면, 그 ref는 이 엔티티의 상태 접근이다. 그 ref가 WRITE면 `toState`에 목표 상태(이 머신 `states[].value` 중 하나)를 적는다 — [[2t-decencia-channel-spec-v2]] §6-2-1.
330
+ spec은 이 상태머신을 **`columnRef`로 잇는다**. spec의 dataFlow ref에서 `field`가 이 머신의 `columnRef`와 같으면, 그 ref는 이 엔티티의 상태 접근이다. 그 ref가 WRITE면 `toState`에 목표 상태(이 머신 `states[].value` 중 하나)를 적는다 — [[2t-decencia-channel-spec-v2]] §10-2.
331
331
 
332
332
  - **링크 방향**: db-tables가 상태를 **정의**(states·transitions)하고, spec은 `tableId` + `field`(=columnRef) + `toState`로 **참조**만 한다.
333
333
  - `ch specs get`은 이 머신 요약(states·transitions)을 spec ref 옆에 **읽기 시점에 인라인**해 준다. 그래서 상태 목록을 spec에 베낄 필요가 없다.
@@ -372,7 +372,7 @@ spec은 이 상태머신을 **`columnRef`로 잇는다**. spec의 dataFlow ref
372
372
  ## 8. 흔한 함정
373
373
 
374
374
  - columns/indexes/securityRules/stateMachines JSON은 **전체 교체**. 일부 수정 시 반드시 `get` 후 편집.
375
- - 상태 컬럼의 생애주기(주문 status 등)를 spec.logic.stateTransitions에 적으면 SSOT 위반 — 저장되는 엔티티 상태는 db-tables.stateMachines가 SSOT. spec의 stateTransitions는 화면 휘발성 전이만.
375
+ - 상태 컬럼의 생애주기(주문 status 등)를 spec 쪽(흐름·레거시 stateTransitions)정의하면 SSOT 위반 — 저장되는 엔티티 상태는 db-tables.stateMachines가 SSOT. spec의 흐름은 `toState` 링크로 참조만 한다.
376
376
  - 전체 스펙 문서의 `--content`도 통째 교체. 작은 수정도 `get` 후 부분 편집해 통째 전송.
377
377
  - `relatedSpecIds`를 JSON에 명시해도 서버가 무시 (자동 관리 영역).
378
378
  - 새 테이블을 만들고 전체 스펙 인벤토리 갱신을 잊으면, 문서 읽는 사람이 그 테이블의 존재를 모른다.
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-github-issue
3
3
  description: gh CLI로 현재 repo에 GitHub 이슈를 작성한다. 이슈 1개=유형 1개(feat/fix/bug), 표준 본문 양식(작업내용·관련 명세 백링크·완료조건)으로 발행. "이슈 만들어줘"/"깃헙 이슈로 등록해줘" 요청 시, 또는 소통채널 기획·명세 작업 후 처리할 일들을 GitHub 이슈로 옮길 때 사용. 멱등성/중복방지·확인단계는 다루지 않음(요청대로 바로 생성).
4
4
  allowed-tools: Bash(gh:*) Bash(git:*) Read Write
5
- version: 1.30.0
5
+ version: 1.31.1
6
6
  ---
7
7
 
8
8
  <!-- ch-version-gate -->
@@ -2,7 +2,7 @@
2
2
  name: 2t-decencia-channel-orchestrator
3
3
  description: 소통채널 작업의 단일 진입점(디스패처). 사용자 요청을 듣고 7종(bootstrap·terraformer·change-manager·github-issue·issue-coder·pr-merger·sprint-runner) 중 적절한 곳으로 라우팅하고, 필요하면 여러 단계를 순차 오케스트레이션한다. 대화형 스킬은 메인 세션에서 Skill로, 자율 에이전트는 Agent로 위임. "소통채널 작업 해줘"·"이거 어떻게 처리하지?"처럼 무엇부터 할지 모를 때, 또는 신규기획/코드편입/기획변경/이슈/구현/머지/스프린트실행 어디로든 시작할 때.
4
4
  allowed-tools: Skill Agent Read Bash(ch:*) Bash(gh:*) Bash(git:*)
5
- version: 1.30.0
5
+ version: 1.31.1
6
6
  ---
7
7
 
8
8
  <!-- ch-version-gate -->