create-claude-pipeline 0.1.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.
Files changed (76) hide show
  1. package/bin/cli.js +359 -0
  2. package/package.json +32 -0
  3. package/template/.claude/agents/be-developer.md +218 -0
  4. package/template/.claude/agents/designer.md +192 -0
  5. package/template/.claude/agents/fe-developer.md +175 -0
  6. package/template/.claude/agents/infra-developer.md +270 -0
  7. package/template/.claude/agents/planner.md +126 -0
  8. package/template/.claude/agents/pm.md +130 -0
  9. package/template/.claude/agents/qa-engineer.md +270 -0
  10. package/template/.claude/agents/security-reviewer.md +281 -0
  11. package/template/.claude/settings.json +5 -0
  12. package/template/.claude/skills/analyze-requirements/SKILL.md +166 -0
  13. package/template/.claude/skills/api-integration/SKILL.md +354 -0
  14. package/template/.claude/skills/assemble-context/SKILL.md +192 -0
  15. package/template/.claude/skills/db-migration/SKILL.md +228 -0
  16. package/template/.claude/skills/explore-be-codebase/SKILL.md +260 -0
  17. package/template/.claude/skills/explore-codebase/SKILL.md +190 -0
  18. package/template/.claude/skills/explore-design-system/SKILL.md +150 -0
  19. package/template/.claude/skills/explore-fe-codebase/SKILL.md +209 -0
  20. package/template/.claude/skills/explore-implementation/SKILL.md +147 -0
  21. package/template/.claude/skills/explore-infra/SKILL.md +242 -0
  22. package/template/.claude/skills/implement-api/SKILL.md +477 -0
  23. package/template/.claude/skills/implement-components/SKILL.md +217 -0
  24. package/template/.claude/skills/review-auth/SKILL.md +175 -0
  25. package/template/.claude/skills/scan-vulnerabilities/SKILL.md +200 -0
  26. package/template/.claude/skills/write-cicd/SKILL.md +293 -0
  27. package/template/.claude/skills/write-design-spec/SKILL.md +363 -0
  28. package/template/.claude/skills/write-dockerfile/SKILL.md +269 -0
  29. package/template/.claude/skills/write-plan-doc/SKILL.md +164 -0
  30. package/template/.claude/skills/write-plan-doc/assets/plan_template.html +251 -0
  31. package/template/.claude/skills/write-qa-report/SKILL.md +151 -0
  32. package/template/.claude/skills/write-security-report/SKILL.md +185 -0
  33. package/template/.claude/skills/write-test-cases/SKILL.md +234 -0
  34. package/template/.claude-pipeline/dashboard/.env.example +1 -0
  35. package/template/.claude-pipeline/dashboard/.eslintrc.json +3 -0
  36. package/template/.claude-pipeline/dashboard/README.md +36 -0
  37. package/template/.claude-pipeline/dashboard/next.config.mjs +6 -0
  38. package/template/.claude-pipeline/dashboard/package-lock.json +8148 -0
  39. package/template/.claude-pipeline/dashboard/package.json +36 -0
  40. package/template/.claude-pipeline/dashboard/postcss.config.mjs +8 -0
  41. package/template/.claude-pipeline/dashboard/server.ts +24 -0
  42. package/template/.claude-pipeline/dashboard/src/app/api/pipelines/[id]/checkpoint/route.ts +23 -0
  43. package/template/.claude-pipeline/dashboard/src/app/api/pipelines/[id]/outputs/[...filepath]/route.ts +18 -0
  44. package/template/.claude-pipeline/dashboard/src/app/api/pipelines/[id]/route.ts +10 -0
  45. package/template/.claude-pipeline/dashboard/src/app/api/pipelines/route.ts +64 -0
  46. package/template/.claude-pipeline/dashboard/src/app/favicon.ico +0 -0
  47. package/template/.claude-pipeline/dashboard/src/app/fonts/GeistMonoVF.woff +0 -0
  48. package/template/.claude-pipeline/dashboard/src/app/fonts/GeistVF.woff +0 -0
  49. package/template/.claude-pipeline/dashboard/src/app/globals.css +52 -0
  50. package/template/.claude-pipeline/dashboard/src/app/layout.tsx +33 -0
  51. package/template/.claude-pipeline/dashboard/src/app/page.tsx +49 -0
  52. package/template/.claude-pipeline/dashboard/src/app/pipeline/[id]/page.tsx +84 -0
  53. package/template/.claude-pipeline/dashboard/src/components/agent-card.tsx +40 -0
  54. package/template/.claude-pipeline/dashboard/src/components/agent-logs.tsx +65 -0
  55. package/template/.claude-pipeline/dashboard/src/components/artifact-viewer.tsx +130 -0
  56. package/template/.claude-pipeline/dashboard/src/components/checkpoint-banner.tsx +59 -0
  57. package/template/.claude-pipeline/dashboard/src/components/new-pipeline-modal.tsx +63 -0
  58. package/template/.claude-pipeline/dashboard/src/components/output-list.tsx +57 -0
  59. package/template/.claude-pipeline/dashboard/src/components/phase-dots.tsx +37 -0
  60. package/template/.claude-pipeline/dashboard/src/components/pipeline-card.tsx +53 -0
  61. package/template/.claude-pipeline/dashboard/src/components/resizable-panels.tsx +91 -0
  62. package/template/.claude-pipeline/dashboard/src/hooks/use-pipeline-detail.ts +65 -0
  63. package/template/.claude-pipeline/dashboard/src/hooks/use-pipelines.ts +60 -0
  64. package/template/.claude-pipeline/dashboard/src/hooks/use-websocket.ts +58 -0
  65. package/template/.claude-pipeline/dashboard/src/lib/agents.ts +30 -0
  66. package/template/.claude-pipeline/dashboard/src/lib/checkpoint.ts +37 -0
  67. package/template/.claude-pipeline/dashboard/src/lib/pipelines.ts +91 -0
  68. package/template/.claude-pipeline/dashboard/src/lib/watcher.ts +90 -0
  69. package/template/.claude-pipeline/dashboard/src/lib/ws-server.ts +123 -0
  70. package/template/.claude-pipeline/dashboard/src/types/pipeline.ts +61 -0
  71. package/template/.claude-pipeline/dashboard/tailwind.config.ts +31 -0
  72. package/template/.claude-pipeline/dashboard/tsconfig.json +26 -0
  73. package/template/CLAUDE.md +301 -0
  74. package/template/references/context-structure.md +34 -0
  75. package/template/references/pm-context-assembly.md +34 -0
  76. package/template/references/task-context-template.md +65 -0
@@ -0,0 +1,354 @@
1
+ ---
2
+ name: api-integration
3
+ description: "FE 개발자가 BE API를 연동할 때 일관된 패턴을 유지하기 위해 참조하는 skill. 커스텀 훅 작성, 에러 핸들링, 타입 정의 방법을 제공한다. API 연동 코드를 작성하거나, 새 API 엔드포인트를 프론트엔드에 붙이거나, 에러 핸들링 로직을 구현할 때 반드시 사용한다. 'API 연동', 'API 호출', '에러 처리', 'useQuery', 'useMutation', 'fetch 함수 작성' 등의 상황에서 트리거된다."
4
+ ---
5
+
6
+ # API Integration
7
+
8
+ FE 개발자가 BE API를 연동할 때 따르는 패턴이다.
9
+
10
+ API 연동은 "타입 → API 함수 → 커스텀 훅 → 에러 핸들링" 순서로 진행한다. 이 순서가 중요한 이유는, 타입을 먼저 정의해야 API 함수와 훅에서 타입 안전성을 확보할 수 있고, 에러 핸들링을 마지막에 일괄 적용해야 누락 없이 모든 API 호출을 커버할 수 있기 때문이다.
11
+
12
+ ---
13
+
14
+ ## STEP 1: 타입 정의
15
+
16
+ API 명세(`context/03_api_spec.md`)를 읽고 각 엔드포인트의 타입을 정의한다.
17
+
18
+ 모든 API 호출에는 3종류의 타입이 필요하다:
19
+
20
+ ```tsx
21
+ // types/[feature].ts
22
+
23
+ // Request — API에 보내는 데이터
24
+ export interface CreateOrderRequest {
25
+ productId: string;
26
+ quantity: number;
27
+ shippingAddress: string;
28
+ }
29
+
30
+ // Response — API에서 받는 데이터
31
+ export interface Order {
32
+ id: string;
33
+ productId: string;
34
+ quantity: number;
35
+ status: "pending" | "confirmed" | "shipped" | "delivered";
36
+ totalPrice: number;
37
+ createdAt: string;
38
+ }
39
+
40
+ // Error — API 에러 응답 구조
41
+ export interface ApiError {
42
+ statusCode: number;
43
+ message: string;
44
+ code?: string; // 비즈니스 에러 코드 (예: "INSUFFICIENT_STOCK")
45
+ }
46
+ ```
47
+
48
+ **판단 기준:**
49
+ - GET 요청은 query params 타입 + Response 타입
50
+ - POST/PUT 요청은 Request body 타입 + Response 타입
51
+ - 공통 에러 타입은 프로젝트에 하나만 정의하고 재사용한다
52
+
53
+ 기존 프로젝트에 이미 `ApiError` 타입이 있으면 그것을 사용한다.
54
+
55
+ ---
56
+
57
+ ## STEP 2: API 함수 작성
58
+
59
+ `lib/api/` 또는 `services/` 디렉토리에 API 함수를 작성한다. 기존 프로젝트의 디렉토리 구조를 따른다.
60
+
61
+ ```tsx
62
+ // lib/api/orders.ts
63
+ import { apiClient } from "./client";
64
+ import type { CreateOrderRequest, Order } from "@/types/order";
65
+
66
+ // GET — 목록 조회
67
+ export async function fetchOrders(): Promise<Order[]> {
68
+ const { data } = await apiClient.get<Order[]>("/orders");
69
+ return data;
70
+ }
71
+
72
+ // GET — 단건 조회
73
+ export async function fetchOrder(id: string): Promise<Order> {
74
+ const { data } = await apiClient.get<Order>(`/orders/${id}`);
75
+ return data;
76
+ }
77
+
78
+ // POST — 생성
79
+ export async function createOrder(input: CreateOrderRequest): Promise<Order> {
80
+ const { data } = await apiClient.post<Order>("/orders", input);
81
+ return data;
82
+ }
83
+
84
+ // PUT — 수정
85
+ export async function updateOrder(id: string, input: Partial<CreateOrderRequest>): Promise<Order> {
86
+ const { data } = await apiClient.put<Order>(`/orders/${id}`, input);
87
+ return data;
88
+ }
89
+
90
+ // DELETE — 삭제
91
+ export async function deleteOrder(id: string): Promise<void> {
92
+ await apiClient.delete(`/orders/${id}`);
93
+ }
94
+ ```
95
+
96
+ **핵심 원칙:**
97
+ - 성공 응답에 반드시 타입을 지정한다 (`apiClient.get<Order[]>`)
98
+ - 에러는 throw해서 상위(훅)로 전달한다 — API 함수에서 try/catch하지 않는다
99
+ - URL path에 변수가 들어가면 template literal을 사용한다
100
+
101
+ ---
102
+
103
+ ## STEP 3: 커스텀 훅으로 감싸기
104
+
105
+ 컴포넌트에서 API 함수를 직접 호출하지 않는다. 반드시 커스텀 훅으로 감싼다.
106
+
107
+ 프로젝트에 사용 중인 데이터 fetching 라이브러리에 따라 패턴이 달라진다. 기존 프로젝트를 확인하고 해당 패턴을 사용한다.
108
+
109
+ ### React Query (TanStack Query) 사용 시
110
+
111
+ ```tsx
112
+ // hooks/useOrders.ts
113
+ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
114
+ import { fetchOrders, fetchOrder, createOrder, deleteOrder } from "@/lib/api/orders";
115
+ import type { CreateOrderRequest } from "@/types/order";
116
+
117
+ // GET → useQuery
118
+ export function useOrders() {
119
+ return useQuery({
120
+ queryKey: ["orders"],
121
+ queryFn: fetchOrders,
122
+ });
123
+ }
124
+
125
+ export function useOrder(id: string) {
126
+ return useQuery({
127
+ queryKey: ["orders", id],
128
+ queryFn: () => fetchOrder(id),
129
+ enabled: !!id, // id가 없으면 요청하지 않음
130
+ });
131
+ }
132
+
133
+ // POST/PUT/DELETE → useMutation
134
+ export function useCreateOrder() {
135
+ const queryClient = useQueryClient();
136
+
137
+ return useMutation({
138
+ mutationFn: (input: CreateOrderRequest) => createOrder(input),
139
+ onSuccess: () => {
140
+ queryClient.invalidateQueries({ queryKey: ["orders"] });
141
+ },
142
+ });
143
+ }
144
+
145
+ export function useDeleteOrder() {
146
+ const queryClient = useQueryClient();
147
+
148
+ return useMutation({
149
+ mutationFn: (id: string) => deleteOrder(id),
150
+ onSuccess: () => {
151
+ queryClient.invalidateQueries({ queryKey: ["orders"] });
152
+ },
153
+ });
154
+ }
155
+ ```
156
+
157
+ ### SWR 사용 시
158
+
159
+ ```tsx
160
+ // hooks/useOrders.ts
161
+ import useSWR from "swr";
162
+ import useSWRMutation from "swr/mutation";
163
+ import { fetchOrders, createOrder } from "@/lib/api/orders";
164
+ import type { CreateOrderRequest } from "@/types/order";
165
+
166
+ // GET → useSWR
167
+ export function useOrders() {
168
+ return useSWR("orders", fetchOrders);
169
+ }
170
+
171
+ // POST/PUT/DELETE → useSWRMutation
172
+ export function useCreateOrder() {
173
+ return useSWRMutation(
174
+ "orders",
175
+ (_key: string, { arg }: { arg: CreateOrderRequest }) => createOrder(arg)
176
+ );
177
+ }
178
+ ```
179
+
180
+ ### 라이브러리 없이 직접 구현 시
181
+
182
+ ```tsx
183
+ // hooks/useOrders.ts
184
+ import { useState, useEffect } from "react";
185
+ import { fetchOrders } from "@/lib/api/orders";
186
+ import type { Order } from "@/types/order";
187
+
188
+ export function useOrders() {
189
+ const [data, setData] = useState<Order[] | null>(null);
190
+ const [isLoading, setIsLoading] = useState(true);
191
+ const [error, setError] = useState<Error | null>(null);
192
+
193
+ useEffect(() => {
194
+ fetchOrders()
195
+ .then(setData)
196
+ .catch(setError)
197
+ .finally(() => setIsLoading(false));
198
+ }, []);
199
+
200
+ return { data, isLoading, error };
201
+ }
202
+ ```
203
+
204
+ **반환값 규칙:**
205
+
206
+ 모든 커스텀 훅은 컴포넌트가 필요한 3가지를 반환한다:
207
+ - `data` — 응답 데이터 (로딩 중이면 `undefined` 또는 `null`)
208
+ - `isLoading` — 로딩 중 여부
209
+ - `isError` 또는 `error` — 에러 발생 여부
210
+
211
+ 이 3가지가 있어야 컴포넌트에서 Loading/Error/Empty/Success 4상태를 처리할 수 있다.
212
+
213
+ ---
214
+
215
+ ## STEP 4: 에러 핸들링
216
+
217
+ 에러 핸들링은 두 레이어로 구성한다: **글로벌 인터셉터** (공통 에러)와 **컴포넌트 레벨** (개별 에러).
218
+
219
+ ### 글로벌 인터셉터
220
+
221
+ HTTP 상태 코드별 공통 처리를 API 클라이언트에 설정한다. 모든 API 호출에 자동 적용되므로 개별 컴포넌트에서 반복하지 않아도 된다.
222
+
223
+ ```tsx
224
+ // lib/api/client.ts
225
+ import axios from "axios";
226
+
227
+ export const apiClient = axios.create({
228
+ baseURL: process.env.NEXT_PUBLIC_API_URL || "/api",
229
+ timeout: 10000,
230
+ });
231
+
232
+ apiClient.interceptors.response.use(
233
+ (response) => response,
234
+ (error) => {
235
+ const status = error.response?.status;
236
+
237
+ // 401 Unauthorized → 로그인 페이지로 리다이렉트
238
+ if (status === 401) {
239
+ window.location.href = "/login";
240
+ return Promise.reject(error);
241
+ }
242
+
243
+ // 403 Forbidden → 권한 없음 알림
244
+ // toast는 기존 프로젝트의 토스트 라이브러리를 사용한다
245
+ // (react-hot-toast, sonner, react-toastify 등)
246
+ if (status === 403) {
247
+ toast.error("접근 권한이 없습니다.");
248
+ return Promise.reject(error);
249
+ }
250
+
251
+ // 네트워크 오류 (서버 응답 자체가 없는 경우)
252
+ if (!error.response) {
253
+ toast.error("네트워크 연결을 확인해주세요.");
254
+ return Promise.reject(error);
255
+ }
256
+
257
+ // 그 외 에러는 상위로 전달 (컴포넌트에서 처리)
258
+ return Promise.reject(error);
259
+ }
260
+ );
261
+ ```
262
+
263
+ ### 에러 핸들링 기준표
264
+
265
+ | 상태 코드 | 처리 방식 | 처리 위치 |
266
+ |-----------|-----------|-----------|
267
+ | 401 Unauthorized | 로그인 페이지로 리다이렉트 | 글로벌 인터셉터 |
268
+ | 403 Forbidden | 권한 없음 토스트 | 글로벌 인터셉터 |
269
+ | 404 Not Found | 빈 상태 UI 표시 | 컴포넌트 |
270
+ | 422 Validation Error | 폼 필드별 에러 메시지 | 컴포넌트 |
271
+ | 500 Internal Server Error | 에러 상태 UI + 재시도 버튼 | 컴포넌트 |
272
+ | 네트워크 오류 | 연결 확인 토스트 | 글로벌 인터셉터 |
273
+
274
+ ### 컴포넌트 레벨 에러 처리
275
+
276
+ 글로벌 인터셉터가 처리하지 않는 에러(404, 422, 500)는 컴포넌트에서 처리한다.
277
+
278
+ ```tsx
279
+ // 404 — 빈 상태 UI
280
+ export function OrderDetail({ orderId }: { orderId: string }) {
281
+ const { data, isLoading, error } = useOrder(orderId);
282
+
283
+ if (isLoading) return <OrderDetailSkeleton />;
284
+
285
+ if (error?.response?.status === 404) {
286
+ return <EmptyState message="주문을 찾을 수 없습니다." />;
287
+ }
288
+
289
+ if (error) {
290
+ return (
291
+ <ErrorMessage
292
+ message="주문 정보를 불러올 수 없습니다."
293
+ onRetry={() => window.location.reload()}
294
+ />
295
+ );
296
+ }
297
+
298
+ return <OrderInfo order={data} />;
299
+ }
300
+ ```
301
+
302
+ ```tsx
303
+ // 422 — 폼 유효성 에러
304
+ export function CreateOrderForm() {
305
+ const { mutate, isPending, error } = useCreateOrder();
306
+
307
+ const fieldErrors = error?.response?.status === 422
308
+ ? error.response.data.errors
309
+ : {};
310
+
311
+ return (
312
+ <form onSubmit={(e) => { e.preventDefault(); mutate(formData); }}>
313
+ <Input
314
+ name="quantity"
315
+ error={fieldErrors?.quantity}
316
+ />
317
+ <Button type="submit" loading={isPending}>주문하기</Button>
318
+ </form>
319
+ );
320
+ }
321
+ ```
322
+
323
+ ```tsx
324
+ // 500 — 에러 UI + 재시도
325
+ // useQuery의 refetch 또는 직접 재호출로 재시도한다
326
+ export function OrderList() {
327
+ const { data, isLoading, error, refetch } = useOrders();
328
+
329
+ if (error) {
330
+ return (
331
+ <ErrorMessage
332
+ message="서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요."
333
+ onRetry={refetch}
334
+ />
335
+ );
336
+ }
337
+
338
+ // ...
339
+ }
340
+ ```
341
+
342
+ ---
343
+
344
+ ## 구현 순서 체크리스트
345
+
346
+ API 연동 시 아래 순서로 진행한다:
347
+
348
+ 1. [ ] `context/03_api_spec.md`에서 연동할 엔드포인트 확인
349
+ 2. [ ] `types/`에 Request / Response / Error 타입 정의
350
+ 3. [ ] `lib/api/`에 API 함수 작성 (타입 지정, 에러는 throw)
351
+ 4. [ ] `hooks/`에 커스텀 훅 작성 (useQuery / useMutation)
352
+ 5. [ ] 글로벌 에러 인터셉터 확인 (이미 있으면 스킵)
353
+ 6. [ ] 컴포넌트에서 훅 호출 + 4상태 처리 (Loading/Error/Empty/Success)
354
+ 7. [ ] 에러 시나리오별 UI 동작 확인 (401/403/404/500/네트워크)
@@ -0,0 +1,192 @@
1
+ ---
2
+ name: assemble-context
3
+ description: "PM이 PHASE 3 진입 시 각 Agent에게 작업을 넘기기 전에 context/ 폴더의 산출물들(00_requirements.md, 01_plan.md, 02_design_spec.md, 03_api_spec.md 등)을 읽어서 Agent별 task 파일(04_task_*.md)을 조립할 때 사용하는 skill. 'task context 조립', '04_task 파일 생성', 'Agent에게 작업 넘기기', 'Phase 3 시작' 등의 상황에서 반드시 사용한다. QA Phase(Phase 4)에서 04_task_QA.md를 생성할 때도 이 skill을 사용한다."
4
+ ---
5
+
6
+ # Assemble Context
7
+
8
+ PM Agent가 Phase 0~2 산출물을 조합하여 각 실행 Agent에게 전달할 `04_task_*.md` 파일을 조립하는 skill이다.
9
+
10
+ 핵심 원칙은 **자족성(self-contained)**이다. 각 Agent는 자신의 task 파일 하나만 읽으면 작업에 필요한 모든 정보가 담겨 있어야 한다. 외부 파일을 추가로 참조할 필요가 없어야 한다.
11
+
12
+ ---
13
+
14
+ ## 조립 절차
15
+
16
+ ### Step 1: 소스 파일 읽기
17
+
18
+ `context/` 폴더에서 아래 파일들을 읽는다. 파일이 없으면 해당 섹션은 건너뛴다.
19
+
20
+ | 파일 | 용도 | 필수 여부 |
21
+ |------|------|-----------|
22
+ | `context/00_requirements.md` | Section 1(프로젝트 현황), Section 2(요구사항) | **필수** |
23
+ | `context/01_plan.md` | Section 3(기획안 요약) | 있으면 포함 |
24
+ | `context/02_design_spec.md` | Section 5 참고 자료 (FE, QA용) | 있으면 포함 |
25
+ | `context/03_api_spec.md` | Section 5 참고 자료 (BE, FE, QA용) | 있으면 포함 |
26
+ | `context/03_erd.md` | Section 5 참고 자료 (BE, Infra용) | 있으면 포함 |
27
+
28
+ `00_requirements.md`가 없으면 조립을 중단하고 사용자에게 "Phase 0이 아직 완료되지 않았습니다"라고 알린다.
29
+
30
+ ### Step 2: 대상 Agent 확인
31
+
32
+ 호출 시 전달받은 Agent 목록을 확인한다. 일반적으로 `00_requirements.md`의 "필요 Agent" 섹션에 명시되어 있다.
33
+
34
+ 가능한 Agent 유형:
35
+ - **FE** — 프론트엔드 개발
36
+ - **BE** — 백엔드 개발
37
+ - **INFRA** — 인프라/DevOps
38
+ - **QA** — QA/테스트 (Phase 4에서 생성할 수도 있음)
39
+
40
+ ### Step 3: 공통 섹션 조립 (Section 1~3)
41
+
42
+ 모든 Agent에게 동일하게 들어가는 내용을 먼저 구성한다.
43
+
44
+ ```markdown
45
+ # TASK CONTEXT
46
+
47
+ ## 1. 프로젝트 현황
48
+ ```
49
+
50
+ `00_requirements.md`에서 서비스명, 기술 스택, 현재 서비스 상태 정보를 추출하여 작성한다. 코드베이스 탐색 결과가 있다면 그것도 반영한다.
51
+
52
+ ```markdown
53
+ ## 2. 이번 요구사항
54
+ ```
55
+
56
+ `00_requirements.md`의 요청 내용과 분석 결과(작업 유형, 영향 범위)를 그대로 포함한다.
57
+
58
+ ```markdown
59
+ ## 3. 기획안 요약
60
+ ```
61
+
62
+ `01_plan.md`의 핵심 내용을 요약하여 포함한다. 기능 명세, 화면 목록, API 목록, 엣지케이스 등을 포함한다. `01_plan.md`가 없으면 이 섹션은 "(기획안 없음 — 요구사항 기반으로 작업)" 으로 표기한다.
63
+
64
+ ### Step 4: Agent별 섹션 조립 (Section 4~5)
65
+
66
+ 각 Agent의 역할에 맞게 작업 지시와 참고 자료를 작성한다.
67
+
68
+ #### Section 4: 네 역할과 작업 지시
69
+
70
+ Agent마다 아래 항목을 구체적으로 작성한다:
71
+
72
+ | 항목 | 설명 |
73
+ |------|------|
74
+ | **역할** | 이 Agent가 맡은 역할 (예: 프론트엔드 개발자) |
75
+ | **해야 할 일** | 구체적인 작업 목록 (체크리스트 형태 권장) |
76
+ | **산출물 형식** | 무엇을 만들어야 하는지 (파일, 컴포넌트, API 등) |
77
+ | **완료 기준** | 이 작업이 "끝났다"의 기준 |
78
+ | **건드리면 안 되는 것** | 이 Agent의 관할 밖인 것을 명시 |
79
+
80
+ **Agent별 작성 가이드:**
81
+
82
+ **FE Agent** — `02_design_spec.md`의 화면 시안과 컴포넌트 구조를 기반으로 해야 할 일을 도출한다. API 명세에서 FE가 호출해야 할 엔드포인트 목록도 포함한다.
83
+
84
+ **BE Agent** — `03_api_spec.md`의 API 명세와 `03_erd.md`의 DB 스키마를 기반으로 해야 할 일을 도출한다. 각 엔드포인트의 요청/응답 형식, 비즈니스 로직, 에러 처리를 포함한다.
85
+
86
+ **INFRA Agent** — DB 마이그레이션, Docker 설정 변경, CI/CD 파이프라인 수정 등 인프라 관련 작업을 도출한다.
87
+
88
+ **QA Agent** — 기획안의 기능 명세와 엣지케이스를 기반으로 테스트 항목을 도출한다. FE/BE 구현 결과물을 검증하는 관점에서 작성한다.
89
+
90
+ #### Section 5: 참고 파일
91
+
92
+ Agent가 작업 중 참조해야 할 정보를 **인라인으로 포함**한다. 파일 경로만 나열하는 것이 아니라, 해당 Agent에게 필요한 부분을 발췌하여 직접 넣는다.
93
+
94
+ **Agent별 참고 자료 선별 기준:**
95
+
96
+ | Agent | 포함하는 것 | 포함하지 않는 것 |
97
+ |-------|------------|----------------|
98
+ | FE | 화면 시안, 컴포넌트 구조, 호출할 API 목록(엔드포인트+요청/응답) | ERD, DB 스키마, 인프라 설정 |
99
+ | BE | API 명세 전체, ERD/DB 스키마, 비즈니스 로직 규칙 | 화면 시안, CSS 구조 |
100
+ | INFRA | DB 스키마(마이그레이션용), 배포 관련 설정, 환경 변수 목록 | 화면 시안, 상세 API 로직 |
101
+ | QA | 기능 명세, 화면 플로우, API 엔드포인트 목록, 엣지케이스 목록 | DB 스키마 상세, 인프라 설정 |
102
+
103
+ ### Step 5: 파일 저장
104
+
105
+ 완성된 task 파일을 `context/` 폴더에 저장한다:
106
+
107
+ ```
108
+ context/04_task_FE.md
109
+ context/04_task_BE.md
110
+ context/04_task_INFRA.md
111
+ context/04_task_QA.md
112
+ ```
113
+
114
+ 필요한 Agent의 파일만 생성한다. 예를 들어 FE만 필요한 작업이면 `04_task_FE.md`만 생성한다.
115
+
116
+ 기존 `04_task_*.md`가 있으면 덮어쓰기 전에 사용자에게 확인한다.
117
+
118
+ ### Step 6: 결과 보고
119
+
120
+ 생성 완료 후 아래 형식으로 보고한다:
121
+
122
+ ```
123
+ Task Context 조립 완료:
124
+ - context/04_task_FE.md ✓
125
+ - context/04_task_BE.md ✓
126
+ - context/04_task_QA.md ✓
127
+
128
+ 각 파일의 Section 구성:
129
+ Section 1~3: 공통 (프로젝트 현황, 요구사항, 기획안)
130
+ Section 4: Agent별 작업 지시
131
+ Section 5: Agent별 참고 자료
132
+ ```
133
+
134
+ ---
135
+
136
+ ## 완성 파일 구조 예시
137
+
138
+ ```markdown
139
+ # TASK CONTEXT
140
+
141
+ ## 1. 프로젝트 현황
142
+ - 서비스명: MyApp
143
+ - 기술 스택: React + NestJS + PostgreSQL
144
+ - 현재 단계: MVP 운영 중
145
+
146
+ ## 2. 이번 요구사항
147
+ - 작업 유형: 기능 수정
148
+ - 영향 범위: FE, BE
149
+ - 내용: 소셜 로그인(Google, Kakao) 추가
150
+
151
+ ## 3. 기획안 요약
152
+ - Google/Kakao OAuth 2.0 연동
153
+ - 기존 이메일 로그인과 병행 운영
154
+ - 소셜 계정으로 첫 로그인 시 자동 회원가입
155
+ - 엣지케이스: 같은 이메일로 이메일 가입 + 소셜 가입 시 계정 연동
156
+
157
+ ## 4. 네 역할과 작업 지시
158
+ - 역할: 프론트엔드 개발자
159
+ - 해야 할 일:
160
+ - [ ] 로그인 페이지에 Google/Kakao 소셜 로그인 버튼 추가
161
+ - [ ] OAuth 리다이렉트 콜백 페이지 구현
162
+ - [ ] 소셜 로그인 상태 관리 (토큰 저장/갱신)
163
+ - 산출물: React 컴포넌트 + OAuth 콜백 페이지
164
+ - 완료 기준: 소셜 로그인 버튼 클릭 → OAuth 인증 → 토큰 수신 → 로그인 완료
165
+ - 건드리면 안 되는 것: API 서버 코드, DB 스키마
166
+
167
+ ## 5. 참고 파일
168
+
169
+ ### 화면 시안
170
+ (02_design_spec.md에서 발췌한 로그인 화면 관련 내용)
171
+
172
+ ### 호출할 API
173
+ | Method | Endpoint | 설명 |
174
+ |--------|----------|------|
175
+ | GET | /auth/google | Google OAuth 시작 |
176
+ | GET | /auth/google/callback | Google 콜백 처리 |
177
+ | GET | /auth/kakao | Kakao OAuth 시작 |
178
+ | GET | /auth/kakao/callback | Kakao 콜백 처리 |
179
+ ```
180
+
181
+ ---
182
+
183
+ ## 품질 체크리스트
184
+
185
+ 파일을 저장하기 전에 점검한다:
186
+
187
+ - [ ] `00_requirements.md`를 읽었는가?
188
+ - [ ] Section 1~3이 모든 Agent 파일에서 동일한가?
189
+ - [ ] Section 4의 "해야 할 일"이 구체적이고 체크리스트 형태인가?
190
+ - [ ] Section 5에 경로만 나열하지 않고 실제 내용을 발췌했는가?
191
+ - [ ] 각 Agent에게 불필요한 정보를 포함하지 않았는가? (FE에게 ERD 등)
192
+ - [ ] Agent가 이 파일 하나만 읽으면 작업을 시작할 수 있는가? (자족성)