@simplysm/sd-claude 14.0.62 → 14.0.63
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/claude/rules/sd-clarify.md +36 -23
- package/claude/rules/sd-claude-rules.md +1 -3
- package/claude/skills/sd-plan/SKILL.md +22 -0
- package/claude/skills/sd-plan/references/api-spec.md +64 -0
- package/claude/skills/sd-plan/references/db-model-change.md +45 -0
- package/claude/skills/sd-plan/references/sequence-diagram.md +66 -0
- package/claude/skills/sd-plan/references/state-machine.md +83 -0
- package/package.json +1 -1
|
@@ -48,31 +48,38 @@ UI 구조·메뉴/네비게이션·라우팅·도메인 엔터티·네이밍·
|
|
|
48
48
|
근거 추측 금지:
|
|
49
49
|
|
|
50
50
|
- 출처 인용은 실제 읽은 좌표만 허용한다.
|
|
51
|
-
- 미확인 출처(예: "~~ 문서에 있을 것", "보통 ~~ 패턴이니")로
|
|
51
|
+
- 미확인 출처(예: "~~ 문서에 있을 것", "보통 ~~ 패턴이니")로 확정 또는 추론 90% 이상으로 분류 금지.
|
|
52
52
|
- "어차피 모를 것"이라는 판단으로 근거 확인을 건너뛰는 것 금지.
|
|
53
53
|
|
|
54
54
|
### 2-2. 명확성 분류
|
|
55
55
|
|
|
56
56
|
결정 사안을 다음 기준으로 분류한다.
|
|
57
57
|
|
|
58
|
-
-
|
|
58
|
+
- 확정 (100%): 다음 중 하나에 명시된 항목
|
|
59
59
|
- 사용자 직접 발언(현재/이전 턴), 사용자 제공 외부 자료(첨부 문서·회의록·메일 등)
|
|
60
60
|
- 프로젝트 룰·참조 문서(`.claude/rules/`, `CLAUDE.md`, `.claude/references/`)
|
|
61
61
|
- 세션 내 이미 확정된 결정(이전 단계 산출물 spec/plan/wbs, 이전 sd-clarify 답변)
|
|
62
62
|
- 타겟 코드베이스의 코드·타입 정의
|
|
63
|
-
-
|
|
64
|
-
-
|
|
63
|
+
- 추론 (0~100%): 근거 강도에 따라 % 부여
|
|
64
|
+
- 근거가 될 수 있는 출처:
|
|
65
65
|
- 타겟 코드베이스(모노레포 동일 워크스페이스 포함)의 동일/유사 패턴
|
|
66
66
|
- 공식 문서·업계 표준·규격(RFC/ISO/W3C/KS)·법률·규제
|
|
67
67
|
- 일반적 도메인 관행, 유사 사례, 외부 프로젝트의 패턴
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
- 마이그레이션 원본·이전 버전 등 같은 프로젝트의 과거 상태
|
|
69
|
+
- 그 외 약한 유추나 제한적 근거
|
|
70
|
+
- 추측 (0%): 근거 없는 가정
|
|
71
|
+
|
|
72
|
+
추론 % 사용 규칙:
|
|
73
|
+
|
|
74
|
+
- 미세 차등(±10% 내)으로 의사결정을 분기하지 않는다.
|
|
75
|
+
- 임계값 1개로만 이진 판단을 한다.
|
|
76
|
+
- 추론 90% 이상 → 진행
|
|
77
|
+
- 추론 90% 미만 → 질문 대기열 등록
|
|
78
|
+
- 임계값을 미세 조정해 질문을 회피하지 않는다.
|
|
72
79
|
|
|
73
80
|
### 2-3. 근거 재분석
|
|
74
81
|
|
|
75
|
-
|
|
82
|
+
추론 90% 미만 또는 추측으로 분류된 항목 전부를 재분석한다 (일부만 적용 금지).
|
|
76
83
|
항목별 1건씩 처리한다 (그룹·묶음 일괄 처리 금지).
|
|
77
84
|
|
|
78
85
|
목적: 초기 분류가 부실한 분석에 기반했을 수 있다. 누적 맥락에서 이미 아는 것 이상으로, 해당 건의 근거가 될 수 있는 원본을 완독하여 실제 상황을 파악한 뒤 재분류한다.
|
|
@@ -83,13 +90,13 @@ INFERRED-Medium, INFERRED-Low, ASSUMED로 분류된 항목 전부를 재분석
|
|
|
83
90
|
- 이미 아는 것만으로 확정할 수 없는 부분을 식별한다.
|
|
84
91
|
- 그 부분의 근거가 될 수 있는 원본을 tool로 완독한다. 발췌·부분 읽기가 아니라 해당 원본 전체를 읽는다.
|
|
85
92
|
- 완독한 실제 상황을 기반으로 2-2 기준에 따라 재분류한다.
|
|
86
|
-
- 근거 발견 시
|
|
87
|
-
-
|
|
93
|
+
- 근거 발견 시 분류를 갱신한다 (확정 또는 추론 % 로 갱신).
|
|
94
|
+
- 근거 미발견 시 기존 분류를 유지하되, 완독 과정에서 파악한 실제 상황을 기반으로 선택지를 구성한다.
|
|
88
95
|
|
|
89
96
|
금지:
|
|
90
97
|
|
|
91
98
|
- "어차피 모를 것"이라는 판단으로 재분석을 건너뛰는 것.
|
|
92
|
-
- 확인하면 바로 알 수 있는 내용을 확인 없이
|
|
99
|
+
- 확인하면 바로 알 수 있는 내용을 확인 없이 추측으로 분류해 사용자에게 묻는 것.
|
|
93
100
|
- 사용자 발언의 가능성 시사("이미 ~~ 있을 것")를 완독 없이 신규 구조 도입의 근거로 삼는 것.
|
|
94
101
|
|
|
95
102
|
### 2-4. 분류 보고
|
|
@@ -98,20 +105,20 @@ INFERRED-Medium, INFERRED-Low, ASSUMED로 분류된 항목 전부를 재분석
|
|
|
98
105
|
|
|
99
106
|
| 대상 | 원분류 | 재분석분류 | 인용 |
|
|
100
107
|
|---|---|---|---|
|
|
101
|
-
| {식별자/경로:라인} |
|
|
102
|
-
| {식별자2} |
|
|
108
|
+
| {식별자/경로:라인} | 추론 60% | 확정 | path/file.ts:42 — "..." |
|
|
109
|
+
| {식별자2} | 추측 | 추측 | (없음 — 질문 대기열 등록) |
|
|
103
110
|
|
|
104
111
|
- 원분류: 근거 확인 직후 분류 결과.
|
|
105
|
-
- 재분석분류: 근거 재분석 후 분류 결과 (
|
|
106
|
-
- 인용:
|
|
107
|
-
-
|
|
112
|
+
- 재분석분류: 근거 재분석 후 분류 결과 (갱신 또는 유지).
|
|
113
|
+
- 인용: 확정 / 추론 90% 이상만 출처 인용 작성.
|
|
114
|
+
- 추측은 "(없음 — 질문 대기열 등록)" 표기.
|
|
108
115
|
|
|
109
116
|
결정 사안이 다건이면 항목별로 각각 분류하고, 명확/불명확을 한 번에 일괄 보고한다.
|
|
110
117
|
|
|
111
118
|
분기:
|
|
112
119
|
|
|
113
|
-
- 근거 명확(
|
|
114
|
-
- 근거 불명확(
|
|
120
|
+
- 근거 명확(확정 / 추론 90% 이상)만 있음: 출처 인용을 호출자에게 보고하고 종료.
|
|
121
|
+
- 근거 불명확(추론 90% 미만 / 추측) 항목 있음: 질문 대기열에 등록하고 Step 3으로 진행한다.
|
|
115
122
|
|
|
116
123
|
## Step 3: 질문 진행
|
|
117
124
|
|
|
@@ -137,10 +144,16 @@ INFERRED-Medium, INFERRED-Low, ASSUMED로 분류된 항목 전부를 재분석
|
|
|
137
144
|
- 누락 답변 처리: 사용자가 현재 질문에 답하지 않으면 같은 질문을 다시 묻는다.
|
|
138
145
|
- 누락 항목을 임의 추천안으로 처리하지 않는다.
|
|
139
146
|
- 추가 질문 처리: 답변 수집 중 또는 작업 중 새로 물어봐야 할 항목이 발견되면 질문 대기열에 추가하고, 다시 한 번에 하나씩 질문한다.
|
|
140
|
-
- 질문 정렬:
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
- 질문 정렬: 의존성 → 정보이득 → 발견 출처 순으로 정렬한다.
|
|
148
|
+
1. 의존성 우선: 상위 결정이 하위에 영향을 미치면 상위 먼저.
|
|
149
|
+
2. 동일 의존성 내에서 정보이득 상/중/하 내림차순.
|
|
150
|
+
- 정보이득 = 응답이 후속 작업의 분기·영향 범위를 가르는 정도.
|
|
151
|
+
- 상: 라우터·스키마·아키텍처 등 광범위 영향
|
|
152
|
+
- 중: 모듈/컴포넌트 내 영향
|
|
153
|
+
- 하: 단일 위치 영향
|
|
154
|
+
3. 동일 정보이득 내에서 발견 출처(Step/Feature 번호/대상 식별자) 단위로 묶음 분류.
|
|
155
|
+
- 한 묶음을 모두 소진한 뒤 다음 묶음으로 넘어간다.
|
|
156
|
+
- 진행 중 묶음 내에서 발견된 새 질문은 해당 묶음 끝에 추가한다.
|
|
144
157
|
|
|
145
158
|
도구 호출:
|
|
146
159
|
|
|
@@ -18,9 +18,7 @@
|
|
|
18
18
|
- 시스템 내부 용어(행·컬럼·필드·메타 분류·코드 식별자 등) 노출 금지.
|
|
19
19
|
- 사용자가 일상 업무에서 부르는 이름·동사로 바꾼다.
|
|
20
20
|
- 정독·검색 없이 1회독으로 이해되는지로 점검한다.
|
|
21
|
-
- **CRITICAL**:
|
|
22
|
-
- 명시적 요청없이 다음 단계를 추측하여 바로 작업 하지 말것
|
|
23
|
-
- 명시적 요청없이 코드/문서등을 바로 수정하지 말것
|
|
21
|
+
- **CRITICAL**: 명시적 요청없이 코드/문서등을 바로 수정하지 말것
|
|
24
22
|
|
|
25
23
|
# 질문 vs 수정 분리
|
|
26
24
|
|
|
@@ -121,6 +121,20 @@ Feature: Story {번호} {이름}
|
|
|
121
121
|
|
|
122
122
|
모든 사용자 결정사항은 `### 설계 결정` 표에 기록한다 (D1, D2, ... 순번 부여).
|
|
123
123
|
|
|
124
|
+
### 선택적 자료
|
|
125
|
+
|
|
126
|
+
구현 설계와 함께 개발자 시점 자료를 Task 성격에 따라 선택적으로 포함한다.
|
|
127
|
+
작성 시 해당 references 파일을 읽고 가이드에 따른다.
|
|
128
|
+
|
|
129
|
+
| 자료 | 작성 위치 | 가이드 | 적용 기준 |
|
|
130
|
+
|---|---|---|---|
|
|
131
|
+
| 시퀀스 다이어그램 | 구현 설계 시작 (영향 범위 다음) | `references/sequence-diagram.md` | client·server·db 등 다중 모듈이 협력하는 Task |
|
|
132
|
+
| DB 모델 변경 표 | 엔티티 섹션 안 | `references/db-model-change.md` | 신규/수정 모델·컬럼·관계가 있는 Task |
|
|
133
|
+
| API/서비스 메서드 명세 | 서비스 / API 섹션 안 | `references/api-spec.md` | 서버 메서드·엔드포인트 신규/변경이 있는 Task |
|
|
134
|
+
| 상태 전이도 (FSM) | 엔티티 섹션 인접 | `references/state-machine.md` | 도메인 객체에 status 컬럼 + 전이 3개 이상인 경우 |
|
|
135
|
+
|
|
136
|
+
자료가 불필요한 Task면 해당 항목을 생략한다.
|
|
137
|
+
|
|
124
138
|
```markdown
|
|
125
139
|
## 구현 설계
|
|
126
140
|
|
|
@@ -129,14 +143,22 @@ Feature: Story {번호} {이름}
|
|
|
129
143
|
- 신규: {파일 목록}
|
|
130
144
|
- 수정: {파일 목록}
|
|
131
145
|
|
|
146
|
+
### 시퀀스 다이어그램 (선택, references/sequence-diagram.md 참조)
|
|
147
|
+
|
|
132
148
|
### 엔티티 [근거: ...]
|
|
133
149
|
|
|
134
150
|
{시그니처 또는 코드}
|
|
135
151
|
|
|
152
|
+
#### DB 모델 변경 표 (선택, references/db-model-change.md 참조)
|
|
153
|
+
|
|
154
|
+
#### 상태 전이도 (선택, references/state-machine.md 참조)
|
|
155
|
+
|
|
136
156
|
### 서비스 / API [근거: ...]
|
|
137
157
|
|
|
138
158
|
{시그니처}
|
|
139
159
|
|
|
160
|
+
#### API/서비스 메서드 명세 (선택, references/api-spec.md 참조)
|
|
161
|
+
|
|
140
162
|
### UI [근거: ...]
|
|
141
163
|
|
|
142
164
|
{구조}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# API/서비스 메서드 명세 작성 가이드
|
|
2
|
+
|
|
3
|
+
서비스 / API 섹션 안에 작성. 메서드별 요청·응답·에러·권한을 상세히 정리한다.
|
|
4
|
+
|
|
5
|
+
## 표현 형식
|
|
6
|
+
|
|
7
|
+
메서드별로 표 또는 정의 블록으로 작성한다.
|
|
8
|
+
|
|
9
|
+
| 항목 | 내용 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| 메서드 | `WorkService.createWork(dto): Promise<Work>` |
|
|
12
|
+
| 요청 (CreateWorkDto) | 필드별 타입·필수·검증 규칙 |
|
|
13
|
+
| 응답 (성공) | 응답 타입의 모든 필드 |
|
|
14
|
+
| 에러 케이스 | 에러 타입 + 발생 조건 |
|
|
15
|
+
| 권한 | 호출 가능한 권한 |
|
|
16
|
+
|
|
17
|
+
## 작성 원칙
|
|
18
|
+
|
|
19
|
+
- 요청 스키마: 필드명·타입·필수/선택·검증 규칙(길이/범위/형식) 모두 명시.
|
|
20
|
+
- 응답 스키마: 모든 반환 필드. nullable 필드 표시.
|
|
21
|
+
- 에러 케이스: 발생 조건과 에러 타입을 짝으로. 사용자 메시지 또는 에러 코드 포함.
|
|
22
|
+
- 권한: Role 명시 + 조건부 권한(예: "본인 데이터만")이면 조건도 명시.
|
|
23
|
+
- 페이지네이션·정렬·필터가 있는 조회 메서드는 그 옵션도 명시.
|
|
24
|
+
|
|
25
|
+
## 좋은 예 (작업 등록)
|
|
26
|
+
|
|
27
|
+
| 항목 | 내용 |
|
|
28
|
+
|---|---|
|
|
29
|
+
| 메서드 | `WorkService.createWork(dto: CreateWorkDto): Promise<Work>` |
|
|
30
|
+
| 요청 | `title (string, 필수, 1~200자, trim)`, `dueDate (Date, 선택, 오늘 이후)`, `assigneeId (uuid, 필수)`, `description (string, 선택, 0~1000자)` |
|
|
31
|
+
| 응답 | `Work { id, title, dueDate (nullable), assigneeId, status: 'pending', createdAt }` |
|
|
32
|
+
| 에러 | `ValidationError` (title 빈/초과, dueDate 과거, description 초과), `NotFoundError` (assigneeId에 해당 User 없음), `PermissionError` (호출자가 ADMIN 아님) |
|
|
33
|
+
| 권한 | `ROLE.ADMIN` |
|
|
34
|
+
|
|
35
|
+
## 좋은 예 (조회 메서드 — 페이지네이션 포함)
|
|
36
|
+
|
|
37
|
+
| 항목 | 내용 |
|
|
38
|
+
|---|---|
|
|
39
|
+
| 메서드 | `WorkService.listWorks(query: ListWorksQuery): Promise<{ items: Work[], total: number }>` |
|
|
40
|
+
| 요청 | `status (Work.status, 선택, 다중 선택 가능)`, `assigneeId (uuid, 선택)`, `keyword (string, 선택, title 부분 일치)`, `page (number, 기본 1)`, `pageSize (number, 기본 20, 최대 100)`, `sort (Enum, 기본 'createdAt:desc')` |
|
|
41
|
+
| 응답 | `{ items: Work[], total: number }` |
|
|
42
|
+
| 에러 | `ValidationError` (pageSize 범위 초과) |
|
|
43
|
+
| 권한 | `ROLE.ADMIN` (전체 조회) / `ROLE.STAFF` (`assigneeId = self` 자동 적용) |
|
|
44
|
+
|
|
45
|
+
## 무엇을 잡아주나
|
|
46
|
+
|
|
47
|
+
- 검증 규칙 (길이·형식·범위) 명시 — Gherkin Scenario 작성의 기반
|
|
48
|
+
- 에러 케이스 누락 — 어떤 입력에 어떤 에러를 내는지
|
|
49
|
+
- 권한 요구사항 — 누가 호출할 수 있는지, 조건부 권한은 어떤 조건인지
|
|
50
|
+
- 응답 필드 누락 — 클라이언트가 어떤 필드를 받는지
|
|
51
|
+
- nullable·선택 필드 — 클라이언트의 처리 분기
|
|
52
|
+
|
|
53
|
+
## 나쁜 예
|
|
54
|
+
|
|
55
|
+
- "title을 받아서 Work 생성" — 검증 규칙·에러 누락
|
|
56
|
+
- 에러 케이스에 "ValidationError 발생"만 기록 (어떤 조건에 발생하는지 모호)
|
|
57
|
+
- 권한 누락 (누구나 호출 가능한지 ADMIN만인지 모호)
|
|
58
|
+
- 응답을 `Work` 한 단어로만 표현 (필드 정보 모호)
|
|
59
|
+
- 페이지네이션 메서드인데 `page`/`pageSize` 기본값·최대값 누락
|
|
60
|
+
|
|
61
|
+
## 기존 시그니처와의 차이
|
|
62
|
+
|
|
63
|
+
- 시그니처: `createWork(dto): Promise<Work>` — 함수의 형태만
|
|
64
|
+
- 명세: 검증 규칙 + 에러 케이스 + 권한 + 응답 필드까지 — 함수의 계약 전체
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# DB 모델 변경 표 작성 가이드
|
|
2
|
+
|
|
3
|
+
엔티티 섹션 안에 작성. 신규/수정 모델·컬럼·관계·인덱스를 하나의 매트릭스로 정리한다.
|
|
4
|
+
|
|
5
|
+
## 표현 형식
|
|
6
|
+
|
|
7
|
+
| 모델 | 변경 종류 | 컬럼·내용 | 인덱스 |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
|
|
10
|
+
컬럼 단위 표현이 더 명확하면 컬럼 단위 행으로 풀어 쓴다.
|
|
11
|
+
|
|
12
|
+
## 작성 원칙
|
|
13
|
+
|
|
14
|
+
- 변경 종류: `신규` / `컬럼 추가` / `컬럼 수정` / `컬럼 삭제` / `인덱스 추가/삭제` / `관계 변경`
|
|
15
|
+
- 컬럼은 타입·NULL 여부·기본값·외래키·`ON DELETE` 동작을 모두 명시.
|
|
16
|
+
- 인덱스는 단일/복합 구분, 사용 목적(조회 빈번 컬럼) 명시.
|
|
17
|
+
- 외래키는 `FK → {대상모델}.{컬럼}` 형식. 카스케이드 동작 명시.
|
|
18
|
+
- 컬럼 길이·정밀도는 도메인 값 범위에 충분한지 검토 후 결정.
|
|
19
|
+
|
|
20
|
+
## 좋은 예 (작업 등록)
|
|
21
|
+
|
|
22
|
+
| 모델 | 변경 | 컬럼·내용 | 인덱스 |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `Work` | 신규 | `id (uuid, PK)`, `title (varchar 200, NOT NULL)`, `dueDate (date, NULL)`, `assigneeId (uuid, NOT NULL, FK → User.id)`, `status (varchar 20, NOT NULL, default 'pending')`, `createdAt (datetime, NOT NULL, default NOW())` | `assigneeId`, `status` |
|
|
25
|
+
| `WorkLog` | 신규 | `id (uuid, PK)`, `workId (uuid, NOT NULL, FK → Work.id, ON DELETE CASCADE)`, `userId (uuid, NOT NULL, FK → User.id)`, `action (varchar 20)`, `createdAt (datetime, NOT NULL, default NOW())` | `workId`, `userId` |
|
|
26
|
+
| `User` | 컬럼 추가 | `lastWorkAt (datetime, NULL)` | — |
|
|
27
|
+
|
|
28
|
+
## 검증 체크리스트
|
|
29
|
+
|
|
30
|
+
작성 후 다음을 확인한다.
|
|
31
|
+
|
|
32
|
+
- 모든 외래키에 `ON DELETE` 동작 명시했는가 (`CASCADE` / `RESTRICT` / `SET NULL`)
|
|
33
|
+
- 조회 빈번한 컬럼에 인덱스가 있는가
|
|
34
|
+
- `NOT NULL` 컬럼에 기본값이 있거나 INSERT 시 반드시 채워지는가
|
|
35
|
+
- 신규 테이블의 PK가 정의됐는가
|
|
36
|
+
- 컬럼 타입·길이가 도메인 값 범위에 충분한가
|
|
37
|
+
- 복합 유일 제약(unique)이 필요한 케이스를 놓치지 않았는가
|
|
38
|
+
|
|
39
|
+
## 나쁜 예
|
|
40
|
+
|
|
41
|
+
- "Work 테이블 추가" — 컬럼 누락
|
|
42
|
+
- 외래키 동작 명시 안 함 — `ON DELETE CASCADE` vs `RESTRICT` vs `SET NULL` 모호
|
|
43
|
+
- 인덱스 누락 — 조회 자주 하는 컬럼인데 INDEX 없음
|
|
44
|
+
- `NOT NULL`인데 기본값·INSERT 경로 모호 (마이그레이션 시 실패 위험)
|
|
45
|
+
- 길이 미정 (`varchar`만 적고 길이 없음)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# 시퀀스 다이어그램 작성 가이드
|
|
2
|
+
|
|
3
|
+
구현 설계 시작(영향 범위 다음)에 작성. 모듈 간 호출 흐름을 mermaid `sequenceDiagram`으로 시각화한다.
|
|
4
|
+
|
|
5
|
+
## 작성 원칙
|
|
6
|
+
|
|
7
|
+
- 참여자(`participant`)는 패키지·모듈 단위로 정의 (예: `client-admin`, `server`, `WorkService`, `db-main`).
|
|
8
|
+
- 외부 사용자는 `actor`로 표시.
|
|
9
|
+
- 호출 화살표는 동기 `->>`, 응답 `-->>`. 비동기는 `->>` + `Note`로 명시.
|
|
10
|
+
- 트랜잭션·반복·분기는 `Note`/`alt`/`loop`로 표현.
|
|
11
|
+
- 권한 체크·검증·로그 같은 부수 동작도 메시지로 표시 (자주 누락되는 영역).
|
|
12
|
+
- 한 다이어그램의 메시지 수는 20개 이내. 넘으면 단계별로 분할.
|
|
13
|
+
|
|
14
|
+
## 좋은 예 (작업 등록)
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
sequenceDiagram
|
|
18
|
+
actor U as 관리자
|
|
19
|
+
participant UI as client-admin
|
|
20
|
+
participant API as server (라우터)
|
|
21
|
+
participant SVC as WorkService
|
|
22
|
+
participant DB as db-main
|
|
23
|
+
participant Q as 알림 큐
|
|
24
|
+
|
|
25
|
+
U->>UI: 작업 등록 폼 저장
|
|
26
|
+
UI->>API: createWork(dto)
|
|
27
|
+
API->>API: 권한 체크 (ROLE.ADMIN)
|
|
28
|
+
API->>SVC: createWork(dto)
|
|
29
|
+
SVC->>SVC: dto 검증
|
|
30
|
+
|
|
31
|
+
Note over SVC,DB: TX BEGIN (READ COMMITTED)
|
|
32
|
+
SVC->>DB: INSERT Work
|
|
33
|
+
SVC->>DB: INSERT WorkLog (action='created')
|
|
34
|
+
Note over SVC,DB: TX COMMIT
|
|
35
|
+
|
|
36
|
+
SVC->>Q: enqueue 담당자 알림 (TX 외부)
|
|
37
|
+
SVC-->>API: Work
|
|
38
|
+
API-->>UI: 201 Created
|
|
39
|
+
UI-->>U: 토스트 + 목록 갱신
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 무엇을 명시해야 하나
|
|
43
|
+
|
|
44
|
+
- **권한 체크 위치**: 어느 참여자에서? (API 진입? Service?)
|
|
45
|
+
- **트랜잭션 경계**: BEGIN ~ COMMIT을 `Note over`로 명시
|
|
46
|
+
- **외부 호출**: 알림·이메일·외부 API. TX 외부에 둘지 안에 둘지
|
|
47
|
+
- **에러 분기**: 실패 케이스가 핵심이면 `alt`/`else`로 표현
|
|
48
|
+
- **비동기 처리**: 반환을 기다리지 않으면 `Note`로 명시
|
|
49
|
+
|
|
50
|
+
## 나쁜 예
|
|
51
|
+
|
|
52
|
+
- `participant`에 클래스명만 (`WorkServiceImpl`) — 모듈/패키지 컨텍스트 누락
|
|
53
|
+
- 권한 체크 누락 (그냥 `SVC.createWork`만 호출하는 걸로 끝)
|
|
54
|
+
- 트랜잭션 경계 표시 없음 (어디서 BEGIN/COMMIT인지 모호)
|
|
55
|
+
- 외부 호출이 TX 안에 있는데 명시 안 됨 (락 길어짐 위험)
|
|
56
|
+
- 한 다이어그램에 모든 시나리오를 욱여넣어 메시지 30개 이상
|
|
57
|
+
|
|
58
|
+
## sd-wbs mermaid와의 차이
|
|
59
|
+
|
|
60
|
+
| 구분 | sd-wbs (사용자 시점) | sd-plan 시퀀스 (개발자 시점) |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| 노드 | 사용자가 인지하는 단계 | 패키지/모듈/클래스 |
|
|
63
|
+
| 동작 라벨 | "도서 검색", "대출 신청" | `findWork(id)`, `createWork(dto)` |
|
|
64
|
+
| 부수 동작 | (없음) | 트랜잭션, 권한 체크, 알림 큐 |
|
|
65
|
+
|
|
66
|
+
같은 정보를 양쪽에 중복하지 않는다.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# 상태 전이도 (FSM) 작성 가이드
|
|
2
|
+
|
|
3
|
+
엔티티 섹션 인접에 작성. 도메인 객체의 내부 상태 머신을 mermaid `stateDiagram-v2` + 전이 표로 정리한다.
|
|
4
|
+
|
|
5
|
+
## 표현 형식
|
|
6
|
+
|
|
7
|
+
다이어그램과 표를 함께 작성한다.
|
|
8
|
+
|
|
9
|
+
### 다이어그램
|
|
10
|
+
|
|
11
|
+
```mermaid
|
|
12
|
+
stateDiagram-v2
|
|
13
|
+
[*] --> {초기상태}: {생성 이벤트}
|
|
14
|
+
{상태} --> {다음상태}: {전이 이벤트}
|
|
15
|
+
{상태} --> [*]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 전이 표
|
|
19
|
+
|
|
20
|
+
| 현재 상태 | 이벤트 | 다음 상태 | 가드 | 사이드 이펙트 |
|
|
21
|
+
|---|---|---|---|---|
|
|
22
|
+
|
|
23
|
+
## 작성 원칙
|
|
24
|
+
|
|
25
|
+
- 상태 라벨은 DB `status` 컬럼 값 그대로 사용 (`pending`, `in_progress` 등). 한글 라벨 금지.
|
|
26
|
+
- 전이 이벤트는 메서드명 또는 시스템 이벤트명.
|
|
27
|
+
- 가드: 권한 조건·데이터 조건·타이밍 조건. 비어있으면 `—`.
|
|
28
|
+
- 사이드 이펙트: 알림·로그·외부 호출·다른 컬럼 갱신. 자주 누락되는 영역이라 명시 강제.
|
|
29
|
+
- 모든 가능 전이를 빠짐없이 나열한다 (완전성).
|
|
30
|
+
- 종료 상태(`[*]`)로 가는 경로를 명시.
|
|
31
|
+
|
|
32
|
+
## 좋은 예 (작업 도메인)
|
|
33
|
+
|
|
34
|
+
```mermaid
|
|
35
|
+
stateDiagram-v2
|
|
36
|
+
[*] --> pending: createWork
|
|
37
|
+
pending --> in_progress: startWork
|
|
38
|
+
pending --> cancelled: cancelWork
|
|
39
|
+
in_progress --> completed: completeWork
|
|
40
|
+
in_progress --> blocked: blockWork
|
|
41
|
+
in_progress --> cancelled: cancelWork
|
|
42
|
+
blocked --> in_progress: unblockWork
|
|
43
|
+
completed --> [*]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
| 현재 | 이벤트 | 다음 | 가드 | 사이드 이펙트 |
|
|
47
|
+
|---|---|---|---|---|
|
|
48
|
+
| (initial) | `createWork` | `pending` | — | 담당자 알림 |
|
|
49
|
+
| `pending` | `startWork` | `in_progress` | 호출자 = 담당자 | `startedAt` 기록 |
|
|
50
|
+
| `pending` | `cancelWork` | `cancelled` | 호출자 = `ADMIN` | 담당자 알림 |
|
|
51
|
+
| `in_progress` | `completeWork` | `completed` | 호출자 = 담당자 | 완료 알림 + 보고서 생성 |
|
|
52
|
+
| `in_progress` | `blockWork` | `blocked` | 사유 필수 | 관리자 알림 |
|
|
53
|
+
| `in_progress` | `cancelWork` | `cancelled` | 호출자 = `ADMIN` | 담당자 알림 |
|
|
54
|
+
| `blocked` | `unblockWork` | `in_progress` | 호출자 = 담당자/`ADMIN` | — |
|
|
55
|
+
|
|
56
|
+
## 검증 체크리스트
|
|
57
|
+
|
|
58
|
+
작성 후 다음을 확인한다.
|
|
59
|
+
|
|
60
|
+
- 모든 상태에서 가능한 모든 이벤트가 표에 있는가
|
|
61
|
+
- 종료 상태(`[*]`)로 가는 경로가 정의됐는가
|
|
62
|
+
- 가드 조건의 검증 위치가 명확한가 (Service 안? DB constraint?)
|
|
63
|
+
- 사이드 이펙트가 트랜잭션 내부인지 외부인지 (알림은 보통 TX 외부)
|
|
64
|
+
- 동시성 — 같은 객체에 두 이벤트가 동시에 오면? 락·낙관적 동시성 정책
|
|
65
|
+
|
|
66
|
+
## 나쁜 예
|
|
67
|
+
|
|
68
|
+
- 상태 라벨이 한글 (`진행중`) — DB `status` 값과 불일치, sd-wbs와 헷갈림
|
|
69
|
+
- 가드·사이드 이펙트 컬럼 빠진 단순 다이어그램 (전이만 그림)
|
|
70
|
+
- 일부 전이 누락 — 어떤 상태에서 `cancelWork`가 가능한지 모호
|
|
71
|
+
- 종료 상태로 가는 경로 누락
|
|
72
|
+
- 사이드 이펙트(알림·로그)를 트랜잭션 안에 두면서 명시 안 함
|
|
73
|
+
|
|
74
|
+
## sd-wbs stateDiagram과의 차이
|
|
75
|
+
|
|
76
|
+
| 구분 | sd-wbs (사용자 시점) | sd-plan FSM (개발자 시점) |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| 라벨 | "진행 중" (사용자 표시) | `in_progress` (DB 컬럼 값) |
|
|
79
|
+
| 트리거 | "완료 표시" (사용자 동작) | `completeWork` (메서드명) |
|
|
80
|
+
| 가드 | (없음 또는 단순 권한) | 권한·데이터·타이밍 조건 |
|
|
81
|
+
| 사이드 이펙트 | (없음) | 알림·로그·외부 호출 명시 |
|
|
82
|
+
|
|
83
|
+
같은 객체 상태라도 정보 깊이가 다르다. sd-wbs와 sd-plan에 같은 정보를 중복 작성하지 않는다.
|