@wooojin/forgen 0.4.7 → 0.4.9

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 (159) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +40 -0
  3. package/assets/dev-guide/be/README.md +226 -0
  4. package/assets/dev-guide/be/adapters/build-agents-md.sh +63 -0
  5. package/assets/dev-guide/be/principles/common.md +433 -0
  6. package/assets/dev-guide/be/principles/go.md +469 -0
  7. package/assets/dev-guide/be/principles/node.md +388 -0
  8. package/assets/dev-guide/be/skills/go/be-build/SKILL.md +262 -0
  9. package/assets/dev-guide/be/skills/go/be-perf/SKILL.md +308 -0
  10. package/assets/dev-guide/be/skills/go/be-review/SKILL.md +119 -0
  11. package/assets/dev-guide/be/skills/go/be-security/SKILL.md +362 -0
  12. package/assets/dev-guide/be/skills/node/be-build/SKILL.md +239 -0
  13. package/assets/dev-guide/be/skills/node/be-perf/SKILL.md +272 -0
  14. package/assets/dev-guide/be/skills/node/be-review/SKILL.md +118 -0
  15. package/assets/dev-guide/be/skills/node/be-security/SKILL.md +355 -0
  16. package/assets/dev-guide/be/sources/12factor/INDEX.md +53 -0
  17. package/assets/dev-guide/be/sources/api-design/INDEX.md +56 -0
  18. package/assets/dev-guide/be/sources/ddia/INDEX.md +55 -0
  19. package/assets/dev-guide/be/sources/go-runtime/INDEX.md +62 -0
  20. package/assets/dev-guide/be/sources/node-runtime/INDEX.md +60 -0
  21. package/assets/dev-guide/be/sources/otel/INDEX.md +53 -0
  22. package/assets/dev-guide/be/sources/owasp-api/INDEX.md +52 -0
  23. package/assets/dev-guide/be/sources/postgres/INDEX.md +55 -0
  24. package/assets/dev-guide/be/sources/sre-book/INDEX.md +48 -0
  25. package/assets/dev-guide/fe/README.md +197 -0
  26. package/assets/dev-guide/fe/adapters/build-agents-md.sh +63 -0
  27. package/assets/dev-guide/fe/adapters/refresh.sh +68 -0
  28. package/assets/dev-guide/fe/principles/common.md +160 -0
  29. package/assets/dev-guide/fe/principles/react.md +183 -0
  30. package/assets/dev-guide/fe/principles/vue.md +196 -0
  31. package/assets/dev-guide/fe/skills/react/fe-build/SKILL.md +139 -0
  32. package/assets/dev-guide/fe/skills/react/fe-perf/SKILL.md +179 -0
  33. package/assets/dev-guide/fe/skills/react/fe-review/SKILL.md +141 -0
  34. package/assets/dev-guide/fe/skills/vue/fe-build/SKILL.md +148 -0
  35. package/assets/dev-guide/fe/skills/vue/fe-perf/SKILL.md +163 -0
  36. package/assets/dev-guide/fe/skills/vue/fe-review/SKILL.md +136 -0
  37. package/assets/dev-guide/fe/sources/a11y-dx/INDEX.md +41 -0
  38. package/assets/dev-guide/fe/sources/a11y-dx/chrome-devtools-memory.md +150 -0
  39. package/assets/dev-guide/fe/sources/a11y-dx/chrome-devtools-performance.md +99 -0
  40. package/assets/dev-guide/fe/sources/a11y-dx/lighthouse-audits.md +146 -0
  41. package/assets/dev-guide/fe/sources/a11y-dx/react-devtools-profiler.md +128 -0
  42. package/assets/dev-guide/fe/sources/a11y-dx/wcag22-new-criteria.md +174 -0
  43. package/assets/dev-guide/fe/sources/perf/01-core-web-vitals.md +58 -0
  44. package/assets/dev-guide/fe/sources/perf/02-inp.md +83 -0
  45. package/assets/dev-guide/fe/sources/perf/03-lcp-cls.md +130 -0
  46. package/assets/dev-guide/fe/sources/perf/04-speculation-rules.md +148 -0
  47. package/assets/dev-guide/fe/sources/perf/05-view-transitions.md +153 -0
  48. package/assets/dev-guide/fe/sources/perf/06-nextjs-caching.md +188 -0
  49. package/assets/dev-guide/fe/sources/perf/07-server-components.md +181 -0
  50. package/assets/dev-guide/fe/sources/perf/08-ppr.md +133 -0
  51. package/assets/dev-guide/fe/sources/perf/09-nextjs-image.md +200 -0
  52. package/assets/dev-guide/fe/sources/perf/10-optimize-lcp.md +201 -0
  53. package/assets/dev-guide/fe/sources/perf/INDEX.md +88 -0
  54. package/assets/dev-guide/fe/sources/react/INDEX.md +41 -0
  55. package/assets/dev-guide/fe/sources/react/keeping-components-pure.md +135 -0
  56. package/assets/dev-guide/fe/sources/react/no-effect-patterns.md +183 -0
  57. package/assets/dev-guide/fe/sources/react/react-compiler.md +182 -0
  58. package/assets/dev-guide/fe/sources/react/server-components.md +194 -0
  59. package/assets/dev-guide/fe/sources/react/server-functions.md +192 -0
  60. package/assets/dev-guide/fe/sources/react/suspense.md +218 -0
  61. package/assets/dev-guide/fe/sources/react/use-action-state.md +123 -0
  62. package/assets/dev-guide/fe/sources/react/use-form-status.md +158 -0
  63. package/assets/dev-guide/fe/sources/react/use-hook.md +153 -0
  64. package/assets/dev-guide/fe/sources/react/use-optimistic.md +194 -0
  65. package/assets/dev-guide/fe/sources/toss-ff/INDEX.md +58 -0
  66. package/assets/dev-guide/fe/sources/toss-ff/cohesion-code-directory.md +79 -0
  67. package/assets/dev-guide/fe/sources/toss-ff/cohesion-form-fields.md +110 -0
  68. package/assets/dev-guide/fe/sources/toss-ff/cohesion-magic-number.md +47 -0
  69. package/assets/dev-guide/fe/sources/toss-ff/coupling-item-edit-modal.md +124 -0
  70. package/assets/dev-guide/fe/sources/toss-ff/coupling-use-bottom-sheet.md +57 -0
  71. package/assets/dev-guide/fe/sources/toss-ff/coupling-use-page-state.md +71 -0
  72. package/assets/dev-guide/fe/sources/toss-ff/overview-4-principles.md +77 -0
  73. package/assets/dev-guide/fe/sources/toss-ff/predictability-hidden-logic.md +59 -0
  74. package/assets/dev-guide/fe/sources/toss-ff/predictability-http.md +77 -0
  75. package/assets/dev-guide/fe/sources/toss-ff/predictability-use-user.md +110 -0
  76. package/assets/dev-guide/fe/sources/toss-ff/readability-comparison-order.md +52 -0
  77. package/assets/dev-guide/fe/sources/toss-ff/readability-condition-name.md +64 -0
  78. package/assets/dev-guide/fe/sources/toss-ff/readability-login-start-page.md +183 -0
  79. package/assets/dev-guide/fe/sources/toss-ff/readability-magic-number.md +53 -0
  80. package/assets/dev-guide/fe/sources/toss-ff/readability-submit-button.md +73 -0
  81. package/assets/dev-guide/fe/sources/toss-ff/readability-ternary-operator.md +38 -0
  82. package/assets/dev-guide/fe/sources/toss-ff/readability-use-page-state.md +77 -0
  83. package/assets/dev-guide/fe/sources/toss-ff/readability-user-policy.md +98 -0
  84. package/assets/dev-guide/fe/sources/vue/INDEX.md +17 -0
  85. package/assets/dev-guide/fe/sources/vue/composition-api.md +251 -0
  86. package/assets/dev-guide/fe/sources/vue/nuxt-data-fetching.md +232 -0
  87. package/assets/dev-guide/fe/sources/vue/pinia-state-management.md +134 -0
  88. package/assets/dev-guide/fe/sources/vue/reactivity-pitfalls.md +261 -0
  89. package/assets/dev-guide/fe/sources/vue/style-guide-priority-a.md +117 -0
  90. package/assets/dev-guide/fe/sources/vue/style-guide-priority-b.md +231 -0
  91. package/assets/dev-guide/fe/sources/vue/style-guide-priority-c.md +86 -0
  92. package/assets/dev-guide/fe/sources/vue/style-guide-priority-d.md +72 -0
  93. package/dist/checks/self-score-deflation.js +6 -4
  94. package/dist/cli.js +47 -2
  95. package/dist/core/auto-compound-runner.js +6 -2
  96. package/dist/core/dashboard-cli.d.ts +12 -0
  97. package/dist/core/dashboard-cli.js +226 -0
  98. package/dist/core/dashboard.js +2 -2
  99. package/dist/core/dev-guide-injector.d.ts +26 -0
  100. package/dist/core/dev-guide-injector.js +137 -0
  101. package/dist/core/doctor.d.ts +10 -0
  102. package/dist/core/doctor.js +49 -8
  103. package/dist/core/harness.js +8 -2
  104. package/dist/core/init.js +53 -0
  105. package/dist/core/inspect-cli.js +4 -4
  106. package/dist/core/lifecycle-classifier.d.ts +23 -0
  107. package/dist/core/lifecycle-classifier.js +104 -0
  108. package/dist/core/migrate-evidence-host.js +1 -1
  109. package/dist/core/notify.js +7 -0
  110. package/dist/core/observability-backfill.d.ts +31 -0
  111. package/dist/core/observability-backfill.js +178 -0
  112. package/dist/core/observability-store.d.ts +58 -0
  113. package/dist/core/observability-store.js +195 -0
  114. package/dist/core/paths.d.ts +16 -2
  115. package/dist/core/paths.js +16 -2
  116. package/dist/core/session-store.d.ts +12 -1
  117. package/dist/core/session-store.js +77 -1
  118. package/dist/core/spawn.d.ts +17 -0
  119. package/dist/core/spawn.js +191 -8
  120. package/dist/core/statusline-cli.js +34 -1
  121. package/dist/core/v1-bootstrap.d.ts +7 -0
  122. package/dist/core/v1-bootstrap.js +28 -6
  123. package/dist/engine/compound-extractor.js +40 -1
  124. package/dist/engine/compound-loop.js +6 -0
  125. package/dist/engine/compound-retire.d.ts +20 -0
  126. package/dist/engine/compound-retire.js +85 -0
  127. package/dist/engine/learn-cli.js +2 -2
  128. package/dist/engine/lifecycle/bypass-detector.js +3 -2
  129. package/dist/engine/lifecycle/meta-reclassifier.js +1 -1
  130. package/dist/engine/lifecycle/signals.js +2 -2
  131. package/dist/engine/lifecycle/trigger-t1-correction.js +1 -1
  132. package/dist/engine/solution-candidate.js +1 -1
  133. package/dist/engine/solution-outcomes.js +1 -1
  134. package/dist/engine/solution-quarantine.js +1 -1
  135. package/dist/engine/solution-weakness.js +8 -2
  136. package/dist/forge/cli.js +1 -1
  137. package/dist/hooks/context-guard.js +25 -1
  138. package/dist/hooks/keyword-detector.js +1 -1
  139. package/dist/hooks/post-tool-use.js +48 -0
  140. package/dist/hooks/secret-filter.js +2 -2
  141. package/dist/hooks/shared/hook-response.js +1 -1
  142. package/dist/hooks/shared/hook-timing.js +3 -3
  143. package/dist/hooks/solution-injector.js +94 -1
  144. package/dist/hooks/stop-guard.js +3 -3
  145. package/dist/host/install-claude.d.ts +6 -2
  146. package/dist/host/install-claude.js +74 -2
  147. package/dist/host/install-codex.d.ts +4 -0
  148. package/dist/host/install-codex.js +72 -1
  149. package/dist/host/install-orchestrator.js +1 -0
  150. package/dist/mcp/tools.js +1 -1
  151. package/dist/preset/facet-catalog.js +2 -2
  152. package/dist/renderer/rule-renderer.js +7 -7
  153. package/dist/store/compound-usage-store.js +1 -1
  154. package/dist/store/implicit-feedback-store.js +2 -2
  155. package/dist/store/profile-store.d.ts +11 -0
  156. package/dist/store/profile-store.js +23 -0
  157. package/package.json +6 -6
  158. package/plugin.json +1 -1
  159. package/scripts/postinstall.js +134 -0
@@ -0,0 +1,308 @@
1
+ ---
2
+ name: be-perf-go
3
+ description: Go 서비스의 p95/p99 성능 문제를 진단하고 수정. DB N+1, GC pause, goroutine leak, lock contention, allocation 최적화, network roundtrip 카테고리별 절차로 접근한다.
4
+ ---
5
+
6
+ # be-perf (Go)
7
+
8
+ > **호출 시점**: "p99가 800ms야 잡아줘", "GC pause가 심해", "goroutine 수가 계속 올라가", "메모리 사용량이 이상해".
9
+ > **선행 로딩**: `principles/common.md` + `principles/go.md` 필수.
10
+
11
+ ## 0. 절대 금지
12
+
13
+ 1. 측정 없이 최적화 추측 금지 — pprof 데이터 없이 "아마 GC겠지"는 근거 없음.
14
+ 2. p50만 보고 OK 선언 금지 — p95/p99 반드시 확인.
15
+ 3. unsafe 패키지 성능 최적화 목적 사용 금지 — 이득이 미미하고 버그 위험 높음.
16
+
17
+ ## 1. 진단 절차
18
+
19
+ ### Step 1 — 현재 지표 수집
20
+
21
+ ```bash
22
+ # pprof 활성화 (프로덕션에서는 조건부로만)
23
+ import _ "net/http/pprof"
24
+ go func() { http.ListenAndServe(":6060", nil) }()
25
+
26
+ # 30초 CPU 프로파일 수집
27
+ go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
28
+
29
+ # 메모리 프로파일
30
+ go tool pprof http://localhost:6060/debug/pprof/heap
31
+
32
+ # goroutine 덤프
33
+ curl http://localhost:6060/debug/pprof/goroutine?debug=2
34
+
35
+ # 벤치마크 기준선
36
+ go test -bench=. -benchmem -count=5 ./...
37
+ ```
38
+
39
+ ### Step 2 — 병목 카테고리 분류
40
+
41
+ | 증상 | 카테고리 |
42
+ |------|----------|
43
+ | pprof CPU에서 GC 관련 함수 상위 | GC pause / allocation 과다 |
44
+ | goroutine 수 지속 증가 | goroutine leak |
45
+ | 특정 goroutine이 mutex 대기 | lock contention |
46
+ | DB slow query | N+1 / 인덱스 누락 |
47
+ | 외부 API 대기 | network roundtrip |
48
+
49
+ ## 2. 카테고리별 진단 및 픽스
50
+
51
+ ### 2.1 DB N+1
52
+
53
+ ```go
54
+ // WRONG: N+1
55
+ orders, _ := repo.FindOrders(ctx)
56
+ for _, o := range orders {
57
+ o.User, _ = repo.FindUser(ctx, o.UserID) // N번 쿼리
58
+ }
59
+
60
+ // RIGHT: JOIN 또는 IN 쿼리
61
+ orders, _ := repo.FindOrdersWithUsers(ctx)
62
+ // SELECT o.*, u.name FROM orders o JOIN users u ON o.user_id = u.id
63
+
64
+ // 또는 IN 쿼리
65
+ userIDs := make([]string, len(orders))
66
+ for i, o := range orders { userIDs[i] = o.UserID }
67
+ users, _ := repo.FindUsersByIDs(ctx, userIDs)
68
+ // SELECT * FROM users WHERE id = ANY($1)
69
+ userMap := make(map[string]*User, len(users))
70
+ for _, u := range users { userMap[u.ID] = u }
71
+ ```
72
+
73
+ ### 2.2 GC Pause / 과도한 Allocation
74
+
75
+ **탐지**: pprof heap 에서 alloc_objects 상위 함수 확인.
76
+
77
+ ```bash
78
+ go tool pprof -alloc_objects http://localhost:6060/debug/pprof/heap
79
+ # top 10 으로 allocation 많은 함수 확인
80
+ ```
81
+
82
+ **픽스**:
83
+ ```go
84
+ // sync.Pool로 자주 할당하는 버퍼 재사용
85
+ var bufPool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}
86
+
87
+ func encodeJSON(v interface{}) ([]byte, error) {
88
+ buf := bufPool.Get().(*bytes.Buffer)
89
+ defer func() { buf.Reset(); bufPool.Put(buf) }()
90
+ if err := json.NewEncoder(buf).Encode(v); err != nil {
91
+ return nil, err
92
+ }
93
+ return append([]byte(nil), buf.Bytes()...), nil
94
+ }
95
+
96
+ // 슬라이스 용량 사전 할당
97
+ func buildResult(items []Item) []Result {
98
+ results := make([]Result, 0, len(items)) // capacity 미리 지정
99
+ for _, item := range items {
100
+ results = append(results, transform(item))
101
+ }
102
+ return results
103
+ }
104
+
105
+ // 문자열 빌더 (+ concat 대신)
106
+ var sb strings.Builder
107
+ sb.Grow(len(parts) * 20) // 예상 크기 미리 할당
108
+ for _, p := range parts {
109
+ sb.WriteString(p)
110
+ }
111
+ result := sb.String()
112
+ ```
113
+
114
+ ### 2.3 Goroutine Leak
115
+
116
+ **탐지**:
117
+ ```bash
118
+ # goroutine 덤프 - 비정상적으로 많으면 leak
119
+ curl -s http://localhost:6060/debug/pprof/goroutine?debug=2 | head -50
120
+ # 또는 goleak 라이브러리 (테스트에서)
121
+ ```
122
+
123
+ ```go
124
+ // 테스트에서 leak 탐지
125
+ import "go.uber.org/goleak"
126
+
127
+ func TestCreateOrder(t *testing.T) {
128
+ defer goleak.VerifyNone(t)
129
+ // ...
130
+ }
131
+ ```
132
+
133
+ **픽스**:
134
+ ```go
135
+ // WRONG: 종료 조건 없는 goroutine
136
+ func startWorker() {
137
+ go func() {
138
+ for {
139
+ processJob() // context 없음 — 영원히 실행
140
+ }
141
+ }()
142
+ }
143
+
144
+ // RIGHT: context 기반 종료
145
+ func startWorker(ctx context.Context) {
146
+ go func() {
147
+ for {
148
+ select {
149
+ case <-ctx.Done():
150
+ return
151
+ default:
152
+ processJob(ctx)
153
+ }
154
+ }
155
+ }()
156
+ }
157
+
158
+ // 고정 크기 worker pool
159
+ func NewWorkerPool(ctx context.Context, n int, jobs <-chan Job) {
160
+ var wg sync.WaitGroup
161
+ for i := 0; i < n; i++ {
162
+ wg.Add(1)
163
+ go func() {
164
+ defer wg.Done()
165
+ for {
166
+ select {
167
+ case job, ok := <-jobs:
168
+ if !ok { return }
169
+ job.Execute(ctx)
170
+ case <-ctx.Done():
171
+ return
172
+ }
173
+ }
174
+ }()
175
+ }
176
+ wg.Wait()
177
+ }
178
+ ```
179
+
180
+ ### 2.4 Lock Contention
181
+
182
+ **탐지**: pprof mutex 프로파일.
183
+ ```bash
184
+ go tool pprof http://localhost:6060/debug/pprof/mutex
185
+ ```
186
+
187
+ **픽스**:
188
+ ```go
189
+ // sync.RWMutex: 읽기 많고 쓰기 적을 때
190
+ type Cache struct {
191
+ mu sync.RWMutex
192
+ items map[string]Item
193
+ }
194
+
195
+ func (c *Cache) Get(key string) (Item, bool) {
196
+ c.mu.RLock() // 읽기 lock (다중 동시 읽기 허용)
197
+ defer c.mu.RUnlock()
198
+ item, ok := c.items[key]
199
+ return item, ok
200
+ }
201
+
202
+ func (c *Cache) Set(key string, item Item) {
203
+ c.mu.Lock() // 쓰기 lock (단독)
204
+ defer c.mu.Unlock()
205
+ c.items[key] = item
206
+ }
207
+
208
+ // atomic 연산 (카운터)
209
+ import "sync/atomic"
210
+ var requestCount int64
211
+ atomic.AddInt64(&requestCount, 1) // mutex 불필요
212
+ ```
213
+
214
+ ### 2.5 Network Roundtrip
215
+
216
+ ```go
217
+ // HTTP 클라이언트 연결 풀 설정
218
+ transport := &http.Transport{
219
+ MaxIdleConns: 100,
220
+ MaxIdleConnsPerHost: 10,
221
+ IdleConnTimeout: 90 * time.Second,
222
+ // Keep-Alive 기본 활성화
223
+ }
224
+ client := &http.Client{
225
+ Transport: transport,
226
+ Timeout: 5 * time.Second,
227
+ }
228
+
229
+ // 독립적인 외부 호출 병렬화
230
+ g, ctx := errgroup.WithContext(ctx)
231
+ var user *User
232
+ var inventory *Inventory
233
+
234
+ g.Go(func() error {
235
+ var err error
236
+ user, err = userClient.GetUser(ctx, userID)
237
+ return err
238
+ })
239
+ g.Go(func() error {
240
+ var err error
241
+ inventory, err = inventoryClient.GetStock(ctx, productID)
242
+ return err
243
+ })
244
+ if err := g.Wait(); err != nil { ... }
245
+
246
+ // gRPC: 스트리밍 활용 (대용량 응답)
247
+ // 단건 요청 반복 → 배치 RPC
248
+ ```
249
+
250
+ ### 2.6 DB 연결 풀 / 쿼리 최적화
251
+
252
+ ```go
253
+ db.SetMaxOpenConns(25)
254
+ db.SetMaxIdleConns(10)
255
+ db.SetConnMaxLifetime(5 * time.Minute)
256
+ db.SetConnMaxIdleTime(5 * time.Minute)
257
+
258
+ // 슬로우 쿼리 로깅
259
+ // PostgreSQL: log_min_duration_statement = 100
260
+ // 또는 ORM 레벨 후킹
261
+ ```
262
+
263
+ ## 3. 벤치마크 패턴
264
+
265
+ ```go
266
+ func BenchmarkCreateOrder(b *testing.B) {
267
+ svc := setupService(b)
268
+ req := validRequest()
269
+
270
+ b.ResetTimer()
271
+ b.RunParallel(func(pb *testing.PB) {
272
+ for pb.Next() {
273
+ _, err := svc.CreateOrder(context.Background(), req)
274
+ if err != nil {
275
+ b.Fatal(err)
276
+ }
277
+ }
278
+ })
279
+ // 메모리 할당도 확인: go test -bench=. -benchmem
280
+ }
281
+ ```
282
+
283
+ ## 4. 출력 형식
284
+
285
+ ```
286
+ ## 성능 진단 결과
287
+
288
+ ### 측정 기준선
289
+ - p50: Xms / p95: Xms / p99: Xms
290
+ - goroutine 수: N
291
+ - heap: XMB
292
+
293
+ ### 발견된 병목
294
+ 1. [DB N+1] internal/service/order.go:55 — 주문 목록 조회 시 N번 user 쿼리
295
+ 2. [GC] internal/handler/serialize.go:30 — 요청마다 bytes.Buffer 새로 할당
296
+
297
+ ### 적용한 픽스
298
+ - 변경 파일: <목록>
299
+ - 재측정: p95 Xms → Xms, heap XMB → XMB
300
+
301
+ ### 추가 권고
302
+ - ...
303
+ ```
304
+
305
+ ## 5. 관련 문서
306
+
307
+ - 원칙: [`principles/common.md`](../../../principles/common.md) F섹션, [`principles/go.md`](../../../principles/go.md) G6
308
+ - 코퍼스: `sources/go-runtime/`, `sources/postgres/`
@@ -0,0 +1,119 @@
1
+ ---
2
+ name: be-review-go
3
+ description: Go PR을 사내 BE 원칙 기준으로 리뷰. [SEVERITY] file:line — 이슈 형식으로 출력하고, 머지 차단/비차단을 명확히 구분한다.
4
+ ---
5
+
6
+ # be-review (Go)
7
+
8
+ > **호출 시점**: "이 PR 리뷰해줘", "이 Go 코드 리뷰해줘", "OWASP 관점에서 검토해줘".
9
+ > **선행 로딩**: `principles/common.md` + `principles/go.md` 필수.
10
+
11
+ ## 0. 절대 금지
12
+
13
+ 1. golangci-lint가 잡는 이슈를 수동 리뷰에 중복 포함하지 마라 (자동 도구 역할 존중).
14
+ 2. 주관적 스타일 의견을 [HIGH]로 분류 금지.
15
+ 3. Go idiom이 아닌 이유로 [HIGH] 처리 금지 — 보안/안전성 기준으로만.
16
+
17
+ ## 1. 리뷰 출력 형식
18
+
19
+ ```
20
+ ## 리뷰 요약
21
+ - 변경: N files +X -Y
22
+ - HIGH N, MED N, LOW N / 머지 [차단|비차단]
23
+
24
+ [HIGH] internal/handler/order.go:42 — context 없는 DB 쿼리 (N9 antipa.)
25
+ [HIGH] internal/handler/order.go:88 — 에러 무시 (_ = err), 결제 실패 묵살
26
+ [MED] internal/service/order.go:120 — goroutine 종료 조건 없음 (leak 위험)
27
+ [LOW] internal/repository/order.go:55 — 인터페이스 구현 패키지에서 정의
28
+ ```
29
+
30
+ ### SEVERITY 기준
31
+
32
+ | SEVERITY | 정의 | 머지 |
33
+ |----------|------|------|
34
+ | **HIGH** | 에러 묵살, goroutine leak, context 미전파, OWASP 취약점, panic 남용, race condition | 차단 |
35
+ | **MED** | 큰 인터페이스, goroutine 종료 조건 불명확, 에러 래핑 누락, defer cancel 누락 | 권고 |
36
+ | **LOW** | 네이밍, 패키지 구조, 코멘트 스타일 | 비차단 |
37
+
38
+ ## 2. 체크리스트
39
+
40
+ ### 2.1 에러 처리 (HIGH)
41
+
42
+ ```
43
+ [ ] 에러 무시 없음 — _ = err 패턴
44
+ [ ] 빈 에러 처리 없음 — if err != nil { return } (로그 없는 경우)
45
+ [ ] 에러 래핑 — fmt.Errorf("funcName: %w", err)
46
+ [ ] panic 사용이 정당한가 — 초기화 실패 / 프로그래밍 오류에만
47
+ [ ] sentinel error 정의 — errors.New로 변수화
48
+ [ ] errors.Is / errors.As 올바른 사용
49
+ ```
50
+
51
+ ### 2.2 context 전파 (HIGH/MED)
52
+
53
+ ```
54
+ [ ] I/O 함수 첫 인자가 context.Context
55
+ [ ] DB 쿼리: QueryContext, ExecContext, QueryRowContext 사용
56
+ [ ] HTTP 요청: http.NewRequestWithContext 사용
57
+ [ ] context.WithTimeout 후 defer cancel() 존재
58
+ [ ] context.Value — 비즈니스 파라미터 전달에 미사용
59
+ ```
60
+
61
+ ### 2.3 goroutine 안전성 (HIGH/MED)
62
+
63
+ ```
64
+ [ ] goroutine 종료 조건 존재 (ctx.Done() 또는 done channel)
65
+ [ ] WaitGroup / errgroup으로 완료 대기
66
+ [ ] 채널 close — sender가 담당
67
+ [ ] 버퍼드 채널 크기 의도적으로 선택
68
+ [ ] sync.Mutex Lock 후 defer Unlock
69
+ [ ] go test -race 통과 (PR CI에 포함)
70
+ ```
71
+
72
+ ### 2.4 보안 (HIGH)
73
+
74
+ ```
75
+ [ ] SQL 파라미터화 — 문자열 concat 없음
76
+ [ ] 소유권 검증 — URL params로 타인 리소스 접근 불가
77
+ [ ] 입력 검증 — 외부 데이터 go-validator 또는 수동 검증
78
+ [ ] 응답에 내부 필드 노출 없음
79
+ [ ] 시크릿 코드 내 하드코딩 없음
80
+ ```
81
+
82
+ ### 2.5 인터페이스 설계 (MED/LOW)
83
+
84
+ ```
85
+ [ ] 인터페이스 크기 — 1~3 메서드 (5+ 메서드 경고)
86
+ [ ] 인터페이스 정의 위치 — consumer 패키지 (구현 패키지 X)
87
+ [ ] 표준 라이브러리 인터페이스 재활용 (io.Reader 등)
88
+ ```
89
+
90
+ ### 2.6 코드 품질 (LOW)
91
+
92
+ ```
93
+ [ ] 함수 50줄 이하
94
+ [ ] 중첩 깊이 4 이하 (early return 활용)
95
+ [ ] 네이밍 — Go 관습 (CamelCase, receiver 단문자)
96
+ [ ] 패키지 이름 — 단수 소문자 (orders X → order O)
97
+ [ ] golangci-lint 이슈 없음
98
+ ```
99
+
100
+ ## 3. 이슈 카탈로그 (즉시 참조)
101
+
102
+ | 패턴 | SEVERITY | 설명 |
103
+ |------|----------|------|
104
+ | `_ = err` | HIGH | 에러 묵살 |
105
+ | `db.Query(ctx, "... WHERE id = " + id)` | HIGH | SQL injection |
106
+ | `go func() { for { process() } }()` | HIGH | goroutine leak |
107
+ | `ctx, cancel := ...; cancel()` (defer 없음) | MED | context 누수 |
108
+ | `resp, _ := http.Get(url)` | HIGH | context 없음 + 에러 무시 |
109
+ | `resp.Body.Close()` 누락 | MED | resource leak |
110
+ | `interface` 5+ 메서드 | MED | 분리 필요 |
111
+ | `type Repo interface { ... }` in repo pkg | LOW | consumer 측 정의 권장 |
112
+ | `panic(err)` in handler | HIGH | 서버 크래시 |
113
+ | `fmt.Println(...)` in prod | LOW | slog 구조화 로그 |
114
+ | `json.Unmarshal(data, &v)` 에러 무시 | HIGH | 에러 처리 |
115
+
116
+ ## 4. 관련 문서
117
+
118
+ - 원칙: [`principles/common.md`](../../../principles/common.md), [`principles/go.md`](../../../principles/go.md)
119
+ - 보안: [`skills/go/be-security/SKILL.md`](../be-security/SKILL.md)