@kood/claude-code 0.6.5 → 0.6.7
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/dist/index.js +255 -149
- package/package.json +1 -1
- package/templates/.claude/agents/researcher.md +8 -1
- package/templates/.claude/instructions/sourcing/reliable-search.md +49 -2
- package/templates/.claude/scripts/deploy/build-run.sh +36 -0
- package/templates/.claude/scripts/deploy/deploy-check.sh +38 -0
- package/templates/.claude/scripts/git/git-all.sh +57 -0
- package/templates/.claude/scripts/git/git-clean-check.sh +31 -0
- package/templates/.claude/scripts/git/git-commit.sh +51 -0
- package/templates/.claude/scripts/git/git-info.sh +34 -0
- package/templates/.claude/scripts/git/git-push.sh +50 -0
- package/templates/.claude/scripts/lint/lint-check.sh +56 -0
- package/templates/.claude/scripts/lint/lint-file.sh +41 -0
- package/templates/.claude/scripts/pm/pm-detect.sh +25 -0
- package/templates/.claude/scripts/pm/pm-run.sh +41 -0
- package/templates/.claude/scripts/version/version-bump.sh +54 -0
- package/templates/.claude/scripts/version/version-find.sh +49 -0
- package/templates/.claude/skills/docs-fetch/SKILL.md +5 -4
- package/templates/.claude/skills/project-optimizer/AGENTS.md +275 -0
- package/templates/.claude/skills/project-optimizer/SKILL.md +374 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-config-centralize.md +66 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-hot-path.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-interface-segregation.md +51 -0
- package/templates/.claude/skills/project-optimizer/rules/arch-module-boundary.md +42 -0
- package/templates/.claude/skills/project-optimizer/rules/build-cache.md +57 -0
- package/templates/.claude/skills/project-optimizer/rules/build-code-split.md +56 -0
- package/templates/.claude/skills/project-optimizer/rules/build-incremental.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/build-minify.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/build-tree-shake.md +60 -0
- package/templates/.claude/skills/project-optimizer/rules/code-complexity.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/code-dead-elimination.md +32 -0
- package/templates/.claude/skills/project-optimizer/rules/code-duplication.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/code-error-handling.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/code-naming.md +52 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-defer-await.md +54 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-parallel.md +90 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pipeline.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/concurrency-pool.md +68 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-lightweight-alt.md +37 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-peer-align.md +44 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-security-audit.md +45 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-unused-removal.md +25 -0
- package/templates/.claude/skills/project-optimizer/rules/deps-version-pin.md +40 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-ci-speed.md +47 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-dev-server.md +35 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-lint-config.md +36 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-test-coverage.md +34 -0
- package/templates/.claude/skills/project-optimizer/rules/dx-type-safety.md +49 -0
- package/templates/.claude/skills/project-optimizer/rules/io-batch-queries.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-cache-layer.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-connection-reuse.md +67 -0
- package/templates/.claude/skills/project-optimizer/rules/io-serialize-minimal.md +61 -0
- package/templates/.claude/skills/project-optimizer/rules/io-stream.md +75 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-bounded-cache.md +65 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-large-data.md +64 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-lazy-init.md +78 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-leak-prevention.md +79 -0
- package/templates/.claude/skills/project-optimizer/rules/memory-pool-reuse.md +70 -0
- package/templates/.claude/skills/sql-optimizer/SKILL.md +437 -0
- package/templates/.claude/skills/sql-optimizer/orm-patterns.md +218 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/AGENTS.md +53 -14
- package/templates/.claude/skills/tanstack-start-react-best-practices/SKILL.md +93 -27
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/bundle-defer-third-party.md +42 -19
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-optimistic-updates.md +109 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-suspense-query.md +74 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/client-use-hook.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/rerender-react-compiler.md +81 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-beforeload-auth.md +121 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-file-conventions.md +104 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-link-navigation.md +119 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-nested-layouts.md +155 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-path-params.md +89 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-pending-component.md +110 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-preload-strategy.md +91 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-router-context.md +120 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/routing-search-params.md +114 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-deferred-data.md +1 -1
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-error-boundaries.md +79 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-middleware.md +85 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-serialization.md +56 -21
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-streaming.md +84 -0
- package/templates/.claude/skills/tanstack-start-react-best-practices/rules/server-validator.md +71 -0
- package/templates/.claude/skills/tauri-react-best-practices/AGENTS.md +527 -0
- package/templates/.claude/skills/tauri-react-best-practices/SKILL.md +570 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-barrel-imports.md +140 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-cargo-profile.md +96 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-frontend-treeshake.md +242 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-lazy-components.md +255 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/bundle-remove-unused-commands.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-ci-pipeline.md +269 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-signing.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/deploy-updater.md +226 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-async-commands.md +172 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-batch-commands.md +133 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-binary-response.md +198 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-channel-streaming.md +186 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-error-handling.md +250 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/ipc-type-safe.md +227 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-derived-state.md +231 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-functional-setstate.md +191 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-index-maps.md +276 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/perf-lazy-state-init.md +196 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-lifecycle.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-mobile-compat.md +199 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/plugin-permission-scope.md +193 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-error-boundary.md +239 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-event-listener.md +151 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-file-src.md +155 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-invoke-hook.md +139 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/react-optimistic-update.md +211 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-capability-split.md +205 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-csp.md +207 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-least-privilege.md +106 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-no-wildcard.md +253 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/security-scope-paths.md +160 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-async-mutex.md +270 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-mutex-pattern.md +265 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-react-sync.md +375 -0
- package/templates/.claude/skills/tauri-react-best-practices/rules/state-single-container.md +275 -0
- package/templates/tanstack-start/docs/architecture.md +238 -167
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +777 -38
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +549 -37
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +895 -111
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +641 -43
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +889 -38
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +891 -29
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +972 -36
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +1525 -881
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +1099 -20
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +796 -30
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +953 -35
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +371 -15
- package/templates/tauri/CLAUDE.md +189 -0
- package/templates/tauri/docs/guides/distribution.md +261 -0
- package/templates/tauri/docs/guides/getting-started.md +302 -0
- package/templates/tauri/docs/guides/mobile.md +288 -0
- package/templates/tauri/docs/library/tauri/index.md +510 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Guarantee Resource Cleanup
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Prevents memory leaks, file handle exhaustion, connection leaks
|
|
5
|
+
tags: memory, resource, leak, cleanup, dispose
|
|
6
|
+
languages: all
|
|
7
|
+
related: [memory-pool-reuse, io-connection-reuse]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 리소스 해제 보장
|
|
11
|
+
|
|
12
|
+
파일, DB 커넥션, 소켓, 락 등 시스템 리소스는 예외 발생 시에도 반드시 해제합니다.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시:**
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
f = open("data.csv")
|
|
18
|
+
data = f.read() # 예외 시 f.close() 호출 안 됨
|
|
19
|
+
|
|
20
|
+
conn = db.connect()
|
|
21
|
+
result = conn.execute(query) # 예외 시 커넥션 누수
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**✅ 올바른 예시:**
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
# Python - context manager
|
|
28
|
+
with open("data.csv") as f:
|
|
29
|
+
data = f.read()
|
|
30
|
+
|
|
31
|
+
async with pool.acquire() as conn:
|
|
32
|
+
result = await conn.execute(query)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```go
|
|
36
|
+
// Go - defer
|
|
37
|
+
resp, err := http.Get(url)
|
|
38
|
+
if err != nil { return err }
|
|
39
|
+
defer resp.Body.Close()
|
|
40
|
+
|
|
41
|
+
f, err := os.Open("data.csv")
|
|
42
|
+
if err != nil { return err }
|
|
43
|
+
defer f.Close()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// JS/TS - try/finally
|
|
48
|
+
const conn = await pool.acquire()
|
|
49
|
+
try {
|
|
50
|
+
return await conn.query(sql)
|
|
51
|
+
} finally {
|
|
52
|
+
conn.release()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// TC39 Explicit Resource Management (using)
|
|
56
|
+
await using conn = await pool.acquire()
|
|
57
|
+
return await conn.query(sql)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```rust
|
|
61
|
+
// Rust - RAII (자동)
|
|
62
|
+
let file = File::open("data.csv")?; // Drop trait으로 스코프 끝에서 자동 해제
|
|
63
|
+
let data = read_to_string(&file)?;
|
|
64
|
+
// file 자동 해제
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```java
|
|
68
|
+
// Java - try-with-resources
|
|
69
|
+
try (var conn = dataSource.getConnection();
|
|
70
|
+
var stmt = conn.prepareStatement(sql)) {
|
|
71
|
+
return stmt.executeQuery();
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```csharp
|
|
76
|
+
// C# - using
|
|
77
|
+
await using var conn = await pool.GetConnectionAsync();
|
|
78
|
+
return await conn.QueryAsync(sql);
|
|
79
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pool and Reuse Expensive Objects
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Reduces GC pressure, allocation overhead
|
|
5
|
+
tags: memory, pool, reuse, allocation, gc
|
|
6
|
+
languages: all
|
|
7
|
+
related: [memory-leak-prevention, concurrency-pool, io-connection-reuse]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 비싼 객체 풀링/재사용
|
|
11
|
+
|
|
12
|
+
반복 생성-소멸되는 비싼 객체(버퍼, 커넥션, HTTP 클라이언트)를 풀에서 재사용합니다.
|
|
13
|
+
|
|
14
|
+
**❌ 잘못된 예시:**
|
|
15
|
+
|
|
16
|
+
```go
|
|
17
|
+
// 매 요청마다 새 버퍼 할당
|
|
18
|
+
func handler(w http.ResponseWriter, r *http.Request) {
|
|
19
|
+
buf := make([]byte, 32*1024) // 32KB 매번 할당 + GC
|
|
20
|
+
io.CopyBuffer(w, r.Body, buf)
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
# 매번 새 HTTP 세션
|
|
26
|
+
def fetch(url):
|
|
27
|
+
return requests.get(url) # 매번 새 커넥션
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**✅ 올바른 예시:**
|
|
31
|
+
|
|
32
|
+
```go
|
|
33
|
+
// Go - sync.Pool
|
|
34
|
+
var bufPool = sync.Pool{
|
|
35
|
+
New: func() any { return make([]byte, 32*1024) },
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
func handler(w http.ResponseWriter, r *http.Request) {
|
|
39
|
+
buf := bufPool.Get().([]byte)
|
|
40
|
+
defer bufPool.Put(buf)
|
|
41
|
+
io.CopyBuffer(w, r.Body, buf)
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
# Python - 세션 재사용
|
|
47
|
+
session = requests.Session() # 모듈 레벨에서 한 번 생성
|
|
48
|
+
|
|
49
|
+
def fetch(url):
|
|
50
|
+
return session.get(url) # 커넥션 재사용, Keep-Alive
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Node.js - HTTP Agent 재사용
|
|
55
|
+
import { Agent } from 'undici'
|
|
56
|
+
const agent = new Agent({ connections: 10, keepAliveTimeout: 30_000 })
|
|
57
|
+
|
|
58
|
+
// 또는 전역 fetch에서 agent 사용
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```rust
|
|
62
|
+
// Rust - 정적 클라이언트
|
|
63
|
+
use reqwest::Client;
|
|
64
|
+
use std::sync::LazyLock;
|
|
65
|
+
static CLIENT: LazyLock<Client> = LazyLock::new(|| {
|
|
66
|
+
Client::builder().pool_max_idle_per_host(10).build().unwrap()
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**적용 대상:** HTTP 클라이언트, DB 커넥션, 버퍼, 정규식 컴파일 결과, 시리얼라이저 인스턴스.
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sql-optimizer
|
|
3
|
+
description: PostgreSQL SQL 쿼리 최적화. ORM/Raw SQL 안티패턴 감지, EXPLAIN ANALYZE 분석, 인덱스 제안, 쿼리 리라이팅.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
metadata:
|
|
6
|
+
author: kood
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
@../../instructions/workflow-patterns/sequential-thinking.md
|
|
11
|
+
@../../instructions/agent-patterns/parallel-execution.md
|
|
12
|
+
@../../instructions/agent-patterns/model-routing.md
|
|
13
|
+
@../../instructions/validation/forbidden-patterns.md
|
|
14
|
+
@../../instructions/validation/required-behaviors.md
|
|
15
|
+
|
|
16
|
+
# SQL Optimizer Skill
|
|
17
|
+
|
|
18
|
+
> PostgreSQL 쿼리 최적화. ORM 코드 + Raw SQL 안티패턴 감지 → EXPLAIN 분석 → 최적화 제안 → 자동 수정.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<purpose>
|
|
23
|
+
|
|
24
|
+
ORM(Prisma, Drizzle, TypeORM, Sequelize) 또는 Raw SQL 쿼리의 성능 문제 감지 및 최적화.
|
|
25
|
+
|
|
26
|
+
**입력:** SQL 쿼리, ORM 코드, 파일 경로, 또는 "프로젝트 전체 분석"
|
|
27
|
+
**출력:** 안티패턴 리포트 + 최적화된 쿼리/코드 + 인덱스 제안
|
|
28
|
+
|
|
29
|
+
**ORM별 수정 코드:** @./orm-patterns.md
|
|
30
|
+
|
|
31
|
+
</purpose>
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
<trigger_conditions>
|
|
36
|
+
|
|
37
|
+
| 트리거 | 반응 |
|
|
38
|
+
|--------|------|
|
|
39
|
+
| `/sql-optimizer src/db/queries.ts` | 파일 내 SQL/ORM 코드 분석 |
|
|
40
|
+
| `/sql-optimizer SELECT * FROM users...` | 단일 쿼리 최적화 |
|
|
41
|
+
| `/sql-optimizer` (인자 없음) | 프로젝트 전체 DB 레이어 스캔 |
|
|
42
|
+
| "쿼리가 느려요" / "slow" | 슬로우 쿼리 분석 가이드 |
|
|
43
|
+
| "N+1 문제" / "인덱스 추천" | 특정 문제 집중 분석 |
|
|
44
|
+
|
|
45
|
+
</trigger_conditions>
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
<argument_validation>
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
$ARGUMENTS 없음 → 프로젝트 전체 DB 레이어 스캔:
|
|
53
|
+
"프로젝트에서 SQL/ORM 관련 파일을 탐색하여 최적화할 쿼리를 찾겠습니다."
|
|
54
|
+
→ Phase 1 전체 스캔 실행
|
|
55
|
+
|
|
56
|
+
$ARGUMENTS = 파일 경로 → 해당 파일 분석
|
|
57
|
+
$ARGUMENTS = SQL 쿼리 → 단일 쿼리 분석
|
|
58
|
+
$ARGUMENTS = "slow" → pg_stat_statements 기반 분석 가이드
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
</argument_validation>
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
<detection_rules>
|
|
66
|
+
|
|
67
|
+
## 안티패턴 감지 규칙
|
|
68
|
+
|
|
69
|
+
### CRITICAL (즉시 수정)
|
|
70
|
+
|
|
71
|
+
| ID | 패턴 | 감지 방법 | 영향 |
|
|
72
|
+
|----|------|----------|------|
|
|
73
|
+
| C1 | **N+1 쿼리** | for 루프 내 ORM 관계 접근 | 쿼리 수 N배 증가 |
|
|
74
|
+
| C2 | **Cartesian Product** | JOIN 조건 없는 다중 테이블 | 행 수 폭발 |
|
|
75
|
+
| C3 | **무제한 SELECT** | LIMIT 없이 대량 테이블 조회 | 메모리 폭발 |
|
|
76
|
+
| C4 | **SELECT \*** | 불필요한 컬럼 전체 로드 | 네트워크/메모리 낭비 |
|
|
77
|
+
|
|
78
|
+
### HIGH (성능 리스크)
|
|
79
|
+
|
|
80
|
+
| ID | 패턴 | 감지 방법 | 영향 |
|
|
81
|
+
|----|------|----------|------|
|
|
82
|
+
| H1 | **Seq Scan** | EXPLAIN에서 10만+ 행 Seq Scan | 풀 테이블 스캔 |
|
|
83
|
+
| H2 | **서브쿼리 in WHERE** | IN (SELECT ...) 패턴 | 반복 실행 |
|
|
84
|
+
| H3 | **과다 JOIN** | 5개+ 테이블 조인 | 플래너 부하 |
|
|
85
|
+
| H4 | **ORM include 남용** | Prisma include 3단계+ 중첩 | 메모리 폭발 |
|
|
86
|
+
| H5 | **Lazy Loading 루프** | TypeORM Promise 관계 루프 접근 | N+1 변형 |
|
|
87
|
+
|
|
88
|
+
### MEDIUM (최적화 기회)
|
|
89
|
+
|
|
90
|
+
| ID | 패턴 | 감지 방법 | 영향 |
|
|
91
|
+
|----|------|----------|------|
|
|
92
|
+
| M1 | **DISTINCT 마스킹** | DISTINCT + JOIN | 잘못된 JOIN 은폐 |
|
|
93
|
+
| M2 | **서브쿼리 → CTE** | 중첩 서브쿼리 2단계+ | 가독성/성능 |
|
|
94
|
+
| M3 | **Window Function 미사용** | 집계 서브쿼리 | 불필요한 스캔 |
|
|
95
|
+
| M4 | **Partial Index 미적용** | 상수 WHERE 조건 반복 | 인덱스 크기 낭비 |
|
|
96
|
+
| M5 | **Covering Index 부재** | SELECT 컬럼 ≠ 인덱스 | 테이블 룩업 |
|
|
97
|
+
| M6 | **Prepared Statement 미사용** | Drizzle에서 .prepare() 없음 | 파싱 반복 |
|
|
98
|
+
|
|
99
|
+
### LOW (베스트 프랙티스)
|
|
100
|
+
|
|
101
|
+
| ID | 패턴 | 감지 방법 | 영향 |
|
|
102
|
+
|----|------|----------|------|
|
|
103
|
+
| L1 | **ANALYZE 미실행** | 대량 INSERT/UPDATE 후 | 통계 부정확 |
|
|
104
|
+
| L2 | **Connection Pool 미설정** | Serverless + 매번 new Client | 연결 소모 |
|
|
105
|
+
| L3 | **Expression Index 부재** | WHERE LOWER(col) 등 | 인덱스 미사용 |
|
|
106
|
+
|
|
107
|
+
</detection_rules>
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
<index_strategy>
|
|
112
|
+
|
|
113
|
+
## 인덱스 추천 전략
|
|
114
|
+
|
|
115
|
+
### 유형 선택
|
|
116
|
+
|
|
117
|
+
| 상황 | 인덱스 유형 | 예시 |
|
|
118
|
+
|------|-----------|------|
|
|
119
|
+
| WHERE = / ORDER BY | B-tree (기본) | `CREATE INDEX idx ON t(col)` |
|
|
120
|
+
| WHERE LOWER(col) | Expression | `CREATE INDEX idx ON t(LOWER(col))` |
|
|
121
|
+
| WHERE status = 'active' | Partial | `CREATE INDEX idx ON t(col) WHERE status = 'active'` |
|
|
122
|
+
| SELECT a,b WHERE a = ? | Covering | `CREATE INDEX idx ON t(a) INCLUDE (b)` |
|
|
123
|
+
| JSONB 필드 검색 | GIN | `CREATE INDEX idx ON t USING gin(data)` |
|
|
124
|
+
| 시계열 대량 (100만+) | BRIN | `CREATE INDEX idx ON t USING brin(created_at)` |
|
|
125
|
+
|
|
126
|
+
### 복합 인덱스 컬럼 순서
|
|
127
|
+
|
|
128
|
+
```sql
|
|
129
|
+
-- 규칙: 동등 조건 → 범위 조건 → 정렬
|
|
130
|
+
-- WHERE status = 'active' AND created_at > '2024-01-01' ORDER BY priority
|
|
131
|
+
CREATE INDEX idx_optimal ON tasks(status, created_at, priority);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 인덱스 제안 전 필수 확인
|
|
135
|
+
|
|
136
|
+
```sql
|
|
137
|
+
-- 1. 기존 인덱스 중복 확인 (새 인덱스가 기존과 겹치는지)
|
|
138
|
+
SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'target_table';
|
|
139
|
+
|
|
140
|
+
-- 2. 사용되지 않는 인덱스 찾기 (idx_scan = 0이면 삭제 후보)
|
|
141
|
+
SELECT indexname, idx_scan, pg_size_pretty(pg_relation_size(indexrelid)) as size
|
|
142
|
+
FROM pg_stat_user_indexes WHERE tablename = 'target_table'
|
|
143
|
+
ORDER BY idx_scan ASC;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
</index_strategy>
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
<explain_analysis>
|
|
151
|
+
|
|
152
|
+
## EXPLAIN ANALYZE 분석 가이드
|
|
153
|
+
|
|
154
|
+
### 실행 패턴
|
|
155
|
+
|
|
156
|
+
```sql
|
|
157
|
+
-- 기본 분석 (FORMAT JSON → 프로그래밍 파싱 용이)
|
|
158
|
+
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT ...;
|
|
159
|
+
|
|
160
|
+
-- 수정 쿼리 안전 분석 (롤백 필수)
|
|
161
|
+
BEGIN;
|
|
162
|
+
EXPLAIN (ANALYZE, BUFFERS) UPDATE/DELETE ...;
|
|
163
|
+
ROLLBACK;
|
|
164
|
+
|
|
165
|
+
-- 상세 분석 (SETTINGS: PG 12+)
|
|
166
|
+
EXPLAIN (ANALYZE, VERBOSE, BUFFERS, SETTINGS) SELECT ...;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 문제 식별 기준 (정량적)
|
|
170
|
+
|
|
171
|
+
| 신호 | 임계값 | 조치 |
|
|
172
|
+
|------|--------|------|
|
|
173
|
+
| **Seq Scan** | 행 10만+ 테이블 | 인덱스 추가 |
|
|
174
|
+
| **예상 rows / 실제 rows** | 비율 10x+ 차이 | `ANALYZE table_name` |
|
|
175
|
+
| **Nested Loop** | 내부 루프 1만+ rows | Hash Join 유도 또는 인덱스 |
|
|
176
|
+
| **Sort** | Cost 1000+ | ORDER BY 컬럼에 인덱스 |
|
|
177
|
+
| **Buffers shared read** | 1만+ 블록 | 인덱스 또는 shared_buffers 증가 |
|
|
178
|
+
| **Filter: Rows Removed** | 제거율 90%+ | WHERE 조건 최적화 |
|
|
179
|
+
|
|
180
|
+
### pg_stat_statements 슬로우 쿼리
|
|
181
|
+
|
|
182
|
+
```sql
|
|
183
|
+
-- TOP 10 느린 쿼리 (avg_ms 기준)
|
|
184
|
+
SELECT left(query, 80) as query, calls,
|
|
185
|
+
(total_exec_time/calls)::numeric(10,2) as avg_ms, rows
|
|
186
|
+
FROM pg_stat_statements
|
|
187
|
+
WHERE calls > 10
|
|
188
|
+
ORDER BY total_exec_time DESC LIMIT 10;
|
|
189
|
+
|
|
190
|
+
-- 캐시 미스율 높은 쿼리
|
|
191
|
+
SELECT left(query, 80) as query, shared_blks_read,
|
|
192
|
+
(100.0 * shared_blks_read / NULLIF(shared_blks_hit + shared_blks_read, 0))::numeric(5,2) as miss_pct
|
|
193
|
+
FROM pg_stat_statements
|
|
194
|
+
WHERE shared_blks_hit + shared_blks_read > 0
|
|
195
|
+
ORDER BY miss_pct DESC LIMIT 10;
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
</explain_analysis>
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
<workflow>
|
|
203
|
+
|
|
204
|
+
## 실행 흐름
|
|
205
|
+
|
|
206
|
+
| 단계 | 작업 | 도구 | 에이전트 |
|
|
207
|
+
|------|------|------|---------|
|
|
208
|
+
| **0** | ARGUMENT 파싱, 모드 결정 | - | - |
|
|
209
|
+
| **1** | DB 레이어 파일 탐색, ORM 종류+버전 감지 | Glob, Read | explore x2 (haiku) 병렬 |
|
|
210
|
+
| **2** | 복잡도 판단 | sequentialthinking (1단계) | - |
|
|
211
|
+
| **3** | detection_rules 기반 안티패턴 분석 | Read, Grep | architect + code-reviewer (sonnet) 병렬 |
|
|
212
|
+
| **4** | 최적화 방법 2-3개 선정 | sequentialthinking (2-5단계) | - |
|
|
213
|
+
| **5** | 옵션 제시 (장단점, 추천안) | - | - |
|
|
214
|
+
| **6** | 사용자 선택 후 코드 수정 | Edit | implementation-executor (sonnet) |
|
|
215
|
+
| **7** | typecheck + EXPLAIN 비교 검증 | Bash | - |
|
|
216
|
+
|
|
217
|
+
</workflow>
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
<thinking_strategy>
|
|
222
|
+
|
|
223
|
+
## Sequential Thinking 가이드
|
|
224
|
+
|
|
225
|
+
### 복잡도별 전략
|
|
226
|
+
|
|
227
|
+
| 복잡도 | 사고 횟수 | 기준 |
|
|
228
|
+
|--------|----------|------|
|
|
229
|
+
| **간단** | 3 | 단일 쿼리, 명확한 안티패턴 1-2개 |
|
|
230
|
+
| **보통** | 5 | 2-5개 쿼리, ORM 패턴 혼합 |
|
|
231
|
+
| **복잡** | 7+ | 다중 파일, 인덱스+쿼리+ORM 복합 |
|
|
232
|
+
|
|
233
|
+
### 보통 복잡도 (5단계)
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
thought 1: "user.service.ts 분석 - Prisma v7, findMany 3개, for 루프 2개
|
|
237
|
+
→ 보통 복잡도 (5개 쿼리, ORM 패턴)"
|
|
238
|
+
|
|
239
|
+
thought 2: "안티패턴 식별:
|
|
240
|
+
C1 - line 45: findMany + for 루프 = N+1 (100명 조회 시 101쿼리)
|
|
241
|
+
H4 - line 72: include 3단계 중첩 (user→posts→comments→author)
|
|
242
|
+
M6 - line 90: 동일 쿼리 반복인데 prepare 미사용"
|
|
243
|
+
|
|
244
|
+
thought 3: "수정 방법:
|
|
245
|
+
C1 → select + 관계 로딩 또는 findMany + in 배치
|
|
246
|
+
H4 → select + _count 또는 별도 쿼리 분리
|
|
247
|
+
M6 → prepare() 추가"
|
|
248
|
+
|
|
249
|
+
thought 4: "옵션 비교:
|
|
250
|
+
A) ORM만: select 변환 (즉시, DB 변경 없음, 쿼리 80% 감소)
|
|
251
|
+
B) ORM+인덱스: + Partial Index (마이그레이션 필요, 90% 감소)
|
|
252
|
+
C) Raw SQL: 완전 제어 (유지보수 비용 증가)"
|
|
253
|
+
|
|
254
|
+
thought 5: "추천: 옵션 B - ORM 최적화 + Partial Index
|
|
255
|
+
근거: 단계적 적용 가능, ORM 먼저 → 인덱스 추가
|
|
256
|
+
인덱스: CREATE INDEX idx_posts_author ON posts(author_id) WHERE published = true"
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
</thinking_strategy>
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
<parallel_agent_execution>
|
|
264
|
+
|
|
265
|
+
## 병렬 에이전트 실행
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// Phase 1: DB 레이어 탐색 (병렬)
|
|
269
|
+
Task(subagent_type="explore", model="haiku",
|
|
270
|
+
prompt="SQL/ORM 파일 탐색: prisma/, drizzle/, *.sql, migration, repository, service")
|
|
271
|
+
|
|
272
|
+
Task(subagent_type="explore", model="haiku",
|
|
273
|
+
prompt="ORM 설정 분석: schema.prisma (버전 확인), drizzle.config.ts, 관계/인덱스 정의, 연결 풀")
|
|
274
|
+
|
|
275
|
+
// Phase 3: 안티패턴 분석 (병렬)
|
|
276
|
+
Task(subagent_type="architect", model="sonnet",
|
|
277
|
+
prompt="쿼리 아키텍처 분석: N+1, JOIN 구조, 서브쿼리, 인덱스 전략 (기존 vs 필요)")
|
|
278
|
+
|
|
279
|
+
Task(subagent_type="code-reviewer", model="sonnet",
|
|
280
|
+
prompt="ORM 안티패턴 리뷰: include/select, 배치 처리, Connection Pool, ORM 버전별 API 차이")
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
</parallel_agent_execution>
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
<option_presentation>
|
|
288
|
+
|
|
289
|
+
## 옵션 제시 형식
|
|
290
|
+
|
|
291
|
+
```markdown
|
|
292
|
+
## SQL 최적화 분석 결과
|
|
293
|
+
|
|
294
|
+
### 감지된 문제
|
|
295
|
+
|
|
296
|
+
| 심각도 | ID | 문제 | 위치 | 영향 |
|
|
297
|
+
|--------|-----|------|------|------|
|
|
298
|
+
| CRITICAL | C1 | N+1 쿼리 | src/users.ts:45 | 쿼리 100→2 |
|
|
299
|
+
| HIGH | H1 | Seq Scan (50만 행) | users 테이블 | 풀 스캔 |
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
### 옵션 1: ORM 코드 최적화 (추천)
|
|
304
|
+
|
|
305
|
+
| 장점 | 단점 |
|
|
306
|
+
|------|------|
|
|
307
|
+
| 코드만 수정, DB 변경 없음 | ORM 제약 내 최적화 |
|
|
308
|
+
|
|
309
|
+
**예상 효과:** 쿼리 수 80% 감소
|
|
310
|
+
**수정 파일:** src/users.ts:45, src/posts.ts:23
|
|
311
|
+
|
|
312
|
+
### 옵션 2: + 인덱스 추가
|
|
313
|
+
|
|
314
|
+
| 장점 | 단점 |
|
|
315
|
+
|------|------|
|
|
316
|
+
| 근본적 성능 개선 | DB 마이그레이션 필요 |
|
|
317
|
+
|
|
318
|
+
**예상 효과:** 쿼리 시간 90% 감소
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
추천: 옵션 [N]. [근거]
|
|
323
|
+
어떤 옵션을 선택하시겠습니까? (1/2/3)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
</option_presentation>
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
<validation>
|
|
331
|
+
|
|
332
|
+
## 검증 체크리스트
|
|
333
|
+
|
|
334
|
+
### Phase 0-1 (탐색)
|
|
335
|
+
|
|
336
|
+
```text
|
|
337
|
+
✅ ARGUMENT 확인 (없으면 프로젝트 전체 스캔)
|
|
338
|
+
✅ ORM 종류 + 버전 감지 (package.json, schema 파일)
|
|
339
|
+
✅ Task (explore) x2 병렬로 DB 레이어 탐색
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Phase 2-5 (분석 + 옵션)
|
|
343
|
+
|
|
344
|
+
```text
|
|
345
|
+
✅ Sequential Thinking 최소 3단계 (보통 5단계)
|
|
346
|
+
✅ 안티패턴 CRITICAL → HIGH → MEDIUM → LOW 순서
|
|
347
|
+
✅ 옵션 최소 2개, 권장 3개 + 장단점 + 예상 효과
|
|
348
|
+
✅ 수정 파일 위치 (file:line 포함)
|
|
349
|
+
✅ 인덱스 제안 시 기존 인덱스 중복 확인 + CREATE INDEX 문
|
|
350
|
+
✅ ORM 수정 시 Before/After 코드 제공
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Phase 6-7 (수정 + 검증)
|
|
354
|
+
|
|
355
|
+
```text
|
|
356
|
+
✅ npx tsc --noEmit (typecheck 통과)
|
|
357
|
+
✅ 기존 테스트 통과 (npm test)
|
|
358
|
+
✅ 수정 전후 EXPLAIN ANALYZE 비교 권장
|
|
359
|
+
✅ 인덱스 추가 시 마이그레이션 파일 생성
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### 절대 금지
|
|
363
|
+
|
|
364
|
+
```text
|
|
365
|
+
❌ EXPLAIN 없이 "이게 더 빠를 것" 추측
|
|
366
|
+
❌ 코드 탐색 없이 안티패턴 추측
|
|
367
|
+
❌ 옵션 1개만 제시
|
|
368
|
+
❌ 기존 인덱스 확인 없이 인덱스 제안 (중복 위험)
|
|
369
|
+
❌ ORM 버전 미확인 (Prisma v5 select vs v7 omit)
|
|
370
|
+
❌ 수정 후 typecheck 미실행
|
|
371
|
+
❌ 100만+ 행 테이블에 무조건 B-tree (BRIN 고려)
|
|
372
|
+
❌ Partial Index 추가 시 기존 전체 인덱스 중복 무시
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
</validation>
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
<examples>
|
|
380
|
+
|
|
381
|
+
## 실전 예시
|
|
382
|
+
|
|
383
|
+
### 예시 1: Prisma N+1 최적화
|
|
384
|
+
|
|
385
|
+
```
|
|
386
|
+
사용자: /sql-optimizer src/services/user.service.ts
|
|
387
|
+
|
|
388
|
+
Phase 0: 파일 경로 모드
|
|
389
|
+
Phase 1: ORM 감지 → Prisma v7 (package.json + schema.prisma)
|
|
390
|
+
Phase 2-4: Sequential Thinking (5단계)
|
|
391
|
+
thought 1: "Prisma v7, findMany 3개, for 루프 2개 - 보통 복잡도"
|
|
392
|
+
thought 2: "C1 line:45 N+1, H4 line:72 include 3단계"
|
|
393
|
+
thought 3: "select 변환, _count, 배치 로딩"
|
|
394
|
+
thought 4: "A) select만 vs B) +인덱스 vs C) Raw SQL"
|
|
395
|
+
thought 5: "옵션 B 추천 - 단계적 적용"
|
|
396
|
+
|
|
397
|
+
Phase 5: 옵션 제시 (3개)
|
|
398
|
+
Phase 6: 선택 후 Edit 수정
|
|
399
|
+
Phase 7: 검증
|
|
400
|
+
$ npx tsc --noEmit → ✅
|
|
401
|
+
$ npm test → ✅
|
|
402
|
+
EXPLAIN ANALYZE 비교 → 쿼리 시간 85% 감소
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### 예시 2: 프로젝트 전체 스캔
|
|
406
|
+
|
|
407
|
+
```
|
|
408
|
+
사용자: /sql-optimizer
|
|
409
|
+
|
|
410
|
+
Phase 1 (병렬):
|
|
411
|
+
explore: "prisma/, *.sql, service 파일 탐색" → 12 파일 발견
|
|
412
|
+
explore: "schema.prisma, 인덱스 정의 분석" → 8 인덱스, 3 누락
|
|
413
|
+
|
|
414
|
+
Phase 3 (병렬):
|
|
415
|
+
architect: 쿼리 아키텍처 → C1 x2, H1 x1, H2 x1
|
|
416
|
+
code-reviewer: ORM 패턴 → H4 x1, M4 x2, M6 x3
|
|
417
|
+
|
|
418
|
+
결과: CRITICAL 2 / HIGH 3 / MEDIUM 5
|
|
419
|
+
→ 우선순위별 옵션 제시 → 선택 후 수정 + 검증
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### 예시 3: 슬로우 쿼리
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
사용자: /sql-optimizer slow
|
|
426
|
+
|
|
427
|
+
1. pg_stat_statements 분석 쿼리 제공 (복사 가능)
|
|
428
|
+
2. 사용자가 결과 공유
|
|
429
|
+
3. EXPLAIN ANALYZE 실행 가이드
|
|
430
|
+
4. 결과 분석:
|
|
431
|
+
- Seq Scan on orders (50만 행, H1) → Partial Index
|
|
432
|
+
- Nested Loop 3만 rows (H3) → Hash Join 유도
|
|
433
|
+
5. 인덱스 CREATE 문 + 쿼리 리라이팅 제안
|
|
434
|
+
6. 마이그레이션 파일 생성
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
</examples>
|