timsquad 2.0.0
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/LICENSE +21 -0
- package/README.md +347 -0
- package/bin/tsq.js +6 -0
- package/dist/commands/feedback.d.ts +3 -0
- package/dist/commands/feedback.d.ts.map +1 -0
- package/dist/commands/feedback.js +142 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/full.d.ts +3 -0
- package/dist/commands/full.d.ts.map +1 -0
- package/dist/commands/full.js +87 -0
- package/dist/commands/full.js.map +1 -0
- package/dist/commands/git/commit.d.ts +3 -0
- package/dist/commands/git/commit.d.ts.map +1 -0
- package/dist/commands/git/commit.js +88 -0
- package/dist/commands/git/commit.js.map +1 -0
- package/dist/commands/git/index.d.ts +5 -0
- package/dist/commands/git/index.d.ts.map +1 -0
- package/dist/commands/git/index.js +5 -0
- package/dist/commands/git/index.js.map +1 -0
- package/dist/commands/git/pr.d.ts +3 -0
- package/dist/commands/git/pr.d.ts.map +1 -0
- package/dist/commands/git/pr.js +138 -0
- package/dist/commands/git/pr.js.map +1 -0
- package/dist/commands/git/release.d.ts +3 -0
- package/dist/commands/git/release.d.ts.map +1 -0
- package/dist/commands/git/release.js +158 -0
- package/dist/commands/git/release.js.map +1 -0
- package/dist/commands/git/sync.d.ts +3 -0
- package/dist/commands/git/sync.d.ts.map +1 -0
- package/dist/commands/git/sync.js +132 -0
- package/dist/commands/git/sync.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +150 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/log.d.ts +3 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +271 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/metrics.d.ts +3 -0
- package/dist/commands/metrics.d.ts.map +1 -0
- package/dist/commands/metrics.js +299 -0
- package/dist/commands/metrics.js.map +1 -0
- package/dist/commands/quick.d.ts +3 -0
- package/dist/commands/quick.d.ts.map +1 -0
- package/dist/commands/quick.js +136 -0
- package/dist/commands/quick.js.map +1 -0
- package/dist/commands/retro.d.ts +3 -0
- package/dist/commands/retro.d.ts.map +1 -0
- package/dist/commands/retro.js +280 -0
- package/dist/commands/retro.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +127 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/watch.d.ts +3 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +213 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +34 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +108 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/project.d.ts +47 -0
- package/dist/lib/project.d.ts.map +1 -0
- package/dist/lib/project.js +191 -0
- package/dist/lib/project.js.map +1 -0
- package/dist/lib/template.d.ts +33 -0
- package/dist/lib/template.d.ts.map +1 -0
- package/dist/lib/template.js +151 -0
- package/dist/lib/template.js.map +1 -0
- package/dist/types/config.d.ts +75 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +66 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/feedback.d.ts +59 -0
- package/dist/types/feedback.d.ts.map +1 -0
- package/dist/types/feedback.js +26 -0
- package/dist/types/feedback.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/project.d.ts +89 -0
- package/dist/types/project.d.ts.map +1 -0
- package/dist/types/project.js +44 -0
- package/dist/types/project.js.map +1 -0
- package/dist/utils/colors.d.ts +30 -0
- package/dist/utils/colors.d.ts.map +1 -0
- package/dist/utils/colors.js +54 -0
- package/dist/utils/colors.js.map +1 -0
- package/dist/utils/date.d.ts +25 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/date.js +65 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/fs.d.ts +49 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +84 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/prompts.d.ts +31 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +95 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/yaml.d.ts +21 -0
- package/dist/utils/yaml.d.ts.map +1 -0
- package/dist/utils/yaml.js +40 -0
- package/dist/utils/yaml.js.map +1 -0
- package/package.json +71 -0
- package/templates/common/CLAUDE.md.template +254 -0
- package/templates/common/claude/agents/tsq-dba.md +290 -0
- package/templates/common/claude/agents/tsq-designer.md +304 -0
- package/templates/common/claude/agents/tsq-developer.md +118 -0
- package/templates/common/claude/agents/tsq-planner.md +90 -0
- package/templates/common/claude/agents/tsq-prompter.md +336 -0
- package/templates/common/claude/agents/tsq-qa.md +134 -0
- package/templates/common/claude/agents/tsq-retro.md +168 -0
- package/templates/common/claude/agents/tsq-security.md +190 -0
- package/templates/common/claude/skills/architecture/SKILL.md +123 -0
- package/templates/common/claude/skills/backend/node/SKILL.md +1015 -0
- package/templates/common/claude/skills/coding/SKILL.md +171 -0
- package/templates/common/claude/skills/database/prisma/SKILL.md +357 -0
- package/templates/common/claude/skills/frontend/nextjs/SKILL.md +279 -0
- package/templates/common/claude/skills/frontend/react/SKILL.md +1729 -0
- package/templates/common/claude/skills/methodology/bdd/SKILL.md +234 -0
- package/templates/common/claude/skills/methodology/ddd/SKILL.md +311 -0
- package/templates/common/claude/skills/methodology/tdd/SKILL.md +512 -0
- package/templates/common/claude/skills/planning/SKILL.md +90 -0
- package/templates/common/claude/skills/security/SKILL.md +234 -0
- package/templates/common/claude/skills/testing/SKILL.md +146 -0
- package/templates/common/claude/skills/typescript/SKILL.md +435 -0
- package/templates/common/config.template.yaml +131 -0
- package/templates/common/timsquad/architectures/clean/ARCHITECTURE.md +49 -0
- package/templates/common/timsquad/architectures/clean/backend.xml +210 -0
- package/templates/common/timsquad/architectures/clean/frontend.xml +148 -0
- package/templates/common/timsquad/architectures/fsd/ARCHITECTURE.md +67 -0
- package/templates/common/timsquad/architectures/fsd/frontend.xml +288 -0
- package/templates/common/timsquad/architectures/hexagonal/ARCHITECTURE.md +60 -0
- package/templates/common/timsquad/architectures/hexagonal/backend.xml +300 -0
- package/templates/common/timsquad/constraints/competency-framework.xml +501 -0
- package/templates/common/timsquad/constraints/ssot-schema.xml +433 -0
- package/templates/common/timsquad/feedback/feedback-router.sh +341 -0
- package/templates/common/timsquad/feedback/routing-rules.yaml +352 -0
- package/templates/common/timsquad/generators/data-design.xml +290 -0
- package/templates/common/timsquad/generators/prd.xml +280 -0
- package/templates/common/timsquad/generators/requirements.xml +220 -0
- package/templates/common/timsquad/generators/service-spec.xml +266 -0
- package/templates/common/timsquad/logs/_example.md +81 -0
- package/templates/common/timsquad/logs/_template.md +46 -0
- package/templates/common/timsquad/patterns/cqrs.xml +127 -0
- package/templates/common/timsquad/patterns/event-sourcing.xml +85 -0
- package/templates/common/timsquad/patterns/repository.xml +64 -0
- package/templates/common/timsquad/process/state-machine.xml +343 -0
- package/templates/common/timsquad/process/validation-rules.xml +308 -0
- package/templates/common/timsquad/process/workflow-base.xml +202 -0
- package/templates/common/timsquad/retrospective/cycle-report.template.md +205 -0
- package/templates/common/timsquad/retrospective/metrics/metrics-schema.json +203 -0
- package/templates/common/timsquad/retrospective/patterns/failure-patterns.md +199 -0
- package/templates/common/timsquad/retrospective/patterns/success-patterns.md +262 -0
- package/templates/common/timsquad/retrospective/retrospective-config.xml +294 -0
- package/templates/common/timsquad/retrospective/retrospective-state.xml +210 -0
- package/templates/common/timsquad/ssot/adr/ADR-000-template.md +121 -0
- package/templates/common/timsquad/ssot/adr/ADR-001-example.md +115 -0
- package/templates/common/timsquad/ssot/data-design.template.md +132 -0
- package/templates/common/timsquad/ssot/deployment-spec.template.md +384 -0
- package/templates/common/timsquad/ssot/env-config.template.md +346 -0
- package/templates/common/timsquad/ssot/error-codes.template.md +114 -0
- package/templates/common/timsquad/ssot/functional-spec.template.md +185 -0
- package/templates/common/timsquad/ssot/glossary.template.md +148 -0
- package/templates/common/timsquad/ssot/integration-spec.template.md +391 -0
- package/templates/common/timsquad/ssot/planning.template.md +94 -0
- package/templates/common/timsquad/ssot/prd.template.md +102 -0
- package/templates/common/timsquad/ssot/requirements.template.md +117 -0
- package/templates/common/timsquad/ssot/security-spec.template.md +309 -0
- package/templates/common/timsquad/ssot/service-spec.template.md +194 -0
- package/templates/common/timsquad/ssot/test-spec.template.md +264 -0
- package/templates/common/timsquad/ssot/ui-ux-spec.template.md +262 -0
- package/templates/common/timsquad/state/workspace.xml +217 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<pattern name="cqrs">
|
|
3
|
+
<metadata>
|
|
4
|
+
<full-name>Command Query Responsibility Segregation</full-name>
|
|
5
|
+
<applies-to>Clean Architecture, Hexagonal Architecture</applies-to>
|
|
6
|
+
<complexity>high</complexity>
|
|
7
|
+
</metadata>
|
|
8
|
+
|
|
9
|
+
<description>
|
|
10
|
+
읽기(Query)와 쓰기(Command)를 분리하는 패턴.
|
|
11
|
+
기존 아키텍처의 Use Case / Application 레이어에 적용.
|
|
12
|
+
</description>
|
|
13
|
+
|
|
14
|
+
<when-to-use>
|
|
15
|
+
<use>읽기/쓰기 부하 패턴이 크게 다를 때</use>
|
|
16
|
+
<use>복잡한 도메인 로직 vs 단순 조회</use>
|
|
17
|
+
<use>읽기 성능 최적화가 중요할 때</use>
|
|
18
|
+
<avoid>단순 CRUD 애플리케이션</avoid>
|
|
19
|
+
<avoid>팀 CQRS 경험 없을 때</avoid>
|
|
20
|
+
</when-to-use>
|
|
21
|
+
|
|
22
|
+
<core-concepts>
|
|
23
|
+
<concept name="command">
|
|
24
|
+
<description>상태 변경 요청. void 또는 ID만 반환</description>
|
|
25
|
+
<example>CreateUserCommand, PlaceOrderCommand</example>
|
|
26
|
+
</concept>
|
|
27
|
+
<concept name="query">
|
|
28
|
+
<description>데이터 조회. 상태 변경 없음</description>
|
|
29
|
+
<example>GetUserQuery, ListOrdersQuery</example>
|
|
30
|
+
</concept>
|
|
31
|
+
<concept name="read-model">
|
|
32
|
+
<description>조회 최적화된 비정규화 모델</description>
|
|
33
|
+
</concept>
|
|
34
|
+
</core-concepts>
|
|
35
|
+
|
|
36
|
+
<!-- Clean Architecture에 CQRS 적용 시 변경점 -->
|
|
37
|
+
<apply-to architecture="clean">
|
|
38
|
+
<modification layer="application">
|
|
39
|
+
<before>
|
|
40
|
+
<dir name="use-cases">
|
|
41
|
+
<file name="create-user.ts" />
|
|
42
|
+
<file name="get-user.ts" />
|
|
43
|
+
</dir>
|
|
44
|
+
</before>
|
|
45
|
+
<after>
|
|
46
|
+
<dir name="command">
|
|
47
|
+
<dir name="user">
|
|
48
|
+
<file name="create-user.command.ts" />
|
|
49
|
+
<file name="create-user.handler.ts" />
|
|
50
|
+
</dir>
|
|
51
|
+
</dir>
|
|
52
|
+
<dir name="query">
|
|
53
|
+
<dir name="user">
|
|
54
|
+
<file name="get-user.query.ts" />
|
|
55
|
+
<file name="get-user.handler.ts" />
|
|
56
|
+
<file name="user.read-model.ts" />
|
|
57
|
+
</dir>
|
|
58
|
+
</dir>
|
|
59
|
+
<dir name="shared">
|
|
60
|
+
<file name="command-bus.ts" />
|
|
61
|
+
<file name="query-bus.ts" />
|
|
62
|
+
</dir>
|
|
63
|
+
</after>
|
|
64
|
+
</modification>
|
|
65
|
+
</apply-to>
|
|
66
|
+
|
|
67
|
+
<!-- Hexagonal Architecture에 CQRS 적용 시 변경점 -->
|
|
68
|
+
<apply-to architecture="hexagonal">
|
|
69
|
+
<modification layer="application">
|
|
70
|
+
<before>
|
|
71
|
+
<dir name="port">
|
|
72
|
+
<dir name="inbound">
|
|
73
|
+
<file name="user.port.ts" />
|
|
74
|
+
</dir>
|
|
75
|
+
</dir>
|
|
76
|
+
<dir name="service">
|
|
77
|
+
<file name="user.service.ts" />
|
|
78
|
+
</dir>
|
|
79
|
+
</before>
|
|
80
|
+
<after>
|
|
81
|
+
<dir name="command">
|
|
82
|
+
<file name="create-user.command.ts" />
|
|
83
|
+
<file name="create-user.handler.ts" />
|
|
84
|
+
</dir>
|
|
85
|
+
<dir name="query">
|
|
86
|
+
<file name="get-user.query.ts" />
|
|
87
|
+
<file name="get-user.handler.ts" />
|
|
88
|
+
<file name="user.read-model.ts" />
|
|
89
|
+
</dir>
|
|
90
|
+
</after>
|
|
91
|
+
</modification>
|
|
92
|
+
</apply-to>
|
|
93
|
+
|
|
94
|
+
<code-example language="typescript">
|
|
95
|
+
<title>Command/Query 기본 구조</title>
|
|
96
|
+
<code><![CDATA[
|
|
97
|
+
// Command
|
|
98
|
+
class CreateUserCommand {
|
|
99
|
+
constructor(
|
|
100
|
+
readonly email: string,
|
|
101
|
+
readonly name: string
|
|
102
|
+
) {}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Command Handler
|
|
106
|
+
class CreateUserHandler implements ICommandHandler<CreateUserCommand> {
|
|
107
|
+
async handle(command: CreateUserCommand): Promise<UserId> {
|
|
108
|
+
const user = User.create(command.email, command.name);
|
|
109
|
+
await this.userRepository.save(user);
|
|
110
|
+
return user.id;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Query
|
|
115
|
+
class GetUserQuery {
|
|
116
|
+
constructor(readonly userId: string) {}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Query Handler (Read Model 사용)
|
|
120
|
+
class GetUserHandler implements IQueryHandler<GetUserQuery, UserReadModel> {
|
|
121
|
+
async handle(query: GetUserQuery): Promise<UserReadModel> {
|
|
122
|
+
return this.readRepository.findById(query.userId);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]]></code>
|
|
126
|
+
</code-example>
|
|
127
|
+
</pattern>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<pattern name="event-sourcing">
|
|
3
|
+
<metadata>
|
|
4
|
+
<full-name>Event Sourcing</full-name>
|
|
5
|
+
<applies-to>Clean Architecture, Hexagonal Architecture</applies-to>
|
|
6
|
+
<often-with>CQRS</often-with>
|
|
7
|
+
<complexity>very-high</complexity>
|
|
8
|
+
</metadata>
|
|
9
|
+
|
|
10
|
+
<description>
|
|
11
|
+
상태를 직접 저장하지 않고, 상태 변경 이벤트를 순차적으로 저장.
|
|
12
|
+
현재 상태는 이벤트를 재생(replay)하여 도출.
|
|
13
|
+
</description>
|
|
14
|
+
|
|
15
|
+
<when-to-use>
|
|
16
|
+
<use>완전한 감사 로그(audit trail) 필요</use>
|
|
17
|
+
<use>시간 여행(time travel) - 과거 상태 조회</use>
|
|
18
|
+
<use>복잡한 도메인 이벤트 추적</use>
|
|
19
|
+
<use>금융, 의료 등 규제 산업</use>
|
|
20
|
+
<avoid>단순 CRUD</avoid>
|
|
21
|
+
<avoid>이벤트 스키마 변경 빈번</avoid>
|
|
22
|
+
</when-to-use>
|
|
23
|
+
|
|
24
|
+
<core-concepts>
|
|
25
|
+
<concept name="event-store">
|
|
26
|
+
<description>이벤트를 append-only로 저장하는 저장소</description>
|
|
27
|
+
</concept>
|
|
28
|
+
<concept name="aggregate">
|
|
29
|
+
<description>이벤트를 발행하고, 이벤트로부터 상태 복원</description>
|
|
30
|
+
</concept>
|
|
31
|
+
<concept name="projection">
|
|
32
|
+
<description>이벤트 스트림을 읽어 Read Model 구축</description>
|
|
33
|
+
</concept>
|
|
34
|
+
<concept name="snapshot">
|
|
35
|
+
<description>성능 최적화를 위한 중간 상태 저장</description>
|
|
36
|
+
</concept>
|
|
37
|
+
</core-concepts>
|
|
38
|
+
|
|
39
|
+
<code-example language="typescript">
|
|
40
|
+
<title>Event Sourced Aggregate</title>
|
|
41
|
+
<code><![CDATA[
|
|
42
|
+
// Domain Event
|
|
43
|
+
class OrderPlaced extends DomainEvent {
|
|
44
|
+
constructor(
|
|
45
|
+
readonly orderId: string,
|
|
46
|
+
readonly customerId: string,
|
|
47
|
+
readonly items: OrderItem[]
|
|
48
|
+
) { super(); }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Aggregate
|
|
52
|
+
class Order extends EventSourcedAggregate {
|
|
53
|
+
private status: OrderStatus;
|
|
54
|
+
private items: OrderItem[] = [];
|
|
55
|
+
|
|
56
|
+
// Command → Event
|
|
57
|
+
place(customerId: string, items: OrderItem[]): void {
|
|
58
|
+
this.apply(new OrderPlaced(this.id, customerId, items));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Event → State (재생 시 호출)
|
|
62
|
+
onOrderPlaced(event: OrderPlaced): void {
|
|
63
|
+
this.status = 'placed';
|
|
64
|
+
this.items = event.items;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Event Store에서 로드
|
|
68
|
+
static fromEvents(events: DomainEvent[]): Order {
|
|
69
|
+
const order = new Order();
|
|
70
|
+
events.forEach(e => order.applyFromHistory(e));
|
|
71
|
+
return order;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
]]></code>
|
|
75
|
+
</code-example>
|
|
76
|
+
|
|
77
|
+
<trade-offs>
|
|
78
|
+
<pro>완전한 이력 보존</pro>
|
|
79
|
+
<pro>디버깅 용이 (이벤트 재생)</pro>
|
|
80
|
+
<pro>temporal query 가능</pro>
|
|
81
|
+
<con>복잡도 증가</con>
|
|
82
|
+
<con>이벤트 스키마 버전 관리 필요</con>
|
|
83
|
+
<con>eventual consistency</con>
|
|
84
|
+
</trade-offs>
|
|
85
|
+
</pattern>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<pattern name="repository">
|
|
3
|
+
<metadata>
|
|
4
|
+
<full-name>Repository Pattern</full-name>
|
|
5
|
+
<applies-to>모든 아키텍처</applies-to>
|
|
6
|
+
<complexity>low</complexity>
|
|
7
|
+
</metadata>
|
|
8
|
+
|
|
9
|
+
<description>
|
|
10
|
+
도메인과 데이터 매핑 레이어 사이를 중재하는 패턴.
|
|
11
|
+
컬렉션처럼 도메인 객체에 접근하는 인터페이스 제공.
|
|
12
|
+
</description>
|
|
13
|
+
|
|
14
|
+
<core-concepts>
|
|
15
|
+
<concept name="repository-interface">
|
|
16
|
+
<description>도메인 레이어에 정의. 영속성 세부사항 숨김</description>
|
|
17
|
+
<location>domain 또는 application 레이어</location>
|
|
18
|
+
</concept>
|
|
19
|
+
<concept name="repository-implementation">
|
|
20
|
+
<description>인프라 레이어에서 구현 (Prisma, TypeORM 등)</description>
|
|
21
|
+
<location>infrastructure 또는 adapter 레이어</location>
|
|
22
|
+
</concept>
|
|
23
|
+
</core-concepts>
|
|
24
|
+
|
|
25
|
+
<code-example language="typescript">
|
|
26
|
+
<title>Repository Interface + Implementation</title>
|
|
27
|
+
<code><![CDATA[
|
|
28
|
+
// Domain Layer - Interface
|
|
29
|
+
interface IUserRepository {
|
|
30
|
+
findById(id: UserId): Promise<User | null>;
|
|
31
|
+
findByEmail(email: Email): Promise<User | null>;
|
|
32
|
+
save(user: User): Promise<void>;
|
|
33
|
+
delete(id: UserId): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Infrastructure Layer - Implementation
|
|
37
|
+
class PrismaUserRepository implements IUserRepository {
|
|
38
|
+
constructor(private prisma: PrismaClient) {}
|
|
39
|
+
|
|
40
|
+
async findById(id: UserId): Promise<User | null> {
|
|
41
|
+
const data = await this.prisma.user.findUnique({
|
|
42
|
+
where: { id: id.value }
|
|
43
|
+
});
|
|
44
|
+
return data ? UserMapper.toDomain(data) : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async save(user: User): Promise<void> {
|
|
48
|
+
const data = UserMapper.toPersistence(user);
|
|
49
|
+
await this.prisma.user.upsert({
|
|
50
|
+
where: { id: data.id },
|
|
51
|
+
create: data,
|
|
52
|
+
update: data
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]]></code>
|
|
57
|
+
</code-example>
|
|
58
|
+
|
|
59
|
+
<rules>
|
|
60
|
+
<rule>Repository는 Aggregate Root 단위로 생성</rule>
|
|
61
|
+
<rule>Repository 인터페이스에 DB 용어 사용 금지 (findAll O, SELECT X)</rule>
|
|
62
|
+
<rule>복잡한 쿼리는 별도 Query Service로 분리</rule>
|
|
63
|
+
</rules>
|
|
64
|
+
</pattern>
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<state-machine>
|
|
3
|
+
<metadata>
|
|
4
|
+
<description>TimSquad Phase 상태 전환 규칙</description>
|
|
5
|
+
<version>1.0</version>
|
|
6
|
+
<initial-state>planning</initial-state>
|
|
7
|
+
</metadata>
|
|
8
|
+
|
|
9
|
+
<!-- ============================================================
|
|
10
|
+
State 정의
|
|
11
|
+
============================================================ -->
|
|
12
|
+
<states>
|
|
13
|
+
<state id="planning" name="기획/설계">
|
|
14
|
+
<description>요구사항 분석, SSOT 문서 작성, 아키텍처 설계</description>
|
|
15
|
+
<primary-agent>tsq-planner</primary-agent>
|
|
16
|
+
<allowed-actions>
|
|
17
|
+
<action>SSOT 문서 생성/수정</action>
|
|
18
|
+
<action>ADR 작성</action>
|
|
19
|
+
<action>요구사항 분석</action>
|
|
20
|
+
<action>아키텍처 설계</action>
|
|
21
|
+
</allowed-actions>
|
|
22
|
+
<forbidden-actions>
|
|
23
|
+
<action>코드 구현</action>
|
|
24
|
+
<action>테스트 작성</action>
|
|
25
|
+
</forbidden-actions>
|
|
26
|
+
</state>
|
|
27
|
+
|
|
28
|
+
<state id="implementation" name="구현">
|
|
29
|
+
<description>SSOT 기반 코드 구현, 테스트 작성</description>
|
|
30
|
+
<primary-agent>tsq-developer</primary-agent>
|
|
31
|
+
<allowed-actions>
|
|
32
|
+
<action>코드 구현</action>
|
|
33
|
+
<action>테스트 작성</action>
|
|
34
|
+
<action>리팩토링</action>
|
|
35
|
+
<action>버그 수정</action>
|
|
36
|
+
</allowed-actions>
|
|
37
|
+
<forbidden-actions>
|
|
38
|
+
<action>SSOT 임의 수정</action>
|
|
39
|
+
<action>요구사항 변경</action>
|
|
40
|
+
</forbidden-actions>
|
|
41
|
+
</state>
|
|
42
|
+
|
|
43
|
+
<state id="review" name="검증">
|
|
44
|
+
<description>코드 리뷰, 테스트 검증, SSOT 일치 확인</description>
|
|
45
|
+
<primary-agent>tsq-qa</primary-agent>
|
|
46
|
+
<allowed-actions>
|
|
47
|
+
<action>코드 리뷰</action>
|
|
48
|
+
<action>테스트 검증</action>
|
|
49
|
+
<action>SSOT 일치 확인</action>
|
|
50
|
+
<action>피드백 작성</action>
|
|
51
|
+
</allowed-actions>
|
|
52
|
+
<forbidden-actions>
|
|
53
|
+
<action>코드 직접 수정</action>
|
|
54
|
+
<action>SSOT 직접 수정</action>
|
|
55
|
+
</forbidden-actions>
|
|
56
|
+
</state>
|
|
57
|
+
|
|
58
|
+
<state id="security" name="보안 검토">
|
|
59
|
+
<description>보안 취약점 분석, 컴플라이언스 체크</description>
|
|
60
|
+
<primary-agent>tsq-security</primary-agent>
|
|
61
|
+
<allowed-actions>
|
|
62
|
+
<action>취약점 분석</action>
|
|
63
|
+
<action>보안 검토</action>
|
|
64
|
+
<action>컴플라이언스 체크</action>
|
|
65
|
+
<action>보안 피드백 작성</action>
|
|
66
|
+
</allowed-actions>
|
|
67
|
+
<forbidden-actions>
|
|
68
|
+
<action>코드 직접 수정</action>
|
|
69
|
+
</forbidden-actions>
|
|
70
|
+
</state>
|
|
71
|
+
|
|
72
|
+
<state id="complete" name="완료">
|
|
73
|
+
<description>작업 완료, 회고 준비</description>
|
|
74
|
+
<allowed-actions>
|
|
75
|
+
<action>최종 로그 정리</action>
|
|
76
|
+
<action>회고 데이터 수집</action>
|
|
77
|
+
</allowed-actions>
|
|
78
|
+
</state>
|
|
79
|
+
|
|
80
|
+
<!-- 특수 상태 -->
|
|
81
|
+
<state id="blocked" name="차단됨" type="special">
|
|
82
|
+
<description>검증 실패로 진행 불가</description>
|
|
83
|
+
<requires>이슈 해결 후 이전 상태로 복귀</requires>
|
|
84
|
+
</state>
|
|
85
|
+
|
|
86
|
+
<state id="waiting-approval" name="승인 대기" type="special">
|
|
87
|
+
<description>User 승인 대기 중</description>
|
|
88
|
+
<requires>User 승인 후 다음 상태로 전환</requires>
|
|
89
|
+
</state>
|
|
90
|
+
</states>
|
|
91
|
+
|
|
92
|
+
<!-- ============================================================
|
|
93
|
+
Transition 정의
|
|
94
|
+
============================================================ -->
|
|
95
|
+
<transitions>
|
|
96
|
+
<!-- Planning → Implementation -->
|
|
97
|
+
<transition id="T-001">
|
|
98
|
+
<from>planning</from>
|
|
99
|
+
<to>implementation</to>
|
|
100
|
+
<name>기획 완료 → 구현 시작</name>
|
|
101
|
+
|
|
102
|
+
<conditions>
|
|
103
|
+
<condition type="required">
|
|
104
|
+
<check>prd.md 존재</check>
|
|
105
|
+
</condition>
|
|
106
|
+
<condition type="required">
|
|
107
|
+
<check>requirements.md 존재</check>
|
|
108
|
+
</condition>
|
|
109
|
+
<condition type="required">
|
|
110
|
+
<check>service-spec.md 존재</check>
|
|
111
|
+
</condition>
|
|
112
|
+
<condition type="required">
|
|
113
|
+
<check>User 승인 완료</check>
|
|
114
|
+
</condition>
|
|
115
|
+
</conditions>
|
|
116
|
+
|
|
117
|
+
<on-transition>
|
|
118
|
+
<action>상태 파일 업데이트</action>
|
|
119
|
+
<action>Planning Phase 완료 로그 기록</action>
|
|
120
|
+
<notification>User에게 구현 시작 알림</notification>
|
|
121
|
+
</on-transition>
|
|
122
|
+
|
|
123
|
+
<on-failure>
|
|
124
|
+
<action>차단 사유 표시</action>
|
|
125
|
+
<suggestion>누락된 SSOT 문서 작성 필요</suggestion>
|
|
126
|
+
</on-failure>
|
|
127
|
+
</transition>
|
|
128
|
+
|
|
129
|
+
<!-- Implementation → Review -->
|
|
130
|
+
<transition id="T-002">
|
|
131
|
+
<from>implementation</from>
|
|
132
|
+
<to>review</to>
|
|
133
|
+
<name>구현 완료 → 검증 시작</name>
|
|
134
|
+
|
|
135
|
+
<conditions>
|
|
136
|
+
<condition type="required">
|
|
137
|
+
<check>테스트 통과 (커버리지 80% 이상)</check>
|
|
138
|
+
<command>npm run test:coverage</command>
|
|
139
|
+
<threshold>80</threshold>
|
|
140
|
+
</condition>
|
|
141
|
+
<condition type="required">
|
|
142
|
+
<check>린트 에러 없음</check>
|
|
143
|
+
<command>npm run lint</command>
|
|
144
|
+
</condition>
|
|
145
|
+
<condition type="required">
|
|
146
|
+
<check>타입 에러 없음</check>
|
|
147
|
+
<command>npm run type-check</command>
|
|
148
|
+
</condition>
|
|
149
|
+
<condition type="required">
|
|
150
|
+
<check>작업 로그 기록 완료</check>
|
|
151
|
+
</condition>
|
|
152
|
+
</conditions>
|
|
153
|
+
|
|
154
|
+
<on-transition>
|
|
155
|
+
<action>상태 파일 업데이트</action>
|
|
156
|
+
<action>QA 에이전트에게 리뷰 요청 전달</action>
|
|
157
|
+
</on-transition>
|
|
158
|
+
</transition>
|
|
159
|
+
|
|
160
|
+
<!-- Review → Security (optional) -->
|
|
161
|
+
<transition id="T-003">
|
|
162
|
+
<from>review</from>
|
|
163
|
+
<to>security</to>
|
|
164
|
+
<name>검증 완료 → 보안 검토</name>
|
|
165
|
+
<optional-for>level-1, level-2</optional-for>
|
|
166
|
+
<required-for>level-3, fintech</required-for>
|
|
167
|
+
|
|
168
|
+
<conditions>
|
|
169
|
+
<condition type="required">
|
|
170
|
+
<check>Critical/Major 이슈 없음</check>
|
|
171
|
+
</condition>
|
|
172
|
+
<condition type="required">
|
|
173
|
+
<check>QA 체크리스트 통과</check>
|
|
174
|
+
</condition>
|
|
175
|
+
</conditions>
|
|
176
|
+
</transition>
|
|
177
|
+
|
|
178
|
+
<!-- Review → Complete (security 생략 시) -->
|
|
179
|
+
<transition id="T-004">
|
|
180
|
+
<from>review</from>
|
|
181
|
+
<to>complete</to>
|
|
182
|
+
<name>검증 완료 → 완료 (보안 생략)</name>
|
|
183
|
+
<allowed-for>level-1, level-2</allowed-for>
|
|
184
|
+
<forbidden-for>level-3, fintech</forbidden-for>
|
|
185
|
+
|
|
186
|
+
<conditions>
|
|
187
|
+
<condition type="required">
|
|
188
|
+
<check>Critical/Major 이슈 없음</check>
|
|
189
|
+
</condition>
|
|
190
|
+
<condition type="required">
|
|
191
|
+
<check>QA 체크리스트 통과</check>
|
|
192
|
+
</condition>
|
|
193
|
+
</conditions>
|
|
194
|
+
</transition>
|
|
195
|
+
|
|
196
|
+
<!-- Security → Complete -->
|
|
197
|
+
<transition id="T-005">
|
|
198
|
+
<from>security</from>
|
|
199
|
+
<to>complete</to>
|
|
200
|
+
<name>보안 검토 완료 → 완료</name>
|
|
201
|
+
|
|
202
|
+
<conditions>
|
|
203
|
+
<condition type="required">
|
|
204
|
+
<check>Critical 취약점 없음</check>
|
|
205
|
+
</condition>
|
|
206
|
+
<condition type="required">
|
|
207
|
+
<check>High 취약점 해결됨</check>
|
|
208
|
+
</condition>
|
|
209
|
+
<condition type="required">
|
|
210
|
+
<check>User 승인 (Level 3 / fintech)</check>
|
|
211
|
+
<applies-to>level-3, fintech</applies-to>
|
|
212
|
+
</condition>
|
|
213
|
+
</conditions>
|
|
214
|
+
</transition>
|
|
215
|
+
|
|
216
|
+
<!-- 회귀 전환 (Regression) -->
|
|
217
|
+
<transition id="T-REG-001" type="regression">
|
|
218
|
+
<from>review</from>
|
|
219
|
+
<to>implementation</to>
|
|
220
|
+
<name>Level 1 피드백 → 구현 수정</name>
|
|
221
|
+
<trigger>Level 1 피드백 발생</trigger>
|
|
222
|
+
|
|
223
|
+
<on-transition>
|
|
224
|
+
<action>피드백 내용 Developer에게 전달</action>
|
|
225
|
+
<action>수정 필요 항목 기록</action>
|
|
226
|
+
</on-transition>
|
|
227
|
+
</transition>
|
|
228
|
+
|
|
229
|
+
<transition id="T-REG-002" type="regression">
|
|
230
|
+
<from>review</from>
|
|
231
|
+
<to>planning</to>
|
|
232
|
+
<name>Level 2 피드백 → 설계 수정</name>
|
|
233
|
+
<trigger>Level 2 피드백 발생</trigger>
|
|
234
|
+
|
|
235
|
+
<on-transition>
|
|
236
|
+
<action>피드백 내용 Planner에게 전달</action>
|
|
237
|
+
<action>SSOT 수정 필요 항목 기록</action>
|
|
238
|
+
</on-transition>
|
|
239
|
+
</transition>
|
|
240
|
+
|
|
241
|
+
<transition id="T-REG-003" type="regression">
|
|
242
|
+
<from>review</from>
|
|
243
|
+
<to>waiting-approval</to>
|
|
244
|
+
<name>Level 3 피드백 → User 승인 대기</name>
|
|
245
|
+
<trigger>Level 3 피드백 발생</trigger>
|
|
246
|
+
|
|
247
|
+
<on-transition>
|
|
248
|
+
<action>User에게 승인 요청</action>
|
|
249
|
+
<action>피드백 내용 상세 보고</action>
|
|
250
|
+
</on-transition>
|
|
251
|
+
|
|
252
|
+
<next-state-options>
|
|
253
|
+
<option condition="User 승인">planning (수정 진행)</option>
|
|
254
|
+
<option condition="User 거부">blocked (재검토 필요)</option>
|
|
255
|
+
</next-state-options>
|
|
256
|
+
</transition>
|
|
257
|
+
|
|
258
|
+
<transition id="T-REG-004" type="regression">
|
|
259
|
+
<from>security</from>
|
|
260
|
+
<to>implementation</to>
|
|
261
|
+
<name>Low/Medium 보안 이슈 → 코드 수정</name>
|
|
262
|
+
<trigger>Low/Medium 보안 취약점</trigger>
|
|
263
|
+
</transition>
|
|
264
|
+
|
|
265
|
+
<transition id="T-REG-005" type="regression">
|
|
266
|
+
<from>security</from>
|
|
267
|
+
<to>planning</to>
|
|
268
|
+
<name>High 보안 이슈 → 설계 수정</name>
|
|
269
|
+
<trigger>High 보안 취약점 (설계 문제)</trigger>
|
|
270
|
+
</transition>
|
|
271
|
+
|
|
272
|
+
<transition id="T-REG-006" type="regression">
|
|
273
|
+
<from>security</from>
|
|
274
|
+
<to>waiting-approval</to>
|
|
275
|
+
<name>Critical 보안 이슈 → 긴급 보고</name>
|
|
276
|
+
<trigger>Critical 보안 취약점</trigger>
|
|
277
|
+
|
|
278
|
+
<on-transition>
|
|
279
|
+
<action>User에게 즉시 알림</action>
|
|
280
|
+
<action>배포 차단</action>
|
|
281
|
+
</on-transition>
|
|
282
|
+
</transition>
|
|
283
|
+
</transitions>
|
|
284
|
+
|
|
285
|
+
<!-- ============================================================
|
|
286
|
+
상태 파일 스키마
|
|
287
|
+
============================================================ -->
|
|
288
|
+
<state-file-schema>
|
|
289
|
+
<file-path>.timsquad/state/current-phase.json</file-path>
|
|
290
|
+
<schema>
|
|
291
|
+
<![CDATA[
|
|
292
|
+
{
|
|
293
|
+
"current_phase": "implementation",
|
|
294
|
+
"previous_phase": "planning",
|
|
295
|
+
"entered_at": "2026-02-03T10:00:00Z",
|
|
296
|
+
"transition_history": [
|
|
297
|
+
{
|
|
298
|
+
"from": "planning",
|
|
299
|
+
"to": "implementation",
|
|
300
|
+
"at": "2026-02-03T10:00:00Z",
|
|
301
|
+
"reason": "SSOT 완료, User 승인"
|
|
302
|
+
}
|
|
303
|
+
],
|
|
304
|
+
"pending_actions": [],
|
|
305
|
+
"blocked_by": null
|
|
306
|
+
}
|
|
307
|
+
]]>
|
|
308
|
+
</schema>
|
|
309
|
+
</state-file-schema>
|
|
310
|
+
|
|
311
|
+
<!-- ============================================================
|
|
312
|
+
User 개입 지점
|
|
313
|
+
============================================================ -->
|
|
314
|
+
<user-intervention-points>
|
|
315
|
+
<point id="UI-001">
|
|
316
|
+
<state>planning</state>
|
|
317
|
+
<event>SSOT 완료</event>
|
|
318
|
+
<action>승인 요청</action>
|
|
319
|
+
<description>기획 문서 완료 후 구현 진행 전 User 승인</description>
|
|
320
|
+
</point>
|
|
321
|
+
|
|
322
|
+
<point id="UI-002">
|
|
323
|
+
<state>review</state>
|
|
324
|
+
<event>Level 3 피드백</event>
|
|
325
|
+
<action>결정 요청</action>
|
|
326
|
+
<description>요구사항/비즈니스 로직 관련 결정 필요</description>
|
|
327
|
+
</point>
|
|
328
|
+
|
|
329
|
+
<point id="UI-003">
|
|
330
|
+
<state>security</state>
|
|
331
|
+
<event>Critical 취약점</event>
|
|
332
|
+
<action>긴급 알림</action>
|
|
333
|
+
<description>심각한 보안 이슈 즉시 보고</description>
|
|
334
|
+
</point>
|
|
335
|
+
|
|
336
|
+
<point id="UI-004">
|
|
337
|
+
<state>any</state>
|
|
338
|
+
<event>User 요청</event>
|
|
339
|
+
<action>즉시 응답</action>
|
|
340
|
+
<description>User는 언제든 개입 가능</description>
|
|
341
|
+
</point>
|
|
342
|
+
</user-intervention-points>
|
|
343
|
+
</state-machine>
|