Skip to content

Sangmoo/Claude-Java-Toolkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

275 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Claude Java Toolkit

AI-powered tools for Oracle DB & Java/Spring enterprise development Powered by Anthropic Claude API

Build License Java Spring Boot Version Helm


๐ŸŒ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ ํŽ˜์ด์ง€

๐Ÿ‘‰ https://sangmoo.github.io/Claude-Java-Toolkit/#ko

ํ”„๋กœ์ ํŠธ์˜ ์ „์ฒด ๊ธฐ๋Šฅ, ์„ค์น˜ ๋ฐฉ๋ฒ•, REST API ๋ชฉ๋ก์„ ํ•œ๋ˆˆ์— ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” GitHub Pages ์†Œ๊ฐœ ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค. ํ•œ๊ตญ์–ด(#ko) / ์˜์–ด(#en) ์ „ํ™˜์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.


โœจ ์†Œ๊ฐœ

claude-java-toolkit์€ Java/Spring ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ™˜๊ฒฝ์—์„œ Claude API๋ฅผ ์‹ค๋ฌด์— ๋ฐ”๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜คํ”ˆ์†Œ์Šค ํˆดํ‚ท์ž…๋‹ˆ๋‹ค.

Python์šฉ Claude ํ†ตํ•ฉ ๋„๊ตฌ๋Š” ๋งŽ์ง€๋งŒ, JDK 1.8+ / Oracle 11g+ / Spring Boot ๋ ˆ๊ฑฐ์‹œ ํ™˜๊ฒฝ์— ํŠนํ™”๋œ Java ํ†ตํ•ฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ตญ๋‚ด SI / ๊ธˆ์œต / ์œ ํ†ต ํ™˜๊ฒฝ์˜ ํ˜„์‹ค์„ ๋ฐ˜์˜ํ•˜์—ฌ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ†• v4.7.x ์ฐจ์„ธ๋Œ€ โ€” Platform / MCP Server (#M3)

๋„๊ตฌ์˜ ์ •์ฒด์„ฑ ๋ณ€ํ™”: Consumer โ†’ Platform. Claude Code / Cursor / Cline ๋“ฑ AI agent ๊ฐ€ IDE ์•ˆ์—์„œ ๋„๊ตฌ์˜ 12+ ๋ถ„์„ ๊ธฐ๋Šฅ์„ ์ง์ ‘ ํ˜ธ์ถœ. CI/CD pipeline / curl / ์‚ฌ๋‚ด ์ž๋™ํ™”๋„ ๊ฐ™์€ X-Api-Key ํ—ค๋”๋กœ ์ฆ‰์‹œ ํ˜ธ์ถœ ๊ฐ€๋Šฅ.

  • ๐Ÿ” API Key ์ธํ”„๋ผ โ€” ๋ฉ€ํ‹ฐ ํ‚ค + RBAC โ€” /admin/api-keys

    • SHA-256 ํ•ด์‹œ ์ €์žฅ + ๋ฐœ๊ธ‰ ์งํ›„ plaintext 1ํšŒ ๋…ธ์ถœ
    • per-key role (READ_ONLY / WRITE / ADMIN) + ๋ถ„๋‹น ํ˜ธ์ถœ ํ•œ๋„ (sliding window)
    • ๋งŒ๋ฃŒ / ํšŒ์ˆ˜ / ์‚ฌ์šฉ ํ†ต๊ณ„ (lastUsedAt + totalCalls)
    • timing-safe ๋น„๊ต + audit_log ์ž๋™ ๊ธฐ๋ก
  • ๐ŸŒ ๊ณต์‹ REST API v1 โ€” POST /api/v1/analyze ๋™๊ธฐ ์ง„์ž…์ 

    • 12๊ฐœ feature ํ†ตํ•ฉ ์ง„์ž…์  + ์บ์‹œ / Live DB / history ์ž๋™
    • ์‘๋‹ต์— ํ† ํฐ + ๋น„์šฉ + latency + ๋ชจ๋ธ ์ •๋ณด
    • GET /api/v1/features discovery (MCP / SDK ์ž๋™ ์ƒ์„ฑ์šฉ)
  • ๐Ÿค– MCP Server โ€” @claude-toolkit/mcp-server (Node.js)

    • Claude Code / Cursor / Cline / Continue.dev ์ž๋™ ํ˜ธํ™˜
    • 12๊ฐœ ๋ถ„์„ tool ๋…ธ์ถœ: SQL ๋ถ„์„ 6 + Java/Code ๋ถ„์„ 6
    • stdio transport (ํ‘œ์ค€) + ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ธฐ๋ฐ˜ ์„ค์ •
    • 5๋ถ„ ํ†ตํ•ฉ: ADMIN ํ‚ค ๋ฐœ๊ธ‰ โ†’ mcp_settings.json ํ•œ ์ค„ โ†’ IDE ์žฌ์‹œ์ž‘
    • ๐Ÿ“˜ docs/mcp-setup.md ํ†ตํ•ฉ ๊ฐ€์ด๋“œ
# Claude Code ํ†ตํ•ฉ ์˜ˆ์‹œ โ€” ~/.config/claude/mcp_settings.json
{
  "mcpServers": {
    "claude-toolkit": {
      "command": "npx",
      "args": ["-y", "@claude-toolkit/mcp-server"],
      "env": {
        "CTK_URL":     "http://localhost:8027",
        "CTK_API_KEY": "ctk_live_..."
      }
    }
  }
}
# CI/CD / curl ์ง์ ‘ ํ˜ธ์ถœ ์˜ˆ์‹œ
curl -X POST $CTK_URL/api/v1/analyze \
  -H "X-Api-Key: ctk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"feature":"sql_review","input":"SELECT * FROM T_ORDER ..."}' | jq

๐Ÿš€ ์ตœ์‹  ๊ธฐ๋Šฅ ์ถ”๊ฐ€ โ€” 8์ข… ์ถ”๊ฐ€ ๊ฐœ์„ 

  • ๐Ÿ” MCP ํฌํŠธ ์†Œ์ผ“ ๋ฆฌ์Šค๋‹ ํ—ฌ์Šค์ฒดํฌ โ€” McpServerHealthIndicator ์— TCP ์†Œ์ผ“ 500ms ์ฒดํฌ ์ถ”๊ฐ€. ํ”„๋กœ์„ธ์Šค ์ƒ์กด + ํฌํŠธ ์‹ค์ œ ์˜คํ”ˆ ์—ฌ๋ถ€๋ฅผ portListening: true/false detail ๋กœ ๊ตฌ๋ถ„. ๊ธฐ๋™ ์ค‘ ์ƒํƒœ๋ฅผ starting ์œผ๋กœ ๋ถ„๋ฆฌํ•ด Grafana ์•Œ๋žŒ ์˜คํƒ ๋ฐฉ์ง€.
  • โœ๏ธ DB ํ”„๋กœํ•„ ํŽธ์ง‘ ๋ชจ๋‹ฌ โ€” /db-profiles ๋ชฉ๋ก ๊ฐ ํ–‰์— ํŽธ์ง‘(โœ) ๋ฒ„ํŠผ ์ถ”๊ฐ€. ๊ธฐ์กด ์ €์žฅ๊ฐ’์„ GET /{id}/json ์œผ๋กœ ๋ถˆ๋Ÿฌ์™€ ํŽธ์ง‘ ๋ชจ๋‹ฌ ํ‘œ์‹œ. POST /{id}/update-json AJAX ์—”๋“œํฌ์ธํŠธ๋กœ ์ €์žฅ.
  • ๐Ÿ“Š ์ด๋ ฅ CSV ์„ ํƒ ๋‚ด๋ณด๋‚ด๊ธฐ โ€” ์ฒดํฌ๋ฐ•์Šค ์„ ํƒ ๊ฑด๋งŒ CSV ๋กœ ๋‚ด๋ณด๋‚ด๋Š” POST /api/v1/export/csv/history/selected ์ถ”๊ฐ€. ์„ ํƒ ์—†์œผ๋ฉด ์ „์ฒด 1000๊ฑด fallback. ๋ฒ„ํŠผ ๋ ˆ์ด๋ธ”๋„ ์„ ํƒ ๊ฑด์ˆ˜ ์‹ค์‹œ๊ฐ„ ๋ฐ˜์˜.
  • ๐Ÿ“‹ Live DB ์ฟผ๋ฆฌ ์‹คํ–‰ ์ด๋ ฅ โ€” livedb_query_log JPA ํ…Œ์ด๋ธ”์— Live DB ํ˜ธ์ถœ๋งˆ๋‹ค ์ž๋™ ๊ธฐ๋ก (profileId ยท username ยท SQL ยท ์†Œ์š”์‹œ๊ฐ„ ยท ์ƒํƒœ). GET /api/v1/admin/livedb/query-log ๋กœ ์กฐํšŒ.
  • ๐Ÿงช LiveDbBreakerStateRepository @DataJpaTest โ€” H2 ์ธ๋ฉ”๋ชจ๋ฆฌ๋กœ ์‹ค์ œ JPA ๋™์ž‘ ๊ฒ€์ฆ (save/findAll/deleteById 3 ์ผ€์ด์Šค).
  • โš™๏ธ DB ํšŒ๋กœ์ฐจ๋‹จ๊ธฐ @PostConstruct ํ”„๋ฆฌ๋กœ๋“œ โ€” ์•ฑ ์žฌ์‹œ์ž‘ ์‹œ DB ์— ๋‚จ์€ OPEN ์ƒํƒœ๋ฅผ in-memory ์บ์‹œ๋กœ ๋ณต์›. secondsUntilHalfOpen() ์ด ์žฌ์‹œ์ž‘ ์งํ›„์—๋„ ์ •ํ™•ํ•œ ๊ฐ’ ๋ฐ˜ํ™˜.
  • ๐Ÿ“ฆ API ์‘๋‹ต Gzip ์••์ถ• โ€” server.compression.enabled: true, min-response-size: 2048, JSON/CSV/HTML ์ „ ์œ ํ˜• ํฌํ•จ. ๋Œ€์šฉ๋Ÿ‰ ์ด๋ ฅ ์‘๋‹ต์—์„œ ๋„คํŠธ์›Œํฌ ์ „์†ก๋Ÿ‰ ๋Œ€ํญ ๊ฐ์†Œ.
  • ๐Ÿฉบ Readiness Probe ๋ช…์‹œ์  mcpServer ์ œ์™ธ โ€” /health/readiness ๊ทธ๋ฃน์—์„œ mcpServer ์ œ๊ฑฐ ์ด์œ ๋ฅผ ์ฃผ์„์œผ๋กœ ๋ช…์‹œ. MCP ํ”„๋กœ์„ธ์Šค ๋‹ค์šด์ด K8s Pod ์žฌ์‹œ์ž‘ ๋ฃจํ”„๋กœ ์ด์–ด์ง€์ง€ ์•Š๋„๋ก ๋ฐฉ์ง€.

๐Ÿš€ ์ด์ „ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ โ€” 8์ข… ๊ฐœ์„ 

  • ๐Ÿ“Š ์ด๋ ฅ CSV ๋‚ด๋ณด๋‚ด๊ธฐ โ€” /history ํŽ˜์ด์ง€์— CSV ๋ฒ„ํŠผ ์ถ”๊ฐ€. GET /api/v1/export/csv/history ์—”๋“œํฌ์ธํŠธ๊ฐ€ UTF-8 BOM ํฌํ•จ CSV ๋ฅผ ๋ฐ˜ํ™˜ โ€” Excel ์—์„œ ํ•œ๊ธ€ ๊นจ์ง ์—†์Œ. ๊ธฐ์กด Excel ๋‚ด๋ณด๋‚ด๊ธฐ์™€ ๋ณ‘ํ–‰ ์ œ๊ณต.
  • ๐Ÿ”— ํšŒ๋กœ์ฐจ๋‹จ๊ธฐ DB ๊ณต์œ  โ€” LiveDbCircuitBreaker ๊ฐ€ livedb_breaker_state JPA ํ…Œ์ด๋ธ”์„ source-of-truth ๋กœ ์‚ฌ์šฉ. ๋ฉ€ํ‹ฐ ์ธ์Šคํ„ด์Šค ๋ฐฐํฌ์—์„œ ํ•œ ์ธ์Šคํ„ด์Šค์˜ ์ฐจ๋‹จ ๊ฒฐ์ •์ด ์ „์ฒด ์ธ์Šคํ„ด์Šค์— ์ฆ‰์‹œ ์ „ํŒŒ. ๋‹จ์ผ ์ธ์Šคํ„ด์Šค์—์„œ๋Š” ๊ธฐ์กด in-memory ๋™์ž‘ ์œ ์ง€ (DB ์ž๋™ ๊ฐ์ง€).
  • ๐Ÿ“ˆ Grafana MCP ํŒจ๋„ โ€” claude-toolkit-overview.json ๋Œ€์‹œ๋ณด๋“œ์— MCP Server ์„น์…˜ ์ถ”๊ฐ€ (์ƒํƒœ stat ํŒจ๋„ 2๊ฐœ).
  • ๐Ÿฉบ Admin ํ—ฌ์Šค ํŽ˜์ด์ง€ MCP ์นด๋“œ โ€” /admin/health ์— MCP Server ์ƒํƒœ ์นด๋“œ ๋…ธ์ถœ. GET /api/v1/admin/health/mcp ์—”๋“œํฌ์ธํŠธ์—์„œ autoStart / running / pid / port ์กฐํšŒ.
  • ๐Ÿ”Œ DB ํ”„๋กœํ•„ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ ๋ฒ„ํŠผ โ€” /db-profiles ๋ชฉ๋ก์˜ ๊ฐ ํ–‰์— "์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ" ๋ฒ„ํŠผ ์ถ”๊ฐ€. POST /db-profiles/{id}/test-existing ์ด ์ €์žฅ๋œ ์ž๊ฒฉ์ฆ๋ช…์œผ๋กœ ์‹ค์ œ JDBC ์—ฐ๊ฒฐ ์‹œ๋„.
  • โš™๏ธ TOOLKIT_MCP_AUTOSTART ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋…ธ์ถœ โ€” docker-compose.yml ์—์„œ ${TOOLKIT_MCP_AUTOSTART:-false} ๋กœ ๋ณ€๊ฒฝ. .env ํŒŒ์ผ ํ•œ ์ค„๋กœ MCP ์ž๋™ ๊ธฐ๋™ ์ „ํ™˜ ๊ฐ€๋Šฅ.
  • ๐Ÿงช McpServerHealthIndicator ๋‹จ์œ„ ํ…Œ์ŠคํŠธ โ€” 4 ์ผ€์ด์Šค: disabled/running+pid/running-no-pid/not-running.
  • ๐Ÿงช ApiKeyFilter 512์ž ์ฐจ๋‹จ ํ…Œ์ŠคํŠธ โ€” MockedStatic ์œผ๋กœ SecuritySettings ๋ฅผ ๊ฒฉ๋ฆฌ, 513์ž ํ‚ค โ†’ 401, 512์ž ํ‚ค โ†’ BCrypt ๋‹จ๊ณ„๊นŒ์ง€ ํ†ต๊ณผ ๊ฒ€์ฆ.

๐Ÿ”’ ์ตœ์‹  ๋ณด์•ˆยท์•ˆ์ •์„ฑ ๊ฐœ์„  โ€” ์ธํ”„๋ผ ํ•˜๋“œ๋‹

์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ํ†ตํ•ด ๋ฐœ๊ฒฌ๋œ ์šด์˜ ๋ฆฌ์Šคํฌ๋ฅผ ์„ ์ œ์ ์œผ๋กœ ํ•ด์†Œ.

  • ๐Ÿ”‘ ์•”ํ˜ธํ™” ํ‚ค ํŒŒ์ผ ๊ถŒํ•œ ๊ฐ•์ œ (600) โ€” CryptoUtils ๊ฐ€ ~/.claude-toolkit/.encryption-key ์ƒ์„ฑ ์‹œ OS ์— ์ƒ๊ด€์—†์ด owner read/write only ๋กœ ์„ค์ •. Docker/Linux ํ™˜๊ฒฝ์—์„œ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ‚ค๋ฅผ ์ฝ์„ ์ˆ˜ ์—†๋„๋ก ์ฐจ๋‹จ.
  • ๐Ÿ›ก API Key DoS ๋ฐฉ์–ด โ€” ApiKeyFilter ์—์„œ BCrypt ๋น„๊ต ์ „ ํ‚ค ๊ธธ์ด 512์ž ์ดˆ๊ณผ ์‹œ ์‚ฌ์ „ ์ฐจ๋‹จ. ๋น„์ •์ƒ์ ์œผ๋กœ ๊ธด ์ž…๋ ฅ์œผ๋กœ CPU ๋ฅผ ์†Œ๋ชจ์‹œํ‚ค๋Š” ์š”์ฒญ ์ž๋™ ๊ฑฐ๋ถ€.
  • ๐Ÿ”Œ DataSource ์บ์‹œ ์ •์ƒ ์ข…๋ฃŒ โ€” LiveDbContextService / IndexSimulatorService ์— @PreDestroy ์ถ”๊ฐ€. JVM graceful shutdown ์‹œ ์บ์‹œ ๋งต ๋ช…์‹œ์  ์ •๋ฆฌ.
  • โš™๏ธ Claude ๋ชจ๋ธ ํ™˜๊ฒฝ๋ณ€์ˆ˜ํ™” โ€” application.yml ์˜ claude.model ์ด ${CLAUDE_MODEL:claude-sonnet-4-6} ์œผ๋กœ ๋ณ€๊ฒฝ. ์žฌ๋นŒ๋“œ ์—†์ด ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํ•œ ์ค„๋กœ ๋ชจ๋ธ ์ „ํ™˜ ๊ฐ€๋Šฅ.
  • ๐Ÿฉบ MCP Server ํ—ฌ์Šค ์ธ๋””์ผ€์ดํ„ฐ โ€” McpServerHealthIndicator ์‹ ๊ทœ ์ถ”๊ฐ€. /actuator/health ์— mcpServer ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋…ธ์ถœ๋˜์–ด Prometheus / Grafana ์•Œ๋žŒ์— ์ž๋™ ์—ฐ๋™.

๐Ÿ†• v4.7.2 ํŒจ์น˜ โ€” ADMIN 2FA ํ•„์ˆ˜ํ™” + ๋ณด์•ˆ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

๋ณด์•ˆ ์ •์ฑ… ๊ฐ•ํ™”: ADMIN ๊ณ„์ •์˜ 2FA(TOTP)๋ฅผ ์„ ํƒ์ด ์•„๋‹Œ ํ•„์ˆ˜๋กœ ์ „ํ™˜. ๋™์‹œ์— ์ธ์ฆยท2FA ํ•ต์‹ฌ ๋กœ์ง ์ „๋ฐ˜์— ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•ด ํšŒ๊ท€ ์•ˆ์ „๋ง์„ ๊ตฌ์ถ•.

  • ๐Ÿ” ADMIN 2FA ํ•„์ˆ˜ํ™” โ€” POST /account/disable-2fa ์— ADMIN ์—ญํ•  ์ฐจ๋‹จ ์ถ”๊ฐ€

    • ADMIN ๊ณ„์ •์ด 2FA ๋น„ํ™œ์„ฑํ™” ์š”์ฒญ ์‹œ { "success": false, "error": "ADMIN ๊ณ„์ •์€ 2FA๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." } ๋ฐ˜ํ™˜
    • ๋กœ๊ทธ์ธ ํ๋ฆ„(TwoFactorAuthHandler)์€ ์ด๋ฏธ ADMIN ์„ ๊ฐ•์ œ๋กœ /login/2fa ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜์—ฌ ๋ฏธ์„ค์ • ์‹œ ์ดˆ๊ธฐ ๋“ฑ๋ก ํŽ˜์ด์ง€ ํ‘œ์‹œ โ€” ์ด๋ฒˆ ํŒจ์น˜๋Š” ์‚ฌํ›„ ๋น„ํ™œ์„ฑํ™” ๊ฒฝ๋กœ๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๋งˆ์ง€๋ง‰ ํผ์ฆ
    • REVIEWER / VIEWER ๋Š” ๊ธฐ์กด๋Œ€๋กœ 2FA ์„ ํƒ ์ ์šฉ
  • ๐Ÿงช ๋‹จ์œ„ ํ…Œ์ŠคํŠธ 24๊ฐœ ์‹ ๊ทœ โ€” TotpServiceTest / TwoFactorAuthHandlerTest / AccountController2faTest + SecuritySmokeTests 4๊ฑด ์ถ”๊ฐ€

    • TotpServiceTest (14 ์ผ€์ด์Šค) โ€” RFC 6238 TOTP ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ฒ€์ฆ: generateSecret() Base32 ํฌ๋งทยท์œ ์ผ์„ฑ, Base32 ์™•๋ณต ๋ณ€ํ™˜, verifyCode() null/๋น„์ •์ƒ ์ฝ”๋“œ ๊ฑฐ๋ถ€, buildOtpAuthUri() ํ˜•์‹
    • TwoFactorAuthHandlerTest (5 ์ผ€์ด์Šค) โ€” ๋กœ๊ทธ์ธ ์„ฑ๊ณต ํ•ธ๋“ค๋Ÿฌ: ADMIN โ†’ 2fa_pending ์„ธ์…˜ ์„ธํŒ… + /login/2fa ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ, Non-ADMIN โ†’ / ์งํ–‰, ์‹คํŒจ ์นด์šดํ„ฐ ๋ฆฌ์…‹, ์‚ฌ์šฉ์ž ๋ฏธ์กด์žฌ ์•ˆ์ „ ์ฒ˜๋ฆฌ
    • AccountController2faTest (5 ์ผ€์ด์Šค) โ€” ADMIN ๋น„ํ™œ์„ฑํ™” ๊ฑฐ๋ถ€, REVIEWER/VIEWER ์ •์ƒ ๋น„ํ™œ์„ฑํ™”, ์‚ฌ์šฉ์ž ๋ฏธ์กด์žฌ no-op
    • SecuritySmokeTests (4 ์ผ€์ด์Šค ์ถ”๊ฐ€) โ€” 2fa_pending=true ์ธํ„ฐ์…‰ํ„ฐ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๊ฒ€์ฆ + ADMIN disable-2fa API ์‘๋‹ต success=false ๊ฒ€์ฆ

๐Ÿ†• v4.7.1 ํŒจ์น˜ โ€” ์šด์˜ ์ธํ”„๋ผ + ์‚ฌ์šฉ์ž ์›Œํฌํ”Œ๋กœ 5์ข… ๊ฐ•ํ™”

v4.7.0 ๋ฉ”์ด์ € ๋ฆด๋ฆฌ์Šค ์งํ›„ ์šด์˜ํŒ€ / ์™ธ๋ถ€๊ฐ์‚ฌ์ธ / ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž๊ฐ€ ํ˜„์žฅ์—์„œ ๋ฐ”๋กœ ์ฒด๊ฐํ•  ์ˆ˜ ์žˆ๋Š” 5๊ฐ€์ง€ ์˜์—ญ์„ ํ•œ ๋ฒˆ์— ๊ฐ•ํ™”ํ•œ ๋ˆ„์  ํŒจ์น˜. ๋ชจ๋‘ ๊ธฐ์กด ์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ ์œ„์ฃผ๋กœ ๋ฐฑ์—”๋“œ ๊ตฌ์กฐ ๋ณ€๊ฒฝ ์ตœ์†Œํ™”.

  • ๐Ÿ›ก Settings ๋ณ€๊ฒฝ ๊ฐ์‚ฌ ๋กœ๊ทธ (#15, ADMIN ์ „์šฉ ์‹ ๊ทœ ํŽ˜์ด์ง€) โ€” /admin/config-changes

    • 22๊ฐœ ์‹œ์Šคํ…œ ์„ค์ • (DB / Claude / scanPath / SMTP / rate-limit ๋“ฑ) ๋ณ€๊ฒฝ ์‹œ ์ด์ „๊ฐ’/์ƒˆ๊ฐ’/๋ณ€๊ฒฝ์ž/IP/์‹œ๊ฐ์„ config_change_log ํ…Œ์ด๋ธ”์— ์ž๋™ ๊ธฐ๋ก
    • ์™ธ๋ถ€๊ฐ์‚ฌ์ธ์ด "settings ๊ฐ€ ์–ธ์ œ ๋ˆ„๊ตฌ์— ์˜ํ•ด ์–ด๋–ป๊ฒŒ ๋ฐ”๋€Œ์—ˆ๋Š”์ง€" 1์ฟผ๋ฆฌ๋กœ ์ถ”์ 
    • ํŒจ์Šค์›Œ๋“œ/API ํ‚ค ๋“ฑ ๋ฏผ๊ฐ ํ•„๋“œ๋Š” ์ž๋™ ๋งˆ์Šคํ‚น (*** ๋กœ ์ €์žฅ โ€” ํ‰๋ฌธ ๋ณด๊ด€ X)
  • โšก ํŒŒ์ผ ํ•ด์‹œ ๊ธฐ๋ฐ˜ ๋ถ„์„ ์บ์‹œ (#18) โ€” AnalysisCacheService 4-arg key + ์ •๊ทœํ™”

    • ์ž…๋ ฅ ์ •๊ทœํ™”: BOM ์ œ๊ฑฐ / CRLFโ†’LF / trailing whitespace / ์—ฐ์† ๋นˆ ์ค„ ์ถ•์•ฝ โ†’ ๊ฐ™์€ ์˜๋ฏธ์˜ ์ž…๋ ฅ์€ ํ•ญ์ƒ ๊ฐ™์€ ์บ์‹œ ํ‚ค๋กœ ๋งคํ•‘ (์ฒด๊ฐ ์ ์ค‘๋ฅ  ํ–ฅ์ƒ)
    • ์บ์‹œ ํ‚ค: feature + input + input2 + sourceType 4๊ฐœ SHA-256 ํ•ด์‹ฑ โ†’ sql_review + ๊ฐ™์€ SQL ์ด๋ผ๋„ review vs security ์˜ต์…˜์ด ๋‹ค๋ฅด๋ฉด ๋ถ„๋ฆฌ (์ถฉ๋Œ ๋ฒ„๊ทธ ํšŒ๊ท€ ๋ฐฉ์ง€)
    • JVM ๋ผ์ดํ”„ํƒ€์ž„ hit/miss ์นด์šดํ„ฐ + ์ ์ค‘๋ฅ  (/api/v1/admin/cache/stats)
    • ๋ชจ๋“  ๋ถ„์„ ํŽ˜์ด์ง€ ๊ฒฐ๊ณผ ํ—ค๋”์— โšก ์บ์‹œ ์ ์ค‘ ์นฉ (์บ์‹œ๋กœ ์ฆ‰์‹œ ๋ฐ˜ํ™˜๋œ ๊ฒฝ์šฐ, Claude API ๋น„์šฉ 0)
  • ๐Ÿท ๋ฆฌ๋ทฐ ์ด๋ ฅ ํƒœ๊น… ์‹œ์Šคํ…œ (#12) โ€” /history ํŽ˜์ด์ง€ ํ™•์žฅ

    • ๊ฐ ๋ถ„์„ ๊ฒฐ๊ณผ์— ์ฝค๋งˆ ๊ตฌ๋ถ„ ํƒœ๊ทธ (์˜ˆ: ์„ฑ๋Šฅ, SLA์œ„๋ฐ˜, DB) โ€” ๋ณธ์ธ ๋˜๋Š” ADMIN ๋งŒ ์ˆ˜์ •
    • ํ—ค๋” dropdown ์—์„œ ๋นˆ๋„์ˆœ ํƒœ๊ทธ ๋น ๋ฅธ ์„ ํƒ / ํด๋ฆญ์œผ๋กœ ํ† ๊ธ€ ํ•„ํ„ฐ
    • ์นด๋“œ ํ–‰์— ํƒœ๊ทธ ์นฉ + ํ™•์žฅ ์˜์—ญ์— ์ž๋™์™„์„ฑ dropdown (Enter ์ €์žฅ / Esc ์ทจ์†Œ)
    • ํƒœ๊ทธ ์ •๊ทœํ™”: trim / ๋นˆยท์ค‘๋ณต ์ œ๊ฑฐ / 30์ž ์ƒํ•œ, ์ฝค๋งˆ ๋งค์นญ ์ถฉ๋Œ ๋ฐฉ์ง€(,DB, ํŒจํ„ด)
  • ๐Ÿ’ฌ ๊ฒฐ๊ณผ ํ›„์† ์งˆ๋ฌธ ํŒจ๋„ โ€” Follow-up Q&A (#4) โ€” 22+ ๋ถ„์„ ํŽ˜์ด์ง€์— ํ•œ ๋ฒˆ์— ์ ์šฉ

    • ๋ถ„์„ ๊ฒฐ๊ณผ ์งํ›„ ๊ฐ™์€ ํ™”๋ฉด์—์„œ "์™œ ์ด ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๋‚˜์š”?" / "PostgreSQL ์—์„œ๋Š”?" ๋“ฑ ์ถ”๊ฐ€ ์งˆ๋ฌธ ๊ฐ€๋Šฅ โ€” ํŽ˜์ด์ง€ ์ด๋™ ์—†์ด ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด์„œ ์งˆ๋ฌธ
    • ๊ธฐ์กด /chat/send + /chat/stream SSE ์ธํ”„๋ผ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉ (๋ฐฑ์—”๋“œ ๋ณ€๊ฒฝ 0)
    • ๊ฒฐ๊ณผ + ์›๋ณธ ์ž…๋ ฅ + ํŽ˜์ด์ง€ ๋ผ๋ฒจ์„ ์ฒซ ์งˆ๋ฌธ ์‹œ 1ํšŒ ์ปจํ…์ŠคํŠธ๋กœ ์ „๋‹ฌ, ์ดํ›„ ๋ฉ€ํ‹ฐํ„ด
    • ๊ฒฐ๊ณผ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด (์žฌ๋ถ„์„) ๋ฉ”์‹œ์ง€/์„ธ์…˜ ์ž๋™ ๋ฆฌ์…‹
  • ๐Ÿ”— ๋ถ„์„ ์ฒด์ด๋‹ โ€” ๊ฒฐ๊ณผ ํ›„ ๋‹ค์Œ ๋‹จ๊ณ„ 1-ํด๋ฆญ (#2) โ€” 22+ ๋ถ„์„ ํŽ˜์ด์ง€์— ํ•œ ๋ฒˆ์— ์ ์šฉ

    • 14๊ฐœ feature ร— ํ‰๊ท  3๊ฐœ ๋‹ค์Œ๋‹จ๊ณ„ ๋งคํ•‘ (์ด ~40๊ฐœ ์ฒด์ด๋‹ ๊ฒฝ๋กœ) sql_review โ†’ /explain โ†’ /sql/index-advisor โ†’ /sql-translate โ†’ /erd ๋“ฑ
    • sessionStorage ๊ธฐ๋ฐ˜ 1ํšŒ์šฉ handoff (60์ดˆ TTL), URL ๊ธธ์ด ์ œํ•œยท๋กœ๊ทธ ๋…ธ์ถœ ์šฐ๋ ค 0
    • sameInput / extractFirstCodeBlock ๋ณ€ํ™˜ ์ •์ฑ…์œผ๋กœ ๋‹ค์Œ ํŽ˜์ด์ง€ ์ž…๋ ฅ ์ž๋™ ์ฑ„์›€
    • ์ž๋™ ์ฑ„์›Œ์ง„ ํŽ˜์ด์ง€์—๋Š” ์ž…๋ ฅ ํ—ค๋”์— ๐Ÿ”— ์ฒด์ด๋‹ ์ž…๋ ฅ ์ธ๋””์ผ€์ดํ„ฐ
  • ๐Ÿ”Œ Live DB ์ง์ ‘ ์—ฐ๊ฒฐ โ€” EXPLAIN/ํ†ต๊ณ„ ์ž๋™ ์ˆ˜์ง‘ + ์ธ๋ฑ์Šค ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ + ์šด์˜ ๋Œ€์‹œ๋ณด๋“œ (#G3, Phase 0~5 ์™„๋ฃŒ) โ€” Oracle + PostgreSQL

    • ์‚ฌ์šฉ์ž๊ฐ€ SQL ๋งŒ ์ž…๋ ฅ โ†’ ๋ฐฑ์—”๋“œ๊ฐ€ ์ž๋™์œผ๋กœ EXPLAIN PLAN + ํ…Œ์ด๋ธ” ํ†ต๊ณ„ + ์ธ๋ฑ์Šค ๋ฉ”ํƒ€ ์ˆ˜์ง‘ โ†’ Claude system prompt ์— prepend (์‹ค๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ๋ถ„์„)
    • ๊ธฐ์กด 22+ ๋ถ„์„ ํŽ˜์ด์ง€ ์ค‘ 6๊ฐœ SQL ํŽ˜์ด์ง€ (/advisor, /explain, /sql/index-advisor, /sql-translate, /sql-batch, /erd) ์— ์ž๋™ ์ ์šฉ โ€” ํŽ˜์ด์ง€์— ๐Ÿ”Œ Live DB chip ๋…ธ์ถœ
    • ์ด์ค‘ ๋ณด์•ˆ ์ฐจ๋‹จ: โ‘  SqlClassifier ๊ฐ€ SELECT/EXPLAIN/DESC/WITH ๋งŒ ํ†ต๊ณผ (๋ฉ€ํ‹ฐ statement / ์ฃผ์„ ์šฐํšŒ / ๋ฌธ์ž์—ด ๋ฆฌํ„ฐ๋Ÿด ์•ˆ ; ๊นŒ์ง€ ์ฒ˜๋ฆฌ), โ‘ก ReadOnlyJdbcTemplate ๊ฐ€ statement timeout + max rows ๊ฐ•์ œ, โ‘ข toolkit.livedb.enabled=false kill switch + DbProfile ๋ณ„ ๋ช…์‹œ์  ADMIN ํ† ๊ธ€
    • Default OFF โ€” ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์ž๋™ ํ™œ์„ฑํ™” ์‚ฌ๊ณ  ๋ฐฉ์ง€
    • DBMS ๋ณ„ ๋งคํ•‘:
      • Oracle 11g~19c: DBA_TABLES/ALL_TABLES/USER_TABLES ๊ถŒํ•œ๋ณ„ fallback, DBA_INDEXES + DBA_IND_COLUMNS, EXPLAIN PLAN SET STATEMENT_ID + DBMS_XPLAN.DISPLAY
      • PostgreSQL 11+: pg_class.reltuples + pg_stat_user_tables, pg_index + pg_attribute + LATERAL unnest WITH ORDINALITY ๋กœ ์ปฌ๋Ÿผ ์œ„์น˜ ๋ณด์กด, EXPLAIN (FORMAT TEXT, COSTS true) (ANALYZE ์—†์ด โ€” ๋ถ€ํ•˜ 0)
    • (Phase 4) ์ธ๋ฑ์Šค ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ โ€” /sql/index-advisor ํŽ˜์ด์ง€์˜ ์ถ”์ฒœ ์ธ๋ฑ์Šค๋ฅผ Oracle INVISIBLE INDEX ํŠธ๋ฆญ์œผ๋กœ ์ž ์‹œ ๋งŒ๋“ค์–ด EXPLAIN ๋น„๊ต. ์šด์˜ ์˜ํ–ฅ 0.
      • ์•ˆ์ „์žฅ์น˜: ์ด๋ฆ„ prefix CTK_SIM_* ๊ฐ•์ œ / INVISIBLE ์˜ต์…˜ ๊ฐ•์ œ / ์ตœ๋Œ€ 5๊ฐœ ์ธ๋ฑ์Šค / 60s timeout / try-finally cleanup (์‹คํŒจํ•ด๋„ ํ•ญ์ƒ DROP) / ALTER SESSION SET optimizer_use_invisible_indexes ์„ธ์…˜ ๋‹จ์œ„ ๊ฒฉ๋ฆฌ
      • UI: ์ถ”์ฒœ ์ธ๋ฑ์Šค ์˜† ๐Ÿ”Œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๋ฒ„ํŠผ โ†’ before/after cost ์ง„ํ–‰๋ฐ” + ๊ฐœ์„ ๋ฅ  % + ํŽผ์น˜๋ฉด EXPLAIN PLAN ์ขŒ์šฐ ๋น„๊ต
      • ์‹ ๊ทœ endpoint: POST /api/v1/livedb/simulate-index (JSON body)
    • (Phase 5) ์šด์˜ ๋Œ€์‹œ๋ณด๋“œ + Rate Limit + ํšŒ๋กœ์ฐจ๋‹จ๊ธฐ โ€” ์šด์˜ํŒ€์ด ์ฆ‰์‹œ ๋ชจ๋‹ˆํ„ฐ๋ง ๊ฐ€๋Šฅํ•œ ํ—ฌ์Šค ์ธํ”„๋ผ:
      • Rate Limiter โ€” sliding window per (user ร— profile), ๋ถ„๋‹น max 10 ํ˜ธ์ถœ (์„ค์ • ๊ฐ€๋Šฅ, 0 ์ด๋ฉด ๋น„ํ™œ์„ฑ). ์‚ฌ์šฉ์ž ๊ฒฉ๋ฆฌ.
      • ํšŒ๋กœ์ฐจ๋‹จ๊ธฐ โ€” 10๋ถ„ ๋‚ด timeout 5๊ฑด ๋ฐœ์ƒ ์‹œ 5๋ถ„ ์ž๋™ ๋น„ํ™œ์„ฑ. ๋งŒ๋ฃŒ ํ›„ ์ž๋™ ๋ณต๊ตฌ. ADMIN ์ด ๊ฐ•์ œ ๋ณต๊ตฌ ๊ฐ€๋Šฅ (POST /api/v1/admin/livedb/breaker/{id}/close)
      • ํ˜ธ์ถœ ํ†ต๊ณ„ โ€” ํ”„๋กœํ•„๋ณ„ ์„ฑ๊ณต/์‹คํŒจ/timeout ์นด์šดํŠธ + ํ‰๊ท  latency, JVM ๋ผ์ดํ”„ํƒ€์ž„ ๋ˆ„์ 
      • /admin/health ์‹ ๊ทœ ์นด๋“œ โ€” ํ†ต๊ณ„ ํ‘œ + ํšŒ๋กœ ์ƒํƒœ (๐ŸŸข CLOSED / ๐Ÿ”ด OPEN) + ADMIN ๊ฐ•์ œ ๋ณต๊ตฌ ๋ฒ„ํŠผ
      • ์‹ ๊ทœ endpoint: GET /api/v1/admin/livedb/stats, POST /api/v1/admin/livedb/stats/reset, POST /api/v1/admin/livedb/breaker/{id}/close
    • ์‹ ๊ทœ ํŒจํ‚ค์ง€ io.github.claudetoolkit.ui.livedb โ€” 25 ํด๋ž˜์Šค + 107 ๋‹จ์œ„/ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ
    • ๐Ÿ“˜ ์šด์˜ ๊ฐ€์ด๋“œ: docs/livedb-operations.md โ€” ํ™œ์„ฑํ™” 3-step
      • DB ๊ถŒํ•œ ์š”๊ตฌ์‚ฌํ•ญ (Oracle/PG) + ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… 7๊ฐœ Q&A + Kill Switch ์ ˆ์ฐจ

๐Ÿ†• v4.7.0 ํ•˜์ด๋ผ์ดํŠธ โ€” ์ธ์‚ฌ์ดํŠธ + ์ปดํ”Œ๋ผ์ด์–ธ์Šค + UX ํ’€ ์Šคํƒ ์—…๊ทธ๋ ˆ์ด๋“œ

5๊ฐœ ํฐ ์˜์—ญ์„ ํ•œ ๋ฒˆ์— ๋Œ์–ด์˜ฌ๋ฆฐ ๋ฉ”์ด์ € ๋ฆด๋ฆฌ์Šค. ๊ฐ ํ•ญ๋ชฉ์€ ์šด์˜ํŒ€ / ์™ธ๋ถ€๊ฐ์‚ฌ์ธ / ์‚ฌ์šฉ์ž ๋ชจ๋‘๋ฅผ ๋ณ„๋„ ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ์ง€์›ํ•˜๋„๋ก ์„ค๊ณ„๋๊ณ , ๋ชจ๋“  ๋ณ€๊ฒฝ์€ ๊ธฐ์กด ํŒŒ์ดํ”„๋ผ์ธ ๋ถ€๋‹ด ์—†์ด ์„ ํƒ์ ์œผ๋กœ ํ™œ์„ฑํ™”/์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๐Ÿ›ก ํ•œ๊ตญ ์ปดํ”Œ๋ผ์ด์–ธ์Šค ๋ฆฌํฌํŠธ (4์ข…, ADMIN ์ „์šฉ ์‹ ๊ทœ ํŽ˜์ด์ง€) โ€” /admin/compliance-report
    • ์ „์ž๊ธˆ์œต๊ฐ๋…๊ทœ์ • (FSS) / ๊ฐœ์ธ์ •๋ณด๋ณดํ˜ธ๋ฒ• (PIPA) / ์ •๋ณดํ†ต์‹ ๋ง๋ฒ• / ์™ธ๋ถ€๊ฐ์‚ฌ ์ข…ํ•ฉ 4์ข… ๋ชจ๋‘ ํ™œ์„ฑํ™”. 8~10๊ฐœ ์„น์…˜ markdown + ์ž๋™ ์ ๊ฒ€ ํ‘œ + ์ˆ˜๋™ ๊ฒ€ํ†  ์ฒดํฌ๋ฆฌ์ŠคํŠธ.
    • ์™ธ๋ถ€๊ฐ์‚ฌ ์ข…ํ•ฉ ๋ฆฌํฌํŠธ๋Š” 3๊ฐœ ๋ฒ•๋ น ํšก๋‹จ ๋น„๊ต ํ‘œ ๋กœ โœ…/โš ๏ธ ํ•œ๋ˆˆ์— ํŒŒ์•… ๊ฐ€๋Šฅ
    • ๋‹ค์šด๋กœ๋“œ 3์ข…: .md / .xlsx (Apache POI 4์‹œํŠธ) / ์ธ์‡„ยทPDF (๋ธŒ๋ผ์šฐ์ € ๋„ค์ดํ‹ฐ๋ธŒ ์ €์žฅ)
    • ์˜ต์…˜ ๐Ÿค– AI ๊ฒฝ์˜์ง„ ์š”์•ฝ โ€” Claude ๊ฐ€ 3-5๋ฌธ์žฅ ํ•œ๊ตญ์–ด ์š”์•ฝ์„ markdown ์ƒ๋‹จ์— prepend
    • ์˜๊ตฌ ์ €์žฅ ์ด๋ ฅ โ€” ์ƒ์„ฑ๋œ ๋ฆฌํฌํŠธ๋Š” H2 DB(compliance_report ํ…Œ์ด๋ธ”)์— ์ž๋™ ์ €์žฅ, "์ €์žฅ๋œ ๋ฆฌํฌํŠธ ์ด๋ ฅ" ๋ชจ๋‹ฌ์—์„œ ๊ณผ๊ฑฐ ๋ฆฌํฌํŠธ ๋‹ค์‹œ ๋ณด๊ธฐยท๋‹ค์šด๋กœ๋“œยท์‚ญ์ œ (์ตœ๋Œ€ 500๊ฑด)
  • ๐Ÿ”ฌ ์‹œ์Šคํ…œ ํ—ฌ์Šค ๋Œ€์‹œ๋ณด๋“œ ํ™•์žฅ โ€” /admin/health ๊ฐ€ ๊ธฐ์กด 4๊ฐœ ์นด๋“œ(์„œ๋ฒ„/JVM/DB/์‹œ์Šคํ…œ) + 5๊ฐœ ์‹ ๊ทœ ์นด๋“œ (์ธ๋ฑ์„œ 5์ข… / ์บ์‹œ 3์ข… / Claude API / ๊ฐ์‚ฌ ๋กœ๊ทธ / ์˜ค๋ฅ˜ ๋กœ๊ทธ) ๋กœ ํ™•์žฅ. silent JPQL ์‹คํŒจ ๊ฐ™์€ ์‚ฌ๊ณ ๊ฐ€ ๋˜ ๋ฐœ์ƒํ•˜๋ฉด ์šด์˜ํŒ€์ด ์ฆ‰์‹œ ๋ฐœ๊ฒฌ ๊ฐ€๋Šฅ. 30์ดˆ ์ž๋™ ๊ฐฑ์‹ .
  • ๐Ÿ“Š ์‚ฌ์šฉ์ž/ํŒ€ ์ธ์‚ฌ์ดํŠธ (/roi-report ํ™•์žฅ) โ€” ๊ธฐ์กด ์‹œ์Šคํ…œ ํ†ต๊ณ„ + ์ƒˆ ๋‘ ์„น์…˜:
    • ๋‚ด ํ™œ๋™ โ€” ๋ณธ์ธ ๋ถ„์„/์ฑ„ํŒ…/์‹œ๊ฐ„ ์ ˆ๊ฐ + Top 5 ๊ธฐ๋Šฅ BarChart + 12์ฃผ ๋ˆ„์  LineChart
    • ํŒ€ ๋น„๊ต โ€” ํŒ€ ํ‰๊ท /๋ˆ„์  + ๋ณธ์ธ ์ˆœ์œ„ยท๋ฐฑ๋ถ„์œ„ ์‹œ๊ฐ ์ง„ํ–‰ ๋ฐ” + Top 5 ์‚ฌ์šฉ์ž (ADMIN)
  • ๐Ÿ” ๊ฒ€์ƒ‰ ๊ฐ•ํ™” (ํ•„ํ„ฐ + ์ •๋ ฌ + ๋งค์น˜ ๊ฐ•์กฐ) โ€” /api/v1/search ์— type/from/to/sort ํŒŒ๋ผ๋ฏธํ„ฐ, ๋งค์น˜ ์œ„์น˜ ยฑ60์ž ๋ฐœ์ทŒ snippet, ๊ฒฐ๊ณผ์— <mark> ๋…ธ๋ž€ ๊ฐ•์กฐ. SearchPage ์— ํ•„ํ„ฐ ํ† ๊ธ€ + URL ๋™๊ธฐํ™”.
  • โšก ๋ถ„์„ ๋น„์šฉ ๋ฏธ๋ฆฌ๋ณด๊ธฐ โ€” ๋ชจ๋“  ๋ถ„์„ ์‹œ์ž‘ ๋ฒ„ํŠผ ์˜†์— ์ธ๋ผ์ธ ํ‘œ์‹œ: ๐Ÿช™ ~12K ํ† ํฐ ยท ์˜ˆ์ƒ $0.062 (Sonnet 4). ํ•œ๊ตญ์–ด 1.8 chars/token + ์˜์–ด 3.5 chars/token ํœด๋ฆฌ์Šคํ‹ฑ(ยฑ15% ์˜ค์ฐจ). 23๊ฐœ ๋ถ„์„ ํŽ˜์ด์ง€ ์ž๋™ ์ ์šฉ.
  • ๐Ÿงช SSE ํšŒ๊ท€ ํ…Œ์ŠคํŠธ 4๊ฑด + FSS ๋‹จ์œ„ ํ…Œ์ŠคํŠธ 8๊ฑด โ€” ์ŠคํŠธ๋ฆฌ๋ฐ ๊ฒฝ๋กœ ์ด๋ ฅ ์ €์žฅ ๋ˆ„๋ฝ / ๋ฆฌํฌํŠธ markdown ๋นŒ๋” ํšŒ๊ท€ ๋ฐฉ์ง€. mvn test ํ•œ ๋ฒˆ์ด๋ฉด ๋ฐฑ์—”๋“œ ์ „๋ฐ˜ ๊ฒ€์ฆ.

v4.6.1 ํ•˜์ด๋ผ์ดํŠธ โ€” UX ๊ฐœ์„  + ์ •ํ™•๋„/์•ˆ์ •์„ฑ ํŒจ์น˜

์ด๋ฒˆ ํŒจ์น˜๋Š” ์‚ฌ์šฉ์ž ์›Œํฌํ”Œ๋กœ์˜ ์ž์ž˜ํ•œ ๋งˆ์ฐฐ์„ ํ•œ ๋ฒˆ์— ์ •๋ฆฌํ•˜๋Š” ๋ฐ ์ง‘์ค‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ํฐ ์‹ ๊ทœ ๊ธฐ๋Šฅ์€ ์—†์ง€๋งŒ, ํ˜„์žฅ์—์„œ ๋ฐ”๋กœ ์ฒด๊ฐ๋˜๋Š” ๊ฐœ์„ ์ด ๋ชจ์—ฌ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๐Ÿ”Ž ์ƒ๋‹จ๋ฐ” ๊ธ€๋กœ๋ฒŒ ๊ฒ€์ƒ‰ โ€” ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ์ƒ๋‹จ ๊ฐ€์šด๋ฐ ์˜์—ญ์— ๊ฒ€์ƒ‰์ฐฝ์ด ์ƒ์‹œ ๋…ธ์ถœ๋ฉ๋‹ˆ๋‹ค. Settings ํŒ”๋ ˆํŠธ์˜ accent ์ƒ‰์ƒ์œผ๋กœ ํ…Œ๋‘๋ฆฌ๊ฐ€ ์ž๋™ ๋™๊ธฐํ™”๋˜๊ณ  (ํ…Œ๋งˆ ๋ณ€๊ฒฝ ์‹œ ์ฆ‰์‹œ ์ถ”์ข…), Enter / ๋ฒ„ํŠผ ํด๋ฆญ์œผ๋กœ /search?q=... ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. URL ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ง„์ž…ํ•˜๋ฉด ์ž๋™ ๊ฒ€์ƒ‰๋˜์–ด ๊ณต์œ ยท์ƒˆ๋กœ๊ณ ์นจ์— ์•ˆ์ „.
  • ๐Ÿ—‚ ๊ฒ€์ƒ‰ ํŽ˜์ด์ง€ โ€” ๋ฉ”๋‰ด + ์ด๋ ฅ ํ†ตํ•ฉ โ€” ๋ฉ”๋‰ด ์นดํƒˆ๋กœ๊ทธ๋ฅผ ํด๋ผ์ด์–ธํŠธ ํ•„ํ„ฐ๋กœ ์ฆ‰์‹œ ๋งค์นญ(์˜ˆ: "ํ•˜๋„ค์Šค" โ†’ ์ฝ”๋“œ ๋ฆฌ๋ทฐ/SPโ†’Java/SQL ์ตœ์ ํ™” ํ•˜๋„ค์Šค 3๊ฑด) + ๋ฐฑ์—”๋“œ /api/v1/search ๊ฐ€ review_history ์˜ type/title/inputContent/outputContent 4๊ฐœ ์ปฌ๋Ÿผ์„ LIKE ๊ฒ€์ƒ‰ํ•ด ๋ฉ”๋‰ด์™€ ๋ถ„์„ ์ด๋ ฅ์„ ํ•œ ํ™”๋ฉด์— ๋ณด์—ฌ ์ค๋‹ˆ๋‹ค.
  • ๐Ÿ› ๊ฒ€์ƒ‰ ๋ฐฑ์—”๋“œ ๋ฒ„๊ทธ ์ˆ˜์ • โ€” ์ด์ „ ๊ตฌํ˜„์€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” h.menuName / h.inputText ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•ด JPQL ์ด ๋งค๋ฒˆ throw ํ•˜๊ณ  silent catch ๊ฐ€ ๋นˆ ๊ฒฐ๊ณผ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋˜ ๊ฒฐ์ •์  ๋ฒ„๊ทธ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ ํ•„๋“œ(type/title/inputContent/outputContent) ๋กœ ์ •์ •ํ•˜๊ณ , ํ”„๋ก ํŠธ์—”๋“œ ์นœํ™” DTO({id, menuName, title, snippet, createdAt}) ๋กœ ํ‰ํƒ„ํ™” ์‘๋‹ต.
  • ๐Ÿ’พ ๋ถ„์„ ์ด๋ ฅ ์ €์žฅ โ€” 4๊ฐœ ๊ธฐ๋Šฅ ์ถ”๊ฐ€/์ˆ˜์ • โ€” ๊ธฐ์กด์—” ๋™๊ธฐ /analyze ๊ฒฝ๋กœ๋งŒ review_history ์— ์ €์žฅ๋๊ณ  SSE ์ŠคํŠธ๋ฆฌ๋ฐ ๊ฒฝ๋กœ๋Š” ๋ˆ„๋ฝ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํŒจ์น˜๋กœ ํ…Œ์ด๋ธ” ์˜ํ–ฅ ๋ถ„์„ / SPโ†’Java ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•˜๋„ค์Šค / SQL ์ตœ์ ํ™” ํ•˜๋„ค์Šค / ์˜ค๋ฅ˜ ๋กœ๊ทธ RCA ํ•˜๋„ค์Šค ๊ฐ€ ์ŠคํŠธ๋ฆฌ๋ฐ ์™„๋ฃŒ ์‹œ์ ์—๋„ ์ €์žฅ๋˜๋„๋ก ํ†ต์ผ. ReviewHistoryService.save(type, input, output, username) ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์—์„œ๋„ username ์„ ๋ช…์‹œ ์ „๋‹ฌ ๊ฐ€๋Šฅ.
  • ๐Ÿ“‹ ํ…Œ์ด๋ธ” ์˜ํ–ฅ ๋ถ„์„ โ€” ํŒŒ์ผ ๋ชจ๋‹ฌ ๋ทฐ์–ด + ํด๋ฆฝ๋ณด๋“œ ๋ณต์‚ฌ โ€” /impact ํŽ˜์ด์ง€์—์„œ MiPlatform ๋‹จ๊ณ„๋Š” ์ œ์™ธํ•˜๊ณ  TABLE โ†’ MyBatis โ†’ Java โ†’ Controller 4๋‹จ๊ณ„๋งŒ ๋…ธ์ถœ. MyBatis ๊ตฌ๋ฌธ / Java ํŒŒ์ผ / Controller ํ–‰ ๋ชจ๋‘ ํด๋ฆญํ•˜๋ฉด ๋ชจ๋‹ฌ๋กœ ์ „์ฒด ์†Œ์Šค๊ฐ€ ์—ด๋ฆฌ๊ณ , ์šฐ์ƒ๋‹จ "์ „์ฒด ๋ณต์‚ฌ" ๋ฒ„ํŠผ์œผ๋กœ ํด๋ฆฝ๋ณด๋“œ์— ์ฆ‰์‹œ ๋ณต์‚ฌ. ๋ฐฑ์—”๋“œ GET /api/v1/flow/file?path=... ์—”๋“œํฌ์ธํŠธ(scanPath ์ œํ•œ, 5MB ์ƒํ•œ, path-traversal ๋ฐฉ์–ด) ์‹ ์„ค.
  • ๐Ÿ›  MyBatisCallerIndex false-positive ์ œ๊ฑฐ โ€” ๊ฐ™์€ shortId(์˜ˆ: insertOrder) ๋ฅผ ๊ฐ€์ง„ mapper ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์กด์žฌํ•  ๋•Œ, ๋‹จ์ˆœ .shortId( ๋งค์นญ๋งŒ์œผ๋กœ ๋ชจ๋“  mapper ์˜ ํ˜ธ์ถœ์ž๋กœ ์ž˜๋ชป ๊ธฐ๋ก๋˜๋˜ ๋ฒ„๊ทธ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ fullId ๋ณ„ mapperClass ๋ช…์ด ๊ทธ Java ํŒŒ์ผ์— ๋‹จ์–ด ๊ฒฝ๊ณ„๋กœ ์กด์žฌํ•˜๋Š”์ง€ ๊นŒ์ง€ ๊ฒ€์ฆํ•ด ๋ฌด๊ด€ํ•œ ๋งคํผยท์„œ๋น„์Šค๊ฐ€ ๋Œ๋ ค๋‚˜์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค (ํ…Œ์ด๋ธ” ์˜ํ–ฅ ๋ถ„์„์—์„œ Java/Controller ๊ฒฐ๊ณผ๊ฐ€ ๋ถ€ํ’€์–ด ๋ณด์ด๋˜ ๋ฌธ์ œ ํ•ด๊ฒฐ).
  • ๐Ÿ”Œ DB ๊ฐ์ฒด ์บ์‹œ โ€” TABLE ํฌํ•จ โ€” HarnessCacheService ๊ฐ€ ALL_OBJECTS ์—์„œ PROCEDURE/FUNCTION/PACKAGE/TRIGGER ๋งŒ ๊ฐ€์ ธ์˜ค๋˜ ๊ฒƒ์„ TABLE / VIEW ๊นŒ์ง€ ํ™•์žฅ. "์†Œ์Šค์„ ํƒํ•˜๊ธฐ" ๋ฒ„ํŠผ์ด ์ƒˆ ๋ฉ”๋‰ด์—์„œ ํ…Œ์ด๋ธ” ํ”ฝ์ปค๋กœ ๋™์ž‘.
  • ๐ŸŽฏ ์†Œ์Šค์„ ํƒํ•˜๊ธฐ ๋ฒ„ํŠผ โ€” ๋ฉ”๋‰ด๋ณ„ ํƒ€์ž… ํ•„ํ„ฐ๋ง โ€” SourceSelector ์— dbTypes ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ + pickName(์ด๋ฆ„๋งŒ ๋ฐ˜ํ™˜) ์˜ต์…˜ ์ถ”๊ฐ€. ๋ฉ”๋‰ด๋ณ„ ์ ์šฉ:
    • ํ…Œ์ด๋ธ” ์˜ํ–ฅ ๋ถ„์„ โ†’ TABLE ๋งŒ
    • SPโ†’Java ํ•˜๋„ค์Šค / SQL ์ตœ์ ํ™” ํ•˜๋„ค์Šค โ†’ DB ์˜ค๋ธŒ์ ํŠธ (Java ํŒŒ์ผ ํƒญ ์ œ๊ฑฐ)
  • ๐Ÿž ํ•˜๋„ค์Šค ์ŠคํŠธ๋ฆฌ๋ฐ ๋งˆํฌ๋‹ค์šด ์ค„๋ฐ”๊ฟˆ ๋ฒ„๊ทธ ์ˆ˜์ • โ€” useHarnessStream ์ด ๋งค SSE ๋ฉ”์‹œ์ง€๋งˆ๋‹ค '\n' ์„ ์ธ์œ„์ ์œผ๋กœ ๋ง๋ถ™์ด๊ณ  ์žˆ์–ด Claude ๊ฐ€ ๋‹จ์–ด ์ค‘๊ฐ„("ํ™œ"/"์šฉ") ์—์„œ ์ฒญํฌ๋ฅผ ๋Š์œผ๋ฉด "ํ™œ\n์šฉ" ์ด ๋งˆํฌ๋‹ค์šด soft-break ๋กœ ๋‹จ์–ด๊ฐ€ ๊ฐˆ๋ผ์ ธ ๋ณด์ด๋˜ ๋ฒ„๊ทธ. flush ๊ธฐ์ค€์„ ์ค„๋ฐ”๊ฟˆ ๋‹จ์œ„์—์„œ STAGE_MARKER prefix ๋ณดํ˜ธ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋‹จ์–ด ๋ถ„๋ฆฌ 0๊ฑด.
  • ๐Ÿ—‘ ๋ฉ”๋‰ด ์ •๋ฆฌ โ€” ํŒจํ‚ค์ง€ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„(/package-deps) ยท SP ํ๋ฆ„ ๋ถ„์„(/sp-impact) ๋‘ ๋ฉ”๋‰ด๋ฅผ ๋ฐฑ์—”๋“œ ์—”๋“œํฌ์ธํŠธ + ํ”„๋ก ํŠธ ๋ผ์šฐํŠธ + e2e ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๊นŒ์ง€ ์™„์ „ ์ œ๊ฑฐ. ์ž”์กด ์ฐธ์กฐ 0๊ฑด.

v4.6.0 ํ•˜์ด๋ผ์ดํŠธ โ€” ํ•˜๋„ค์Šค ํŒŒ์ดํ”„๋ผ์ธ ํ™•์žฅ (Phase A ยท D ยท B ยท C)

๊ธฐ์กด "์ฝ”๋“œ ๋ฆฌ๋ทฐ ํ•˜๋„ค์Šค" ์˜ 4๋‹จ๊ณ„(Analyst โ†’ Builder โ†’ Reviewer โ†’ Verifier) ํŒจํ„ด์„ ๊ณตํ†ต ์ธํ”„๋ผ๋กœ ์ถ”์ถœํ•˜๊ณ , ์šด์˜ํŒ€ยทDBA๊ฐ€ ์ž์ฃผ ๋งˆ์ฃผํ•˜๋Š” 3๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋™์ผ ํŒจํ„ด์„ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. 4๊ฐœ ํ•˜๋„ค์Šค๊ฐ€ ๊ฐ™์€ OrchestratorยทPromptLoaderยทUI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

  • ๐Ÿ›  ๊ณตํ†ต ํ•˜๋„ค์Šค ์ธํ”„๋ผ (Phase A) โ€” HarnessOrchestrator (sync + SSE ์ŠคํŠธ๋ฆฌ๋ฐ, sentinel ์ž๋™ emit) ยท PromptLoader (prompts/harness/{name}/{stage}.md classpath ์™ธ๋ถ€ํ™” + ๊ฒฝ๋กœ ์ธ์ ์…˜ ์ฐจ๋‹จ) ยท HarnessAuditWriter (์˜ต์…”๋„ ๊ฐ์‚ฌ ๋กœ๊ทธ, toolkit.harness.audit=true) ยท ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ React useHarnessStream ํ›… + <HarnessStagePanels /> ์ปดํฌ๋„ŒํŠธ
  • ๐Ÿž ์˜ค๋ฅ˜ ๋กœ๊ทธ RCA ํ•˜๋„ค์Šค (Phase D) โ€” /loganalyzer ํŽ˜์ด์ง€์— "RCA ํ•˜๋„ค์Šค (4๋‹จ๊ณ„)" ๋ชจ๋“œ ํ† ๊ธ€. ์ผ๋ฐ˜ RCA / ๋ณด์•ˆ RCA(OWASP Top 10) ๋‘ ๋ชจ๋“œ ์ง€์›. ๊ฐ€์„ค ํ›„๋ณด โ†’ ๊ฒ€์ฆ SQL+ํŒจ์น˜+๋กค๋ฐฑ ๊ณ„ํš โ†’ ์šฐ๋„ ํ‰๊ฐ€ โ†’ ์‚ฌ๋‚ด ํ‘œ์ค€ RCA ๋ณด๊ณ ์„œ + ์žฌ๋ฐœ ๋ฐฉ์ง€ ์ฒดํฌ๋ฆฌ์ŠคํŠธ ์ž๋™ ์ƒ์„ฑ
  • ๐Ÿ”„ SPโ†’Java ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•˜๋„ค์Šค (Phase B) โ€” /sp-migration-harness ์‹ ๊ทœ ํŽ˜์ด์ง€. DB ์˜ค๋ธŒ์ ํŠธ ์„ ํƒ ๋ฒ„ํŠผ์œผ๋กœ Oracle SP/Function/Package/Trigger๋ฅผ ALL_SOURCE์—์„œ ์ž๋™ ๋กœ๋“œ. SP ์˜๋ฏธ ๋ถ„์„ โ†’ Service+Mapper+XML+DTO+ํ…Œ์ŠคํŠธ ์ƒ์„ฑ โ†’ ํ–‰์œ„ ๋™๋“ฑ์„ฑ ๊ฒ€์ฆ โ†’ ์ปดํŒŒ์ผยทMyBatis XML ์ •ํ•ฉ์„ฑ ์ •์  ๊ฒ€์ฆ
  • โšก SQL ์ตœ์ ํ™” ํ•˜๋„ค์Šค (Phase C) โ€” /sql-optimization-harness ์‹ ๊ทœ ํŽ˜์ด์ง€. ์ฟผ๋ฆฌยท์‹คํ–‰๊ณ„ํšยทํ†ต๊ณ„ยท์ธ๋ฑ์Šคยท๋ณ€๊ฒฝ ๋ถˆ๊ฐ€ ์ œ์•ฝ ๋‹ค์ค‘ ์ž…๋ ฅ โ†’ ๋ณ‘๋ชฉ ๋ถ„์„ โ†’ N๊ฐœ ํ›„๋ณด (rewrite + DDL + ํžŒํŠธ, ๋น„์šฉ/๋ฆฌ์Šคํฌ/๋กค๋ฐฑ) โ†’ ๊ฒฐ๊ณผ ๋™๋“ฑ์„ฑยท๋‹ค๋ฅธ ์ฟผ๋ฆฌ ์˜ํ–ฅ ํ‰๊ฐ€ โ†’ ๋‹จ๊ณ„๋ณ„ Rollout Plan
  • ๐Ÿ”’ ๊ถŒํ•œ ๊ฒŒ์ดํŒ… ํ†ตํ•ฉ โ€” 3๊ฐœ ์‹ ๊ทœ feature key (loganalyzer-harness, sp-migration-harness, sql-optimization-harness)๊ฐ€ ์–ด๋“œ๋ฏผ ๊ถŒํ•œ ํ™”๋ฉด์—์„œ ์ฆ‰์‹œ ON/OFF. URL/CSRF/์‚ฌ์ด๋“œ๋ฐ” ๋ฉ”๋‰ด๊นŒ์ง€ ์ž๋™ ์ ์šฉ
  • ๐Ÿงช ํ…Œ์ŠคํŠธ 27๊ฑด ์‹ ๊ทœ โ€” Orchestrator/PromptLoader 14 + Log RCA 10 + SP Migration 9 + SQL Optimization 6 + ๊ถŒํ•œ ๋“ฑ๋ก ํšŒ๊ท€ ๋ฐฉ์ง€ 3. ์ „์ฒด 142๊ฐœ ํ…Œ์ŠคํŠธ ํ†ต๊ณผ, ํšŒ๊ท€ 0๊ฑด

v4.5.0 ํ•˜์ด๋ผ์ดํŠธ

  • ๐Ÿ“ฆ ํŒจํ‚ค์ง€ ๋ถ„์„ (์‹ ๊ทœ) โ€” Java ํŒจํ‚ค์ง€ ๋‹จ์œ„ 4ํƒญ ๋ถ„์„ (/package-overview):
    • ๐Ÿ“Š ์š”์•ฝ โ€” ํด๋ž˜์Šค / Controller / Service / DAO / MyBatis ํ†ต๊ณ„
    • ๐Ÿ”— ERD โ€” ์—ฐ๊ด€ ํ…Œ์ด๋ธ” Mermaid + heatmap (ํžˆํŠธ์นด์šดํŠธ)
    • ๐ŸŒŠ ํ’€ ํ๋ฆ„๋„ โ€” ํŒจํ‚ค์ง€๊ฐ€ ๊ฑด๋“œ๋ฆฌ๋Š” ๋ชจ๋“  ํ…Œ์ด๋ธ” โ†’ MyBatis โ†’ Java โ†’ Controller ์ž๋™ ๋ณ‘ํ•ฉ
    • ๐Ÿ“œ ์Šคํ† ๋ฆฌ โ€” Claude ๊ฐ€ ์‹ ์ž… ์นœํ™” ํ•œ๊ตญ์–ด ๋งˆํฌ๋‹ค์šด ๋‚ด๋Ÿฌํ‹ฐ๋ธŒ ์ƒ์„ฑ
  • ๐Ÿ—บ ์ „์‚ฌ ํŒจํ‚ค์ง€ ์ง€๋„ (์‹ ๊ทœ) โ€” /project-map ๋“œ๋ฆด๋‹ค์šด ์นด๋“œ ๊ทธ๋ฆฌ๋“œ + ๊ฒ€์ƒ‰ ํ•„ํ„ฐ, ๋ฆฌํ”„ ๋ ˆ๋ฒจ ๋„๋‹ฌ ์‹œ ํŒจํ‚ค์ง€ ๊ฐœ์š”๋กœ ์ ํ”„
  • ๐Ÿ”’ ๋ณด์•ˆ ๊ฐ•ํ™” โ€” POST /api/v1/package/refresh ADMIN ๊ถŒํ•œ ๊ฐ•์ œ, prefix 200์ž ๊ธธ์ด ์บก
  • โฑ Claude ํ˜ธ์ถœ 45s ํƒ€์ž„์•„์›ƒ โ€” PackageStoryService ๊ฐ€ ์™ธ๋ถ€ ์ง€์—ฐ์œผ๋กœ ํ†ฐ์บฃ ์Šค๋ ˆ๋“œ๋ฅผ hang ์‹œํ‚ค์ง€ ์•Š์Œ
  • ๐Ÿ›  toolkit.indexer.* ์™ธ๋ถ€ํ™” โ€” application.yml ๋กœ maxJavaScan / maxFileSize ํŠœ๋‹
  • ๐Ÿ“ค ํŒจํ‚ค์ง€ ์Šคํ† ๋ฆฌ Markdown export โ€” GET /api/v1/package/story/export?name=... ์œ„ํ‚ค ๋ณต๋ถ™์šฉ
  • ๐Ÿ“Š ์–ด๋“œ๋ฏผ ์บ์‹œ ํ†ต๊ณ„ โ€” GET /api/v1/admin/caches (ADMIN ์ „์šฉ)
  • ๐Ÿงช ํ…Œ์ŠคํŠธ 12๊ฐœ ์‹ ๊ทœ โ€” PackageAnalysisControllerTest + PackageStoryServiceTest

v4.4.0 ํ•˜์ด๋ผ์ดํŠธ

  • ๐Ÿ“œ OpenAPI / Swagger UI โ€” /swagger-ui.html (ADMIN ์ „์šฉ) ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ API ์นดํƒˆ๋กœ๊ทธ + /v3/api-docs JSON ์ŠคํŽ™
  • ๐Ÿž ์ž์ฒด ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง (Sentry-style) โ€” /admin/error-log dedupe + ์ž๋™ unresolved ๋ณต๊ท€ + ์ŠคํƒํŠธ๋ ˆ์ด์Šค ๋ณด์กด
  • ๐Ÿ“ˆ ๋ฉ”ํŠธ๋ฆญ 5์ข… ์‹ ๊ทœ โ€” ์บ์‹œ / SSE / ํ•˜๋„ค์Šค 4๋‹จ๊ณ„ / ์—๋Ÿฌ์œจ / ํŒŒ์ดํ”„๋ผ์ธ ๋‹จ๊ณ„. Grafana 18 ํŒจ๋„
  • โŽˆ Helm Chart Kind ์ž๋™ ๊ฒ€์ฆ โ€” bash scripts/test-helm.sh ํ•œ ๋ฒˆ์— ๊ฒ€์ฆ
  • ๐Ÿค– ์ž๋™ ๋ณ€๊ฒฝ ๋กœ๊ทธ โ€” release-please-action โ€” feat/fix commit โ†’ CHANGELOG.md + GitHub Release ์ž๋™ ์ƒ์„ฑ
  • ๐Ÿงช ํ…Œ์ŠคํŠธ 64๊ฐœ + JaCoCo โ€” ์ปค๋ฒ„๋ฆฌ์ง€ ์ž๋™ ๋ฆฌํฌํŒ…
  • ๐Ÿ” ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๋ถ„์„ โ€” ํ…Œ์ด๋ธ”/SP/SQL_ID ์‹œ์ž‘์ ์—์„œ MyBatis ยท Java ยท Controller ยท MiPlatform ๊นŒ์ง€ ์ž๋™ ์ถ”์  โ†’ ReactFlow ๋‹ค์ด์–ด๊ทธ๋žจ + LLM narrative + ๋ถ„์„ ์ด๋ ฅ/๊ณต์œ  ๋งํฌ. /flow-analysis (Admin ๊ถŒํ•œ ๊ด€๋ฆฌ์—์„œ ์‚ฌ์šฉ์ž๋ณ„ on/off)

๐Ÿ“‹ ์ „์ฒด ๋ณ€๊ฒฝ ์ด๋ ฅ์€ CHANGELOG.md โ€” release-please ๊ฐ€ ์ž๋™ ๊ฐฑ์‹ 


๐Ÿ“ธ ๋ฐ๋ชจ

์บก์ฒ˜ ๊ฐ€์ด๋“œ: docs/screenshots/README.md

ํ•ต์‹ฌ ๊ธฐ๋Šฅ

ํ™ˆ ๋Œ€์‹œ๋ณด๋“œ SQL ๋ฆฌ๋ทฐ
ํ™ˆ ๋Œ€์‹œ๋ณด๋“œ SQL ๋ฆฌ๋ทฐ
ํŒŒ์ดํ”„๋ผ์ธ ๊ทธ๋ž˜ํ”„ 4๋‹จ๊ณ„ ํ•˜๋„ค์Šค
ํŒŒ์ดํ”„๋ผ์ธ ๊ทธ๋ž˜ํ”„ ํ•˜๋„ค์Šค

v4.3.0 ์‹ ๊ทœ

SQL ์ธ๋ฑ์Šค ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๋น„์šฉ ์˜ตํ‹ฐ๋งˆ์ด์ €
์ธ๋ฑ์Šค ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๋น„์šฉ ์˜ตํ‹ฐ๋งˆ์ด์ €
์–ธ์–ด ์„ ํƒ (5๊ฐœ ์–ธ์–ด) ๋Œ€์‹œ๋ณด๋“œ ํŽธ์ง‘ ๋ชจ๋“œ
์–ธ์–ด ์Šค์œ„์ฒ˜ ๋Œ€์‹œ๋ณด๋“œ ํŽธ์ง‘

v4.4.0 ์‹ ๊ทœ

Swagger UI ์˜ค๋ฅ˜ ๋กœ๊ทธ (Sentry-style) Grafana ๋Œ€์‹œ๋ณด๋“œ
Swagger UI ์˜ค๋ฅ˜ ๋กœ๊ทธ Grafana

v4.3.0 ํ•˜์ด๋ผ์ดํŠธ

์นดํ…Œ๊ณ ๋ฆฌ ์ฃผ์š” ๊ธฐ๋Šฅ
๐Ÿ“ค ๋ฐ์ดํ„ฐ ๋‚ด๋ณด๋‚ด๊ธฐ SARIF 2.1.0 (IDE ์—ฐ๋™) / Excel ์›Œํฌ๋ถ (3 ์‹œํŠธ + ํ•ฉ๊ณ„ ์ˆ˜์‹)
๐Ÿ“ˆ ๋ชจ๋‹ˆํ„ฐ๋ง Prometheus + Grafana ์ž๋™ ํ”„๋กœ๋น„์ €๋‹ (docker-compose --profile monitoring)
๐Ÿ’ฐ ๋น„์šฉ ์ตœ์ ํ™” AI ๋ชจ๋ธ ๋น„์šฉ ์˜ตํ‹ฐ๋งˆ์ด์ € โ€” ๋ถ„์„ ์œ ํ˜•๋ณ„ ์ตœ์  ๋ชจ๋ธ ์ถ”์ฒœ (Haiku/Sonnet/Opus)
โšก DB ๋ถ„์„ SQL ์ธ๋ฑ์Šค ์ž„ํŒฉํŠธ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ โ€” ์ •์  ํŒŒ์‹ฑ + JDBC ๋ฉ”ํƒ€์กฐํšŒ + DDL ์ž๋™ ์ƒ์„ฑ
๐ŸŒ ๋‹ค๊ตญ์–ด ํ•œ / ์˜ / ์ผ / ์ค‘ / ๋… (5๊ฐœ ์–ธ์–ด) + ์‚ฌ์šฉ์ž๋ณ„ ์ž๋™ ๋™๊ธฐํ™”
๐Ÿ“ ๋Œ€์‹œ๋ณด๋“œ ์œ„์ ฏ ๋“œ๋ž˜๊ทธ/๋ฆฌ์‚ฌ์ด์ฆˆ/์ˆจ๊น€ + ์‚ฌ์šฉ์ž๋ณ„ ๋ ˆ์ด์•„์›ƒ ์˜์†ํ™”
๐ŸŒณ ์›Œํฌํ”Œ๋กœ ํŒŒ์ดํ”„๋ผ์ธ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ๊ทธ๋ž˜ํ”„ (reactflow)
โŽˆ K8s ๋ฐฐํฌ Helm Chart (Deployment + Service + Ingress + HPA + ServiceMonitor)

๐Ÿ“ฆ ๋ชจ๋“ˆ ๊ตฌ์„ฑ

๋ชจ๋“ˆ ์„ค๋ช… ํ˜•ํƒœ
claude-spring-boot-starter application.yml ์„ค์ •๋งŒ์œผ๋กœ ClaudeClient Bean ์ž๋™ ์ฃผ์ž…. SSE ์ŠคํŠธ๋ฆฌ๋ฐ + ๋Ÿฐํƒ€์ž„ ๋ชจ๋ธ ์ „ํ™˜ ์ง€์› Library
claude-sql-advisor SQL / Oracle SP ๋ฆฌ๋ทฐ, ๋ณด์•ˆ ๊ฐ์‚ฌ, ์ธ๋ฑ์Šค ์ตœ์ ํ™” ์ œ์•ˆ, ERD ๋ถ„์„, Mock ๋ฐ์ดํ„ฐ ์ƒ์„ฑ, DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ Library + CLI
claude-doc-generator ๊ธฐ์ˆ  ๋ฌธ์„œ(Oracle Package ํฌํ•จ), Javadoc ์ƒ์„ฑ, ๋ฆฌํŒฉํ„ฐ๋ง ์ œ์•ˆ, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ, API ๋ช…์„ธ, ์ฝ”๋“œ ๋ณ€ํ™˜(iBatis ์ง€์›), ์ฝ”๋“œ ๋ฆฌ๋ทฐ, ๋ณต์žก๋„ ๋ถ„์„, pom.xml ์˜์กด์„ฑ ๋ถ„์„, ๋ฐ์ดํ„ฐ ๋งˆ์Šคํ‚น, Spring ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜, ๋กœ๊ทธ ๋ถ„์„, ์ •๊ทœ์‹ ์ƒ์„ฑ, ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ Library + CLI
claude-toolkit-ui ์œ„ ๊ธฐ๋Šฅ๋“ค์„ ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉํ•˜๋Š” React SPA ๋Œ€์‹œ๋ณด๋“œ (v4.0 ์ „ํ™˜) Spring Boot + React

๐Ÿš€ Quick Start

1. ์‚ฌ์ „ ์š”๊ตฌ์‚ฌํ•ญ

  • JDK 1.8+
  • Maven 3.6+
  • Node.js 18+ (React ๋นŒ๋“œ โ€” frontend-maven-plugin์ด ์ž๋™ ์„ค์น˜ํ•˜๋ฏ€๋กœ ์„ ํƒ)
  • Anthropic API Key

2. Clone & Build

git clone https://github.com/Sangmoo/Claude-Java-Toolkit.git
cd claude-java-toolkit

# Maven ๋นŒ๋“œ (React ํ”„๋ก ํŠธ์—”๋“œ ์ž๋™ ๋นŒ๋“œ ํฌํ•จ)
mvn clean package -DskipTests

frontend-maven-plugin์ด ์ž๋™์œผ๋กœ Node.js ์„ค์น˜ โ†’ npm install โ†’ npm run build๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฌผ์€ claude-toolkit-ui/src/main/resources/static/app/์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

ํ”„๋ก ํŠธ์—”๋“œ๋งŒ ๊ฐœ๋ฐœํ•  ๋•Œ: cd claude-toolkit-ui/frontend && npm run dev (Vite ๊ฐœ๋ฐœ ์„œ๋ฒ„ 5173 ํฌํŠธ) IntelliJ ์‚ฌ์šฉ์ž: Maven ํŒจ๋„์—์„œ ๋ฃจํŠธ ํ”„๋กœ์ ํŠธ โ†’ Lifecycle โ†’ package ๋”๋ธ”ํด๋ฆญ

3. Web UI ์‹คํ–‰

# Mac / Linux
export CLAUDE_API_KEY=sk-ant-...

# Windows PowerShell
$env:CLAUDE_API_KEY="sk-ant-..."

cd claude-toolkit-ui
mvn spring-boot:run

๋ธŒ๋ผ์šฐ์ €์—์„œ http://localhost:8027 ์ ‘์† โ†’ ์„ค์น˜ ๋งˆ๋ฒ•์‚ฌ ๋˜๋Š” ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™

์ดˆ๊ธฐ ๋กœ๊ทธ์ธ: admin / admin1234

4. Docker ๋ฐฐํฌ (์„ ํƒ)

# 1. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •
cp .env.example .env
# .env ํŒŒ์ผ์—์„œ CLAUDE_API_KEY ์„ค์ •

# 2-A. H2 DB (๊ธฐ๋ณธ๊ฐ’, ๋ณ„๋„ DB ๋ถˆํ•„์š”)
docker-compose up -d claude-toolkit

# 2-B. MySQL ์‚ฌ์šฉ ์‹œ
DB_TYPE=mysql docker-compose --profile mysql up -d

# 2-C. PostgreSQL ์‚ฌ์šฉ ์‹œ
DB_TYPE=postgresql docker-compose --profile postgresql up -d

# 2-D. Prometheus + Grafana ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํƒ ํ•จ๊ป˜ ์‹คํ–‰ (v4.3.0)
docker-compose --profile monitoring up -d
# โ†’ Grafana:    http://localhost:3000 (admin/admin)
# โ†’ Prometheus: http://localhost:9090
# โ†’ "Claude Toolkit Overview" ๋Œ€์‹œ๋ณด๋“œ ์ž๋™ ํ”„๋กœ๋น„์ €๋‹ (10๊ฐœ ํŒจ๋„)

# ์œ„ ์˜ต์…˜๋“ค์€ ์กฐํ•ฉ ๊ฐ€๋Šฅ:
DB_TYPE=postgresql docker-compose --profile postgresql --profile monitoring up -d
ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค๋ช… ๊ธฐ๋ณธ๊ฐ’
CLAUDE_API_KEY Anthropic API ํ‚ค (ํ•„์ˆ˜)
CLAUDE_MODEL ์‚ฌ์šฉํ•  Claude ๋ชจ๋ธ ID (์žฌ๋นŒ๋“œ ์—†์ด ์ „ํ™˜ ๊ฐ€๋Šฅ) claude-sonnet-4-6
DB_TYPE ๋‚ด๋ถ€ DB ์œ ํ˜• (h2/mysql/postgresql) h2
DB_HOST DB ํ˜ธ์ŠคํŠธ (MySQL/PG) db
DB_PORT DB ํฌํŠธ 3306
DB_NAME DB ์ด๋ฆ„ claude_toolkit
DB_USERNAME / DB_PASSWORD DB ๊ณ„์ • claude / claude1234
PORT ์›น ์„œ๋ฒ„ ํฌํŠธ 8027
GRAFANA_USER / GRAFANA_PASSWORD Grafana ๊ด€๋ฆฌ์ž ๊ณ„์ • (monitoring ํ”„๋กœํ•„) admin / admin
TOOLKIT_LIVEDB_ENABLED Live DB ์ง์ ‘ ์—ฐ๊ฒฐ ๊ธฐ๋Šฅ ํ™œ์„ฑํ™” true
TOOLKIT_LIVEDB_TIMEOUT Live DB ์ฟผ๋ฆฌ ํƒ€์ž„์•„์›ƒ(์ดˆ) 30
TOOLKIT_LIVEDB_MAX_ROWS Live DB ์กฐํšŒ ์ตœ๋Œ€ ํ–‰ ์ˆ˜ 1000
TOOLKIT_LIVEDB_RATE_LIMIT ์‚ฌ์šฉ์ž๋ณ„ ๋ถ„๋‹น Live DB ํ˜ธ์ถœ ํ•œ๋„ 10
TOOLKIT_MCP_AUTOSTART ์‚ฌ๋‚ด๋ง MCP Server ์ž๋™ ๊ธฐ๋™ ์—ฌ๋ถ€ (true/false). Docker ์—์„œ๋Š” false ๊ธฐ๋ณธ โ€” MCP ๋Š” ๋ณ„๋„ ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ถ„๋ฆฌ. dev ํ™˜๊ฒฝ์—์„œ๋Š” true (application.yml ๊ธฐ๋ณธ) false (Docker)
CTK_DB_PROFILE_ID MCP ๋„๊ตฌ ๊ธฐ๋ณธ Live DB ํ”„๋กœํ•„ ID (๋ฏธ์„ค์ •)

Kubernetes / Helm ๋ฐฐํฌ๋Š” ์•„๋ž˜ ๐Ÿšข ๋ฐฐํฌ ๊ฐ€์ด๋“œ ์„น์…˜ ์ฐธ๊ณ .

5. ์„ค์น˜ ๋งˆ๋ฒ•์‚ฌ

์ตœ์ดˆ ์‹คํ–‰ ์‹œ /setup ํŽ˜์ด์ง€๋กœ ์ž๋™ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค:

  1. API ํ‚ค ์ž…๋ ฅ โ†’ ์ €์žฅ + ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ
  2. Oracle DB ์„ค์ • โ†’ ์ €์žฅ + ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ (์„ ํƒ)
  3. ์ด๋ฉ”์ผ ์„ค์ • (๋‚˜์ค‘์— Settings์—์„œ ์„ค์ • ๊ฐ€๋Šฅ)
  4. ์™„๋ฃŒ โ†’ ๊ด€๋ฆฌ์ž ๊ณ„์ • ํ™•์ธ

"๋‚˜์ค‘์— ์„ค์ •ํ•˜๊ธฐ" ๋ฒ„ํŠผ์œผ๋กœ ์Šคํ‚ตํ•˜๊ณ  Settings์—์„œ ๊ฐœ๋ณ„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

6. ํ—ฌ์Šค์ฒดํฌ

curl http://localhost:8027/actuator/health
{
  "status": "UP",
  "components": {
    "claudeApi":   { "status": "UP", "details": { "model": "claude-sonnet-4-6", "responseTime": "342ms" } },
    "oracleDb":    { "status": "UNKNOWN", "details": { "reason": "Oracle DB ๋ฏธ์„ค์ •" } },
    "mcpServer":   { "status": "UP", "details": { "status": "running", "pid": 12345, "port": 8028 } }
  }
}

๐Ÿšข ๋ฐฐํฌ ๊ฐ€์ด๋“œ (Deployment Guide)

v4.3.0 ๊ธฐ์ค€ โ€” ํ™˜๊ฒฝ์— ๋”ฐ๋ผ 3๊ฐ€์ง€ ์˜ต์…˜ ์ค‘ ์„ ํƒํ•˜์„ธ์š”.

๐Ÿ“‹ ์˜ต์…˜ ๋น„๊ต ๋งคํŠธ๋ฆญ์Šค

ํ•ญ๋ชฉ ๐ŸŸข Docker Compose ๐ŸŸก JAR ์ง์ ‘ ์‹คํ–‰ ๐Ÿ”ต Kubernetes (Helm)
์„ค์น˜ ๋‚œ์ด๋„ โญ โญ โญโญโญ
๋‹ค์ค‘ ์ธ์Šคํ„ด์Šค โŒ โŒ โœ…
์ž๋™ ์Šค์ผ€์ผ๋ง (HPA) โŒ โŒ โœ…
๋ฌด์ค‘๋‹จ ๋ฐฐํฌ โŒ ์ˆ˜๋™ โœ…
Prometheus ์—ฐ๋™ โœ… (Compose ํ”„๋กœํ•„) โŒ โœ… (ServiceMonitor)
์˜์† ๋ณผ๋ฅจ โœ… (volume) OS FS โœ… (PVC)
Ingress / TLS ๋ณ„๋„ ์„ค์ • ๋ณ„๋„ ์„ค์ • โœ… (annotation 1์ค„)
๊ถŒ์žฅ ํ™˜๊ฒฝ ๊ฐœ๋ฐœ / ์†Œ๊ทœ๋ชจ (~10๋ช…) VM ๋‹จ์ผ ์„œ๋ฒ„ ์šด์˜, ๋‹ค์ค‘ ์‚ฌ์šฉ์ž

๐ŸŸข ์˜ต์…˜ 1 โ€” Docker Compose (๊ฐ€์žฅ ๊ฐ„๋‹จ)

# 1. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •
cp .env.example .env
# .env ์—์„œ CLAUDE_API_KEY=sk-ant-... ์„ค์ •

# 2-A. H2 DB (๊ธฐ๋ณธ โ€” ๋ณ„๋„ DB ๋ถˆํ•„์š”)
docker-compose up -d

# 2-B. MySQL ์‚ฌ์šฉ
DB_TYPE=mysql docker-compose --profile mysql up -d

# 2-C. PostgreSQL ์‚ฌ์šฉ
DB_TYPE=postgresql docker-compose --profile postgresql up -d

# 2-D. Prometheus + Grafana ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํƒ ํ•จ๊ป˜ ์‹คํ–‰
docker-compose --profile monitoring up -d
#  โ†’ Grafana:    http://localhost:3000 (admin/admin)
#  โ†’ Prometheus: http://localhost:9090
#  โ†’ "Claude Toolkit Overview" ๋Œ€์‹œ๋ณด๋“œ ์ž๋™ ํ”„๋กœ๋น„์ €๋‹

# ์กฐํ•ฉ ๊ฐ€๋Šฅ โ€” ์™ธ๋ถ€ PG + ๋ชจ๋‹ˆํ„ฐ๋ง ๋™์‹œ ํ™œ์„ฑํ™”
DB_TYPE=postgresql docker-compose --profile postgresql --profile monitoring up -d

๐ŸŸก ์˜ต์…˜ 2 โ€” JAR ์ง์ ‘ ์‹คํ–‰ (Docker ๋ฏธ์‚ฌ์šฉ ํ™˜๊ฒฝ)

# 1. ๋นŒ๋“œ
mvn clean package -DskipTests

# 2. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • + ์‹คํ–‰
export CLAUDE_API_KEY=sk-ant-...
export DB_TYPE=h2                              # ๋˜๋Š” mysql / postgresql
java -jar claude-toolkit-ui/target/claude-toolkit-ui-0.1.0-SNAPSHOT.jar

# ๋˜๋Š” systemd ์„œ๋น„์Šค๋กœ ๋“ฑ๋ก (CentOS/Ubuntu)
sudo cp claude-toolkit.service /etc/systemd/system/
sudo systemctl enable --now claude-toolkit

์ ํ•ฉํ•œ ๊ฒฝ์šฐ: Docker ๋ฏธ์‚ฌ์šฉ ์‚ฌ๋‚ด VM, ๊ฐ„๋‹จํ•œ ๋‹จ์ผ ์„œ๋ฒ„ ์šด์˜


๐Ÿ”ต ์˜ต์…˜ 3 โ€” Kubernetes (Helm Chart)

โš ๏ธ ํ˜„์žฌ ์ƒํƒœ: helm/claude-toolkit/ v0.1.0 โ€” helm template ์ •์  ๊ฒ€์ฆ๋งŒ ์™„๋ฃŒ. ์‹ค์ œ K8s ํ™˜๊ฒฝ ์ ์šฉ ์ „ ํ…Œ์ŠคํŠธ ํด๋Ÿฌ์Šคํ„ฐ ๊ฒ€์ฆ ๊ถŒ์žฅ.

Helm Chart ๋ณด๋Š” ๋ฒ•

GitHub ๋˜๋Š” ๋กœ์ปฌ ์ €์žฅ์†Œ์˜ ๋‹ค์Œ ๊ฒฝ๋กœ:

helm/claude-toolkit/
โ”œโ”€โ”€ Chart.yaml          โ† ์ฐจํŠธ ๋ฉ”ํƒ€์ •๋ณด (์ด๋ฆ„, ๋ฒ„์ „, appVersion)
โ”œโ”€โ”€ values.yaml         โ† ๋ชจ๋“  ์„ค์ •๊ฐ’ + ํ•œ๊ธ€ ์ฃผ์„ (ํŠœ๋‹ ์‹œ ์ด ํŒŒ์ผ๋งŒ ๋ณด๋ฉด ๋จ)
โ”œโ”€โ”€ README.md           โ† 6๊ฐ€์ง€ ์„ค์น˜ ์‹œ๋‚˜๋ฆฌ์˜ค + ์˜ต์…˜ ํ‘œ
โ””โ”€โ”€ templates/
    โ”œโ”€โ”€ _helpers.tpl    โ† ๊ณตํ†ต ํ—ฌํผ (์ด๋ฆ„, ๋ผ๋ฒจ)
    โ”œโ”€โ”€ deployment.yaml โ† ์•ฑ ์ปจํ…Œ์ด๋„ˆ + env + healthcheck
    โ”œโ”€โ”€ service.yaml    โ† ClusterIP
    โ”œโ”€โ”€ ingress.yaml    โ† Ingress (์˜ต์…˜)
    โ”œโ”€โ”€ secret.yaml     โ† Claude API Key + DB Password
    โ”œโ”€โ”€ pvc.yaml        โ† H2 ๋ชจ๋“œ ์˜์†ํ™” ๋ณผ๋ฅจ
    โ”œโ”€โ”€ hpa.yaml        โ† Horizontal Pod Autoscaler
    โ”œโ”€โ”€ serviceaccount.yaml
    โ”œโ”€โ”€ servicemonitor.yaml โ† prometheus-operator ์—ฐ๋™
    โ””โ”€โ”€ NOTES.txt       โ† ์„ค์น˜ ํ›„ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€

๋กœ์ปฌ์—์„œ ์ฐจํŠธ ๊ฒ€์ฆ (3๋‹จ๊ณ„)

1๋‹จ๊ณ„ โ€” ๋„๊ตฌ ์„ค์น˜ (ํ•œ ๋ฒˆ๋งŒ)

Windows (winget โ€” ๊ถŒ์žฅ):

# ์‚ฌ์ „: Docker Desktop ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•จ
winget install Kubernetes.kind            # Kind (Kubernetes in Docker)
winget install Kubernetes.kubectl         # kubectl
winget install Helm.Helm                  # Helm

macOS:

brew install kind kubectl helm

Linux (Ubuntu/Debian):

# Kind
[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64
chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind

# kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# Helm
curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null && \
  echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list && \
  sudo apt-get update && sudo apt-get install helm
2๋‹จ๊ณ„ โ€” ์ž๋™ ๊ฒ€์ฆ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ (10~15๋ถ„)
# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • (์žˆ์œผ๋ฉด ์ข‹์Œ, ์—†์–ด๋„ ๋™์ž‘)
export CLAUDE_API_KEY=sk-ant-...

# ๊ฒ€์ฆ ์ž๋™ ์‹คํ–‰
bash scripts/test-helm.sh

# ์˜ต์…˜:
bash scripts/test-helm.sh --skip-build   # ์ด๋ฏธ์ง€ ์žฌ๋นŒ๋“œ ์ƒ๋žต (์žฌ์‹คํ–‰ ์‹œ)
bash scripts/test-helm.sh --keep         # ๊ฒ€์ฆ ํ›„ ํด๋Ÿฌ์Šคํ„ฐ ์œ ์ง€ (์ˆ˜๋™ ๋””๋ฒ„๊น…)

์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ž๋™์œผ๋กœ:

  1. โœ… ๋„๊ตฌ ์„ค์น˜ ํ™•์ธ (docker / kind / kubectl / helm)
  2. โœ… Kind ํด๋Ÿฌ์Šคํ„ฐ claude-test ์ƒ์„ฑ
  3. โœ… Docker ์ด๋ฏธ์ง€ ๋นŒ๋“œ โ†’ Kind ํด๋Ÿฌ์Šคํ„ฐ์— ๋กœ๋“œ (registry ๋ถˆํ•„์š”)
  4. โœ… Namespace + Secret ์ƒ์„ฑ
  5. โœ… helm lint + helm template ์ •์  ๊ฒ€์ฆ
  6. โœ… helm install (์‹œ๋‚˜๋ฆฌ์˜ค A: H2 ๋‹จ์ผ ์ธ์Šคํ„ด์Šค)
  7. โœ… Pod READY 1/1 ๋Œ€๊ธฐ (์ตœ๋Œ€ 3๋ถ„)
  8. โœ… ํ—ฌ์Šค์ฒดํฌ /actuator/health โ†’ status=UP ๊ฒ€์ฆ
  9. โœ… Prometheus ๋ฉ”ํŠธ๋ฆญ ๋…ธ์ถœ ๊ฒ€์ฆ (claude_* ์ค„ ์นด์šดํŠธ)
  10. โœ… Spring Boot ์‹œ์ž‘ ๋กœ๊ทธ ํ™•์ธ
3๋‹จ๊ณ„ โ€” ๋‹จ์ˆœ ๋ช…๋ น์œผ๋กœ ์ง์ ‘ ๊ฒ€์ฆ (์ˆ˜๋™)
# ์ฐจํŠธ๋งŒ ์ •์  ๊ฒ€์ฆ
helm lint ./helm/claude-toolkit                              # ๋ฌธ๋ฒ• ๊ฒ€์ฆ
helm template test ./helm/claude-toolkit --debug | less      # ๋งค๋‹ˆํŽ˜์ŠคํŠธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ

5๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ธ (B: PostgreSQL, C: Ingress+TLS, D: HPA ์ž๋™ ํ™•์žฅ, E: prometheus-operator) ๋Š” helm/claude-toolkit/VALIDATION.md ์ฐธ๊ณ .

Helm ์„ค์น˜ ๋‹จ๊ณ„

# 1. ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ๋‚ด/๊ณต๊ฐœ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ํ‘ธ์‹œ
docker build -t ghcr.io/<your-org>/claude-java-toolkit:4.3.0 .
docker push ghcr.io/<your-org>/claude-java-toolkit:4.3.0

# 2. Claude API Key Secret ์ƒ์„ฑ (๊ถŒ์žฅ โ€” values ํŒŒ์ผ์— ํ‰๋ฌธ ์ €์žฅ ๊ธˆ์ง€)
kubectl create namespace claude-toolkit
kubectl create secret generic claude-api-secret \
  --from-literal=CLAUDE_API_KEY=sk-ant-... \
  -n claude-toolkit

# 3-A. ๋‹จ์ˆœ ์„ค์น˜ (H2 + ๋‹จ์ผ ์ธ์Šคํ„ด์Šค โ€” ๊ฐœ๋ฐœ / ๊ฒ€์ฆ์šฉ)
helm install claude-toolkit ./helm/claude-toolkit \
  -n claude-toolkit \
  --set image.repository=ghcr.io/<your-org>/claude-java-toolkit \
  --set image.tag=4.3.0 \
  --set secret.existingSecret=claude-api-secret

# 3-B. ์šด์˜ ๊ถŒ์žฅ ๊ตฌ์„ฑ (์™ธ๋ถ€ PostgreSQL + Ingress + HPA + Prometheus ์—ฐ๋™)
helm upgrade --install claude-toolkit ./helm/claude-toolkit \
  -n claude-toolkit \
  --set image.repository=ghcr.io/<your-org>/claude-java-toolkit \
  --set image.tag=4.3.0 \
  --set secret.existingSecret=claude-api-secret \
  --set db.type=postgresql --set db.host=postgres.example.com \
  --set persistence.enabled=false \
  --set ingress.enabled=true --set ingress.host=claude.example.com \
  --set ingress.className=nginx \
  --set autoscaling.enabled=true \
  --set autoscaling.minReplicas=2 --set autoscaling.maxReplicas=5 \
  --set monitoring.enabled=true \
  --set monitoring.serviceMonitor.enabled=true

์ฃผ์š” values ์˜ต์…˜

ํ‚ค ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
image.repository ghcr.io/sangmoo/claude-java-toolkit ์ด๋ฏธ์ง€
image.tag "" (= Chart.appVersion) ์ด๋ฏธ์ง€ ํƒœ๊ทธ
replicaCount 1 Pod ๋ณต์ œ ์ˆ˜ (HPA ๋น„ํ™œ์„ฑ ์‹œ)
db.type h2 h2 / mysql / postgresql
claude.apiKey "" API ํ‚ค (๋˜๋Š” secret.existingSecret)
claude.model claude-sonnet-4-6 ๊ธฐ๋ณธ ๋ชจ๋ธ
persistence.size 5Gi H2 PVC ํฌ๊ธฐ
ingress.enabled false Ingress ํ™œ์„ฑํ™”
autoscaling.enabled false HPA ํ™œ์„ฑํ™”
monitoring.enabled false Prometheus annotation/ServiceMonitor

์ „์ฒด ์˜ต์…˜์€ helm/claude-toolkit/values.yaml, ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” helm/claude-toolkit/README.md ์ฐธ๊ณ .

์—…๊ทธ๋ ˆ์ด๋“œ / ์‚ญ์ œ

# ์ƒˆ ๋ฒ„์ „์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ (๋‹ค๋ฅธ ์˜ต์…˜ ์œ ์ง€)
helm upgrade claude-toolkit ./helm/claude-toolkit -n claude-toolkit \
  --reuse-values --set image.tag=4.3.1

# ์‚ญ์ œ (PVC ๋Š” ๋ณ„๋„๋กœ ์‚ญ์ œํ•ด์•ผ ๋ฐ์ดํ„ฐ ์˜๊ตฌ ์‚ญ์ œ๋จ)
helm uninstall claude-toolkit -n claude-toolkit
kubectl delete pvc -l app.kubernetes.io/instance=claude-toolkit -n claude-toolkit

โš ๏ธ ๋ฐฐํฌ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

  1. ์ด๋ฏธ์ง€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํ•„์ˆ˜ (Helm): ์ฐจํŠธ๋Š” ์ด๋ฏธ์ง€๋ฅผ ๋นŒ๋“œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. GHCR / Docker Hub / ์‚ฌ๋‚ด Harbor ๋“ฑ์— ๋ฏธ๋ฆฌ ํ‘ธ์‹œ ํ•„์š”
  2. API Key ๋ณดํ˜ธ: --set claude.apiKey=... ๋ณด๋‹ค kubectl create secret + secret.existingSecret ๊ถŒ์žฅ (--set ๊ฐ’์€ helm history ์— ํ‰๋ฌธ ๋…ธ์ถœ๋จ)
  3. DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜: H2 โ†’ PostgreSQL ์ „ํ™˜ ์‹œ ์›น UI ์˜ "Settings โ†’ DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ" ํŽ˜์ด์ง€ ์ฐธ๊ณ 
  4. ์ฒซ ๋ฐฐํฌ ํ›„: Helm NOTES.txt ์˜ ๋ช…๋ น์–ด๋กœ ํ—ฌ์Šค์ฒดํฌ + ๋กœ๊ทธ ํ™•์ธ ๊ถŒ์žฅ
  5. ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰: Prometheus ~300MB, Grafana ~200MB โ€” ๋ฆฌ์†Œ์Šค ์ œํ•œ๋œ ํ™˜๊ฒฝ์€ ์˜ตํŠธ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ถ„๋ฆฌ๋จ (๊ธฐ๋ณธ OFF)
  6. Helm ์ฐจํŠธ ๋ฏธ๊ฒ€์ฆ: ์‹ค K8s ํ™˜๊ฒฝ ๋ฏธ๋ณด์œ ๋กœ ์ •์  ๊ฒ€์ฆ๋งŒ ์™„๋ฃŒ. ์šด์˜ ์ ์šฉ ์ „ ๋ฐ˜๋“œ์‹œ ํ…Œ์ŠคํŠธ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ๊ฒ€์ฆ ํ•„์š”

๐ŸŒ Web UI ๊ธฐ๋Šฅ ๋ชฉ๋ก

์›น ๋Œ€์‹œ๋ณด๋“œ๋Š” ์‚ฌ์ด๋“œ๋ฐ” ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ตฌ์กฐ๋กœ 65+ ํŽ˜์ด์ง€ ์˜ AI ๋„๊ตฌ / ๋ถ„์„ / ๊ด€๋ฆฌ / ์„ค์ • ํ™”๋ฉด์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋งŒ ์š”์•ฝ. ์ž์„ธํ•œ ์‚ฌ์šฉ๋ฒ•์€ ๊ฐ ํŽ˜์ด์ง€์˜ ์ธ๋ผ์ธ ๋„์›€๋ง ์ฐธ๊ณ .

๐Ÿ” SQL / DB ๋ถ„์„

๊ธฐ๋Šฅ ๊ฒฝ๋กœ ํ•ต์‹ฌ
SQL ๋ฆฌ๋ทฐ /advisor ์ž๋™ SQL ํƒ€์ž… ๊ฐ์ง€, EXPLAIN PLAN ์—ฐ๋™, ๋ณด์•ˆ / ์ธ๋ฑ์Šค / Diff ํƒญ, HIGH/MED/LOW ํ•„ํ„ฐ
SQL ์ธ๋ฑ์Šค ์‹œ๋ฎฌ๋ ˆ์ด์…˜ โœจ /sql/index-advisor WHERE/JOIN ์ •์  ํŒŒ์‹ฑ + JDBC ๋ฉ”ํƒ€์กฐํšŒ โ†’ ํ™œ์šฉ ๊ฐ€๋Šฅ ์ธ๋ฑ์Šค + ์‹ ๊ทœ DDL ์ถ”์ฒœ
ERD ๋ถ„์„ / DDL ์ƒ์„ฑ /erd DB ์ž๋™ ์Šค์บ” + Mermaid ERD + ์—ญ๋ฐฉํ–ฅ DDL (Oracle ๊ทœ๊ฒฉ)
์‹คํ–‰๊ณ„ํš ๋ถ„์„ /explain ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ํŠธ๋ฆฌ, ์˜คํผ๋ ˆ์ด์…˜ ์ƒ‰์ƒ, Cost ๋ฐ”, AI ๋ถ„์„ SSE ์ŠคํŠธ๋ฆฌ๋ฐ
์‹คํ–‰๊ณ„ํš Before/After ๋น„๊ต /explain/compare ๋‘ SQL ๋™์‹œ ์‹คํ–‰ + Cost ๋ณ€ํ™”์œจ (% ๊ฐœ์„ /์•…ํ™”)
SQL ์„ฑ๋Šฅ ํžˆ์Šคํ† ๋ฆฌ ๋Œ€์‹œ๋ณด๋“œ /explain/dashboard Cost ์ถ”์ด ์ฐจํŠธ + ๊ธฐ๊ฐ„ ํ•„ํ„ฐ + ๋ณ€ํ™”์œจ ์ƒ‰์ƒ ๊ตฌ๋ถ„
๋ฐฐ์น˜ SQL ๋ถ„์„ /sql-batch ์ตœ๋Œ€ 30๊ฐœ SQL ์ผ๊ด„ + CSV ์—…๋กœ๋“œ + ์•„์ฝ”๋””์–ธ ๊ฒฐ๊ณผ
SQL DB ๋ฒˆ์—ญ /sql-translate Oracle โ†” MySQL โ†” PostgreSQL ๋ฌธ๋ฒ• ๋ณ€ํ™˜

โšก ์ฝ”๋“œ ๋ถ„์„

๊ธฐ๋Šฅ ๊ฒฝ๋กœ ํ•ต์‹ฌ
์ฝ”๋“œ ๋ฆฌ๋ทฐ ํ•˜๋„ค์Šค /harness Analyst โ†’ Builder โ†’ Reviewer โ†’ Verifier 4๋‹จ๊ณ„ + Diff + ํ’ˆ์งˆ ์ ์ˆ˜ + ๊ฒ€์ฆ ํŒ์ •
SPโ†’Java ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•˜๋„ค์Šค ๐Ÿ†• /sp-migration-harness SP ์˜๋ฏธ ๋ถ„์„ โ†’ Service+Mapper+XML+DTO+ํ…Œ์ŠคํŠธ ์ƒ์„ฑ โ†’ ํ–‰์œ„ ๋™๋“ฑ์„ฑ โ†’ ์ •์  ๊ฒ€์ฆ. DB ์˜ค๋ธŒ์ ํŠธ ์ž๋™ ๋กœ๋“œ
SQL ์ตœ์ ํ™” ํ•˜๋„ค์Šค ๐Ÿ†• /sql-optimization-harness ๋ณ‘๋ชฉ ๋ถ„์„ โ†’ N๊ฐœ ํ›„๋ณด (rewrite + DDL + ํžŒํŠธ) โ†’ ์šฐ๋„ ํ‰๊ฐ€ โ†’ ๋‹จ๊ณ„๋ณ„ Rollout Plan
ํ•˜๋„ค์Šค ๋ฐฐ์น˜ /harness/batch Java/SQL ๋‹ค์ค‘ ํ•ญ๋ชฉ ์ˆœ์ฐจ ๋ถ„์„, ๋‹ค์ค‘ ์ด๋ฉ”์ผ ์•Œ๋ฆผ, ์˜๊ตฌ ์ด๋ ฅ
DB ์˜์กด์„ฑ ๋ถ„์„ /harness/dependency SP/Package/Java ์˜์กด ํ…Œ์ด๋ธ”ยทํ˜ธ์ถœ ๊ด€๊ณ„ยท์ˆœํ™˜ ์œ„ํ—˜
ํ’ˆ์งˆ ๋Œ€์‹œ๋ณด๋“œ /harness/dashboard ๋ˆ„์  ํ†ต๊ณ„ / ํŒ์ • ๋น„์œจ / ํ’ˆ์งˆ ์ ์ˆ˜ ์ถ”์ด + ๋“œ๋ฆด๋‹ค์šด ๋ชจ๋‹ฌ
Java ์ฝ”๋“œ ๋ฆฌ๋ทฐ /codereview OWASP Top 10, SOLID, ์ปจํ…์ŠคํŠธ ์ฃผ์ž…
๋ณต์žก๋„ ๋ถ„์„ /complexity ์ˆœํ™˜ ๋ณต์žก๋„ + ์šฐ์„ ์ˆœ์œ„ ํ•„ํ„ฐ (๋‹จ์ผ/ํ”„๋กœ์ ํŠธ ๋ชจ๋“œ)
๋ฐ์ดํ„ฐ ํ๋ฆ„ ๋ถ„์„ /flow-analysis ํ…Œ์ด๋ธ”/SP/SQL_ID โ†’ MyBatis ยท Java ยท Controller ยท MiPlatform ์ž๋™ ์ถ”์ 
ํ…Œ์ด๋ธ” ์˜ํ–ฅ ๋ถ„์„ โœจ /impact ํ…Œ์ด๋ธ” โ†’ MyBatis โ†’ Java โ†’ Controller 4๋‹จ๊ณ„ ์—ญ์ถ”์ , ํŒŒ์ผ ํ–‰ ํด๋ฆญ โ†’ ๋ชจ๋‹ฌ + ์ „์ฒด ๋ณต์‚ฌ, DB ํ…Œ์ด๋ธ” ํ”ฝ์ปค
ํŒจํ‚ค์ง€ ๋ถ„์„ ๐Ÿ†• /package-overview Java ํŒจํ‚ค์ง€ ๋‹จ์œ„ 4ํƒญ (์š”์•ฝ/ERD/ํ’€ํ๋ฆ„๋„/์Šคํ† ๋ฆฌ), Markdown export
์ „์‚ฌ ํŒจํ‚ค์ง€ ์ง€๋„ ๐Ÿ†• /project-map ๋“œ๋ฆด๋‹ค์šด ์นด๋“œ ๊ทธ๋ฆฌ๋“œ + ๊ฒ€์ƒ‰ ํ•„ํ„ฐ, ๋ฆฌํ”„ โ†’ ํŒจํ‚ค์ง€ ๊ฐœ์š”๋กœ ์ ํ”„

๐Ÿ›  ์ฝ”๋“œ/๋ฌธ์„œ ์ƒ์„ฑ

๊ธฐ๋Šฅ ๊ฒฝ๋กœ ํ•ต์‹ฌ
๊ธฐ์ˆ  ๋ฌธ์„œ ์ƒ์„ฑ /docgen Oracle SP/Package, Java/MyBatis โ†’ Markdown/Typst/HTML, ํ•œ/์˜
Javadoc ์ƒ์„ฑ /javadoc public ๋ฉค๋ฒ„ ์ž๋™ ์ฃผ์„, SSE ์ŠคํŠธ๋ฆฌ๋ฐ
๋ฆฌํŒฉํ„ฐ๋ง ์ œ์•ˆ /refactor ์ฝ”๋“œ ๋ฌธ์ œ์  โ†’ ๊ฐœ์„  ์ฝ”๋“œ (์ „/ํ›„ ๋น„๊ต)
ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ƒ์„ฑ /testgen Controller/Service/Mapper ๋ณ„ JUnit 5 ์ „๋žต
API ๋ช…์„ธ ์ƒ์„ฑ /apispec OpenAPI 3.0 YAML / Swagger 2.0 ์–ด๋…ธํ…Œ์ด์…˜
์ฝ”๋“œ ๋ณ€ํ™˜ /converter SPโ†”Java/MyBatis ์–‘๋ฐฉํ–ฅ + iBatisโ†’MyBatis
Mock ๋ฐ์ดํ„ฐ /mockdata DDL โ†’ INSERT/MERGE/CSV (1~1000 ๊ฑด)
DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ /migration DDL ๋น„๊ต โ†’ Oracle/Flyway/Liquibase + ์œ„ํ—˜๋„
๋ฐ์ดํ„ฐ ๋งˆ์Šคํ‚น /maskgen DDL ๋ถ„์„ โ†’ ๋ฏผ๊ฐ ์ปฌ๋Ÿผ ์ž๋™ ํƒ์ง€ + UPDATE ๋งˆ์Šคํ‚น SQL
pom.xml ๋ถ„์„ /depcheck ์ทจ์•ฝ ์˜์กด์„ฑ, ๋ฒ„์ „ ์ถฉ๋Œ, ์—…๊ทธ๋ ˆ์ด๋“œ ๊ถŒ๊ณ 
Spring Boot 3.x ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ /migrate javax โ†’ jakarta ์ฒดํฌ๋ฆฌ์ŠคํŠธ

๐Ÿ”ง ๊ธฐํƒ€ ๋„๊ตฌ

๊ธฐ๋Šฅ ๊ฒฝ๋กœ ํ•ต์‹ฌ
๋กœ๊ทธ ๋ถ„์„๊ธฐ /loganalyzer ์ผ๋ฐ˜/๋ณด์•ˆ ๋ถ„์„, .log ์—…๋กœ๋“œ, ๐Ÿ†• RCA ํ•˜๋„ค์Šค 4๋‹จ๊ณ„ ๋ชจ๋“œ (๊ฐ€์„คโ†’๊ฒ€์ฆSQL+ํŒจ์น˜+๋กค๋ฐฑโ†’์šฐ๋„โ†’์‚ฌ๋‚ด ํ‘œ์ค€ RCA ๋ณด๊ณ ์„œ)
์ •๊ทœ์‹ ์ƒ์„ฑ๊ธฐ /regex ์ž์—ฐ์–ด โ†’ regex + 5๊ฐœ ์–ธ์–ด ์˜ˆ์ œ + ๋น ๋ฅธ ์˜ˆ์ œ 8์ข…
์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ๊ธฐ /commitmsg Conventional/Gitmoji/Simple/Angular ์Šคํƒ€์ผ
ํ†ตํ•ฉ ์›Œํฌ์ŠคํŽ˜์ด์Šค /workspace ๋‹ค์ค‘ ๋ถ„์„ ๋ณ‘๋ ฌ ์‹คํ–‰ (Java/SQL ์–ธ์–ด๋ณ„ ๊ธฐ๋Šฅ ์ž๋™ ๋…ธ์ถœ)
๋ถ„์„ ํŒŒ์ดํ”„๋ผ์ธ /pipelines YAML ๊ธฐ๋ฐ˜ ๋‹ค๋‹จ๊ณ„, ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ๊ทธ๋ž˜ํ”„ ๋ทฐ โœจ, ์Šค์ผ€์ค„๋ง
AI ์ฑ„ํŒ… /chat Claude ์ž์œ  ๋Œ€ํ™”, ๋ฉ€ํ‹ฐํ„ด ์ปจํ…์ŠคํŠธ

๐Ÿ“š ๊ธฐ๋ก / ํ˜‘์—…

๊ธฐ๋Šฅ ๊ฒฝ๋กœ ํ•ต์‹ฌ
๋ฆฌ๋ทฐ ์ด๋ ฅ /history ์ž๋™ ์ €์žฅ, ๊ฒ€์ƒ‰/ํ•„ํ„ฐ, SARIF/Excel ๋‚ด๋ณด๋‚ด๊ธฐ โœจ, ๊ณต์œ  ๋งํฌ, ์ฆ๊ฒจ์ฐพ๊ธฐ
์ฆ๊ฒจ์ฐพ๊ธฐ /favorites ํƒœ๊ทธ๋ณ„ ์ •๋ฆฌ, H2 ์˜์†ํ™”, (์‚ฌ์šฉ์ž, ์ด๋ ฅ) ์ค‘๋ณต ๋ฐฉ์ง€
๊ฒ€์ƒ‰ โœจ /search ๋ฉ”๋‰ด ์นดํƒˆ๋กœ๊ทธ + ๋ถ„์„ ์ด๋ ฅ ํ†ตํ•ฉ ๊ฒ€์ƒ‰. ์ƒ๋‹จ๋ฐ” ๊ธ€๋กœ๋ฒŒ ๊ฒ€์ƒ‰์ฐฝ(ํŒ”๋ ˆํŠธ accent ์ƒ‰์ƒ)์—์„œ ๋ชจ๋“  ํŽ˜์ด์ง€ ์–ด๋””์„œ๋“  ํ˜ธ์ถœ ๊ฐ€๋Šฅ. ํƒ€์ž…/๋‚ ์งœ ํ•„ํ„ฐ + ์ •๋ ฌ + ๋งค์น˜ ๊ฐ•์กฐ โœจ v4.7
ROI ๋ฆฌํฌํŠธ + ์ธ์‚ฌ์ดํŠธ โœจ v4.7 /roi-report ์‹œ์Šคํ…œ ํ†ต๊ณ„ + ๋‚ด ํ™œ๋™ (Top 5 ๊ธฐ๋Šฅ / 12์ฃผ ์ถ”์ด) + ํŒ€ ๋น„๊ต (๋ฐฑ๋ถ„์œ„ยท์ˆœ์œ„ยท์ง„ํ–‰ ๋ฐ”, ADMIN)
์ปดํ”Œ๋ผ์ด์–ธ์Šค ๋ฆฌํฌํŠธ โœจ v4.7 /admin/compliance-report (ADMIN) FSS / PIPA / ์ •๋ณดํ†ต์‹ ๋ง๋ฒ• / ์™ธ๋ถ€๊ฐ์‚ฌ 4์ข…, Markdown / Excel(POI 4์‹œํŠธ) / ์ธ์‡„ยทPDF + AI ๊ฒฝ์˜์ง„ ์š”์•ฝ + ์˜๊ตฌ ์ €์žฅ ์ด๋ ฅ (์ตœ๋Œ€ 500๊ฑด)
์‚ฌ์šฉ๋Ÿ‰ /usage ์ผ/์›”๋ณ„ ํ† ํฐ ์‚ฌ์šฉ๋Ÿ‰ + ์‚ฌ์šฉ์ž๋ณ„ ์ œํ•œ
ROI ๋ฆฌํฌํŠธ /roi-report ์ ˆ๊ฐ ์‹œ๊ฐ„ ํ™˜์‚ฐ + ๋ˆ„์  ๋ถ„์„ ํ†ต๊ณ„
๋ฆฌ๋ทฐ ์š”์ฒญ /review-requests VIEWER ์ž‘์„ฑ โ†’ REVIEWER/ADMIN ์Šน์ธ/๊ฑฐ์ ˆ + ์ฝ”๋ฉ˜ํŠธ + @๋ฉ˜์…˜
๊ณต์œ  ๋งํฌ /share/{token} 7์ผ ์œ ํšจ read-only URL (๋กœ๊ทธ์ธ ๋ถˆํ•„์š”)

๐Ÿ” ๊ด€๋ฆฌ์ž (ADMIN ์ „์šฉ)

๊ธฐ๋Šฅ ๊ฒฝ๋กœ ํ•ต์‹ฌ
์‚ฌ์šฉ์ž ๊ด€๋ฆฌ /admin/users ๊ณ„์ • ์ƒ์„ฑ/์ˆ˜์ •/์ž ๊ธˆ/IP ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ
์‚ฌ์šฉ์ž ๊ถŒํ•œ ๊ด€๋ฆฌ /admin/permissions featureKey ๋ณ„ ํ™œ์„ฑ/๋น„ํ™œ์„ฑ
ํŒ€ ๋Œ€์‹œ๋ณด๋“œ /admin/team-dashboard ์‚ฌ์šฉ์ž๋ณ„ ๋ถ„์„/์ฑ„ํŒ… ์นด์šดํŠธ
๋ฆฌ๋ทฐ ๋Œ€์‹œ๋ณด๋“œ /admin/review-dashboard ์ผ๋ณ„ ํŠธ๋ Œ๋“œ + ํƒ€์ž…/๋ฆฌ๋ทฐ์–ด๋ณ„ ํ†ต๊ณ„
๊ฐ์‚ฌ ๋กœ๊ทธ /admin/audit-dashboard API ํ˜ธ์ถœ ๊ธฐ๋ก
์—”๋“œํฌ์ธํŠธ ํ†ต๊ณ„ /admin/endpoint-stats Top ์—”๋“œํฌ์ธํŠธ/์‚ฌ์šฉ์ž, ์ƒํƒœ ์ฝ”๋“œ, ์ผ๋ณ„ ํŠธ๋ Œ๋“œ
๋น„์šฉ ์˜ตํ‹ฐ๋งˆ์ด์ € โœจ /admin/cost-optimizer ๋ถ„์„ ์œ ํ˜•๋ณ„ ๋ชจ๋ธ ์ถ”์ฒœ (Haiku/Sonnet/Opus) + ์ ˆ๊ฐ์•ก
์‹œ์Šคํ…œ ํ—ฌ์Šค /admin/health JVM, DB, ๋””์Šคํฌ, ํ—ฌ์Šค์ฒดํฌ
๋ฐฑ์—… / ๋ณต์› /admin/backup H2 ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ + ์—…๋กœ๋“œ ๋ณต์›
DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ /admin/db-migration H2 โ†’ MySQL/PostgreSQL ๊ฐ€์ด๋“œ

๐Ÿ”‘ ๊ณตํ†ต UX

๊ธฐ๋Šฅ ์„ค๋ช…
๋‹คํฌ / ๋ผ์ดํŠธ ํ…Œ๋งˆ ์ƒ๋‹จ๋ฐ” ํ† ๊ธ€ + localStorage
5๊ฐœ ์–ธ์–ด โœจ ko / en / ja / zh / de + ์‚ฌ์šฉ์ž๋ณ„ ์ž๋™ ๋™๊ธฐํ™”
์œ„์ ฏ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• โœจ ํ™ˆ ๋Œ€์‹œ๋ณด๋“œ ๋“œ๋ž˜๊ทธ/๋ฆฌ์‚ฌ์ด์ฆˆ/์ˆจ๊น€ + ์‚ฌ์šฉ์ž๋ณ„ ์ €์žฅ
์ž๋™ ์ž„์‹œ์ €์žฅ ์ž…๋ ฅ localStorage 2์ดˆ ๋””๋ฐ”์šด์Šค
ํ† ํฐ ์ˆ˜ ์‹ค์‹œ๊ฐ„ ์˜ˆ์ธก ์ƒ‰์ƒ ๊ฒฝ๊ณ  (์•ˆ์ „/์ฃผ์˜/์œ„ํ—˜)
์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ (SSE) ๋ฉ˜์…˜, ๋ฆฌ๋ทฐ ๋Œ€๊ธฐ, ์‹œ์Šคํ…œ ์ด๋ฒคํŠธ
์ปค๋งจ๋“œ ํŒ”๋ ˆํŠธ โŒ˜K / Ctrl+K โ€” ํŽ˜์ด์ง€ ์ฆ‰์‹œ ์ด๋™ + ๋ช…๋ น ๊ฒ€์ƒ‰

โœจ = v4.3.0 ์‹ ๊ทœ / ๊ฐœ์„ 

์ถ”๊ฐ€ ๊ณตํ†ต UX ์„ธ๋ถ€์‚ฌํ•ญ (ํŽผ์น˜๊ธฐ)
๊ธฐ๋Šฅ ์„ค๋ช…
์ž…๋ ฅ ์ž๋™ ์ž„์‹œ์ €์žฅ ์ž…๋ ฅ 2์ดˆ ํ›„ localStorage ์ €์žฅ, ์ƒˆ๋กœ๊ณ ์นจ/๋ณต๊ท€ ์‹œ ๋ณต์›
ํ† ํฐ ์ˆ˜ ์˜ˆ์ธก ํ‘œ์‹œ ์ž…๋ ฅ ๊ธ€์ž ์ˆ˜ ๊ธฐ๋ฐ˜ ์˜ˆ์ƒ ํ† ํฐ (40kโ†‘ ๋…ธ๋ž‘, 80kโ†‘ ๋นจ๊ฐ•)
์ค‘๋ณต ์ œ์ถœ ๋ฐฉ์ง€ ๋ถ„์„ ์‹คํ–‰ ์‹œ ๋ฒ„ํŠผ ์ž๋™ ๋น„ํ™œ์„ฑํ™” โ†’ 90์ดˆ ํ›„ ๋ณต์›
โšก ์‹ค์‹œ๊ฐ„ ๋ณด๊ธฐ ๋ชจ๋“  ๋„๊ตฌ์— SSE ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฒ„ํŠผ
ํ”„๋กœ์ ํŠธ ์ปจํ…์ŠคํŠธ ์ž๋™ ์ฃผ์ž… Settings ๋ฉ”๋ชจ๊ฐ€ ์ฝ”๋“œ ๋ฆฌ๋ทฐยทํ…Œ์ŠคํŠธยทJavadoc ๋“ฑ ๋ชจ๋“  AI ๋„๊ตฌ์— ์ž๋™ ์ „๋‹ฌ
Ctrl+Enter ๋‹จ์ถ•ํ‚ค ์ฆ‰์‹œ ๋ถ„์„ ์‹คํ–‰ (Mac: โŒ˜+Enter)
๋ฐ˜์‘ํ˜• ๋ ˆ์ด์•„์›ƒ ๋ชจ๋ฐ”์ผ โ‰ค768px / ํƒœ๋ธ”๋ฆฟ โ‰ค992px ์ตœ์ ํ™”
์‚ฌ์ด๋“œ๋ฐ” ์„น์…˜ ์ ‘๊ธฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ† ๊ธ€, ์ „์ฒด ์ ‘๊ธฐ, localStorage ์ €์žฅ
Syntax Highlighting Prism.js (SQL, Java, XML, YAML, diff)
Mermaid.js ERD mermaid ์ฝ”๋“œ๋ธ”๋ก ์ž๋™ ๋ Œ๋”๋ง
์ƒˆ ํƒญ ์—ด๊ธฐ / ๋‹จ๊ณ„ ๋กœ๋”ฉ / ํด๋ฆฝ๋ณด๋“œ ๋ณต์‚ฌ / ๋งˆํฌ๋‹ค์šด ๋ Œ๋”๋ง ๋“ฑ

โš™๏ธ Settings โ€” /settings

Oracle DB ์—ฐ๊ฒฐ ์ •๋ณด, Java ํ”„๋กœ์ ํŠธ ๊ฒฝ๋กœ, Claude API, ํ”„๋กœ์ ํŠธ ์ปจํ…์ŠคํŠธ, ๋ชจ๋ธ ์„ ํƒ์„ ๋Ÿฐํƒ€์ž„์— ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์„ค์ •์€ ~/.claude-toolkit/settings.json ์— ์ž๋™ ์ €์žฅ๋˜์–ด ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ํ›„์—๋„ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฃน ํ•ญ๋ชฉ ํ™˜๊ฒฝ๋ณ€์ˆ˜ / ํ‚ค
Claude API API ํ‚ค (์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋ฒ„ํŠผ) CLAUDE_API_KEY
๋ชจ๋ธ ๋Ÿฐํƒ€์ž„ ์ „ํ™˜ (์žฌ์‹œ์ž‘ ๋ถˆํ•„์š”) UI ๋“œ๋กญ๋‹ค์šด โ€” opus / sonnet / haiku
Oracle DB SQL ๋ฉ”ํƒ€์กฐํšŒ + EXPLAIN PLAN + ERD ์Šค์บ”์šฉ ORACLE_DB_URL / ORACLE_DB_USERNAME / ORACLE_DB_PASSWORD
ํ”„๋กœ์ ํŠธ ๊ฒฝ๋กœ ์ฝ”๋“œ ๋ฆฌ๋ทฐ / ๋ฌธ์„œ ์ƒ์„ฑ ์‹œ ์—ฐ๊ด€ ํŒŒ์ผ ์ปจํ…์ŠคํŠธ ์ž๋™ ํฌํ•จ toolkit.project.scan-path
์ปจํ…์ŠคํŠธ ๋ฉ”๋ชจ ํ”„๋กœ์ ํŠธ ๊ฐœ์š”ยท์ปจ๋ฒค์…˜ยท๋„๋ฉ”์ธ โ€” ๋ชจ๋“  AI ๋„๊ตฌ์— ์ž๋™ ์ฃผ์ž… toolkit.project-context
์ด๋ฉ”์ผ (SMTP) ๋ฐฐ์น˜ ์™„๋ฃŒ ์•Œ๋ฆผ / ๋ถ„์„ ๊ฒฐ๊ณผ ๋ฐœ์†ก SMTP_HOST / SMTP_PORT / SMTP_USERNAME / SMTP_PASSWORD
Slack / Teams / Jira ์›นํ›… + ์ด์Šˆ ์ž๋™ ์ƒ์„ฑ UI Settings ์ž…๋ ฅ

์ž๋™ ๋ถ„๋ฅ˜ ํŒŒ์ผ ์œ ํ˜• (ํ”„๋กœ์ ํŠธ ์Šค์บ” ์‹œ): Controller (@RestController), Service (@Service), Repository/DAO (@Repository), Mapper (@Mapper), MyBatis XML, DTO/VO (๊ฒฝ๋กœ ๊ธฐ๋ฐ˜), Config (@Configuration). target/, test/, build/, .git/ ์ž๋™ ์ œ์™ธ.

# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์˜ˆ์‹œ
export CLAUDE_API_KEY=sk-ant-...
export ORACLE_DB_URL=jdbc:oracle:thin:@//host:1521/SERVICE_NAME

๐Ÿ”ง Spring Boot Starter / ๐Ÿ’ป CLI ์‚ฌ์šฉ๋ฒ•

claude-spring-boot-starter ๋ฅผ ์˜์กด์„ฑ์— ์ถ”๊ฐ€ํ•˜๋ฉด ClaudeClient ๊ฐ€ ์ž๋™ ์ฃผ์ž…๋ฉ๋‹ˆ๋‹ค.

# application.yml
claude:
  api-key: ${CLAUDE_API_KEY}
  model:   claude-sonnet-4-6
  max-tokens: 4096
@Service
public class MyService {
    private final ClaudeClient claude;
    public MyService(ClaudeClient claude) { this.claude = claude; }

    // ๋™๊ธฐ ํ˜ธ์ถœ
    public String review(String sql) {
        return claude.chat("Oracle DBA", sql);
    }

    // SSE ์ŠคํŠธ๋ฆฌ๋ฐ (JDK 1.8 Consumer)
    public void stream(String code) {
        claude.chatStream("Java reviewer", code, chunk -> System.out.print(chunk));
    }

    // ๋Ÿฐํƒ€์ž„ ๋ชจ๋ธ ์ „ํ™˜ (์žฌ์‹œ์ž‘ ๋ถˆํ•„์š”)
    public void switchModel(String m) { claude.setModelOverride(m); }
    public String currentModel()      { return claude.getEffectiveModel(); }
}
CLI ์‚ฌ์šฉ๋ฒ• (claude-sql-advisor / claude-doc-generator)
# SQL Advisor CLI
java -jar claude-sql-advisor.jar review --file my_query.sql
java -jar claude-sql-advisor.jar review --file SP.sql --type STORED_PROCEDURE                                           --output report.md --api-key sk-ant-...
cat my_query.sql | java -jar claude-sql-advisor.jar review

# Doc Generator CLI
java -jar claude-doc-generator.jar generate --file SP.sql --format md --output docs/SP.md
java -jar claude-doc-generator.jar generate --file OrderService.java                                             --type "Java Service" --format typst

๐Ÿ›  IntelliJ IDEA ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

Maven ๋นŒ๋“œ ๋ฐฉ๋ฒ•

1. IntelliJ Maven ํŒจ๋„ (View โ†’ Tool Windows โ†’ Maven)
2. ๋ฃจํŠธ ํ”„๋กœ์ ํŠธ(claude-java-toolkit-parent) ์„ ํƒ
3. Lifecycle โ†’ install ๋”๋ธ”ํด๋ฆญ (๋˜๋Š” install -DskipTests)
4. claude-toolkit-ui โ†’ Plugins โ†’ spring-boot โ†’ spring-boot:run ์‹คํ–‰

ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • (Run Configuration)

Run โ†’ Edit Configurations โ†’ Environment variables

CLAUDE_API_KEY=sk-ant-...
ORACLE_DB_URL=jdbc:oracle:thin:@//hostname:1521/ORCL
ORACLE_DB_USERNAME=myuser
ORACLE_DB_PASSWORD=mypassword
PROJECT_SCAN_PATH=C:/workspace/my-project/src/main/java

๐Ÿ— ์•„ํ‚คํ…์ฒ˜

๋ธŒ๋ผ์šฐ์ € (React 18 SPA + Zustand + Recharts + Mermaid + reactflow)
    โ”‚  EventSource (SSE) โ”€โ”€โ”€โ”€ GET /stream/{id}
    โ”‚  fetch (JSON) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ /api/v1/**
    โ–ผ
Spring Boot 2.7 + Spring MVC + Spring Security
    โ”‚  REST Controllers (api/v1) โ€” 30+ ์ปจํŠธ๋กค๋Ÿฌ
    โ”‚    โ”œโ”€ ๋ถ„์„/์ƒ์„ฑ: SqlAdvisor, CodeReview, DocGen, Javadoc, Refactor, ApiSpec, ...
    โ”‚    โ”œโ”€ ์›Œํฌํ”Œ๋กœ:  HarnessReview (Analystโ†’Builderโ†’Reviewerโ†’Verifier 4๋‹จ๊ณ„)
    โ”‚    โ”œโ”€ ๋ฉ”ํƒ€์กฐํšŒ:  IndexAdvisor (JDBC ๋ฉ”ํƒ€ + DDL ์ถ”์ฒœ), ErdAnalyzer
    โ”‚    โ”œโ”€ ์ธํ”„๋ผ:    Auth, Settings, Pipeline, Notification, Share, Export
    โ”‚    โ””โ”€ ๊ด€๋ฆฌ์ž:    AdminPermission, CostOptimizer, AuditLog, Backup, Health
    โ–ผ
Service Layer + JPA (claude-toolkit-ui)
    โ”‚  ReviewHistoryService / FavoriteService / PipelineExecutor
    โ”‚  ToolkitMetrics (Prometheus 4์ข… + ์ž๋™ ๋ฉ”ํŠธ๋ฆญ) โœจ
    โ”‚  ModelCostService / IndexAdvisorService โœจ
    โ”‚  H2 (๊ฐœ๋ฐœ) / MySQL / PostgreSQL (์šด์˜)
    โ–ผ
ClaudeClient (claude-spring-boot-starter)
    โ”‚  chat() / chatStream() / chatStreamWithContinuation() โ€” SSE
    โ”‚  setModelOverride() / getEffectiveModel() โ€” ๋Ÿฐํƒ€์ž„ ๋ชจ๋ธ ์ „ํ™˜
    โ”‚  ํ† ํฐ ์‚ฌ์šฉ๋Ÿ‰ ์บก์ฒ˜ (lastInputTokens / lastOutputTokens)
    โ”‚  OkHttp3 + Forward Proxy + TLSv1.2/1.3
    โ–ผ
Anthropic Claude API (Opus 4.x / Sonnet 4.x / Haiku 4.x)

๋ชจ๋‹ˆํ„ฐ๋ง ํ๋ฆ„ (v4.3.0)

Spring App  โ†’  /actuator/prometheus  โ†’  Prometheus  โ†’  Grafana
   โ†‘                                       (15s scrape)    (๋Œ€์‹œ๋ณด๋“œ 10ํŒจ๋„)
   โ””โ”€ ToolkitMetrics (claude_api_calls_total / claude_api_tokens_total /
                       analysis_duration_seconds / pipeline_execution_total)

๐Ÿ“‚ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

claude-java-toolkit/
โ”œโ”€โ”€ claude-spring-boot-starter/     # Library (ClaudeClient + Auto-config)
โ”œโ”€โ”€ claude-sql-advisor/             # Library + CLI (SQL ๋ฆฌ๋ทฐ, ERD, EXPLAIN PLAN)
โ”œโ”€โ”€ claude-doc-generator/           # Library + CLI (๋ฌธ์„œ/Javadoc/๋ฆฌํŒฉํ„ฐ๋ง/...)
โ”œโ”€โ”€ claude-toolkit-ui/              # Spring Boot + React SPA (๋ฉ”์ธ ์›น ๋Œ€์‹œ๋ณด๋“œ)
โ”‚   โ”œโ”€โ”€ src/main/java/io/github/claudetoolkit/ui/
โ”‚   โ”‚   โ”œโ”€โ”€ api/             # REST ์ปจํŠธ๋กค๋Ÿฌ (Auth, Data, Sql, Doc, Erd, Health)
โ”‚   โ”‚   โ”œโ”€โ”€ controller/      # SSE ์ŠคํŠธ๋ฆผ, Pipeline, Notification, Share ์ปจํŠธ๋กค๋Ÿฌ
โ”‚   โ”‚   โ”œโ”€โ”€ config/          # SecurityConfig, ToolkitSettings, GlobalException
โ”‚   โ”‚   โ”œโ”€โ”€ pipeline/        # PipelineExecutor + Spec/Yaml + StepResult
โ”‚   โ”‚   โ”œโ”€โ”€ harness/         # 4๋‹จ๊ณ„ ์ฝ”๋“œ ๋ฆฌ๋ทฐ (Analyst/Builder/Reviewer/Verifier)
โ”‚   โ”‚   โ”œโ”€โ”€ workspace/       # AnalysisType + Service Registry
โ”‚   โ”‚   โ”œโ”€โ”€ history/         # ReviewHistory + Repository
โ”‚   โ”‚   โ”œโ”€โ”€ user/            # AppUser + Permission + 2FA
โ”‚   โ”‚   โ”œโ”€โ”€ notification/    # SSE ์•Œ๋ฆผ + PendingReviewNotifier
โ”‚   โ”‚   โ”œโ”€โ”€ metrics/         # ToolkitMetrics (Micrometer)                โœจ v4.3.0
โ”‚   โ”‚   โ”œโ”€โ”€ cost/            # ModelCostService + Optimizer Controller    โœจ v4.3.0
โ”‚   โ”‚   โ”œโ”€โ”€ sqlindex/        # IndexAdvisor (JDBC ๋ฉ”ํƒ€์กฐํšŒ + DDL ์ถ”์ฒœ)    โœจ v4.3.0
โ”‚   โ”‚   โ”œโ”€โ”€ dashboard/       # UserDashboardLayout + Controller          โœจ v4.3.0
โ”‚   โ”‚   โ””โ”€โ”€ export/          # SARIF + Excel Export Service              โœจ v4.3.0
โ”‚   โ”œโ”€โ”€ src/main/resources/
โ”‚   โ”‚   โ”œโ”€โ”€ application.yml          # ๋ฉ”์ธ ์„ค์ • (DB / Claude / Actuator / Metrics)
โ”‚   โ”‚   โ””โ”€โ”€ static/app/              # React ๋ฒˆ๋“ค (Vite ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฌผ)
โ”‚   โ””โ”€โ”€ frontend/
โ”‚       โ”œโ”€โ”€ src/
โ”‚       โ”‚   โ”œโ”€โ”€ pages/               # 65+ ํŽ˜์ด์ง€ (analysis/admin/auth)
โ”‚       โ”‚   โ”œโ”€โ”€ components/          # ๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ (PipelineGraphView, MentionInput, ...)
โ”‚       โ”‚   โ”œโ”€โ”€ stores/              # Zustand (auth/theme/sidebar/notification/toast)
โ”‚       โ”‚   โ”œโ”€โ”€ i18n/                # ko/en/ja/zh/de                    โœจ v4.3.0
โ”‚       โ”‚   โ””โ”€โ”€ hooks/utils/types/
โ”‚       โ””โ”€โ”€ e2e/                     # Playwright ํšŒ๊ท€ ํ…Œ์ŠคํŠธ
โ”œโ”€โ”€ helm/claude-toolkit/            # Kubernetes Helm Chart                โœจ v4.3.0
โ”‚   โ”œโ”€โ”€ Chart.yaml / values.yaml / README.md
โ”‚   โ””โ”€โ”€ templates/                   # Deployment / Service / Ingress / Secret /
โ”‚                                    # PVC / HPA / ServiceAccount / ServiceMonitor / NOTES
โ”œโ”€โ”€ monitoring/                     # Prometheus + Grafana ํ”„๋กœ๋น„์ €๋‹       โœจ v4.3.0
โ”‚   โ”œโ”€โ”€ prometheus.yml
โ”‚   โ””โ”€โ”€ grafana/
โ”‚       โ”œโ”€โ”€ provisioning/datasources/    # Prometheus ์ž๋™ ๋“ฑ๋ก
โ”‚       โ”œโ”€โ”€ provisioning/dashboards/     # ๋Œ€์‹œ๋ณด๋“œ ์ž๋™ ๋กœ๋“œ
โ”‚       โ””โ”€โ”€ dashboards/claude-toolkit-overview.json    # 10 ํŒจ๋„
โ”œโ”€โ”€ docs/index.html                 # GitHub Pages ์†Œ๊ฐœ ํŽ˜์ด์ง€
โ”œโ”€โ”€ docker-compose.yml              # 4๊ฐœ ํ”„๋กœํ•„ (default/mysql/postgresql/monitoring)
โ”œโ”€โ”€ Dockerfile                      # Multi-stage (Maven + Node + JDK 8 JRE)
โ””โ”€โ”€ pom.xml                         # ๋ถ€๋ชจ POM (BOM ๋ฒ„์ „ ๊ด€๋ฆฌ)

โœจ = v4.3.0 ์‹ ๊ทœ ๋ชจ๋“ˆ / ๋””๋ ‰ํ† ๋ฆฌ

๐Ÿ“‹ ์ฃผ์š” ๊ธฐ์ˆ  ์Šคํƒ

๊ตฌ๋ถ„ ๊ธฐ์ˆ 
Language Java 1.8 (var / Stream.of / List.of ๋ฏธ์‚ฌ์šฉ)
Framework Spring Boot 2.7.18, Spring MVC, Thymeleaf 3.0
HTTP Client OkHttp3 4.12.0
JSON Jackson 2.15.4
CLI Picocli 4.7.5
DB Driver Oracle JDBC ojdbc8 21.5.0
Frontend Bootstrap 5.3, Font Awesome 6.4, Prism.js 1.29.0, marked.js 9.x, Mermaid.js 10.x
Build Maven 3.6+ (multi-module)
Persistence (Settings) ~/.claude-toolkit/settings.json (OutputStreamWriter + UTF-8)
Persistence (History) Spring Data JPA 2.7 + H2 2.x ํŒŒ์ผ DB (~/.claude-toolkit/history-db.mv.db)
Persistence (Favorites) Spring Data JPA 2.7 + H2 2.x ํŒŒ์ผ DB (์žฌ์‹œ์ž‘ ํ›„ ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ณต์›) โญ NEW

๐Ÿ—บ ๋กœ๋“œ๋งต

โœ… v4.3.0 โ€” ์‹ ๊ทœ ๊ธฐ๋Šฅ & ํ†ตํ•ฉ ๊ฐ•ํ™”

9๊ฐœ ๊ธฐ๋Šฅ์„ 5๊ฐœ Phase ๋กœ ๋‚˜๋ˆ„์–ด ๋‹จ๊ณ„๋ณ„๋กœ ๋„์ž… ์™„๋ฃŒ. ์šด์˜ ๊ฐ€์‹œ์„ฑ, ๋น„์šฉ ์ตœ์ ํ™”, ๋‹ค๊ตญ์–ด ํ™•์žฅ, K8s ๋ฐฐํฌ ์ค€๋น„๋ฅผ ํ•œ ์‚ฌ์ดํด์— ์ •๋ฆฌ.

Phase 1 โ€” Export ๊ฐ•ํ™” โœ…

  • SARIF 2.1.0 ๋‚ด๋ณด๋‚ด๊ธฐ โ€” /api/v1/export/sarif/{id}. ์ด๋ ฅ ํŽ˜์ด์ง€ ํ–‰๋งˆ๋‹ค ๋‹ค์šด๋กœ๋“œ ๋ฒ„ํŠผ + โ„น๏ธ ๋„์›€๋ง ํ† ๊ธ€ (VS Code SARIF Viewer / JetBrains Qodana / GitHub Code Scanning ์‚ฌ์šฉ๋ฒ• ์•ˆ๋‚ด)
  • Excel ์›Œํฌ๋ถ ๋‚ด๋ณด๋‚ด๊ธฐ โ€” Apache POI 5.2.5 ๊ธฐ๋ฐ˜. 3 ์‹œํŠธ (์š”์•ฝ/์ด๋ ฅ ์ƒ์„ธ/์œ ํ˜•๋ณ„ ํ†ต๊ณ„) + ํ•ฉ๊ณ„ ์ˆ˜์‹ + ํ—ค๋” ์Šคํƒ€์ผ. /api/v1/export/excel/history?limit=N

Phase 2 โ€” ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํƒ โœ…

  • Prometheus ๋ฉ”ํŠธ๋ฆญ ์ต์Šคํฌํ„ฐ โ€” micrometer-registry-prometheus + /actuator/prometheus. ์ปค์Šคํ…€ ๋ฉ”ํŠธ๋ฆญ 4์ข…: claude_api_calls_total{model,feature,status}, claude_api_tokens_total{model,direction}, analysis_duration_seconds{type}, pipeline_execution_total{status} + Spring ์ž๋™ ๋ฉ”ํŠธ๋ฆญ (HTTP, JVM)
  • Grafana ์Šคํƒ โ€” docker-compose.yml ์˜ monitoring ํ”„๋กœํ•„ (Prometheus + Grafana). ์‹œ์ž‘: docker-compose --profile monitoring up -d โ†’ http://localhost:3000 (admin/admin)
  • ๋ฉ”ํŠธ๋ฆญ ํ˜ธ์ถœ์ฒ˜ ํ†ตํ•ฉ โ€” SseStreamController/ReviewHistoryService/PipelineExecutor + 3 REST ์ปจํŠธ๋กค๋Ÿฌ Timer ๋ž˜ํ•‘. ์•ฝ 95% ๋ถ„์„ ํ๋ฆ„ ์ปค๋ฒ„

Phase 3 โ€” ๋ถ„์„ ๊ฐ•ํ™” โœ…

  • AI ๋ชจ๋ธ ๋น„์šฉ ์˜ตํ‹ฐ๋งˆ์ด์ € โ€” /admin/cost-optimizer (ADMIN). Anthropic ๊ณต์‹ ๋‹จ๊ฐ€ํ‘œ + ๋ถ„์„ ์œ ํ˜•๋ณ„ ํ‰๊ท  ์ž…๋ ฅ/์Šน์ธ๋ฅ  ๊ธฐ๋ฐ˜ ์ถ”์ฒœ (Haiku/Sonnet/Opus). ์ ˆ๊ฐ์•ก + ๋น„์šฉ ๋น„๊ต ์ฐจํŠธ
  • SQL ์ธ๋ฑ์Šค ์ž„ํŒฉํŠธ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ โ€” /sql/index-advisor. ์ •์  SQL ํŒŒ์‹ฑ + JDBC ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ (MySQL/PostgreSQL/Oracle/H2 ์ž๋™ ํ˜ธํ™˜) โ†’ ๊ธฐ์กด ์ธ๋ฑ์Šค ํ™œ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ + ์‹ ๊ทœ ์ธ๋ฑ์Šค DDL ์ถ”์ฒœ (Oracle 30์ž ์ œํ•œ ์ค€์ˆ˜). ํ†ตํ•ฉ ์›Œํฌ์ŠคํŽ˜์ด์Šค SQL ์–ธ์–ด ์„ ํƒ์‹œ nonStreaming ๊ธฐ๋Šฅ์œผ๋กœ๋„ ๋…ธ์ถœ

Phase 4 โ€” UX ํ™•์žฅ โœ…

  • ๋‹ค๊ตญ์–ด ํ™•์žฅ (์ผ/์ค‘/๋…) โ€” ํ•œ/์˜ โ†’ 5๊ฐœ ์–ธ์–ด (ja.ts/zh.ts/de.ts). TopBar ์— LanguageSwitcher (๐ŸŒ + ๊ตญ๊ธฐ). ๋ฐฑ์—”๋“œ app_user.locale ์ปฌ๋Ÿผ + PUT /api/v1/auth/locale. /me ์‘๋‹ต์— locale ํฌํ•จ โ†’ ๋‹ค๋ฅธ ๊ธฐ๊ธฐ ์ž๋™ ๋™๊ธฐํ™”
  • ๋Œ€์‹œ๋ณด๋“œ ์œ„์ ฏ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• โ€” react-grid-layout. HomePage ํŽธ์ง‘ ๋ชจ๋“œ: ๋“œ๋ž˜๊ทธ/๋ฆฌ์‚ฌ์ด์ฆˆ/ํ‘œ์‹œ-์ˆจ๊น€ ํ† ๊ธ€ + ์ €์žฅ/๊ธฐ๋ณธ๊ฐ’ ๋ณต์›. UserDashboardLayout ์—”ํ‹ฐํ‹ฐ๋กœ ์‚ฌ์šฉ์ž๋ณ„ ๋ ˆ์ด์•„์›ƒ DB ์˜์†ํ™”. ๋ˆ„๋ฝ ์œ„์ ฏ ์ž๋™ ๋ณด๊ฐ• (๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์•ˆ์ „)

Phase 5 โ€” ์›Œํฌํ”Œ๋กœ + ์ธํ”„๋ผ โœ…

  • ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ๊ทธ๋ž˜ํ”„ ๋ทฐ (PipelineGraphView) โ€” reactflow 11. ํŒŒ์ดํ”„๋ผ์ธ YAML ์„ ๋…ธ๋“œ ๊ทธ๋ž˜ํ”„๋กœ ์‹œ๊ฐํ™”. ๋ณ‘๋ ฌ ๋‹จ๊ณ„๋Š” ๊ฐ™์€ ์ปฌ๋Ÿผ ๋‹ค๋ฅธ row, ์ˆœ์ฐจ๋Š” ๊ฐ€๋กœ ์ง„ํ–‰. context ์˜์กด์„ฑ ์ž๋™ ์ถ”๋ก  + dependsOn ๋ช…์‹œ ์ง€์›. ์กฐ๊ฑด๋ถ€ step ์€ ์ฃผํ™ฉ์ƒ‰ ์—ฃ์ง€. ๋ฏธ๋‹ˆ๋งต + ์คŒ. PipelineEditor ์šฐ์ธก ํŒจ๋„์— "๐Ÿ“Š ๊ทธ๋ž˜ํ”„ / ๐Ÿ“ˆ Mermaid" ํƒญ์œผ๋กœ ์ถ”๊ฐ€ (๊ธฐ์กด PipelineBuilder/Mermaid ๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€)
  • Kubernetes Helm Chart (์ค€๋น„์šฉ) โ€” helm/claude-toolkit/ v0.1.0. Deployment + Service + Ingress + Secret + PVC + HPA + ServiceMonitor. DB ์˜ต์…˜๋ณ„ (h2/mysql/postgresql) values. 6๊ฐ€์ง€ ์„ค์น˜ ์‹œ๋‚˜๋ฆฌ์˜ค README ๋™๋ด‰. ํ˜„ ์‹œ์  ์‹ค์ œ K8s ํ™˜๊ฒฝ ๋ฏธ๋ณด์œ  โ€” helm template ์ •์  ๊ฒ€์ฆ๋งŒ ์™„๋ฃŒ. ์‚ฌ์šฉ ์‹œ์ ์— ์‚ฌ์šฉ์ž ํ™˜๊ฒฝ์—์„œ ์ถ”๊ฐ€ ๊ฒ€์ฆ ํ•„์š”

๐Ÿ”ง ๋ถ€์ˆ˜ ๊ฐœ์„  (์ด๋ฒˆ ์‚ฌ์ดํด)

  • DataRestController/AuthRestController silent catch ๋ธ”๋ก โ†’ SLF4J ๋กœ๊น…์œผ๋กœ ์ „ํ™˜ (~22 ๊ณณ)
  • SQL ์ธ๋ฑ์Šค ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ถŒํ•œ ๋ถ„๋ฆฌ โ€” featureKey: 'index-advisor' ์‹ ๊ทœ ๋“ฑ๋ก. ๊ด€๋ฆฌ์ž๊ฐ€ SQL ๋ฆฌ๋ทฐ์™€ ๋…๋ฆฝ์ ์œผ๋กœ ๊ถŒํ•œ ์ œ์–ด ๊ฐ€๋Šฅ
  • ํ†ตํ•ฉ ์›Œํฌ์ŠคํŽ˜์ด์Šค nonStreaming ํŒจํ„ด โ€” ๋น„-AI ๊ธฐ๋Šฅ(JDBC ๋ฉ”ํƒ€์กฐํšŒ ๋“ฑ)๋„ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‹ค์ค‘ ์„ ํƒ + ๋ณ‘๋ ฌ ์‹คํ–‰ ํ๋ฆ„์— ํ†ตํ•ฉ ๊ฐ€๋Šฅ

๐Ÿ“œ ์ด์ „ ๋ฒ„์ „ ํžˆ์Šคํ† ๋ฆฌ (v0.3.0 ~ v4.2.x) โ€” ํด๋ฆญํ•˜์—ฌ ํŽผ์น˜๊ธฐ

โœ… v0.3.0

์‹ ๊ทœ ๋„๊ตฌ (3์ข…)

  • ๋กœ๊ทธ ๋ถ„์„๊ธฐ /loganalyzer โ€” ์ผ๋ฐ˜ ๋ถ„์„ + ๋ณด์•ˆ ์œ„ํ˜‘ ํƒ์ง€, ํŒŒ์ผ ์—…๋กœ๋“œ
  • ์ •๊ทœ์‹ ์ƒ์„ฑ๊ธฐ /regex โ€” 5๊ฐœ ์–ธ์–ด ์ง€์›, ๋น ๋ฅธ ์˜ˆ์ œ 8์ข…
  • ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ๊ธฐ /commitmsg โ€” 4๊ฐ€์ง€ ์Šคํƒ€์ผ, diff ํŒŒ์ผ ์—…๋กœ๋“œ

๊ธฐ์กด ๊ธฐ๋Šฅ ๊ฐœ์„ 

  • ๋‹คํฌ/๋ผ์ดํŠธ ํ…Œ๋งˆ ํ† ๊ธ€
  • ์ž…๋ ฅ ์ž๋™ ์ž„์‹œ์ €์žฅ (localStorage, 2์ดˆ ๋””๋ฐ”์šด์Šค)
  • ํ† ํฐ ์ˆ˜ ์‹ค์‹œ๊ฐ„ ์˜ˆ์ธก ํ‘œ์‹œ (์ƒ‰์ƒ ๊ฒฝ๊ณ  ํฌํ•จ)
  • ํผ ์ค‘๋ณต ์ œ์ถœ ๋ฐฉ์ง€ (๋ฒ„ํŠผ ์ž๋™ ๋น„ํ™œ์„ฑํ™”)
  • ์ด๋ ฅ ํŽ˜์ด์ง€ ์‹ค์‹œ๊ฐ„ ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰ + ์œ ํ˜•๋ณ„ ํƒญ ํ•„ํ„ฐ

์ธํ”„๋ผ ๊ฐœ์„ 

  • SSE ์ŠคํŠธ๋ฆฌ๋ฐ ์•„ํ‚คํ…์ฒ˜ (POST /stream/init โ†’ GET /stream/{id})
  • ClaudeClient.chatStream() โ€” Consumer<String> ์ฝœ๋ฐฑ ์ŠคํŠธ๋ฆฌ๋ฐ
  • ํ”„๋กœ์ ํŠธ ์ปจํ…์ŠคํŠธ ๋ฉ”๋ชจ (๋ชจ๋“  AI ์š”์ฒญ์— ์ž๋™ ์ถ”๊ฐ€)

โœ… v0.4.0

์‹ ๊ทœ UX ๊ธฐ๋Šฅ

  • โšก ์‹ค์‹œ๊ฐ„ ๋ณด๊ธฐ ๋ฒ„ํŠผ โ€” ๋ชจ๋“  ๋„๊ตฌ ํŽ˜์ด์ง€์— SSE ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฒ„ํŠผ ๋…ธ์ถœ
  • ์‹ค์‹œ๊ฐ„ ๊ฒฐ๊ณผ ํŒจ๋„ + ๋ณต์‚ฌ ๋ฒ„ํŠผ + ์ปค์„œ ์• ๋‹ˆ๋ฉ”์ด์…˜

ํ”„๋กœ์ ํŠธ ์ปจํ…์ŠคํŠธ ์ž๋™ ์ฃผ์ž…

  • Settings ์ปจํ…์ŠคํŠธ ๋ฉ”๋ชจ๋ฅผ ์ฝ”๋“œ ๋ฆฌ๋ทฐยทํ…Œ์ŠคํŠธ ์ƒ์„ฑ ๋“ฑ 8๊ฐœ ๋„๊ตฌ์— ์ž๋™ ์ฃผ์ž…

์ด๋ ฅ ์˜๊ตฌ ์ €์žฅ

  • H2 ํŒŒ์ผ DB ์˜์†ํ™” โ€” ~/.claude-toolkit/history-db.mv.db (์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ํ›„ ๋ณต์›)
  • ReviewHistory โ†’ JPA @Entity ๋ณ€ํ™˜ (javax.persistence.*, Spring Boot 2.7 ํ˜ธํ™˜)
  • ReviewHistoryRepository (Spring Data JPA) ์‹ ๊ทœ ์ถ”๊ฐ€

โœ… v0.5.0

์‹ ๊ทœ ๊ธฐ๋Šฅ

  • iBatis โ†’ MyBatis ๋งคํผ ์ž๋™ ๋ณ€ํ™˜ โ€” /converter ํƒญ ์ถ”๊ฐ€, iBatis XML โ†’ MyBatis 3.x XML ๋ณ€ํ™˜
  • Claude ๋ชจ๋ธ ์„ ํƒ โ€” Settings ํŽ˜์ด์ง€์—์„œ ๋Ÿฐํƒ€์ž„ ๋ชจ๋ธ ์ „ํ™˜, volatile ์˜ค๋ฒ„๋ผ์ด๋“œ
  • Ctrl+Enter ๋‹จ์ถ•ํ‚ค โ€” ๋ชจ๋“  ํŽ˜์ด์ง€ ๊ณตํ†ต ํผ ์ œ์ถœ ๋‹จ์ถ•ํ‚ค (toolkit.js)
  • ์ฆ๊ฒจ์ฐพ๊ธฐ H2 DB ์˜์†ํ™” โ€” Favorite JPA @Entity ๋ณ€ํ™˜, FavoriteRepository ์‹ ๊ทœ ์ถ”๊ฐ€
  • ๋ฆฌ๋ทฐ diff ๋น„๊ต โ€” /history ์—์„œ ๋‘ ํ•ญ๋ชฉ ๋‚˜๋ž€ํžˆ ์ž…๋ ฅ/๊ฒฐ๊ณผ ๋น„๊ต ๋ชจ๋‹ฌ

โœ… v0.6.0

์‹ ๊ทœ ๋„๊ตฌ (3์ข…)

  • Javadoc ์ž๋™ ์ƒ์„ฑ /javadoc โ€” Java ์†Œ์Šค์— ํ•œ๊ตญ์–ด Javadoc ์ฃผ์„ ์ž๋™ ์‚ฝ์ž…, SSE ์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์›
  • ๋ฆฌํŒฉํ„ฐ๋ง ์ œ์•ˆ /refactor โ€” ์ฝ”๋“œ ๋ฌธ์ œ์  ๋ถ„์„ + ๊ฐœ์„  ์ฝ”๋“œ ์ƒ์„ฑ, SSE ์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์›
  • pom.xml ์˜์กด์„ฑ ๋ถ„์„ /depcheck โ€” ์ทจ์•ฝ์ ยท์ถฉ๋Œยท์—…๊ทธ๋ ˆ์ด๋“œ ๊ถŒ๊ณ , HIGH/MEDIUM/LOW ํ•„ํ„ฐ

๋ฐ˜์‘ํ˜• ๋ ˆ์ด์•„์›ƒ

  • ๋ชจ๋ฐ”์ผ(โ‰ค768px) / ํƒœ๋ธ”๋ฆฟ(โ‰ค992px) ๋ฏธ๋””์–ด์ฟผ๋ฆฌ โ€” toolkit.css ๋Œ€๊ทœ๋ชจ ์ถ”๊ฐ€
  • 2์ปฌ๋Ÿผ ๋ ˆ์ด์•„์›ƒ โ†’ ๋ชจ๋ฐ”์ผ ๋‹จ์ผ ์ปฌ๋Ÿผ ์ž๋™ ์ „ํ™˜

โœ… v0.7.0

์‹ ๊ทœ ๋„๊ตฌ (2์ข…)

  • ๋ฐ์ดํ„ฐ ๋งˆ์Šคํ‚น ์Šคํฌ๋ฆฝํŠธ /maskgen โ€” DDL โ†’ ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ Oracle UPDATE ์Šคํฌ๋ฆฝํŠธ ์ƒ์„ฑ
  • Spring Boot 3.x ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ /migrate โ€” Spring Boot 2.xโ†’3.x ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ฒดํฌ๋ฆฌ์ŠคํŠธ ์ž๋™ ์ƒ์„ฑ

๊ธฐ์กด ๊ธฐ๋Šฅ ํ™•์žฅ

  • Oracle Package ๋ฌธ์„œํ™” โ€” /docgen ์†Œ์Šค ์œ ํ˜•์— "Oracle Package (SPEC+BODY)" ์ถ”๊ฐ€
  • ์ธ๋ฑ์Šค ์ตœ์ ํ™” ์ œ์•ˆ โ€” /advisor ์„ธ ๋ฒˆ์งธ ํƒญ ์ถ”๊ฐ€, CREATE INDEX ๊ตฌ๋ฌธ ํฌํ•จ ์ œ์•ˆ ์ƒ์„ฑ
  • ๋ณด๊ณ ์„œ ๋ฌถ์Œ ๋‚ด๋ณด๋‚ด๊ธฐ โ€” /history ๋‹ค์ค‘ ์„ ํƒ โ†’ Markdown ๋ฒˆ๋“ค ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ

์‚ฌ์ด๋“œ๋ฐ” ๊ฐ•ํ™”

  • ์‚ฌ์ด๋“œ๋ฐ” ์„น์…˜๋ณ„(๋ถ„์„/์ƒ์„ฑ/๊ธฐ๋ก/๋„๊ตฌ) ์ ‘๊ธฐ/ํŽผ์น˜๊ธฐ ํ† ๊ธ€
  • ์ „์ฒด ์‚ฌ์ด๋“œ๋ฐ” ์ ‘๊ธฐ/ํŽผ์น˜๊ธฐ + ํ”Œ๋กœํŒ… ์—ด๊ธฐ ํƒญ (position:fixed ์ดํƒˆ ํ•ด๊ฒฐ)
  • localStorage ์ƒํƒœ ์ €์žฅ (ํ˜„์žฌ ํŽ˜์ด์ง€ ์„น์…˜ ์ž๋™ ์˜คํ”ˆ)

โœ… v0.8.0

์‹ ๊ทœ ๋„๊ตฌ (1์ข…)

  • Oracle ์‹คํ–‰๊ณ„ํš ์‹œ๊ฐํ™” /explain โ€” EXPLAIN PLAN ๊ฒฐ๊ณผ๋ฅผ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ํŠธ๋ฆฌ๋กœ ๋ Œ๋”๋ง
    • PLAN_TABLE ์ฟผ๋ฆฌ โ†’ ๋ถ€๋ชจ-์ž์‹ ํŠธ๋ฆฌ ๊ตฌ์กฐ ํŒŒ์‹ฑ
    • ์˜คํผ๋ ˆ์ด์…˜ ์ข…๋ฅ˜๋ณ„ ์ƒ‰์ƒ ๊ตฌ๋ถ„ (FULL=๐Ÿ”ด, INDEX=๐ŸŸข, JOIN=๐ŸŸฃ, SORT=๐ŸŸก, NESTED=๐ŸŸ )
    • ๋…ธ๋“œ๋ณ„ Cost ๋น„์œจ ๋ฐ” ์‹œ๊ฐํ™”
    • Claude AI ์„ฑ๋Šฅ ์ด์Šˆ / ์ตœ์ ํ™” ์ œ์•ˆ / ํ•ต์‹ฌ ๋‹จ๊ณ„ ํ•ด์„ค

โœ… v0.9.0

์‹ ๊ทœ ๋„๊ตฌ (3์ข…)

  • ERD โ†’ Oracle DDL ์—ญ๋ณ€ํ™˜ /erd DDL ์ƒ์„ฑ ํƒญ

    • Mermaid erDiagram, ํ…Œ์ด๋ธ” ๊ตฌ์กฐ ์„ค๋ช…, ์ž์—ฐ์–ด ์ž…๋ ฅ ์ง€์›
    • Oracle 11g/12c ํ˜ธํ™˜ โ€” VARCHAR2, NUMBER, DATE
    • PRIMARY KEY / FOREIGN KEY ์ œ์•ฝ์กฐ๊ฑด + FK ์ธ๋ฑ์Šค + COMMENT ON COLUMN ์ž๋™ ์ƒ์„ฑ
    • ์‹คํ–‰ ์ˆœ์„œ ์˜์กด์„ฑ ์ฃผ์„ ํฌํ•จ
  • ์‹คํ–‰๊ณ„ํš Before/After ๋น„๊ต /explain/compare

    • ์ตœ์ ํ™” ์ „/ํ›„ SQL ๋™์‹œ ์‹คํ–‰๊ณ„ํš ๋ถ„์„
    • ๋‚˜๋ž€ํžˆ ํŠธ๋ฆฌ ๋น„๊ต + Cost ๋ณ€ํ™”์œจ (%) ๋ฐฐ์ง€ (๊ฐœ์„ /์•…ํ™”/๋™์ผ)
    • DBMS_XPLAN ์›๋ฌธ ๊ฐ๊ฐ ์ ‘์ด์‹ ํ‘œ์‹œ
  • ์ด๋ ฅ ์žฌ์‹คํ–‰ /history ์žฌ์‹คํ–‰ ๋ฒ„ํŠผ

    • ์ด๋ ฅ ์ƒ์„ธ ๋ชจ๋‹ฌ โ†’ "์žฌ์‹คํ–‰" ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ•ด๋‹น ๊ธฐ๋Šฅ ํŽ˜์ด์ง€๋กœ ์ž…๋ ฅ ๋‚ด์šฉ ์ž๋™ ์ „๋‹ฌ
    • 22๊ฐ€์ง€ ๊ธฐ๋Šฅ ์œ ํ˜• ๋ชจ๋‘ ์ง€์› (SQL ๋ฆฌ๋ทฐ, ERD, DDL, ์ฝ”๋“œ ๋ฆฌ๋ทฐ, ํ…Œ์ŠคํŠธ, ์‹คํ–‰๊ณ„ํš ๋“ฑ)

โœ… v1.1.0

  • ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ ๊ด€๋ฆฌ โ€” /prompts ์—์„œ ๊ธฐ๋Šฅ๋ณ„ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ ํŽธ์ง‘ยท์ €์žฅยท์ ์šฉ
  • ๋ถ„์„ ๊ฒฐ๊ณผ ๋‚ด๋ณด๋‚ด๊ธฐ โ€” ์‹คํ–‰๊ณ„ํšยทERD ๊ฒฐ๊ณผ Markdown ๋‹ค์šด๋กœ๋“œ, ํžˆ์Šคํ† ๋ฆฌ ๋‹จ๊ฑด /history/{id}/export

โœ… v1.0.0

  • GitHub Actions CI/CD ํŒŒ์ดํ”„๋ผ์ธ (์ž๋™ ๋นŒ๋“œ ยท master push / PR ํŠธ๋ฆฌ๊ฑฐ)
  • REST API ๋ชจ๋“œ (์™ธ๋ถ€ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์—ฐ๋™์šฉ JSON API)

๐Ÿ”Œ REST API ์—”๋“œํฌ์ธํŠธ (/api/v1/)

Method Endpoint ์„ค๋ช…
GET /api/v1/health ์„œ๋ฒ„ ์ƒํƒœ ๋ฐ ์„ค์ • ํ™•์ธ
POST /api/v1/sql/review SQL ์„ฑ๋Šฅยทํ’ˆ์งˆ ๋ฆฌ๋ทฐ
POST /api/v1/sql/security SQL ๋ณด์•ˆ ์ทจ์•ฝ์  ๊ฒ€์‚ฌ
POST /api/v1/sql/explain Oracle ์‹คํ–‰๊ณ„ํš ๋ถ„์„
POST /api/v1/doc/generate ์†Œ์Šค์ฝ”๋“œ ๊ธฐ์ˆ  ๋ฌธ์„œ ์ƒ์„ฑ
POST /api/v1/code/review Java/Spring ์ฝ”๋“œ ๋ฆฌ๋ทฐ
POST /api/v1/code/security Java/Spring ๋ณด์•ˆ ๊ฐ์‚ฌ
POST /api/v1/erd/analyze ERD ๋ถ„์„

์š”์ฒญ/์‘๋‹ต ์˜ˆ์‹œ:

# SQL ๋ฆฌ๋ทฐ
curl -X POST http://localhost:8027/api/v1/sql/review \
  -H "Content-Type: application/json" \
  -d '{"sql": "SELECT * FROM ORDERS WHERE STATUS = 1"}'

# ์‘๋‹ต
{
  "success": true,
  "data": {
    "sqlType": "SELECT",
    "review":  "## Summary\n...",
    "reviewedAt": "2026-04-01 12:00:00"
  },
  "error": null,
  "timestamp": "2026-04-01 12:00:00"
}

โœ… v1.2.0

  • SQL ์„ฑ๋Šฅ ํžˆ์Šคํ† ๋ฆฌ ๋Œ€์‹œ๋ณด๋“œ /explain/dashboard โ€” ์‹คํ–‰๊ณ„ํš Cost ์ถ”์ด Chart.js ๋ผ์ธ ์ฐจํŠธ, ๊ธฐ๊ฐ„ ํ•„ํ„ฐ(์ „์ฒด/30์ผ/7์ผ), ํ†ต๊ณ„ ์นด๋“œ
  • ๋ฐฐ์น˜ SQL ๋ถ„์„ /sql-batch โ€” ํ…์ŠคํŠธ ์ง์ ‘ ์ž…๋ ฅ(--- ๊ตฌ๋ถ„์ž), CSV/ํ…์ŠคํŠธ ํŒŒ์ผ ์—…๋กœ๋“œ, ์ตœ๋Œ€ 30๊ฐœ SQL ์ผ๊ด„ ๋ฆฌ๋ทฐ, MD ๋ณด๊ณ ์„œ ๋‹ค์šด๋กœ๋“œ

โœ… v1.3.0

UI / UX ๊ฐœ์„ 

  • ๋‹คํฌ/๋ผ์ดํŠธ ํ…Œ๋งˆ ์ปค์Šคํ…€ ์ƒ‰์ƒ โ€” ์•ก์„ผํŠธ ์ปฌ๋Ÿฌ ์„ ํƒ (/settings) ยท 5๊ฐœ ํ”„๋ฆฌ์…‹ + ์ปฌ๋Ÿฌํ”ผ์ปค, localStorage ์ฆ‰์‹œ ์ ์šฉ
  • ๊ฒฐ๊ณผ ํŽ˜์ด์ง€ ์ธ์‡„/PDF ๋‚ด๋ณด๋‚ด๊ธฐ โ€” ๋ชจ๋“  ๋ถ„์„ ๊ฒฐ๊ณผ ํŽ˜์ด์ง€ ์šฐ์ธก ํ•˜๋‹จ ์ธ์‡„ ๋ฒ„ํŠผ, ๋ธŒ๋ผ์šฐ์ € ์ธ์‡„ ์ตœ์ ํ™” CSS
  • ๋ถ„์„ ๊ฒฐ๊ณผ ๊ณต์œ  ๋งํฌ โ€” /history ๋‹จ๊ฑด โ†’ POST /history/{id}/share โ†’ 7์ผ ์œ ํšจ UUID ๊ณต์œ  URL ์ƒ์„ฑ, /share/{token} ๋…๋ฆฝ ๋ทฐ

์šด์˜ ํŽธ์˜

  • Claude ๋ชจ๋ธ ์‚ฌ์šฉ๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง /usage โ€” ์‹ค์ œ API ํ† ํฐ ์ˆ˜(input/output) ์ž๋™ ๊ธฐ๋ก, ์ผ๋ณ„ยท๊ธฐ๋Šฅ๋ณ„ Chart.js ์ฐจํŠธ, ๋ชจ๋ธ๋ณ„ ๋น„์šฉ ์ถ”์ •($)
  • ๋ถ„์„ ์Šค์ผ€์ค„๋ง /schedule โ€” cron ํ‘œํ˜„์‹์œผ๋กœ ์ •๊ธฐ SQL ๋ฆฌ๋ทฐ ์ž๋™ ์‹คํ–‰, Spring TaskScheduler ๋™์  ๋“ฑ๋ก/ํ•ด์ œ, ์ฆ‰์‹œ ์‹คํ–‰ ์ง€์›, ๊ฒฐ๊ณผ ์ด๋ ฅ ์ž๋™ ์ €์žฅ

โœ… v1.4.0

SQL ๋ถ„์„ ๊ณ ๋„ํ™”

  • ์‹คํ–‰๊ณ„ํš SQL ์ฆ๊ฒจ์ฐพ๊ธฐ โ€” ๋ถ„์„ ๊ฒฐ๊ณผ โ˜… ์ฆ๊ฒจ์ฐพ๊ธฐ ๋“ฑ๋ก, /explain/dashboard์—์„œ ์žฌ์‹คํ–‰
  • SQL ์ตœ์ ํ™” ์ œ์•ˆ ์ ์šฉ โ€” AI ๋ฆฌ๋ทฐ ๊ฒฐ๊ณผ์—์„œ SQL ์ฝ”๋“œ ๋ธ”๋ก ์ถ”์ถœ โ†’ ์ธ๋ผ์ธ ํŽธ์ง‘ โ†’ ์žฌ๋ถ„์„

์šด์˜ ํŽธ์˜

  • ์Šค์ผ€์ค„ ๊ฒฐ๊ณผ ์ด๋ฉ”์ผ ๋ฐœ์†ก โ€” JavaMail(spring-boot-starter-mail) ์—ฐ๋™, SMTP ์„ค์ •(/settings), ์ˆ˜์‹  ์ฃผ์†Œ ๋“ฑ๋ก ์‹œ ์Šค์ผ€์ค„ ์™„๋ฃŒ ํ›„ ์ž๋™ ๋ฐœ์†ก
  • ๋‹ค์ค‘ SQL ํ”„๋กœํ•„ /db-profiles โ€” Oracle DB ์—ฐ๊ฒฐ ํ”„๋กœํ•„ ์ €์žฅยทํŽธ์ง‘ยท์‚ญ์ œ, ์›ํด๋ฆญ ์ „ํ™˜(ํ˜„์žฌ Settings์— ์ฆ‰์‹œ ๋ฐ˜์˜)

UI / UX ๊ฐœ์„ 

  • ๋Œ€์‹œ๋ณด๋“œ ํ™ˆ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• โ€” ํ™ˆ(/) ์— ์ตœ๊ทผ ์ฆ๊ฒจ์ฐพ๊ธฐยท๋ถ„์„ ์ด๋ ฅ ์œ„์ ฏ ์ถ”๊ฐ€
  • ๊ธ€๋กœ๋ฒŒ ๊ฒ€์ƒ‰ /search โ€” ์ด๋ ฅยท์ฆ๊ฒจ์ฐพ๊ธฐยท๊ธฐ๋Šฅ ๋ชฉ๋ก ํ†ตํ•ฉ ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰, / ๋‹จ์ถ•ํ‚ค ํฌ์ปค์Šค

โœ… v1.5.0

SQL ๋ถ„์„ ๊ณ ๋„ํ™”

  • ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ ์‹คํ–‰๊ณ„ํš ๋ถ„์„ โ€” EXPLAIN PLAN ํŠธ๋ฆฌ๋ฅผ DB ์ฟผ๋ฆฌ ์ฆ‰์‹œ ๋ Œ๋”๋ง ํ›„, Claude AI ๋ถ„์„์„ SSE ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ ์‹ค์‹œ๊ฐ„ ์ถœ๋ ฅ
    • 2๋‹จ๊ณ„ ๋ถ„๋ฆฌ: POST /explain/stream-init (DB ์ „์šฉ) โ†’ GET /stream/{id} (AI ์ŠคํŠธ๋ฆฌ๋ฐ)
    • ๊ฒฐ๊ณผ ์ €์žฅ POST /explain/stream-save โ€” ์ŠคํŠธ๋ฆฌ๋ฐ ์™„๋ฃŒ ํ›„ ์ด๋ ฅ ๊ธฐ๋ก
    • ExplainPlanService.analyzePlanOnly() ์‹ ๊ทœ ์ถ”๊ฐ€ (DB ๋‹จ๊ณ„๋งŒ ๋ถ„๋ฆฌ)
    • SseStreamController.registerStream() ๋‚ด๋ถ€ ๋“ฑ๋ก API ์ถ”๊ฐ€ (HTTP ๋ผ์šด๋“œํŠธ๋ฆฝ ์—†์ด ์ง์ ‘ ๋“ฑ๋ก)
  • SQL ์ž๋™ ๋ฆฌํŒฉํ„ฐ๋ง diff ๋ทฐ โ€” ์›๋ณธ SQL vs AI ์ œ์•ˆ ์ตœ์ ํ™” SQL์„ LCS ๊ธฐ๋ฐ˜ ๋ผ์ธ diff๋กœ ์‹œ๊ฐํ™”
    • /advisor ๋ฆฌ๋ทฐ ๊ฒฐ๊ณผ์—์„œ ์ตœ์ ํ™” SQL ์ฝ”๋“œ ๋ธ”๋ก ์ž๋™ ์ถ”์ถœ
    • ์‚ญ์ œ ๋ผ์ธ(๐Ÿ”ด ๋นจ๊ฐ•ยท์ทจ์†Œ์„ ) / ์ถ”๊ฐ€ ๋ผ์ธ(๐ŸŸข ์ดˆ๋ก) / ๋™์ผ ๋ผ์ธ ์ƒ‰์ƒ ๊ตฌ๋ถ„
    • ์›๋ณธ ๋ณต์‚ฌ / AI ์ œ์•ˆ ๋ณต์‚ฌ ๋ฒ„ํŠผ ยท .md ์ €์žฅ

โœ… v1.6.0

์ฝ”๋“œ ๋ฆฌ๋ทฐ ํ•˜๋„ค์Šค (Harness)

  • ์ฝ”๋“œ ๋ฆฌ๋ทฐ ํ•˜๋„ค์Šค /harness โ€” Analyst โ†’ Builder โ†’ Reviewer 3๋‹จ๊ณ„ AI ํŒŒ์ดํ”„๋ผ์ธ
    • ๋ถ„์„๊ฐ€(Analyst): ์„ฑ๋Šฅ ๋ฌธ์ œยท์•ˆํ‹ฐํŒจํ„ดยท๋ณด์•ˆ ์ทจ์•ฝ์  ํŒŒ์•…
    • ๊ฐœ์„ ๊ฐ€(Builder): ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ ๊ฐœ์„  ์ฝ”๋“œ ์ƒ์„ฑ
    • ๊ฒ€ํ† ์ž(Reviewer): ๋ณ€๊ฒฝ ๋‚ด์—ญ ๊ฒ€์ฆ + APPROVED/NEEDS_REVISION ํŒ์ •
    • LCS ๊ธฐ๋ฐ˜ ์›๋ณธ vs ๊ฐœ์„  ์ฝ”๋“œ side-by-side Diff ๋ทฐ (์‚ญ์ œ๐Ÿ”ด/์ถ”๊ฐ€๐ŸŸข/๋™์ผ ์ƒ‰์ƒ)
    • SSE ์ŠคํŠธ๋ฆฌ๋ฐ ๋ชจ๋“œ: ํŒŒ์ดํ”„๋ผ์ธ ์ง„ํ–‰ ๋‹จ๊ณ„๋ณ„ ์‹ค์‹œ๊ฐ„ ์ถœ๋ ฅ
    • Java / SQL ์–ธ์–ด ์„ ํƒ, ์ด๋ ฅ ์ž๋™ ์ €์žฅ (HARNESS_REVIEW)
    • HarnessReviewService + HarnessController ์‹ ๊ทœ ์ถ”๊ฐ€

โœ… v1.7.0

๐Ÿ“Š ๋ถ„์„ ํ’ˆ์งˆ ๊ฐ•ํ™”

  • ์ฝ”๋“œ ํ’ˆ์งˆ ์ ์ˆ˜ โ€” ํ•˜๋„ค์Šค Reviewer๊ฐ€ ๊ฐ€๋…์„ฑยท์„ฑ๋Šฅยท์œ ์ง€๋ณด์ˆ˜์„ฑยท๋ณด์•ˆ ํ•ญ๋ชฉ๋ณ„ X/10 ์ ์ˆ˜ + ์ข…ํ•ฉ ํŒ์ • ์‚ฐ์ถœ. ์ „์šฉ "ํ’ˆ์งˆ ์ ์ˆ˜" ํƒญ ์ œ๊ณต
  • ๋ฐฐ์น˜ ๋ถ„์„ /harness/batch โ€” ์—ฌ๋Ÿฌ Java ํŒŒ์ผ / SQL ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋™์  ๋ชฉ๋ก์— ์ถ”๊ฐ€ ํ›„ ์ˆœ์ฐจ ๋น„๋™๊ธฐ ๋ถ„์„. ์ง„ํ–‰๋ฅ  ๋ฐ”ยท๊ฒฐ๊ณผ ํ…Œ์ด๋ธ”ยท์ƒ์„ธ ๋ชจ๋‹ฌ ์ œ๊ณต. ์™„๋ฃŒ ํ›„ ๋‹ค์ค‘ ์ด๋ฉ”์ผ ์•Œ๋ฆผ ์ž๋™ ๋ฐœ์†ก. ๋ฐฐ์น˜ ์ด๋ ฅ H2 DB ์˜๊ตฌ ์ €์žฅ (batch_history) + ์ด๋ ฅ ์ƒ์„ธ์—์„œ ํ•ญ๋ชฉ๋ณ„ ๋ถ„์„ ๊ฒฐ๊ณผ ์ง์ ‘ ํ™•์ธ
  • ํ•˜๋„ค์Šค ๋ถ„์„ ํ…œํ”Œ๋ฆฟ โ€” ์ผ๋ฐ˜ยท์„ฑ๋Šฅ ์ตœ์ ํ™”ยท๋ณด์•ˆ ์ทจ์•ฝ์ ยท๋ฆฌํŒฉํ„ฐ๋งยทOracle SQL ์„ฑ๋Šฅยท๊ฐ€๋…์„ฑ 6๊ฐ€์ง€ ํ”„๋ฆฌ์…‹ ์„ ํƒ. Analyst ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ์— ๋ชฉ์ ๋ณ„ ์ง‘์ค‘ ์ง€์‹œ ์ถ”๊ฐ€

๐Ÿ—„๏ธ Oracle / DB ํŠนํ™”

  • DB ์˜ค๋ธŒ์ ํŠธ ์˜์กด์„ฑ ๋ถ„์„ /harness/dependency โ€” Oracle SP/Package/Function ๋˜๋Š” Java ํด๋ž˜์Šค์˜ ํ˜ธ์ถœ ๊ด€๊ณ„ยทํ…Œ์ด๋ธ” ์˜์กด์„ฑ 5๊ฐœ ์„น์…˜ ๋ณด๊ณ ์„œ ์ถœ๋ ฅ. Java ํŒŒ์ผ ๋ธŒ๋ผ์šฐ์ € + DB ์˜ค๋ธŒ์ ํŠธ ๊ฒ€์ƒ‰ ์†Œ์Šค ์„ ํƒ ํŒจ๋„ ๋‚ด์žฅ
  • DB ์บ์‹œ ์ž๋™ ๊ฐฑ์‹  ์Šค์ผ€์ค„ โ€” Settings์—์„œ cron ํ‘œํ˜„์‹ ์ž…๋ ฅ(ํ”„๋ฆฌ์…‹ 5์ข…). @Scheduled(fixedRate=60s) + CronExpression.parse() ๊ธฐ๋ฐ˜ ์ž๋™ ๊ฐฑ์‹ . WAS ์žฌ๊ธฐ๋™ ์—†์ด ์ตœ์‹  ์˜ค๋ธŒ์ ํŠธ ๋ชฉ๋ก ์œ ์ง€

๐Ÿ“ค ๋‚ด๋ณด๋‚ด๊ธฐ / ๋ฆฌํฌํŒ…

  • ๋ถ„์„ ๊ฒฐ๊ณผ HTML ๋‚ด๋ณด๋‚ด๊ธฐ โ€” ํ•˜๋„ค์Šค ๊ฒฐ๊ณผ(์›๋ณธ ์ฝ”๋“œยท๊ฐœ์„  ์ฝ”๋“œยทDiffยท๋ถ„์„ ์š”์•ฝยท๋ณ€๊ฒฝ ๋‚ด์—ญยท๊ฒ€ํ†  ๊ฒฐ๊ณผ)๋ฅผ ๋…๋ฆฝ ์‹คํ–‰ํ˜• HTML ํŒŒ์ผ๋กœ ์ €์žฅ (POST /harness/export-html)
  • ํ’ˆ์งˆ ๋Œ€์‹œ๋ณด๋“œ /harness/dashboard โ€” ๋ˆ„์  HARNESS_REVIEW ์ด๋ ฅ ๊ธฐ๋ฐ˜ ํ†ต๊ณ„ ์นด๋“œ(์ด ๋ถ„์„ ์ˆ˜, APPROVED %, ์–ธ์–ด ๋น„์œจ) + Chart.js ํŒ์ • ๋„๋„›ยท์–ธ์–ด ๋ง‰๋Œ€ยท์ ์ˆ˜ ์ถ”์ด ๋ผ์ธ ์ฐจํŠธ + ์ตœ๊ทผ ๋ถ„์„ ํƒ€์ž„๋ผ์ธ

โšก UX / ์šด์˜ ํŽธ์˜

  • ํ•˜๋„ค์Šค ํžˆ์Šคํ† ๋ฆฌ ์žฌ๋กœ๋“œ โ€” ํžˆ์Šคํ† ๋ฆฌ ์ƒ์„ธ ๋ชจ๋‹ฌ์—์„œ "ํ•˜๋„ค์Šค ์žฌ๋ถ„์„" ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์›๋ณธ ์ฝ”๋“œยท์–ธ์–ด๋ฅผ localStorage์— ์ €์žฅ ํ›„ /harness ํŽ˜์ด์ง€๋กœ ์ž๋™ ์ด๋™ยท๋กœ๋“œ
  • ๋ถ„์„ ์•Œ๋ฆผ (์ด๋ฉ”์ผ) โ€” ๋ฐฐ์น˜ ๋ถ„์„ ์™„๋ฃŒ ์‹œ ์ง€์ • ์ด๋ฉ”์ผ๋กœ emailService.sendJobResult() ์ž๋™ ๋ฐœ์†ก (SMTP ์„ค์ • ํ•„์š”)

๐Ÿ” ๋ณด์•ˆ ๊ฐ•ํ™” (์ฐจ๊ธฐ ๋ฒ„์ „์œผ๋กœ ์ด์›”)

  • REST API ํ‚ค ์ธ์ฆ โ€” REST API ํ˜ธ์ถœ ์‹œ X-API-Key ํ—ค๋” ์ธ์ฆ (/settings์—์„œ ํ‚ค ๋ฐœ๊ธ‰ยท๊ด€๋ฆฌ)
  • Settings ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž ๊ธˆ โ€” ์„ค์ • ํŽ˜์ด์ง€ ์ ‘๊ทผ ์‹œ PIN ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ์š”๊ตฌ

โœ… v1.8.0

๐Ÿ›ก๏ธ ํ•˜๋„ค์Šค 4๋‹จ๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ โ€” Verifier ์ถ”๊ฐ€

  • ๊ฒ€์ฆ์ž(Verifier) ๋‹จ๊ณ„ โ€” Analyst โ†’ Builder โ†’ Reviewer โ†’ Verifier 4๋‹จ๊ณ„ ์™„์„ฑ
    • Java ๊ฒ€์ฆ: ## ๐Ÿ›  ์ปดํŒŒ์ผ ๊ฐ€๋Šฅ์„ฑ (import ๋ˆ„๋ฝยทํƒ€์ž… ๋ถˆ์ผ์น˜ยท์ ‘๊ทผ ์ œ์–ด์ž ์˜ค๋ฅ˜), ## ๐Ÿšจ ์œ„ํ—˜ ๋ณ€๊ฒฝ ๊ฐ์ง€ (๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝยทNullPointerException ์ถ”๊ฐ€ยท๋ฆฌ์†Œ์Šค ๋ˆ„์ˆ˜, ์‹ฌ๊ฐ๋„ HIGH/MEDIUM/LOW), ## ๐Ÿ”— Spring/JPA ํ˜ธํ™˜์„ฑ (์ˆœํ™˜ ์˜์กดยทN+1ยทLazyInitializationExceptionยท@Transactional ๋ˆ„๋ฝ), ## ๐Ÿ ์ตœ์ข… ๊ฒ€์ฆ ํŒ์ •
    • SQL ๊ฒ€์ฆ: ## ๐Ÿ›  SQL ๋ฌธ๋ฒ• ๊ฒ€์ฆ (Oracle ํ‚ค์›Œ๋“œยท๊ด„ํ˜ธ ๋ถˆ์ผ์น˜), ## ๐Ÿšจ ์œ„ํ—˜ ๋ณ€๊ฒฝ ๊ฐ์ง€ (DROP/TRUNCATE/WHERE ์—†๋Š” DELETEยทUPDATE), ## ๐Ÿ”— Oracle ์˜์กด์„ฑ ๊ฒ€์ฆ (DBMS_*ยทํŒŒํ‹ฐ์…˜ยท์‹œํ€€์ŠคยทํžŒํŠธ ๊ตฌ๋ฌธ), ## ๐Ÿ ์ตœ์ข… ๊ฒ€์ฆ ํŒ์ •
    • ํŒ์ • ๋ฐฐ์ง€: ๐ŸŸข VERIFIED (๋ฌธ์ œ ์—†์Œ) / ๐ŸŸก WARNINGS (์ฃผ์˜ ํ•„์š”) / ๐Ÿ”ด FAILED (์‹ฌ๊ฐํ•œ ๋ฌธ์ œ) โ€” ๊ฒ€์ฆ ๊ฒฐ๊ณผ ํƒญ ์ƒ๋‹จ์— ์ปฌ๋Ÿฌ ๋ฐฐ์ง€ ํ‘œ์‹œ
    • SSE ์ŠคํŠธ๋ฆฌ๋ฐ: ํŒŒ์ดํ”„๋ผ์ธ ์ŠคํŠธ๋ฆฌ๋ฐ ์‹œ Verifier ์ง„ํ–‰ ๋‹จ๊ณ„ ์‹ค์‹œ๊ฐ„ ํ‘œ์‹œ (streamStepVerifier)
    • ์‹ฌ๊ฐ๋„ ํ•˜์ด๋ผ์ดํŒ…: HIGH/MEDIUM/LOW ํ‚ค์›Œ๋“œ ์ž๋™ ์ƒ‰์ƒ ๋ Œ๋”๋ง
  • ๋ฐฐ์น˜ ๋ถ„์„ + Verifier ํ†ตํ•ฉ โ€” ๋ฐฐ์น˜ ์‹คํ–‰ ์‹œ ๊ฐ ํ•ญ๋ชฉ์— Verifier ๋‹จ๊ณ„ ํฌํ•จ. ์ด๋ ฅ ์ž๋™ ์ €์žฅ

โœ… v1.9.0

๐Ÿ”„ SQL DB ๋ฒˆ์—ญ โ€” /sql-translate

  • ์ด์ข… DB SQL ๋ฒˆ์—ญ โ€” Oracle / MySQL / PostgreSQL / MSSQL ๊ฐ„ SQL ๋ฌธ๋ฒ• ์ž๋™ ๋ณ€ํ™˜. SSE ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ
  • ์†Œ์Šค/ํƒ€๊ฒŸ DB ์„ ํƒ โ€” 4์ข… DB ์กฐํ•ฉ ์„ ํƒ UI + ๋น ๋ฅธ ์Šค์™‘ ๋ฒ„ํŠผ
  • ๋ฒˆ์—ญ ์ด๋ ฅ ์ €์žฅ โ€” ๋ฒˆ์—ญ ๊ฒฐ๊ณผ ReviewHistory SQL_TRANSLATE ์œ ํ˜•์œผ๋กœ ์ž๋™ ์ €์žฅ

๐Ÿ“Š ROI ๋ฆฌํฌํŠธ โ€” /roi-report

  • ์›”๋ณ„ ROI ์‹œ๊ฐํ™” โ€” ๊ธฐ๊ฐ„ ์„ ํƒ(1~24๊ฐœ์›”) + Chart.js ๋ผ์ธ/๋ฐ” ์ฐจํŠธ (์ ˆ๊ฐ์‹œ๊ฐ„ยท๋น„์šฉ์ ˆ๊ฐยทROI%)
  • ๊ธฐ๋Šฅ๋ณ„ ๋ถ„์„ โ€” ๊ธฐ๋Šฅ ์œ ํ˜•๋ณ„ ์ด๋ ฅ ์ง‘๊ณ„ โ†’ ์ ˆ๊ฐ ํšจ๊ณผ ์ˆœ์œ„ ํ‘œ
  • ๋‹จ๊ฐ€ ์„ค์ • โ€” ์‹œ๊ฐ„๋‹น ์ธ๊ฑด๋น„ยทAI API ๋‹จ๊ฐ€ยทํ™˜์œจ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• (~/.claude-toolkit/roi-settings.json)
  • ROI ์Šค์ผ€์ค„๋Ÿฌ โ€” @Scheduled ์›”๋ณ„ ์š”์•ฝ ์ž๋™ ๊ณ„์‚ฐ

๐Ÿ” ๋ณด์•ˆ ์„ค์ • โ€” /security

  • REST API ํ‚ค ์ธ์ฆ โ€” X-API-Key ํ—ค๋” ์ธ์ฆ. /security์—์„œ ํ‚ค ๋ฐœ๊ธ‰ยทํ๊ธฐยท์žฌ๋ฐœ๊ธ‰. ApiKeyFilter ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ
  • Settings ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž ๊ธˆ โ€” ์„ค์ • ํŽ˜์ด์ง€ ์ ‘๊ทผ ์‹œ BCrypt ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ์š”๊ตฌ. ์„ธ์…˜ ๊ธฐ๋ฐ˜ ์ž ๊ธˆ ํ•ด์ œ
  • ๊ฐ์‚ฌ ๋กœ๊ทธ(Audit Log) โ€” API ํ˜ธ์ถœยท์„ค์ • ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ๋ฅผ ํƒ€์ž„์Šคํƒฌํ”„ยทIP์™€ ํ•จ๊ป˜ H2 DB ๊ธฐ๋ก. ํŽ˜์ด์ง€๋„ค์ด์…˜ ์กฐํšŒ
  • spring-security-crypto ์˜์กด์„ฑ ์ถ”๊ฐ€ (BCryptPasswordEncoder, spring-boot-starter-security ๋ฏธ์‚ฌ์šฉ)

๐Ÿ•ต๏ธ ๋ฏผ๊ฐ์ •๋ณด ๋งˆ์Šคํ‚น โ€” /input-masking

  • 8๊ฐ€์ง€ ํŒจํ„ด โ€” ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธยท์‹ ์šฉ์นด๋“œยท์ด๋ฉ”์ผยท์ „ํ™”๋ฒˆํ˜ธยทIP์ฃผ์†Œยท๋น„๋ฐ€๋ฒˆํ˜ธยทAPIํ‚คยท๊ณ„์ขŒ๋ฒˆํ˜ธ regex ํƒ์ง€
  • ์–‘๋ฐฉํ–ฅ ์ฒ˜๋ฆฌ โ€” ๋งˆ์Šคํ‚น(ํ† ํฐ ์น˜ํ™˜) โ†’ Claude ์ „์†ก โ†’ ๋ณต์›(ํ† ํฐ โ†’ ์›๋ณธ) ์™„์ „ ์›Œํฌํ”Œ๋กœ์šฐ
  • ํ† ํฐ ๋งต ์‹œ๊ฐํ™” โ€” ํ† ํฐโ†”์›๋ณธ ๋งคํ•‘ ํ…Œ์ด๋ธ” + ๋ณต์‚ฌ ๋ฒ„ํŠผ + ์œ ํ˜•๋ณ„ ์นด์šดํŠธ ๋ฐฐ์ง€
  • LocalStorage ์ž„์‹œ์ €์žฅ โ€” ์ƒˆ๋กœ๊ณ ์นจ ํ›„์—๋„ ์ž…๋ ฅ ํ…์ŠคํŠธยทํ† ํฐ ๋งต ๋ณต์›

๐Ÿ›ก๏ธ ํ•˜๋„ค์Šค Verifier ์™„์„ฑ

  • 4๋‹จ๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ ์™„์„ฑ โ€” Analyst โ†’ Builder โ†’ Reviewer โ†’ Verifier ๋™๊ธฐยท์ŠคํŠธ๋ฆฌ๋ฐ ๋ชจ๋‘ ์ง€์›
  • Java ๊ฒ€์ฆ: ์ปดํŒŒ์ผ ๊ฐ€๋Šฅ์„ฑยทSpring/JPA ํ˜ธํ™˜์„ฑยท์œ„ํ—˜ ๋ณ€๊ฒฝ ๊ฐ์ง€ (์‹ฌ๊ฐ๋„ HIGH/MEDIUM/LOW)
  • SQL ๊ฒ€์ฆ: SQL ๋ฌธ๋ฒ•ยทOracle ์˜์กด์„ฑยท์œ„ํ—˜ ๋ณ€๊ฒฝ ๊ฐ์ง€ (DROP/TRUNCATE/WHERE ์—†๋Š” DELETE)
  • ํŒ์ • ๋ฐฐ์ง€: ๐ŸŸข VERIFIED / ๐ŸŸก WARNINGS / ๐Ÿ”ด FAILED โ€” ๊ฒ€์ฆ ๊ฒฐ๊ณผ ํƒญ ์ƒ๋‹จ ์ปฌ๋Ÿฌ ๋ฐฐ์ง€

โœ… v2.0.0

๐Ÿงฉ ํ†ตํ•ฉ ์›Œํฌ์ŠคํŽ˜์ด์Šค + ํ”Œ๋Ÿฌ๊ทธ์ธ ์•„ํ‚คํ…์ฒ˜ (Group 4)

  • AnalysisService ํ”Œ๋Ÿฌ๊ทธ์ธ ์ธํ„ฐํŽ˜์ด์Šค โ€” 9๊ฐ€์ง€ ๋ถ„์„ ์œ ํ˜•(CODE_REVIEWยทSECURITY_AUDITยทTEST_GENERATIONยทJAVADOCยทREFACTORยทSQL_REVIEWยทSQL_SECURITYยทSQL_TRANSLATEยทHARNESS)์„ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ถ”์ƒํ™”. AnalysisServiceRegistry Bean ๋“ฑ๋ก
  • ์ปค์Šคํ…€ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ ์ €์žฅ โ€” custom_prompt ์—”ํ‹ฐํ‹ฐ. ๋ถ„์„ ์œ ํ˜•๋ณ„ ํ”„๋กฌํ”„ํŠธ ํŽธ์ง‘ยท์ €์žฅยท์ดˆ๊ธฐํ™” UI (/settings/prompts). PromptService DBโ†’๋‚ด์žฅ ํ”„๋กฌํ”„ํŠธ ์šฐ์„ ์ˆœ์œ„ ํ•ด์†Œ
  • ํ†ตํ•ฉ ์›Œํฌ์ŠคํŽ˜์ด์Šค /workspace โ€” ๋ณต์ˆ˜ ๋ถ„์„ ์œ ํ˜• ๋™์‹œ ์„ ํƒ โ†’ Thread ๋ณ‘๋ ฌ ์‹คํ–‰ โ†’ ํƒญ๋ณ„ SSE ์ŠคํŠธ๋ฆฌ๋ฐ ๊ฒฐ๊ณผ. ์–ธ์–ด ์ž๋™ ๊ฐ์ง€. ๋ฒˆ๋“ค ์ €์žฅ/๋ถˆ๋Ÿฌ์˜ค๊ธฐ. ์†Œ์Šค ์„ ํƒ๊ธฐ(Java ํŒŒ์ผยทDB ์˜ค๋ธŒ์ ํŠธ) ์ „์ฒด ๋ชฉ๋ก ์ง€์›
  • AI ๋ชจ๋ธ ๋น„๊ต ๋ถ„์„ โ€” /workspace/compare: ๋™์ผ ์ฝ”๋“œ๋ฅผ ๋ณต์ˆ˜ ๋ชจ๋ธ๋กœ ๋ณ‘๋ ฌ ๋ถ„์„, ์ขŒ์šฐ 2์ปฌ๋Ÿผ ๋น„๊ต. ๋Ÿฐํƒ€์ž„ ๋ชจ๋ธ ์ „ํ™˜(setModelOverride) + ์›๋ณต
  • ๋ฉ€ํ‹ฐ ์–ธ์–ด ์ง€์› ํ™•์žฅ โ€” PythonยทJavaScriptยทTypeScriptยทKotlin ์–ธ์–ด๋ณ„ AnalysisType ์ง€์›. ์–ธ์–ด ์ž๋™ ๊ฐ์ง€ ๋ถ„๊ธฐ
  • ์ „์ฒด ๊ฒฐ๊ณผ ์ด๋ฉ”์ผ ์ผ๊ด„ ๋ฐœ์†ก โ€” ๋ชจ๋“  ๋ถ„์„ ํƒญ ๊ฒฐ๊ณผ๋ฅผ ํ•˜๋‚˜๋กœ ํ•ฉ์ณ ์ด๋ฉ”์ผ ๋ฐœ์†ก. ํฌํ•จ ๋ถ„์„ ์œ ํ˜• ๋ฒ”์œ„ ํ‘œ์‹œ
  • ์ด๋ ฅ ์ƒ์„ธ ํŒ์—… โ€” ์ด๋ ฅ ํด๋ฆญ ์‹œ ๋ชจ๋‹ฌ ํŒ์—…์œผ๋กœ ์ „์ฒด ์ƒ์„ธ(์ผ์‹œยท์–ธ์–ดยท๋ถ„์„์œ ํ˜•ยท์ž…๋ ฅ์ฝ”๋“œ) ํ‘œ์‹œ. MD/PDF ๋‹ค์šด๋กœ๋“œ, ํด๋ฆฝ๋ณด๋“œ ๋ณต์‚ฌ
  • ๊ฒฐ๊ณผ PDF ๋‹ค์šด๋กœ๋“œ โ€” ๋ถ„์„ ๊ฒฐ๊ณผ ์ „์ฒด๋ฅผ Markdownโ†’HTML ๋ณ€ํ™˜ ํ›„ ์ธ์‡„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋กœ PDF ์ €์žฅ

๐Ÿ”ง SSE ์ŠคํŠธ๋ฆฌ๋ฐ ์•ˆ์ •ํ™”

  • SSE ๋ฉ€ํ‹ฐ๋ผ์ธ ๋ฐ์ดํ„ฐ ์•ˆ์ „ ์ „์†ก โ€” sendSseData() ์œ ํ‹ธ๋ฆฌํ‹ฐ: chunk.split("\n") ํ›„ ๊ฐ ์ค„์„ ๋ณ„๋„ data: ๋ผ์ธ์œผ๋กœ ์ „์†กํ•˜์—ฌ ์ค„๋ฐ”๊ฟˆ ์†์‹ค ๋ฐฉ์ง€ (Spring SseEmitter ํ•œ๊ณ„ ๊ทน๋ณต)
  • AuditLogFilter SSE ๊ฒฝ๋กœ ์ œ์™ธ โ€” ContentCachingResponseWrapper๊ฐ€ /workspace/stream/ ๊ฒฝ๋กœ๋ฅผ ๋ฒ„ํผ๋งํ•˜์ง€ ์•Š๋„๋ก ์ˆ˜์ • (startsWith โ†’ contains)
  • SQL DB ๋ฒˆ์—ญ ๋…๋ฆฝ ํŽ˜์ด์ง€ โ€” /sql-translate ์‚ฌ์ด๋“œ๋ฐ” "๋ถ„์„" ์นดํ…Œ๊ณ ๋ฆฌ ๋“ฑ๋ก. ์†Œ์Šค/ํƒ€๊ฒŸ DB ์„ ํƒ(4์ข…). ๋™์ผ DB ๋ฐฉ์–ด. Progress bar UI. DB ์˜ค๋ธŒ์ ํŠธ ์†Œ์Šค ๋กœ๋“œ. ์œ ์—ฐํ•œ ์‘๋‹ต ํŒŒ์‹ฑ
  • ์†Œ์Šค ์„ ํƒ๊ธฐ ๊ฐœ์„  โ€” ํŒŒ์ผ ์ˆ˜๋Ÿ‰ ์ œํ•œ(Java 200๊ฐœยทDB 300๊ฐœ) ํ•ด์ œ โ†’ ์ „์ฒด ๋ชฉ๋ก ํ‘œ์‹œ. ์›Œํฌ์ŠคํŽ˜์ด์Šคยท๊ธฐ์ˆ ๋ฌธ์„œยท์ฝ”๋“œ๋ณ€ํ™˜ ๋™์ผ ์ ์šฉ
  • ๊ธฐ์ˆ ๋ฌธ์„œยท์ฝ”๋“œ๋ณ€ํ™˜ ํผ ์•ˆ์ „์„ฑ โ€” ์†Œ์Šค ์„ ํƒ ํƒญ type="button" ๋ˆ„๋ฝ ์ˆ˜์ •. ๋นˆ ์ž…๋ ฅ ๋ฐฉ์–ด(ํ”„๋ก ํŠธ์—”๋“œ onsubmit + ๋ฐฑ์—”๋“œ ๊ฒ€์ฆ)
  • ๊ธ€๋กœ๋ฒŒ ๊ฒ€์ƒ‰ ํ™•์žฅ โ€” ๊ฒ€์ƒ‰ ๋Œ€์ƒ 20๊ฐœโ†’37๊ฐœ ๋ฉ”๋‰ด๋กœ ํ™•๋Œ€. ๋ชจ๋“  ์‚ฌ์ด๋“œ๋ฐ” ๋ฉ”๋‰ด ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ

๐Ÿ‘ฅ ๋ฉ€ํ‹ฐ์œ ์ € / ํŒ€ ๊ธฐ๋Šฅ (Group 5)

  • ๊ณ„์ • ๊ด€๋ฆฌ + RBAC โ€” app_user ์—”ํ‹ฐํ‹ฐ. ADMIN / REVIEWER / VIEWER ์—ญํ• . Spring Security Form ๋กœ๊ทธ์ธ(/login). ์ตœ์ดˆ ์‹คํ–‰ ์‹œ admin/admin1234 ์ž๋™ ์ƒ์„ฑ. sec:authorize๋กœ ์‚ฌ์ด๋“œ๋ฐ” ์—ญํ• ๋ณ„ ๋ฉ”๋‰ด ํ‘œ์‹œ
  • ํŒ€ ์„ค์ • ๊ณต์œ  โ€” shared_config ์—”ํ‹ฐํ‹ฐ. ํ”„๋กœ์ ํŠธ ์ปจํ…์ŠคํŠธยท๋ถ„์„ ํ…œํ”Œ๋ฆฟยท์ปค์Šคํ…€ ํ”„๋กฌํ”„ํŠธ ํŒ€ ๋‹จ์œ„ ๊ณต์œ . /settings/shared
  • ๋ถ„์„ ๊ฒฐ๊ณผ ๊ณต์œ  ๋งํฌ โ€” share_token ์—”ํ‹ฐํ‹ฐ. 7์ผ ๋งŒ๋ฃŒ ๋‹จ์ถ• URL. /share/{token} ๋กœ๊ทธ์ธ ๋ถˆํ•„์š” ๋…๋ฆฝ ๋ทฐ

๐Ÿš€ ์šด์˜ / ๋ฐฐํฌ (Group 6)

  • Docker ๋ฉ€ํ‹ฐ์Šคํ…Œ์ด์ง€ ๋นŒ๋“œ โ€” maven:3.8-openjdk-11-slim โ†’ eclipse-temurin:11-jre-alpine. docker-compose.yml ํฌํ•จ. HEALTHCHECK /actuator/health
  • ์™ธ๋ถ€ DB ์ง€์› โ€” application-h2.yml / application-mysql.yml / application-postgresql.yml. DB_TYPE ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ํ”„๋กœํŒŒ์ผ ์ž๋™ ์„ ํƒ. @Lob โ†’ @Column(columnDefinition="TEXT") ํ˜ธํ™˜์„ฑ ์ฒ˜๋ฆฌ
  • ์„ค์น˜ ๋งˆ๋ฒ•์‚ฌ /setup โ€” 4๋‹จ๊ณ„ ์œ„์ €๋“œ (APIํ‚ค ์ž…๋ ฅ+์ €์žฅ+ํ…Œ์ŠคํŠธ โ†’ DB ์„ค์ •+์ €์žฅ+ํ…Œ์ŠคํŠธ โ†’ ์ด๋ฉ”์ผ(์„ ํƒ) โ†’ ์™„๋ฃŒ). "๋‚˜์ค‘์— ์„ค์ •ํ•˜๊ธฐ" ์Šคํ‚ต ๋ฒ„ํŠผ. SetupInterceptor๋กœ ๋ฏธ์™„๋ฃŒ ์‹œ ์ž๋™ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
  • ํ—ฌ์Šค์ฒดํฌ ๊ฐ•ํ™” โ€” ClaudeApiHealthIndicator (API ping + ์‘๋‹ต์‹œ๊ฐ„) + OracleDbHealthIndicator (SELECT 1 FROM DUAL + ์‘๋‹ต์‹œ๊ฐ„). /actuator/health

๐Ÿ”’ ๊ฐ์‚ฌ ๋กœ๊ทธ ๊ฐ•ํ™”

  • ์‚ฌ์šฉ์ž ์ถ”์  โ€” ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋ช… ์ž๋™ ๊ธฐ๋ก (Spring Security ์—ฐ๋™)
  • ์•ก์…˜ ์œ ํ˜• ๋ถ„๋ฅ˜ โ€” endpoint/method ๊ธฐ๋ฐ˜ ์ž๋™ ๋ถ„๋ฅ˜ (์กฐํšŒยท๋ถ„์„์‹คํ–‰ยท๋‹ค์šด๋กœ๋“œยท์ด๋ฉ”์ผยท๋กœ๊ทธ์ธ ๋“ฑ)
  • ์‘๋‹ต ์‹œ๊ฐ„ ๊ธฐ๋ก โ€” ์š”์ฒญ ์ฒ˜๋ฆฌ ์†Œ์š”์‹œ๊ฐ„(ms) ๊ธฐ๋ก, 1์ดˆโ†‘ ๋…ธ๋ž‘ / 3์ดˆโ†‘ ๋นจ๊ฐ• ํ‘œ์‹œ
  • ํ•„ํ„ฐ๋ง โ€” ์‚ฌ์šฉ์žยท์•ก์…˜์œ ํ˜•ยท์—”๋“œํฌ์ธํŠธยท๋‚ ์งœ๋ฒ”์œ„(1h/์˜ค๋Š˜/7d/30d) ์‹ค์‹œ๊ฐ„ ํ•„ํ„ฐ
  • CSV ๋‚ด๋ณด๋‚ด๊ธฐ โ€” /security/audit-log/export (BOM ํฌํ•จ Excel ํ•œ๊ตญ์–ด ํ˜ธํ™˜)

โœ… v2.1.0

๐Ÿ”— ์™ธ๋ถ€ ์—ฐ๋™ (Group 7)

  • Slack / Teams ์›นํ›… ์•Œ๋ฆผ โ€” NotificationService. Settings์—์„œ URL ์ž…๋ ฅ + ํ…Œ์ŠคํŠธ ๋ฐœ์†ก. ~/.claude-toolkit/settings.json ์˜์†ํ™”
  • GitHub PR ์ž๋™ ์ฝ”๋ฉ˜ํŠธ โ€” /github-pr: PR URL โ†’ diff ๊ฐ€์ ธ์˜ค๊ธฐ โ†’ AI ๋ฆฌ๋ทฐ โ†’ PR ์ฝ”๋ฉ˜ํŠธ ์ž๋™ ๋“ฑ๋ก (GitHub REST API)
  • Jira ์—ฐ๋™ โ€” JiraService REST API v3. Settings์—์„œ URL/์ด๋ฉ”์ผ/APIํ† ํฐ/ํ”„๋กœ์ ํŠธํ‚ค ์„ค์ • + ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ
  • Git ๋กœ์ปฌ ์—ฐ๋™ โ€” /git-diff: ๋กœ์ปฌ ์ €์žฅ์†Œ ์ปค๋ฐ‹ ๋ชฉ๋ก โ†’ diff โ†’ AI ๋ฆฌ๋ทฐ (ProcessBuilder git ์‹คํ–‰)

๐Ÿ‘ค ๋ฉ€ํ‹ฐ์œ ์ € ๊ณ ๋„ํ™”

  • ์‚ฌ์šฉ์ž๋ณ„ ํ”„๋กœ๊ทธ๋žจ ๊ถŒํ•œ ๊ด€๋ฆฌ โ€” /admin/permissions: RBAC(์—ญํ• ) ์™ธ ๊ฐœ๋ณ„ ์‚ฌ์šฉ์ž ๋‹จ์œ„ 35๊ฐœ ๊ธฐ๋Šฅ ์ ‘๊ทผ ํ—ˆ์šฉ/์ฐจ๋‹จ. ์‚ฌ์ด๋“œ๋ฐ” + URL ์ ‘๊ทผ ์ œ์–ด ๋™๊ธฐํ™”
  • Docker Windows ๊ฒฝ๋กœ ์ž๋™ ๋ณ€ํ™˜ โ€” Settings์— D:\path ์ž…๋ ฅ โ†’ Docker์—์„œ /host/d/path๋กœ ์ž๋™ ๋ณ€ํ™˜. ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์ผ๊ด€์„ฑ

โœ… v2.2.0

๐Ÿ” ๊ณ„์ • ๋ฐ ์„ธ์…˜ ๊ด€๋ฆฌ

  • ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ UI โ€” /account/password: ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ + ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ. ์‚ฌ์ด๋“œ๋ฐ” ํ•˜๋‹จ ๐Ÿ”‘ ์•„์ด์ฝ˜
  • ๋‚ด ์„ค์ • ํŽ˜์ด์ง€ โ€” /account/settings: ๋‚ด ์ •๋ณด(์ด๋ฆ„/์ด๋ฉ”์ผ/ํ•ธ๋“œํฐ) ์ˆ˜์ • + ๊ฐœ์ธ API ํ‚ค ์ž…๋ ฅ/์‚ญ์ œ. ์‚ฌ์ด๋“œ๋ฐ” ํ•˜๋‹จ โš™ ์•„์ด์ฝ˜
  • ์„ธ์…˜ ํƒ€์ž„์•„์›ƒ 1์‹œ๊ฐ„ โ€” ๋ฏธํ™œ๋™ 1์‹œ๊ฐ„ ํ›„ ์ž๋™ ๋งŒ๋ฃŒ. ์‚ฌ์šฉ์ž ํ™œ๋™(ํด๋ฆญ/ํ‚ค ์ž…๋ ฅ) ์‹œ ์ž๋™ ๊ฐฑ์‹ . ์šฐ์ธก ์ƒ๋‹จ์— ๋ถ„:์ดˆ ์นด์šดํŠธ๋‹ค์šด + ๐Ÿ”„ ๊ฐฑ์‹  ๋ฒ„ํŠผ. 5๋ถ„โ†“๋…ธ๋ž‘, 1๋ถ„โ†“๋นจ๊ฐ• ๊ฒฝ๊ณ 
  • ์‚ฌ์šฉ์ž๋ณ„ API ํ‚ค โ€” ๊ฐœ์ธ Claude API ํ‚ค ์„ค์ •. ๋ถ„์„ ์‹คํ–‰ ์‹œ ๊ฐœ์ธ ํ‚ค ์ž๋™ ์ „ํ™˜ โ†’ ์š”์ฒญ ์™„๋ฃŒ ํ›„ ์„œ๋ฒ„ ํ‚ค ๋ณต์›. ๋น„์›Œ๋‘๋ฉด ์„œ๋ฒ„ ๊ณต์šฉ ํ‚ค ์‚ฌ์šฉ

โš™๏ธ Settings ๋ฐ ๋ณด์•ˆ ๊ฐ•ํ™”

  • ์ž…๋ ฅ๊ฐ’ ์œ ํšจ์„ฑ ๊ฒ€์ฆ โ€” DB URL jdbc: ํ˜•์‹ ์ฒดํฌ ๋“ฑ ๋ฐฑ์—”๋“œ ๊ฒ€์ฆ
  • API Rate Limiting โ€” ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ์—์„œ ์‚ฌ์šฉ์ž๋ณ„ ๋ถ„๋‹น/์‹œ๊ฐ„๋‹น ํ˜ธ์ถœ ์ œํ•œ ์„ค์ • (์ˆ˜์ • ๋ชจ๋‹ฌ). RateLimitService ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜ ์ถ”์ . ์ดˆ๊ณผ ์‹œ HTTP 429 ์‘๋‹ต
  • ๊ฐ์‚ฌ ๋กœ๊ทธ ํŽ˜์ด์ง€๋„ค์ด์…˜ โ€” 300๊ฑด ์ œํ•œ โ†’ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ 50๊ฑด/ํŽ˜์ด์ง€ + ํŽ˜์ด์ง€ ์ด๋™. ์‚ฌ์šฉ์ž/๊ธฐ๊ฐ„ ์„œ๋ฒ„ ํ•„ํ„ฐ + ์•ก์…˜/์—”๋“œํฌ์ธํŠธ ํด๋ผ์ด์–ธํŠธ ํ•„ํ„ฐ

๐Ÿ’พ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ

  • ๋ฐ์ดํ„ฐ ๋ฐฑ์—…/๋ณต์› โ€” /admin/backup: H2 DB + settings.json + security-settings.json์„ ZIP ๋‹ค์šด๋กœ๋“œ/์—…๋กœ๋“œ. ์‚ฌ์ด๋“œ๋ฐ” ๊ด€๋ฆฌ ์„น์…˜
  • ์ž๋™ ์Šคํ‚ค๋งˆ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ โ€” SchemaMigration: ์•ฑ ์‹œ์ž‘ ์‹œ ๋ˆ„๋ฝ ์ปฌ๋Ÿผ ์ž๋™ ์ถ”๊ฐ€ (DEFAULT ๊ฐ’ ํฌํ•จ). ๊ธฐ์กด Docker volume DB ํ˜ธํ™˜

โœ… v2.3.0

๐Ÿ  ๋Œ€์‹œ๋ณด๋“œ ๊ฐ•ํ™”

  • ์‹œ์Šคํ…œ ์ƒํƒœ ์œ„์ ฏ โ€” ์ด๋ฒˆ ๋‹ฌ ๋ถ„์„ ์š”์ฒญ/ํ† ํฐ ์‚ฌ์šฉ๋Ÿ‰, ์˜ค๋Š˜ API ํ˜ธ์ถœ, ๋“ฑ๋ก ์‚ฌ์šฉ์ž ์ˆ˜ ์š”์•ฝ ์นด๋“œ
  • ์—ฐ๊ฒฐ ์ƒํƒœ ํ‘œ์‹œ โ€” Claude API / Oracle DB / ์ด๋ฉ”์ผ ์—ฐ๊ฒฐ ์ƒํƒœ ์‹ค์‹œ๊ฐ„ ํ‘œ์‹œ
  • ๊ด€๋ฆฌ ๋„๊ตฌ ์„น์…˜ โ€” ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ(ADMIN), ๋ณด์•ˆ ์„ค์ •(ADMIN), ๋‚ด ์„ค์ •(์ „์ฒด) ์นด๋“œ

๐ŸŽจ ํ…Œ๋งˆ ํ”„๋ฆฌ์…‹

  • 5๊ฐ€์ง€ ์ƒ‰์ƒ ํ”„๋ฆฌ์…‹ โ€” Settings์—์„œ ์˜ค๋ Œ์ง€/๋ธ”๋ฃจ/๊ทธ๋ฆฐ/ํผํ”Œ/ํ•‘ํฌ ์›ํด๋ฆญ ์ „ํ™˜

๐Ÿ” 2FA ์ด์ค‘ ์ธ์ฆ

  • Google Authenticator ์—ฐ๋™ โ€” /account/settings์—์„œ QR์ฝ”๋“œ ์Šค์บ” โ†’ 6์ž๋ฆฌ ์ฝ”๋“œ ์ธ์ฆ โ†’ 2FA ํ™œ์„ฑํ™”
  • TOTP (RFC 6238) โ€” TotpService: Base32 ์‹œํฌ๋ฆฟ ์ƒ์„ฑ, HMAC-SHA1 ์ฝ”๋“œ ์ƒ์„ฑ, ยฑ30์ดˆ ํ—ˆ์šฉ
  • ์‚ฌ์šฉ์ž๋ณ„ ๋…๋ฆฝ ์„ค์ • โ€” ๊ฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ž์‹ ์˜ 2FA๋ฅผ ๊ฐœ๋ณ„ ๊ด€๋ฆฌ (ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™”)
  • ADMIN 2FA ๊ฐ•์ œ โ€” TwoFactorAuthHandler + TwoFactorInterceptor. ADMIN ๋กœ๊ทธ์ธ ์‹œ 2FA ๊ฒ€์ฆ ํ•„์ˆ˜. QR์ฝ”๋“œ qrcodejs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

โœ… v2.4.0

๐Ÿ”’ ๋ณด์•ˆ ๊ฐ•ํ™”

  • ๋ฏผ๊ฐ์ •๋ณด AES ์•”ํ˜ธํ™” โ€” settings.json์˜ APIํ‚ค/DB๋น„๋ฐ€๋ฒˆํ˜ธ/์ด๋ฉ”์ผ๋น„๋ฐ€๋ฒˆํ˜ธ/Jiraํ† ํฐ์„ AES-128-CBC๋กœ ์•”ํ˜ธํ™” ์ €์žฅ. ~/.claude-toolkit/.encryption-key ์ž๋™ ์ƒ์„ฑ. ๊ธฐ์กด ํ‰๋ฌธ ๋ฐ์ดํ„ฐ ์ž๋™ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
  • DB ๋ฏผ๊ฐํ•„๋“œ ์•”ํ˜ธํ™” โ€” AppUser.totpSecret, personalApiKey getter/setter์—์„œ ์ž๋™ AES ์•”ํ˜ธํ™”/๋ณตํ˜ธํ™”. ์ปฌ๋Ÿผ 200/64โ†’500์ž ํ™•์žฅ
  • ์ดˆ๊ธฐ admin ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฐ•์ œ ๋ณ€๊ฒฝ โ€” mustChangePassword ํ”Œ๋ž˜๊ทธ + PasswordChangeInterceptor. ์ฒซ ๋กœ๊ทธ์ธ ์‹œ /account/password๋กœ ๊ฐ•์ œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
  • ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฐ•ํ™” โ€” ์ตœ์†Œ 8์ž, ๋Œ€๋ฌธ์ž/์†Œ๋ฌธ์ž/์ˆซ์ž/ํŠน์ˆ˜๋ฌธ์ž ๊ฐ 1๊ฐœ ์ด์ƒ ํ•„์ˆ˜. ์ด์ „ ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์‚ฌ์šฉ ๋ฐฉ์ง€
  • ์„ธ์…˜ ๋ณด์•ˆ โ€” ์„ธ์…˜ ๊ณ ์ • ๊ณต๊ฒฉ ๋ฐฉ์ง€(sessionFixation().newSession()), ์ค‘๋ณต ๋กœ๊ทธ์ธ ์‹œ ๊ธฐ์กด ์„ธ์…˜ ํ•ด์ œ(maximumSessions=1)

๐Ÿ›ก๏ธ ์•ˆ์ •์„ฑ ๊ฐœ์„ 

  • Global Exception Handler โ€” @ControllerAdvice ํ†ตํ•ฉ ์—๋Ÿฌ ์ฒ˜๋ฆฌ. HTML ์š”์ฒญโ†’error.html ์—๋Ÿฌ ํŽ˜์ด์ง€(403/404/500), AJAXโ†’JSON ์—๋Ÿฌ ์‘๋‹ต. SLF4J ๋กœ๊น…
  • Logger ํ†ต์ผ โ€” 12๊ฐœ ํŒŒ์ผ System.err.println / System.out.println โ†’ SLF4J log.error() / log.info() ๊ต์ฒด
  • GitService ํƒ€์ž„์•„์›ƒ โ€” process.waitFor(30, SECONDS) + ์ดˆ๊ณผ ์‹œ destroyForcibly() ๊ฐ•์ œ ์ข…๋ฃŒ
  • ๋ฐฐ์น˜ ์—๋Ÿฌ ํ•ธ๋“ค๋ง โ€” ๊ฐœ๋ณ„ ํŒŒ์ผ ์‹คํŒจ ์‹œ ์Šคํ‚ต + ์„ฑ๊ณต/์‹คํŒจ ๊ฑด์ˆ˜ ์š”์•ฝ (successCount, failCount)
  • AuditLog ๊ฐœ์„  โ€” UserAgent 300โ†’500์ž ํ™•์žฅ. ๋ณด์•ˆ ์„ค์ • ํŽ˜์ด์ง€์— "90์ผ ์ด์ƒ ๋กœ๊ทธ ์ž๋™ ์‚ญ์ œ" ์•ˆ๋‚ด ๋ฌธ๊ตฌ ์ถ”๊ฐ€

๐ŸŽจ UI/UX ๋Œ€๊ทœ๋ชจ ๊ฐœ์„ 

  • ๊ธ€๋กœ๋ฒŒ ํ† ์ŠคํŠธ ์•Œ๋ฆผ โ€” alert() 141๊ฐœ ์ œ๊ฑฐ โ†’ ์šฐํ•˜๋‹จ ์Šคํƒํ˜• ํ† ์ŠคํŠธ (success/error/warning/info, ์ง„ํ–‰ ๋ฐ”, ์ž๋™ ์†Œ๋ฉธ 3์ดˆ, ์ตœ๋Œ€ 5๊ฐœ)
  • Breadcrumb ๋„ค๋น„๊ฒŒ์ด์…˜ โ€” URL ๊ฒฝ๋กœ ๊ธฐ๋ฐ˜ ์ž๋™ ์ƒ์„ฑ (ํ™ˆ > ๋ถ„์„ > ์‹คํ–‰๊ณ„ํš ๋น„๊ต). 40๊ฐœ+ ํ•œ๊ตญ์–ด ๊ฒฝ๋กœ ๋งคํ•‘
  • ํผ ์œ ํšจ์„ฑ ์‹œ๊ฐํ™” โ€” validateForm(formId, rules) ์œ ํ‹ธ๋ฆฌํ‹ฐ + .is-invalid ๋นจ๊ฐ„ ํ…Œ๋‘๋ฆฌ + .invalid-feedback ์—๋Ÿฌ ๋ฉ”์‹œ์ง€
  • ๋ฒ„ํŠผ ์Šคํƒ€์ผ ํ†ต์ผ โ€” .btn-danger-tk / .btn-success-tk / .btn-info-tk CSS ํด๋ž˜์Šค ์ถ”๊ฐ€
  • ๋ชจ๋ฐ”์ผ ๊ฒฐ๊ณผ ๋ฐ˜์‘ํ˜• โ€” ๊ฒฐ๊ณผ ์˜์—ญ max-height: 60vh, ์ŠคํŠธ๋ฆฌ๋ฐ 50vh (๊ธฐ์กด ๊ณ ์ • 400px/300px)
  • ๋‹คํฌ/๋ผ์ดํŠธ ๋ชจ๋“œ ์ •๋ฆฌ โ€” .text-success-tk / .text-danger-tk / .text-warning-tk ํ…Œ๋งˆ ์ธ์‹ ์œ ํ‹ธ ํด๋ž˜์Šค
  • ๊ฒฐ๊ณผ ์ „์ฒด ๋ณต์‚ฌ โ€” copyAllResults() ํ•จ์ˆ˜ + ํ† ์ŠคํŠธ ํ”ผ๋“œ๋ฐฑ
  • ์Šค์ผˆ๋ ˆํ†ค ๋กœ๋”ฉ UI โ€” showSkeleton() / hideSkeleton() + CSS ํŽ„์Šค ์• ๋‹ˆ๋ฉ”์ด์…˜ (.skeleton, .skeleton-line)
  • ์‚ฌ์ด๋“œ๋ฐ” ๊ธฐ๋Šฅ ๊ฒ€์ƒ‰ โ€” ๋ฉ”๋‰ด 30๊ฐœ+ ์‹ค์‹œ๊ฐ„ ํ•„ํ„ฐ๋ง ๊ฒ€์ƒ‰ ์ž…๋ ฅ๋ž€. ๋งค์นญ ์„น์…˜ ์ž๋™ ํŽผ์นจ

โšก ๊ธฐ๋Šฅ ๊ฐœ์„ 

  • CodeMirror ์—๋””ํ„ฐ โ€” initCodeEditor(textareaId, language) CDN ๋™์  ๋กœ๋“œ. Java/SQL/Python/JS/XML 5๊ฐœ ์–ธ์–ด ๋ชจ๋“œ. ๋ผ์ธ ๋ฒˆํ˜ธ, ๊ตฌ๋ฌธ ๊ฐ•์กฐ, ๊ด„ํ˜ธ ๋งค์นญ
  • PDF ๋ฆฌํฌํŠธ ๋‚ด๋ณด๋‚ด๊ธฐ โ€” exportPdf(elementId, title) ์ƒˆ ์ฐฝ ์ธ์‡„ ๊ธฐ๋ฐ˜. ๋ถ„์„ ๊ฒฐ๊ณผ ํ—ค๋”/ํ‘ธํ„ฐ ํฌํ•จ ์ธ์‡„ ๋ ˆ์ด์•„์›ƒ
  • ๋ถ„์„ ๊ฒฐ๊ณผ ๋Œ“๊ธ€ โ€” ReviewComment ์—”ํ‹ฐํ‹ฐ. ์ด๋ ฅ ์ƒ์„ธ์—์„œ ๋Œ“๊ธ€ ์ž‘์„ฑ/์‚ญ์ œ (๋ณธ์ธ ๋˜๋Š” ADMIN). AJAX ์‹ค์‹œ๊ฐ„ ๋ฐ˜์˜
  • ์•Œ๋ฆผ ์„ผํ„ฐ โ€” Notification ์—”ํ‹ฐํ‹ฐ. ๐Ÿ”” ๋ฒจ ์•„์ด์ฝ˜ + ๋ฏธ์ฝ์Œ ๋ฐฐ์ง€ + ๋“œ๋กญ๋‹ค์šด ๋ชฉ๋ก. 60์ดˆ ํด๋ง. ๋Œ“๊ธ€ ์ž‘์„ฑ ์‹œ ๋ถ„์„ ์ž‘์„ฑ์ž์—๊ฒŒ ์ž๋™ ์•Œ๋ฆผ
  • ๋ถ„์„ ๊ฒฐ๊ณผ ์บ์‹ฑ โ€” AnalysisCacheService SHA-256 ํ•ด์‹œ ๊ธฐ๋ฐ˜ LRU ์ธ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ (์ตœ๋Œ€ 200๊ฐœ, TTL 1์‹œ๊ฐ„). ์บ์‹œ ํžˆํŠธ ์‹œ "[์บ์‹œ ๊ฒฐ๊ณผ]" ๋ฐฐ์ง€ ํ‘œ์‹œ

๐Ÿ†• ์ƒˆ ๊ธฐ๋Šฅ

  • AI ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค โ€” /chat: ๋Œ€ํ™”ํ˜• AI ์งˆ์˜์‘๋‹ต. EventSource ๊ธฐ๋ฐ˜ SSE ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ (2๋‹จ๊ณ„: POST ๋ฉ”์‹œ์ง€ ์ €์žฅ โ†’ GET ์ŠคํŠธ๋ฆฌ๋ฐ). Thinking ์ธ๋””์ผ€์ดํ„ฐ(ํŽ„์Šค ์  + ๊ฒฝ๊ณผ ์‹œ๊ฐ„ ํ‘œ์‹œ). ์ŠคํŠธ๋ฆฌ๋ฐ ์ค‘ ์ปค์„œ ๊นœ๋นก์ž„ ํšจ๊ณผ. ํ•˜ํŠธ๋น„ํŠธ keep-alive (์œ ํœด ์—ฐ๊ฒฐ ๋Š๊น€ ๋ฐฉ์ง€). ๋งํ’์„ ๋ณ„ ๋ณต์‚ฌ ๋ฒ„ํŠผ (HTTP fallback ์ง€์›). ๋ถ„์„ ๊ฒฐ๊ณผ ์ปจํ…์ŠคํŠธ ์ฒจ๋ถ€. ์„ธ์…˜ ๊ธฐ๋ฐ˜ 20ํ„ด ํžˆ์Šคํ† ๋ฆฌ. PermissionInterceptor๋กœ ์‚ฌ์šฉ์ž ๊ถŒํ•œ ์ œ์–ด
  • ํŒ€ ๋Œ€์‹œ๋ณด๋“œ โ€” /admin/team-dashboard (ADMIN ์ „์šฉ): ์ผ๋ณ„ ๋ถ„์„ ํŠธ๋ Œ๋“œ ๋ผ์ธ ์ฐจํŠธ, ์‚ฌ์šฉ์ž๋ณ„ ๋ถ„์„ ๊ฑด์ˆ˜/ํ† ํฐ ๋ฐ” ์ฐจํŠธ, ๊ธฐ๋Šฅ๋ณ„ ์‚ฌ์šฉ ๋นˆ๋„ ๋„๋„› ์ฐจํŠธ (Chart.js 4.4.1). ๊ธฐ๊ฐ„ ์„ ํƒ๊ธฐ (7/30/90์ผ)
  • ๊ฐ์‚ฌ ๋กœ๊ทธ ์‹œ๊ฐํ™” โ€” /admin/audit-dashboard (ADMIN ์ „์šฉ): ์‹œ๊ฐ„๋Œ€๋ณ„ ์š”์ฒญ ๋ถ„ํฌ ๋ฐ” ์ฐจํŠธ, ์‚ฌ์šฉ์ž๋ณ„ ํ™œ๋™ Top 10, ์•ก์…˜ ์œ ํ˜• ํŒŒ์ด ์ฐจํŠธ, ์ผ๋ณ„ ์—๋Ÿฌ์œจ ์ถ”์ด. ๊ธฐ๊ฐ„ ์„ ํƒ๊ธฐ (์˜ค๋Š˜/7์ผ/30์ผ)
  • ๋ถ„์„ ๋น„์šฉ ์ถ”์  โ€” ๋ชจ๋ธ๋ณ„ ํ† ํฐ ๋‹จ๊ฐ€ ์ ์šฉ (์ž…๋ ฅ $3/1M, ์ถœ๋ ฅ $15/1M). ์ผ๋ณ„ ๋น„์šฉ ์ถ”์ด (/usage/daily-cost). ์‚ฌ์šฉ์ž๋ณ„ ๋น„์šฉ ๋ถ„๋ฐฐ (/usage/cost-by-user, ADMIN ์ „์šฉ). KRW ํ™˜์‚ฐ

โœ… v2.4.1 (ํ•ซํ”ฝ์Šค)

๐Ÿ”ง ๋ฒ„๊ทธ ์ˆ˜์ •

  • ๋กœ๊ทธ์ธ CSRF ์˜ค๋ฅ˜ ์ˆ˜์ • โ€” POST /login์ด CSRF ํ•„ํ„ฐ์—์„œ ์ฐจ๋‹จ๋˜์–ด 500 ์—๋Ÿฌ ๋ฐœ์ƒ. /login์„ CSRF ์˜ˆ์™ธ ๋ชฉ๋ก์— ์ถ”๊ฐ€
  • Jackson ๋ฒ„์ „ ๋ถˆ์ผ์น˜ ํ•ด๊ฒฐ โ€” jackson-databind 2.15.4๋งŒ ์„ ์–ธํ•˜๊ณ  jackson-core/jackson-annotations๋Š” Spring Boot BOM์˜ 2.13.x ์‚ฌ์šฉ โ†’ NoClassDefFoundError: StreamConstraintsException. 3๊ฐœ ๋ชจ๋“ˆ ๋ชจ๋‘ 2.15.4๋กœ ํ†ต์ผ
  • AuditLogFilter SSE ๋ฒ„ํผ๋ง ์ˆ˜์ • โ€” ContentCachingResponseWrapper๊ฐ€ /chat/stream์„ ๋ฒ„ํผ๋งํ•˜์—ฌ ์ŠคํŠธ๋ฆฌ๋ฐ ๋ถˆ๊ฐ€. shouldSkip() ํŒจํ„ด์„ "/stream/" โ†’ "/stream"์œผ๋กœ ๋ณ€๊ฒฝ
  • ChatController ์—๋Ÿฌ ํ•ธ๋“ค๋ง โ€” catch(Exception) โ†’ catch(Throwable)๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ NoClassDefFoundError ๋“ฑ Error๋„ ํฌ์ฐฉ. ์—๋Ÿฌ ์‹œ ๋นˆ ๋งํ’์„  ๋Œ€์‹  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ

๐Ÿ›ก๏ธ ์‚ฌ์šฉ์ž๋ณ„ ๊ถŒํ•œ ๊ด€๋ฆฌ ๋ณด์™„

  • ์‚ฌ์ด๋“œ๋ฐ” ๊ถŒํ•œ ์ฒดํฌ ๋ˆ„๋ฝ 11๊ฐœ ๋ฉ”๋‰ด ๋ณด์™„ โ€” depcheck, migrate, history, favorites, usage, roi-report, schedule, maskgen, github-pr, git-diff, prompts์— th:if ๊ถŒํ•œ ์ฒดํฌ ์ถ”๊ฐ€. ๊ถŒํ•œ ์—†๋Š” ๋ฉ”๋‰ด ํด๋ฆญ ์‹œ ๋กœ๊ทธ์•„์›ƒ๋˜๋Š” ๋ฌธ์ œ ํ•ด์†Œ
  • AI ์ฑ„ํŒ… ๊ถŒํ•œ ๊ด€๋ฆฌ ์ถ”๊ฐ€ โ€” AdminPermissionController FEATURES ๋ชฉ๋ก์— chat ํ•ญ๋ชฉ ์ถ”๊ฐ€. "์‚ฌ์šฉ์ž ๊ถŒํ•œ ๊ด€๋ฆฌ" ํŽ˜์ด์ง€์—์„œ AI ์ฑ„ํŒ… on/off ๊ฐ€๋Šฅ
  • /admin ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ โ€” /admin ์ ‘๊ทผ ์‹œ 404 ๋Œ€์‹  /admin/users๋กœ ์ž๋™ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ

๐Ÿ’ฌ AI ์ฑ„ํŒ… UX ๋Œ€ํญ ๊ฐœ์„ 

  • EventSource ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ ์ŠคํŠธ๋ฆฌ๋ฐ โ€” fetch + ReadableStream โ†’ EventSource(๋„ค์ดํ‹ฐ๋ธŒ SSE)๋กœ ์ „ํ™˜. ๊ธ€์ž ๋‹จ์œ„ ์‹ค์‹œ๊ฐ„ ํƒ€์ดํ•‘ ํšจ๊ณผ
  • 2๋‹จ๊ณ„ SSE ์•„ํ‚คํ…์ฒ˜ โ€” POST /chat/send(๋ฉ”์‹œ์ง€ ์ €์žฅ) โ†’ GET /chat/stream(EventSource ์ŠคํŠธ๋ฆฌ๋ฐ) ๋ถ„๋ฆฌ
  • ํ•˜ํŠธ๋น„ํŠธ keep-alive โ€” 3์ดˆ ๊ฐ„๊ฒฉ SSE ์ฝ”๋ฉ˜ํŠธ ์ „์†ก์œผ๋กœ Docker/ํ”„๋ก์‹œ ์œ ํœด ์—ฐ๊ฒฐ ๋Š๊น€ ๋ฐฉ์ง€
  • Thinking ์ธ๋””์ผ€์ดํ„ฐ โ€” ํŽ„์Šค ์• ๋‹ˆ๋ฉ”์ด์…˜ 3์  + ๊ฒฝ๊ณผ ์‹œ๊ฐ„ ์‹ค์‹œ๊ฐ„ ์นด์šดํŠธ ("์‘๋‹ต ์ƒ์„ฑ ์ค‘ ยท 5์ดˆ")
  • ์ŠคํŠธ๋ฆฌ๋ฐ ์ปค์„œ โ€” ์‘๋‹ต ์ƒ์„ฑ ์ค‘ ๋งํ’์„  ๋์— ์ฃผํ™ฉ์ƒ‰ ์ปค์„œ ๊นœ๋นก์ž„, ์™„๋ฃŒ ์‹œ ์ž๋™ ์ œ๊ฑฐ
  • ๋งํ’์„  ๋ณต์‚ฌ ๋ฒ„ํŠผ โ€” ํ˜ธ๋ฒ„ ์‹œ ํ‘œ์‹œ, ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€๋Š” ์ขŒ์ธก ํ•˜๋‹จยทAI ์‘๋‹ต์€ ์šฐ์ธก ํ•˜๋‹จ. HTTP ํ™˜๊ฒฝ execCommand fallback ํฌํ•จ. ๋ณต์‚ฌ ์‹œ โœ… ํ”ผ๋“œ๋ฐฑ

โœ… v2.5.0 โ€” ์•ˆ์ •์„ฑ ๋ฐ ํ•ต์‹ฌ ์ˆ˜์ •

๐Ÿ”ง ๋™์‹œ์„ฑ / ์•ˆ์ •์„ฑ

  • API ํ‚ค ๋™์‹œ์„ฑ ์ˆ˜์ • โ€” ClaudeClient์— InheritableThreadLocal ๊ธฐ๋ฐ˜ apiKeyOverride ์ถ”๊ฐ€. PermissionInterceptor๋Š” ๊ณต์œ  ClaudeProperties.setApiKey() ๋Œ€์‹  claudeClient.setApiKeyOverride() ํ˜ธ์ถœ. SSE ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ๋„ ๋ถ€๋ชจ ์Šค๋ ˆ๋“œ์˜ ํ‚ค ์ƒ์†. ๋ฉ€ํ‹ฐ์œ ์ € ๋™์‹œ ์š”์ฒญ ์™„์ „ ๊ฒฉ๋ฆฌ
  • ์ฑ„ํŒ… ์„ธ์…˜ ๋™์‹œ์„ฑ ์ˆ˜์ • โ€” ์‹ ๊ทœ ChatHistoryStore ์ปดํฌ๋„ŒํŠธ (ConcurrentHashMap ๊ธฐ๋ฐ˜). HttpSession ์ง์ ‘ ์“ฐ๊ธฐ ์ œ๊ฑฐ. ์„ธ์…˜ ID๋ฅผ ์กฐํšŒ ํ‚ค๋กœ๋งŒ ์‚ฌ์šฉ. 24์‹œ๊ฐ„ TTL ์ž๋™ ์ •๋ฆฌ (KST ์ƒˆ๋ฒฝ 4์‹œ)
  • ์‚ฌ์ด๋“œ๋ฐ” ๋นˆ ์„น์…˜ ์ž๋™ ์ˆจ๊น€ โ€” fragments/sidebar.html์˜ ๋ถ„์„/์ƒ์„ฑ/๊ธฐ๋ก/๋„๊ตฌ 4๊ฐœ ์„น์…˜์„ Thymeleaf <div th:if="..."> ๋ž˜ํผ๋กœ ๊ฐ์‹ธ ํ•ด๋‹น ์„น์…˜ ๋‚ด ํ—ˆ์šฉ๋œ ๋ฉ”๋‰ด๊ฐ€ ํ•˜๋‚˜๋„ ์—†์œผ๋ฉด ์„น์…˜ ํ—ค๋” ์ž์ฒด๋ฅผ ์ˆจ๊น€
  • CSRF ํ† ํฐ ๋งŒ๋ฃŒ UX โ€” login.html์— ?denied=true / ?expired=true ๊ฐ์ง€ โ†’ "์„ธ์…˜์ด ๋งŒ๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค" ์•ˆ๋‚ด ํ‘œ์‹œ. 15๋ถ„ ํ›„ ์ž…๋ ฅ ํ•„๋“œ ๋น„์–ด์žˆ์œผ๋ฉด ์ž๋™ ์ƒˆ๋กœ๊ณ ์นจ์œผ๋กœ ํ† ํฐ ์žฌ๋ฐœ๊ธ‰

โšก ์„ฑ๋Šฅ

  • AI ์ฑ„ํŒ… ๋ฉ€ํ‹ฐํ„ด ์ตœ์ ํ™” โ€” ClaudeClient์— chatStream(systemPrompt, List<ClaudeMessage>, ...) ์˜ค๋ฒ„๋กœ๋“œ ์ถ”๊ฐ€. ChatController๊ฐ€ ํ…์ŠคํŠธ concatenation([์ด์ „ ๋Œ€ํ™”]\n[user]: ...) ์ œ๊ฑฐํ•˜๊ณ  messages ๋ฐฐ์—ด์„ Claude Messages API์— ์ง์ ‘ ์ „๋‹ฌ. ํ† ํฐ ์ ˆ๊ฐ + prompt caching ํ™œ์šฉ ๊ฐ€๋Šฅ

โœ… v2.6.0 โ€” ๋ณด์•ˆ ๊ฐ•ํ™”

๐Ÿ” ์ธ์ฆ / ์ ‘๊ทผ ์ œ์–ด

  • ๋กœ๊ทธ์ธ ์‹คํŒจ ์ž ๊ธˆ โ€” AppUser์— failedLoginAttempts, lockedUntil ํ•„๋“œ ์ถ”๊ฐ€. LoginAttemptHandler (AuthenticationFailureHandler) ์‹ ๊ทœ ์ถ”๊ฐ€ โ€” 5ํšŒ ์—ฐ์† ์‹คํŒจ ์‹œ 10๋ถ„ ์ž ๊ธˆ + ๊ฐ์‚ฌ ๋กœ๊ทธ ๊ธฐ๋ก. AppUserDetailsService์—์„œ LockedException ๋ฐœ์ƒ. ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ TwoFactorAuthHandler์—์„œ ์นด์šดํ„ฐ ์ž๋™ ๋ฆฌ์…‹. ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ ํŽ˜์ด์ง€์—์„œ ADMIN ์ˆ˜๋™ ํ•ด์ œ ๋ฒ„ํŠผ ์ œ๊ณต
  • ๋น„๋ฐ€๋ฒˆํ˜ธ ๋งŒ๋ฃŒ ์•Œ๋ฆผ โ€” lastPasswordChangeAt, passwordSnoozeAt ํ•„๋“œ ์ถ”๊ฐ€. PasswordExpiryInterceptor ์‹ ๊ทœ ์ถ”๊ฐ€ โ€” 90์ผ ๊ฒฝ๊ณผ ์‹œ ๋ณ€๊ฒฝ ๊ถŒ๊ณ  ํŽ˜์ด์ง€ ํ‘œ์‹œ. "๋‹ค์Œ์— ๋ณ€๊ฒฝํ•˜๊ธฐ" ๋ฒ„ํŠผ(POST /account/snooze-password) ํด๋ฆญ ์‹œ passwordSnoozeAt = now() โ†’ 1์ผ๋ถ€ํ„ฐ ์žฌ์นด์šดํŒ…. ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ์‹œ lastPasswordChangeAt ๊ฐฑ์‹  + ์Šค๋ˆ„์ฆˆ ์ดˆ๊ธฐํ™”
  • IP ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ (์‚ฌ์šฉ์ž๋ณ„) โ€” AppUser.ipWhitelist ํ•„๋“œ ์ถ”๊ฐ€. IpWhitelistChecker ์œ ํ‹ธ๋ฆฌํ‹ฐ (IPv4 + CIDR, ์ˆœ์ˆ˜ Java ๋น„ํŠธ ์—ฐ์‚ฐ). "์‚ฌ์šฉ์ž ๊ด€๋ฆฌ" ํŽ˜์ด์ง€์— ๋ณ„๋„ ํŒ์—… ๋ชจ๋‹ฌ โ€” ๋“ฑ๋ก/์ถ”๊ฐ€/์‚ญ์ œ/์ €์žฅ. AppUserDetailsService.loadUserByUsername()์—์„œ RequestContextHolder๋กœ ํด๋ผ์ด์–ธํŠธ IP ์ถ”์ถœ ํ›„ ๊ฒ€์ฆ. ์ดˆ๊ธฐ๊ฐ’ ๋ฌด์ œํ•œ, ์„ค์ • ์‹œ ํ•ด๋‹น ์‚ฌ์šฉ์ž๋Š” ํ—ˆ์šฉ๋œ IP์—์„œ๋งŒ ๋กœ๊ทธ์ธ ๊ฐ€๋Šฅ
  • API ํ‚ค ์‚ฌ์šฉ๋Ÿ‰ ์ œํ•œ (์ผ์ผ/์›”๊ฐ„) โ€” AppUser.dailyApiLimit, monthlyApiLimit ํ•„๋“œ ์ถ”๊ฐ€. RateLimitService ํ™•์žฅ โ€” ์ผ์ž๋ณ„ ์นด์šดํŠธ ๋งต(Map<LocalDate, AtomicInteger>) ๊ธฐ๋ฐ˜ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์  ์ถ”์ . 32์ผ ์ด์ „ ์นด์šดํŠธ ์ž๋™ ์ •๋ฆฌ(@Scheduled). getUsageStats() API๋กœ ์˜ค๋Š˜/์ด๋ฒˆ ๋‹ฌ ์‚ฌ์šฉ๋Ÿ‰ ์กฐํšŒ. ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ ๋ชจ๋‹ฌ์— ํ•œ๋„ ์ž…๋ ฅ + ํ˜„์žฌ ์‚ฌ์šฉ๋Ÿ‰ ํ‘œ์‹œ

โœ… v2.7.0 โ€” ์ฑ„ํŒ… ๊ณ ๋„ํ™” ๋ฐ ์„ฑ๋Šฅ

๐Ÿ’ฌ AI ์ฑ„ํŒ…

  • AI ์ฑ„ํŒ… Markdown ๋ Œ๋”๋ง โ€” marked.js + DOMPurify + Prism.js๋กœ ์ฝ”๋“œ ๋ธ”๋ก/๋ณผ๋“œ/๋ฆฌ์ŠคํŠธ/ํ…Œ์ด๋ธ”/์ธ์šฉ/ํ‘œ ๋ Œ๋”๋ง. ์ŠคํŠธ๋ฆฌ๋ฐ ์ค‘์—๋Š” ํ‰๋ฌธ + ์ปค์„œ, ์™„๋ฃŒ ์‹œ Markdown ์žฌ๋ Œ๋”๋ง. XSS ๋ฐฉ์ง€ (DOMPurify)
  • ๋Œ€ํ™” ๋‚ด๋ณด๋‚ด๊ธฐ โ€” ํ—ค๋”์— "๐Ÿ“ฅ ๋‚ด๋ณด๋‚ด๊ธฐ" ๋ฒ„ํŠผ. ํ˜„์žฌ ์„ธ์…˜์˜ ์ „์ฒด ๋Œ€ํ™”๋ฅผ .md ํŒŒ์ผ๋กœ ๋‹ค์šด๋กœ๋“œ. ํŒŒ์ผ๋ช…: chat_YYYYMMDD_HHmmss.md
  • ๋Œ€ํ™” ๋ชฉ๋ก/์„ธ์…˜ ๊ด€๋ฆฌ โ€” ChatSession / ChatMessage H2 ์—”ํ‹ฐํ‹ฐ ์˜์†ํ™”. ์ขŒ์ธก 240px ํŒจ๋„์— ๋Œ€ํ™” ๋ชฉ๋ก ํ‘œ์‹œ, + ์ƒˆ ๋Œ€ํ™”, ํ˜ธ๋ฒ„ ์‹œ ์ด๋ฆ„ ๋ณ€๊ฒฝ/์‚ญ์ œ ๋ฒ„ํŠผ. ์‚ฌ์šฉ์ž๋ณ„ ๋‹ค์ค‘ ์„ธ์…˜ ์ง€์›. ์ฒซ ๋ฉ”์‹œ์ง€๋กœ ์ œ๋ชฉ ์ž๋™ ์ƒ์„ฑ. ์„ธ์…˜ ์†Œ์œ ๊ถŒ ๊ฒ€์ฆ

โšก ์„ฑ๋Šฅ

  • ์ •์  ๋ฆฌ์†Œ์Šค ๋กœ์ปฌ ๋ฒˆ๋“ค๋ง โ€” WebJars ๊ธฐ๋ฐ˜ Maven ์˜์กด์„ฑ ์ถ”๊ฐ€: bootstrap 5.3.2, font-awesome 6.5.1, prism 1.29.0, marked 9.1.6, chart.js 4.4.1, dompurify 3.0.8. 60๊ฐœ ํ…œํ”Œ๋ฆฟ์—์„œ 206๊ฑด CDN URL์„ /webjars/**๋กœ ์ผ๊ด„ ๊ต์ฒด. WebJarsConfig๋กœ 1๋…„ ์บ์‹œ ํ—ค๋” ์„ค์ •. ์˜คํ”„๋ผ์ธ/ํ์‡„๋ง ์™„์ „ ์ง€์› (Mermaid, QRCode๋งŒ CDN ์œ ์ง€)
  • ๋ถ„์„ ์บ์‹œ DB ์˜์†ํ™” โ€” AnalysisCache ์—”ํ‹ฐํ‹ฐ + analysis_cache H2 ํ…Œ์ด๋ธ”. AnalysisCacheService ์žฌ์ž‘์„ฑ: findByCacheKey ์กฐํšŒ โ†’ TTL ์ฒดํฌ โ†’ hitCount ์ฆ๊ฐ€. put()์€ upsert. @Scheduled ๋งค ์‹œ๊ฐ„ ๋งŒ๋ฃŒ ์บ์‹œ ์ž๋™ ์‚ญ์ œ. SseStreamController ํ˜ธ์ถœ ์ธํ„ฐํŽ˜์ด์Šค(get/put) ์œ ์ง€

๐Ÿ”ง ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ ๊ฐœ์„ 

  • ChatHistoryStore ์ œ๊ฑฐ (v2.5.0์—์„œ ์ถ”๊ฐ€ํ–ˆ๋˜ ์ž„์‹œ ConcurrentHashMap ๊ธฐ๋ฐ˜ โ†’ v2.7.0 DB ์˜์†ํ™”๋กœ ๋Œ€์ฒด)
  • ChatController ์ „๋ฉด ๋ฆฌํŒฉํ„ฐ๋ง: ์„ธ์…˜ CRUD ์—”๋“œํฌ์ธํŠธ 6๊ฐœ ์‹ ๊ทœ (/chat/sessions, /chat/sessions/new, /chat/sessions/{id}/rename|delete|clear|messages). /chat/send๋Š” sessionId ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ›๊ณ , ์—†์œผ๋ฉด ์ž๋™ ์ƒ์„ฑ

โœ… v2.8.0 โ€” ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ UX

๐Ÿ“Š ๋ชจ๋‹ˆํ„ฐ๋ง

  • SSE ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ โ€” 60์ดˆ ํด๋ง โ†’ Server-Sent Events ์ฆ‰์‹œ ์•Œ๋ฆผ. NotificationPublisher ์ปดํฌ๋„ŒํŠธ(ConcurrentHashMap ๊ธฐ๋ฐ˜ ๊ตฌ๋…์ž ๊ด€๋ฆฌ) + /notifications/stream SSE ์—”๋“œํฌ์ธํŠธ. ์•Œ๋ฆผ ์ƒ์„ฑ ์‹œ publisher.publish() ํ˜ธ์ถœ โ†’ DB ์ €์žฅ + ๊ตฌ๋…์ž์—๊ฒŒ ์ฆ‰์‹œ push. ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ 60์ดˆ ํด๋ง ์ž๋™ fallback + 30์ดˆ ํ›„ ์žฌ์—ฐ๊ฒฐ ์‹œ๋„. ํ† ์ŠคํŠธ ์•Œ๋ฆผ์œผ๋กœ ์ฆ‰๊ฐ ํ”ผ๋“œ๋ฐฑ
  • ๊ฐ์‚ฌ ๋กœ๊ทธ ๊ธฐ๋Šฅ ๋ฉ”๋‰ด ํ•„ํ„ฐ โ€” menuName ๊ธฐ๋ฐ˜ ๋“œ๋กญ๋‹ค์šด ํ•„ํ„ฐ ์ถ”๊ฐ€ (38๊ฐœ ๊ธฐ๋Šฅ ๋ฉ”๋‰ด). ํŠน์ • ๊ธฐ๋Šฅ๋ณ„ ๊ฐ์‚ฌ ๋กœ๊ทธ ์กฐํšŒ ๊ฐ€๋Šฅ. ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์‹ค์‹œ๊ฐ„ ํ•„ํ„ฐ๋ง
  • ์‹œ์Šคํ…œ ํ—ฌ์Šค ๋Œ€์‹œ๋ณด๋“œ โ€” /admin/health ํŽ˜์ด์ง€ + SystemHealthController. JVM ํž™ ๋ฉ”๋ชจ๋ฆฌ/์‚ฌ์šฉ๋ฅ  ๊ฒŒ์ด์ง€, ์—…ํƒ€์ž„, ์Šค๋ ˆ๋“œ ์ˆ˜, Java/OS ๋ฒ„์ „, H2 DB ํŒŒ์ผ ํฌ๊ธฐ, ๋””์Šคํฌ ์—ฌ์œ  ๊ณต๊ฐ„, Claude API ์ƒํƒœ, ๋“ฑ๋ก ์‚ฌ์šฉ์ž ์ˆ˜. Bootstrap 2์—ด ์นด๋“œ ๋ ˆ์ด์•„์›ƒ, 30์ดˆ ์ž๋™ ๊ฐฑ์‹ , /admin/health/data REST API

๐ŸŽจ UX

  • ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค ๊ฐ€์ด๋“œ โ€” ? ํ‚ค๋กœ ๋ชจ๋‹ฌ ํ‘œ์‹œ/ํ† ๊ธ€ (input/textarea ํฌ์ปค์Šค ์‹œ ์ œ์™ธ). ๋‹จ์ถ•ํ‚ค ๋ชฉ๋ก(?, Esc, Ctrl+Enter, โŒ˜+Enter, /, Shift+Enter, Enter) + <kbd> ์Šคํƒ€์ผ๋ง. Esc ๋˜๋Š” ๋ฐ”๊นฅ ํด๋ฆญ์œผ๋กœ ๋‹ซ๊ธฐ
  • ๋ชจ๋ฐ”์ผ ํ•˜๋‹จ ๋„ค๋น„๊ฒŒ์ด์…˜ โ€” 768px ์ดํ•˜์—์„œ ์ž๋™ ํ™œ์„ฑํ™”๋˜๋Š” ํ•˜๋‹จ ๊ณ ์ • ํƒญ ๋ฐ”. 5๊ฐœ ํ•ญ๋ชฉ(ํ™ˆ/์ฑ„ํŒ…/๊ฒ€์ƒ‰/์ด๋ ฅ/๋ฉ”๋‰ด). ํ™œ์„ฑ ์ƒํƒœ ํ•˜์ด๋ผ์ดํŠธ, ์‚ฌ์ด๋“œ๋ฐ” ์—ด๊ธฐ ๋ฒ„ํŠผ ํ†ตํ•ฉ. ๋ฐ˜์‘ํ˜• CSS ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ

โœ… v3.0.0 โ€” ํŒŒ์ดํ”„๋ผ์ธ ๊ณ ๋„ํ™” (์Šค์ผ€์ค„๋ง, Monaco Editor, ํ”Œ๋กœ์šฐ์ฐจํŠธ, ๋ณ‘๋ ฌ ์‹คํ–‰)

โฐ ํŒŒ์ดํ”„๋ผ์ธ ์Šค์ผ€์ค„๋ง (cron)

  • PipelineDefinition์— scheduleCron, scheduleInput, scheduleEnabled ํ•„๋“œ ์ถ”๊ฐ€
  • PipelineScheduler โ€” @Scheduled(fixedRate=60s) ๋งค๋ถ„ cron ๋งค์นญ ํŒŒ์ดํ”„๋ผ์ธ ์ž๋™ ์‹คํ–‰
  • POST /pipelines/{id}/schedule โ€” ์Šค์ผ€์ค„ ์„ค์ • API (cron ์‚ฌ์ „ ๊ฒ€์ฆ)
  • Spring 6-ํ•„๋“œ CronExpression ๊ธฐ๋ฐ˜ ํ‘œํ˜„์‹ ํŒŒ์‹ฑ (์ดˆ ๋ถ„ ์‹œ ์ผ ์›” ์š”์ผ)

๐Ÿ’ป Monaco Editor ํ†ตํ•ฉ

  • ํŒŒ์ดํ”„๋ผ์ธ YAML ํŽธ์ง‘๊ธฐ์— Monaco Editor (jsDelivr CDN, v0.45.0) ์ ์šฉ
  • YAML ๋ฌธ๋ฒ• ๊ฐ•์กฐ, ๋ผ์ธ ๋ฒˆํ˜ธ, ์›Œ๋“œ ๋žฉ, ํƒญ ์‚ฌ์ด์ฆˆ 2, ์ž๋™ ๋ ˆ์ด์•„์›ƒ
  • ๋‹คํฌ/๋ผ์ดํŠธ ํ…Œ๋งˆ ์ž๋™ ๊ฐ์ง€ (vs-dark / vs)
  • ๋‚ด์žฅ ํŒŒ์ดํ”„๋ผ์ธ์€ readOnly ๋ชจ๋“œ
  • Monaco โ†” textarea ์‹ค์‹œ๊ฐ„ ๋™๊ธฐํ™” (Monaco ๋กœ๋“œ ์‹คํŒจ ์‹œ textarea fallback)

๐Ÿ“Š ์‹œ๊ฐ์  ํ”Œ๋กœ์šฐ์ฐจํŠธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ

  • ํŽธ์ง‘๊ธฐ ์šฐ์ธก์— Mermaid.js ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ ํ”Œ๋กœ์šฐ์ฐจํŠธ ํ‘œ์‹œ
  • YAML โ†’ Mermaid graph LR ์ž๋™ ๋ณ€ํ™˜ (๋‹จ๊ณ„ ID, ๋ถ„์„ ์œ ํ˜•, ์กฐ๊ฑด ๋ถ„๊ธฐ ์‹œ๊ฐํ™”)
  • "๊ฐฑ์‹ " ๋ฒ„ํŠผ + 3์ดˆ ๊ฐ„๊ฒฉ ์ž๋™ ๊ฐฑ์‹ 
  • ์กฐ๊ฑด๋ถ€ ๋‹จ๊ณ„๋Š” ๋งˆ๋ฆ„๋ชจ ๋…ธ๋“œ {}, ์ผ๋ฐ˜ ๋‹จ๊ณ„๋Š” ์‚ฌ๊ฐํ˜• []

โšก ๋ณ‘๋ ฌ ๋‹จ๊ณ„ ์‹คํ–‰

  • YAML์— parallel: true / dependsOn: "stepId1,stepId2" ํ•„๋“œ ์ง€์›
  • PipelineExecutor์—์„œ parallel: true ๋‹จ๊ณ„๋Š” ๋ณ„๋„ daemon ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ ์‹คํ–‰
  • dependsOn ๋Œ€๊ธฐ โ€” ์ง€์ •๋œ ๋‹จ๊ณ„๋“ค์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ 500ms ๊ฐ„๊ฒฉ ํด๋ง (์ตœ๋Œ€ 10๋ถ„)
  • completedStepIds (ConcurrentSet) ๊ธฐ๋ฐ˜ ๋™๊ธฐํ™”
  • executeSingleStep() ํ—ฌํผ ๋ฉ”์„œ๋“œ ์ถ”์ถœ โ€” ์ˆœ์ฐจ/๋ณ‘๋ ฌ ๋ชจ๋‘ ๋™์ผ ๋กœ์ง ์žฌ์‚ฌ์šฉ

โœ… v2.9.5 โ€” ๋ถ„์„ ํŒŒ์ดํ”„๋ผ์ธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ + DB ์ž๋™ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

๐Ÿ”— ๋ถ„์„ ํŒŒ์ดํ”„๋ผ์ธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ

  • YAML ๊ธฐ๋ฐ˜ ํŒŒ์ดํ”„๋ผ์ธ ์ •์˜ โ€” PipelineDefinition ์—”ํ‹ฐํ‹ฐ, SnakeYAML ํŒŒ์„œ, SpEL ์กฐ๊ฑด์‹ ํ‰๊ฐ€๊ธฐ
  • 4๊ฐœ ๋‚ด์žฅ ํŒŒ์ดํ”„๋ผ์ธ โ€” SQL ์ตœ์ ํ™” ํ’€ ์Šคํƒ / Java ํ’ˆ์งˆ ํ’€ ์ฒดํฌ / ๋ฌธ์„œํ™” ํŒจํ‚ค์ง€ / ๋ณด์•ˆ ๊ฐ์‚ฌ ํ’€ ํ”Œ๋กœ์šฐ (์•ฑ ์‹œ์ž‘ ์‹œ ์ž๋™ ๋“ฑ๋ก)
  • ์ˆœ์ฐจ ์‹คํ–‰ ์—”์ง„ โ€” PipelineExecutor๊ฐ€ ๋‹จ๊ณ„๋ณ„ ์กฐ๊ฑด๋ถ€ ์‹คํ–‰, ๋ณ€์ˆ˜ ์น˜ํ™˜(${stepId.output}), ๊ฐ ๋‹จ๊ณ„ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์Œ ๋‹จ๊ณ„ ์ปจํ…์ŠคํŠธ๋กœ ์ž๋™ ์ „๋‹ฌ
  • ์‹ค์‹œ๊ฐ„ SSE ์ง„ํ–‰ ์ƒํ™ฉ โ€” PipelineStreamBroker๋กœ ๊ฐ ๋‹จ๊ณ„ ์ฒญํฌ/์ƒํƒœ/์™„๋ฃŒ ์ด๋ฒคํŠธ ์‹ค์‹œ๊ฐ„ push, ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ 3์ดˆ ํด๋ง fallback
  • ์‹คํ–‰ ์ด๋ ฅ ๊ด€๋ฆฌ โ€” PipelineExecution + PipelineStepResult๋กœ ๊ฐ ์‹คํ–‰์˜ ๋ชจ๋“  ๋‹จ๊ณ„ ๊ฒฐ๊ณผ ์˜์†ํ™”, ์žฌ์กฐํšŒ ๊ฐ€๋Šฅ
  • ํŒŒ์ดํ”„๋ผ์ธ CRUD UI โ€” ๋ชฉ๋ก/ํŽธ์ง‘๊ธฐ/์‹คํ–‰ ์ƒ์„ธ ํŽ˜์ด์ง€ 3๊ฐœ. YAML textarea ํŽธ์ง‘๊ธฐ + ๋ถ„์„ ์œ ํ˜•/๋ณ€์ˆ˜ ๋„์›€๋ง ํŒจ๋„ + ๊ฒ€์ฆ ๋ฒ„ํŠผ
  • ์‚ฌ์šฉ์ž ๊ถŒํ•œ ๊ด€๋ฆฌ ํ†ตํ•ฉ โ€” pipelines feature key ์ถ”๊ฐ€ (PermissionInterceptor, AdminPermissionController, AuditLog, ๊ฐ์‚ฌ ๋กœ๊ทธ ํ•„ํ„ฐ)

๐Ÿš€ DB ์ž๋™ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

  • ์›ํด๋ฆญ H2 โ†’ PostgreSQL/MySQL/Oracle ์ด๊ด€ โ€” /admin/db-migration 5๋ฒˆ์งธ ํƒญ "๐Ÿš€ ์ž๋™ ์ด๊ด€"
  • DbMigrationExecutor โ€” JDBC Batch (500๊ฑด/๋ฐฐ์น˜) ๊ธฐ๋ฐ˜ ํ…Œ์ด๋ธ” ๋ณต์‚ฌ, ์™ธ๋ž˜ํ‚ค ์˜์กด์„ฑ ์ˆœ์„œ ์ค€์ˆ˜ (17๊ฐœ ํ…Œ์ด๋ธ”)
  • ์•ˆ์ „ ์žฅ์น˜ โ€” ํƒ€๊ฒŸ DB ์Šคํ‚ค๋งˆ ์กด์žฌ ์ฒดํฌ, ๋น„์–ด์žˆ์Œ ํ™•์ธ(๋˜๋Š” overwrite ์˜ต์…˜), ์ด๊ด€ ํ›„ ๋ ˆ์ฝ”๋“œ ์ˆ˜ ๊ฒ€์ฆ
  • ์ž„์‹œ ํƒ€๊ฒŸ DataSource โ€” DriverManagerDataSource๋กœ ์•ฑ ์žฌ๊ธฐ๋™ ์—†์ด ์ฆ‰์‹œ ์—ฐ๊ฒฐ
  • ์‹ค์‹œ๊ฐ„ SSE ์ง„ํ–‰๋ฅ  โ€” DbMigrationStreamBroker๋กœ ํ…Œ์ด๋ธ”๋ณ„ ์ง„ํ–‰๋ฅ , ํ–‰ ์ˆ˜, ์„ฑ๊ณต/์‹คํŒจ ์ด๋ฒคํŠธ ์‹ค์‹œ๊ฐ„ ํ‘œ์‹œ
  • ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ โ€” ์‹œ์ž‘ ์ „ ํƒ€๊ฒŸ DB ์—ฐ๊ฒฐ ๊ฒ€์ฆ (์ œํ’ˆ/๋ฒ„์ „ ์กฐํšŒ)
  • ์ด๊ด€ ์ด๋ ฅ โ€” DbMigrationJob ์—”ํ‹ฐํ‹ฐ๋กœ ๋ชจ๋“  ์ด๊ด€ ์ž‘์—… ์ด๋ ฅ ์˜์†ํ™”

โœ… v2.9.0 โ€” ํ˜‘์—… ๋ฐ ์•„ํ‚คํ…์ฒ˜

๐Ÿ’ฌ ์ฑ„ํŒ… ํ™•์žฅ

  • ๋ถ„์„ ๊ฒฐ๊ณผ โ†’ ์ฑ„ํŒ… ์—ฐ๊ณ„ โ€” toolkit.js์— askAboutResult() ์œ ํ‹ธ ํ•จ์ˆ˜ + DOMContentLoaded ์ž๋™ ์ฃผ์ž…. ๋ชจ๋“  ๋ถ„์„ ๊ฒฐ๊ณผ ํŽ˜์ด์ง€(#resultMd, #streamResult ๋“ฑ)์— "๐Ÿ’ฌ ์ด ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด AI์—๊ฒŒ ์งˆ๋ฌธํ•˜๊ธฐ" ํ”Œ๋กœํŒ… ๋ฒ„ํŠผ ์ž๋™ ํ‘œ์‹œ. ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๊ฒฐ๊ณผ ํ…์ŠคํŠธ(์ตœ๋Œ€ 3000์ž)๋ฅผ ์ปจํ…์ŠคํŠธ๋กœ /chat?context=... ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ. ํ…œํ”Œ๋ฆฟ ์ˆ˜์ • 0๊ฑด (๋‹จ์ผ JS ์ฃผ์ž… ๋ฐฉ์‹)

๐Ÿ†• ์‹ ๊ทœ ๊ธฐ๋Šฅ

  • ํŒ€ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์›Œํฌํ”Œ๋กœ์šฐ โ€” ReviewRequest ์—”ํ‹ฐํ‹ฐ + review_request H2 ํ…Œ์ด๋ธ”. ์ž‘์„ฑ์ž โ†’ REVIEWER ์Šน์ธ ์š”์ฒญ โ†’ ์Šน์ธ/๋ฐ˜๋ ค โ†’ ์‹ค์‹œ๊ฐ„ SSE ์•Œ๋ฆผ(NotificationPublisher ์žฌ์‚ฌ์šฉ)
    • ์—”๋“œํฌ์ธํŠธ: GET /review-requests (๋ชฉ๋ก), GET /review-requests/{id} (์ƒ์„ธ), POST /review-requests (์ƒ์„ฑ), POST /review-requests/{id}/approve (์Šน์ธ), POST /review-requests/{id}/reject (๋ฐ˜๋ ค), POST /review-requests/{id}/delete (์ทจ์†Œ), GET /review-requests/reviewers (๋ฆฌ๋ทฐ์–ด ๋ชฉ๋ก)
    • ๋ชฉ๋ก ํŽ˜์ด์ง€: "๋‚ด๊ฒŒ ์˜จ ๋ฆฌ๋ทฐ" / "๋‚ด๊ฐ€ ์š”์ฒญํ•œ ๋ฆฌ๋ทฐ" ํƒญ, ์ƒํƒœ ๋ฐฐ์ง€(PENDING/APPROVED/REJECTED), ํ˜ธ๋ฒ„ ์นด๋“œ
    • ์ƒ์„ธ ํŽ˜์ด์ง€: ์›๋ณธ ๋ถ„์„ ๊ฒฐ๊ณผ + ์š”์ฒญ์ž ๋ฉ”๋ชจ + ๋ฆฌ๋ทฐ ์‘๋‹ต ์˜์—ญ (์Šน์ธ/๋ฐ˜๋ ค ๋ฒ„ํŠผ, ๋ฐ˜๋ ค ์‹œ ์ฝ”๋ฉ˜ํŠธ ํ•„์ˆ˜)
    • ์ด๋ ฅ ํ†ตํ•ฉ: history/index.html ์ƒ์„ธ ๋ชจ๋‹ฌ์— "๐Ÿ‘ฅ ๋ฆฌ๋ทฐ ์š”์ฒญ" ๋ฒ„ํŠผ โ†’ ๋ฆฌ๋ทฐ์–ด ์„ ํƒ ๋ชจ๋‹ฌ (REVIEWER/ADMIN ์—ญํ• ๋งŒ ๋…ธ์ถœ)
    • ์•Œ๋ฆผ: ์š”์ฒญ/์‘๋‹ต ์‹œ ์–‘์ชฝ์— SSE ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ + ์ƒ์„ธ ๋งํฌ

๐Ÿ—๏ธ ์•„ํ‚คํ…์ฒ˜

  • DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ โ€” /admin/db-migration ADMIN ํŽ˜์ด์ง€ + DbMigrationController. ํ˜„์žฌ DB ์ž๋™ ๊ฐ์ง€(DatabaseMetaData), URL ๋น„๋ฐ€๋ฒˆํ˜ธ ๋งˆ์Šคํ‚น. 4๊ฐœ ํƒญ ๊ฐ€์ด๋“œ
    • PostgreSQL: Docker Compose ์‹คํ–‰, ํ™˜๊ฒฝ๋ณ€์ˆ˜, ์ž๋™ ์Šคํ‚ค๋งˆ ์ƒ์„ฑ
    • MySQL: 8.0+ ํ•„์ˆ˜ ์ฃผ์˜, utf8mb4 ๋ฌธ์ž์…‹, DB ์ƒ์„ฑ SQL
    • Oracle 11g: BOOLEAN โ†’ NUMBER(1), TEXT โ†’ CLOB, ์‹œํ€€์Šค ID, Oracle10gDialect, ojdbc8 ์˜์กด์„ฑ ์ถ”๊ฐ€ ๊ฐ€์ด๋“œ, ์‹ ๊ทœ application-oracle.yml ์˜ˆ์‹œ
    • ๋ฐฑ์—…/๋ณต์›: H2 SCRIPT TO ๋คํ”„, ZIP ๋ฐฑ์—… ๋‹ค์šด๋กœ๋“œ, CSV ์ด๋ ฅ ๋‚ด๋ณด๋‚ด๊ธฐ
    • ๊ฐ ๋‹จ๊ณ„ ๋ณต์‚ฌ ๊ฐ€๋Šฅ ์ฝ”๋“œ ๋ธ”๋ก, ์ฃผ์˜์‚ฌํ•ญ ๋ฐ•์Šค

๐Ÿ›ก๏ธ ์‚ฌ์šฉ์ž ๊ถŒํ•œ ๊ด€๋ฆฌ ํ†ตํ•ฉ

  • review-requests ๊ธฐ๋Šฅ ๊ถŒํ•œ ์ถ”๊ฐ€ โ€” PermissionInterceptor.FEATURE_PATHS, AdminPermissionController.FEATURES, AuditLog.MENU_NAME_MAP, ๊ฐ์‚ฌ ๋กœ๊ทธ ํ•„ํ„ฐ ๋“œ๋กญ๋‹ค์šด ๋ชจ๋‘ ๋™๊ธฐํ™”. VIEWER/REVIEWER ์‚ฌ์šฉ์ž๋ณ„ on/off ๊ฐ€๋Šฅ
  • v2.5.0 ~ v2.9.0 ์‚ฌ์šฉ์ž ๊ถŒํ•œ ๊ด€๋ฆฌ ๋ฒ”์œ„ ์ ๊ฒ€ ์™„๋ฃŒ โ€” ์•ˆ์ •์„ฑ/๋ณด์•ˆ ๊ฐ•ํ™”(v2.5-2.6)๋Š” ADMIN ๊ธฐ๋Šฅ์ด๋ผ ์ œ์™ธ, ์ฑ„ํŒ… ์„ธ์…˜/Markdown/WebJars(v2.7)๋Š” ๊ธฐ์กด chat ๊ถŒํ•œ ์žฌ์‚ฌ์šฉ, ๋ชจ๋‹ˆํ„ฐ๋ง/UX(v2.8)๋Š” ์ „์—ญ ๋˜๋Š” ADMIN ์ „์šฉ์ด๋ผ ์ œ์™ธ, v2.9 ์‹ ๊ทœ review-requests๋งŒ ์‚ฌ์šฉ์ž ์ œ์–ด ๋Œ€์ƒ์œผ๋กœ ์ถ”๊ฐ€

โœ… v4.0.0 โ€” React ํ”„๋ก ํŠธ์—”๋“œ ์ „ํ™˜ (์™„๋ฃŒ)

Thymeleaf ๊ธฐ๋ฐ˜ ํ”„๋ก ํŠธ์—”๋“œ(69๊ฐœ ํ…œํ”Œ๋ฆฟ, ~24,000์ค„ HTML, 15,000์ค„ JS)๋ฅผ React 18 + TypeScript + Vite ๊ธฐ๋ฐ˜ SPA๋กœ ์ „๋ฉด ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. Phase 15 ๋ฅผ ๊ฑฐ์ณ v4.1.0 ์‹œ์ ์— Thymeleaf ๊ฐ€ ์™„์ „ํžˆ ์ œ๊ฑฐ๋˜์—ˆ๊ณ  (ํ…œํ”Œ๋ฆฟ 0๊ฐœ, pom.xml ์˜์กด์„ฑ ์ œ๊ฑฐ), ์ดํ›„ v4.2.x ์šด์˜ ์•ˆ์ •ํ™” ๋ผ์ธ์ด ์ด์–ด์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ 64๊ฐœ React ํŽ˜์ด์ง€ + ๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ/ํ›…/์Šคํ† ์–ด 35+ ๊ฐœ๊ฐ€ ์ „์ฒด UI ๋ฅผ ๋‹ด๋‹นํ•˜๋ฉฐ Spring Boot ๋ฐฑ์—”๋“œ์˜ REST API + SSE ์ŠคํŠธ๋ฆฌ๋ฐ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

โœ… v4.0.0-alpha.1 โ€” Phase 1: ํ”„๋กœ์ ํŠธ ์…‹์—…

  • Vite + React 18 + TypeScript ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐํ™” (claude-toolkit-ui/frontend/)
  • Vite ๊ฐœ๋ฐœ ์„œ๋ฒ„ ํ”„๋ก์‹œ ์„ค์ • (API/SSE โ†’ Spring Boot 8027 ํฌํŠธ)
  • ๋นŒ๋“œ ์ถœ๋ ฅ โ†’ static/react/ (Spring Boot ์ •์  ๋ฆฌ์†Œ์Šค ์„œ๋น™)
  • SpaForwardController โ€” /react/** SPA ๋ผ์šฐํŒ… ํฌ์›Œ๋”ฉ
  • SecurityConfig โ€” /react/** ์ •์  ๋ฆฌ์†Œ์Šค ๊ณต๊ฐœ ํ—ˆ์šฉ
  • frontend-maven-plugin โ€” mvn package ์‹œ React ์ž๋™ ๋นŒ๋“œ ํ†ตํ•ฉ
  • React Router ๊ธฐ๋ณธ ๋ผ์šฐํŒ… + /api/v1/health ์—ฐ๋™ ํ™•์ธ ํŽ˜์ด์ง€
  • ๊ธฐ์กด Thymeleaf UI ์ „์ฒด ์ •์ƒ ์ž‘๋™ ์œ ์ง€

โœ… v4.0.0-alpha.2 โ€” Phase 2: ๊ณต์šฉ ์ธํ”„๋ผ

  • Layout ์ปดํฌ๋„ŒํŠธ (์‚ฌ์ด๋“œ๋ฐ” 7์„น์…˜ ์ „์ฒด ๋ฉ”๋‰ด, ํƒ‘๋ฐ”, ๋ชจ๋ฐ”์ผ ํ•˜๋‹จ๋ฐ”)
  • ์ธ์ฆ ์—ฐ๋™ (AuthRestController + useAuth + ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€)
  • ๊ณต์šฉ ํ›…: useApi(), useSSE(), useToast()
  • ๋‹คํฌ/๋ผ์ดํŠธ ํ…Œ๋งˆ ์‹œ์Šคํ…œ (CSS ๋ณ€์ˆ˜, localStorage ์ €์žฅ)
  • ๊ธ€๋กœ๋ฒŒ ์ƒํƒœ ๊ด€๋ฆฌ (Zustand โ€” theme, auth, sidebar, toast ์Šคํ† ์–ด)
  • SPA ๋ผ์šฐํŒ… ํฌ์›Œ๋”ฉ (SpaForwardController)
  • Vite ํ”„๋ก์‹œ ์„ค์ • (API/SSE/ํŽ˜์ด์ง€ ๋ผ์šฐํŠธ โ†’ Spring Boot 8027)

โœ… v4.0.0-beta.1 โ€” Phase 3: ํ•ต์‹ฌ ํŽ˜์ด์ง€ ์ „ํ™˜

  • AI ์ฑ„ํŒ… (๋‹ค์ค‘ ์„ธ์…˜ ๊ด€๋ฆฌ, SSE 2-step ์ŠคํŠธ๋ฆฌ๋ฐ, Markdown ๋ Œ๋”๋ง, ๋Œ€ํ™” ๋‚ด๋ณด๋‚ด๊ธฐ)
  • ๋ถ„์„ ํŒŒ์ดํ”„๋ผ์ธ (๋ชฉ๋ก/์‹คํ–‰/์ƒ์„ธ ํŽ˜์ด์ง€, ์‹ค์‹œ๊ฐ„ SSE ์ง„ํ–‰๋ฅ , ์‹คํ–‰ ๋ชจ๋‹ฌ)
  • ๋Œ€์‹œ๋ณด๋“œ ํ™ˆ (Health API ์—ฐ๋™, ๋„๊ตฌ ์นด๋“œ ๊ทธ๋ฆฌ๋“œ, ์ธ์‚ฌ๋ง)
  • /notifications/unread-count ๊ฐ์‚ฌ ๋กœ๊ทธ ์ œ์™ธ ์ฒ˜๋ฆฌ
  • Markdown ์Šคํƒ€์ผ๋ง (react-markdown + remark-gfm, ์ฝ”๋“œ ๋ธ”๋ก/ํ…Œ์ด๋ธ”/์ธ์šฉ)

โœ… v4.0.0-beta.2 โ€” Phase 4: ๋‚˜๋จธ์ง€ ํŽ˜์ด์ง€ ์ „ํ™˜

  • AnalysisPageTemplate ๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ (์ž…๋ ฅ/SSE ์ŠคํŠธ๋ฆฌ๋ฐ/๊ฒฐ๊ณผ ํŒจํ„ด ํ†ตํ•ฉ)
  • SQL ๋ถ„์„ 5์ข… (SQL ๋ฆฌ๋ทฐ, DB ๋ฒˆ์—ญ, ERD ๋ถ„์„, ๋ณต์žก๋„, ์‹คํ–‰๊ณ„ํš)
  • ์ฝ”๋“œ ๋ถ„์„/์ƒ์„ฑ 8์ข… (์ฝ”๋“œ ๋ฆฌ๋ทฐ, ๊ธฐ์ˆ  ๋ฌธ์„œ, API ๋ช…์„ธ, ์ฝ”๋“œ ๋ณ€ํ™˜, Mock ๋ฐ์ดํ„ฐ, DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜, ์˜์กด์„ฑ, Spring ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜)
  • ๋„๊ตฌ 5์ข… (๋กœ๊ทธ ๋ถ„์„๊ธฐ, ์ •๊ทœ์‹, ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€, ๋งˆ์Šคํ‚น ์Šคํฌ๋ฆฝํŠธ, ๋ฏผ๊ฐ์ •๋ณด ๋งˆ์Šคํ‚น)
  • ๊ธฐ๋ก ํŽ˜์ด์ง€ (๋ฆฌ๋ทฐ ์ด๋ ฅ โ€” ๊ฒ€์ƒ‰/ํ•„ํ„ฐ/์•„์ฝ”๋””์–ธ/๋‚ด๋ณด๋‚ด๊ธฐ, ์ฆ๊ฒจ์ฐพ๊ธฐ)
  • ์„ค์ • ํŽ˜์ด์ง€ (๋ชจ๋ธ ์„ ํƒ, ํ† ํฐ ์ˆ˜, ํ”„๋กœ์ ํŠธ ์ปจํ…์ŠคํŠธ)
  • Lazy loading + code splitting (๊ฐ ํŽ˜์ด์ง€ ๋ณ„๋„ ์ฒญํฌ ์ž๋™ ๋ถ„๋ฆฌ)
  • ์‚ฌ์ด๋“œ๋ฐ” React ๋ผ์šฐํŠธ ์ „๋ฉด ์ „ํ™˜ (Thymeleaf ์ „์šฉ ๊ฒฝ๋กœ๋งŒ ์™ธ๋ถ€ ๋งํฌ)

โœ… v4.0.0 โ€” Phase 5: React ์ „๋ฉด ์ „ํ™˜

  • React base path /react/ โ†’ / ๋ฃจํŠธ๋กœ ์ „ํ™˜
  • ๋‚จ์€ Thymeleaf ์ „์šฉ ํŽ˜์ด์ง€ React ์ „ํ™˜ (workspace, sql-batch, harness ํ•˜์œ„, admin ๋“ฑ)
  • ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ (์‚ฌ์šฉ์ž ๊ด€๋ฆฌ, ์‹œ์Šคํ…œ ํ—ฌ์Šค, ๊ฐ์‚ฌ ๋กœ๊ทธ) React ์ „ํ™˜
  • ๊ธฐ๋Šฅ ํŽ˜์ด์ง€ (๊ฒ€์ƒ‰, ์‚ฌ์šฉ๋Ÿ‰, ์Šค์ผ€์ค„, ๋ฆฌ๋ทฐ ์š”์ฒญ, ROI, ํ”„๋กฌํ”„ํŠธ) React ์ „ํ™˜
  • SPA ๋ผ์šฐํŒ… โ€” SpaForwardController ๋ฃจํŠธ ํฌ์›Œ๋”ฉ
  • React ๋นŒ๋“œ ์ถœ๋ ฅ โ†’ static/app/ (49๊ฐœ ์ฒญํฌ, lazy loading)
  • Thymeleaf ๋ ˆ๊ฑฐ์‹œ ํ˜ธํ™˜ ์œ ์ง€ (/react/** โ†’ ๊ธฐ์กด ๋ถ๋งˆํฌ ์ง€์›)
  • ์ „์ฒด 40+ React ํŽ˜์ด์ง€ ์™„์„ฑ

โœ… v4.1.0 โ€” ์ „์ˆ˜ ๊ฒ€ํ†  + ์ตœ์ข… ์ •๋ฆฌ

  • Thymeleaf ์™„์ „ ์ œ๊ฑฐ (templates 69๊ฐœ ์‚ญ์ œ, toolkit.js/css ์‚ญ์ œ, WebJars ์˜์กด์„ฑ ์ œ๊ฑฐ)
  • 56๊ฐœ @Controller ํŽ˜์ด์ง€ GET ๋งคํ•‘ ์ œ๊ฑฐ (POST/API ์œ ์ง€, SpaViewResolver ๋ทฐ ํฌ์›Œ๋”ฉ)
  • REST API ์ „ํ™˜ (/api/v1/auth/login, /api/v1/pipelines, /history, /favorites)
  • 2FA ์ „์šฉ ํŽ˜์ด์ง€, Setup ๋งˆ๋ฒ•์‚ฌ, Share ๋ทฐ์–ด, 404 ํŽ˜์ด์ง€
  • AI ํ”„๋กฌํ”„ํŠธ ๊ด€๋ฆฌ, ํŒ€ ์„ค์ • ๊ณต์œ , ์‚ฌ์šฉ์ž ๊ถŒํ•œ ๊ด€๋ฆฌ, ํŒ€ ๋Œ€์‹œ๋ณด๋“œ, DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ, ๋ฐฑ์—…/๋ณต์›
  • Monaco Editor + Mermaid ํ”Œ๋กœ์šฐ์ฐจํŠธ ์‹ค์‹œ๊ฐ„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํŒŒ์ดํ”„๋ผ์ธ ํŽธ์ง‘๊ธฐ
  • recharts ๋Œ€์‹œ๋ณด๋“œ (์„ฑ๋Šฅ ํžˆ์Šคํ† ๋ฆฌ, ํ’ˆ์งˆ ๋Œ€์‹œ๋ณด๋“œ)
  • ์•Œ๋ฆผ SSE ์‹ค์‹œ๊ฐ„ ๊ตฌ๋… + ์„ธ์…˜ ํƒ€์ด๋จธ 60๋ถ„ + ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค (? ๋„์›€๋ง)
  • i18n (ํ•œ๊ตญ์–ด/์˜์–ด), PWA manifest, ErrorBoundary, ํŒŒ์ผ ์—…๋กœ๋“œ
  • Playwright E2E 5/5 ํ†ต๊ณผ
  • mvn clean package JDK 1.8 ๋นŒ๋“œ ๊ฒ€์ฆ (JAR ๋‚ด React 119๊ฐœ ํŒŒ์ผ ํฌํ•จ ํ™•์ธ)
  • .dockerignore ์ถ”๊ฐ€ (Docker ๋นŒ๋“œ ์ตœ์ ํ™”)
  • ์ „์ฒด 52๊ฐœ React ํŽ˜์ด์ง€, 35๊ฐœ ์ปดํฌ๋„ŒํŠธ/ํ›…/์Šคํ† ์–ด ์™„์„ฑ

โœ… v4.2.0 โ€” ์šด์˜ ์•ˆ์ •ํ™” + UX ๊ฐœ์„ 

ํ•ต์‹ฌ ๊ธฐ๋Šฅ

  • ์‚ฌ์šฉ์ž ๊ถŒํ•œ ๊ด€๋ฆฌ ์—ฐ๋™ โ€” React ์‚ฌ์ด๋“œ๋ฐ”๊ฐ€ per-user ๋น„ํ™œ์„ฑ ๊ธฐ๋Šฅ ์ž๋™ ์ˆจ๊น€ (/api/v1/auth/my-permissions)
  • ํŒŒ์ดํ”„๋ผ์ธ ๋น„์ฃผ์–ผ ๋นŒ๋” โ€” 12์ข… ๋ถ„์„์„ ๋ฒ„ํŠผ ํด๋ฆญ์œผ๋กœ ์กฐ๋ฆฝ โ†’ YAML ์ž๋™ ์ƒ์„ฑ
  • ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์ด๋ ฅ ํŽ˜์ด์ง€ (/pipelines/history)
  • DB ํ”„๋กœํ•„ ์ถ”๊ฐ€ ๋ชจ๋‹ฌ โ€” ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ + ์ €์žฅ ํ†ตํ•ฉ ์›Œํฌํ”Œ๋กœ์šฐ
  • DB ์ž๋™ ์ด๊ด€ (H2 โ†’ Oracle 11g/PostgreSQL/MySQL) โ€” ์›ํด๋ฆญ ์‹คํ–‰ + SSE ์ง„ํ–‰๋ฅ 

UX ๊ฐœ์„ 

  • OS ๋‹คํฌ/๋ผ์ดํŠธ ๋ชจ๋“œ ์ž๋™ ๊ฐ์ง€ (prefers-color-scheme)
  • SSE ์ž๋™ ์žฌ์—ฐ๊ฒฐ (exponential backoff, ์ตœ๋Œ€ 3ํšŒ)
  • ์ฑ„ํŒ… ์„ธ์…˜ ๊ฒ€์ƒ‰ (์‹ค์‹œ๊ฐ„ ํ•„ํ„ฐ)
  • ํŒŒ์ผ ๋“œ๋ž˜๊ทธ์•ค๋“œ๋กญ ์—…๋กœ๋“œ (๋ถ„์„ ํŽ˜์ด์ง€ + ์‹œ๊ฐ ํ”ผ๋“œ๋ฐฑ)
  • ๋ชจ๋ฐ”์ผ ๋ฐ˜์‘ํ˜• ๊ทธ๋ฆฌ๋“œ (repeat(auto-fit, minmax(400px, 1fr)))
  • ์„ธ๋ จ๋œ ์˜ต์…˜ UI โ€” select โ†’ pill/chip ๋ฒ„ํŠผ ์ผ๊ด„ ์ „ํ™˜
  • ์ •๊ทœ์‹ ์ƒ์„ฑ๊ธฐ 8์ข… ์˜ˆ์‹œ ๋ฒ„ํŠผ (ํ•ธ๋“œํฐ/์ฃผ๋ฏผ๋ฒˆํ˜ธ/์ด๋ฉ”์ผ/์ฃผ์†Œ ๋“ฑ)

๋ฐฑ์—”๋“œ REST API ๋ณด๊ฐ•

  • /api/v1/auth/my-permissions โ€” ํ˜„์žฌ ์‚ฌ์šฉ์ž ๋น„ํ™œ์„ฑ ๊ธฐ๋Šฅ ๋ชฉ๋ก
  • /api/v1/db-profiles โ€” DB ํ”„๋กœํ•„ ๋ชฉ๋ก
  • /api/v1/pipelines/executions โ€” ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์ด๋ ฅ
  • /api/v1/explain/dashboard, /api/v1/harness/dashboard โ€” ๋Œ€์‹œ๋ณด๋“œ ๋ฐ์ดํ„ฐ
  • /api/v1/admin/team-dashboard, /api/v1/admin/health/data โ€” ๊ด€๋ฆฌ์ž ํ†ต๊ณ„
  • /api/v1/admin/users, /audit-logs, /permissions โ€” ๊ด€๋ฆฌ์ž ๋ชฉ๋ก API
  • /api/v1/review-requests, /schedule, /roi-report, /prompts, /settings/prompts, /settings/shared, /search

์ธํ„ฐ์…‰ํ„ฐ ์ •๋น„ (5๊ฐœ ์ธํ„ฐ์…‰ํ„ฐ์˜ /assets/**, /api/**, /chat/**, /stream/** ์ œ์™ธ)

  • PermissionInterceptor, SetupInterceptor, PasswordChangeInterceptor
  • PasswordExpiryInterceptor, TwoFactorInterceptor

ํ•ต์‹ฌ ๋ฒ„๊ทธ ์ˆ˜์ •

  • useApi ํ›… ์•ˆ์ •์  ์ฐธ์กฐ (useEffect ๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€)
  • 15๊ฐœ ํŽ˜์ด์ง€ [api] ์˜์กด์„ฑ โ†’ [] (Failed to fetch ๋ฌดํ•œ ๋ฐ˜๋ณต ํ•ด๊ฒฐ)
  • AuthRestController: ADMIN ๋กœ๊ทธ์ธ ์‹œ require2fa=true ๋ฐ˜ํ™˜ โ†’ 2FA ํŽ˜์ด์ง€ ์ด๋™
  • TwoFactorController: ResponseEntity<String> ๋ฐ˜ํ™˜ (redirect ๋ฌธ์ž์—ด ๋ฒ„๊ทธ ์ˆ˜์ •)
  • GlobalExceptionHandler: 405 Method Not Allowed โ†’ React SPA ํฌ์›Œ๋”ฉ
  • Vite outDir์„ static/ ๋ฃจํŠธ๋กœ ๋ณ€๊ฒฝ (์—์…‹ MIME ํƒ€์ž… ์˜ค๋ฅ˜ ํ•ด๊ฒฐ)
  • React ๋นŒ๋“œ JS ๊ฒฝ๋กœ ์ผ๊ด€์„ฑ ํ™•๋ณด (/assets/**)

โœ… v4.2.2 โ€” ์‚ฌ๋‚ด๋ง ์šด์˜ ์ด์Šˆ ์ •๋ฆฌ

์ธํ”„๋ผ/TLS/ํƒ€์ž„์กด

  • Runtime ์ด๋ฏธ์ง€ eclipse-temurin:8-jre-alpine โ†’ 8-jre-jammy (Ubuntu glibc โ€” TLS handshake ์•ˆ์ •)
  • docker-compose.yml ์˜ JAVA_OPTS override ์ œ๊ฑฐ โ€” Dockerfile ๊ธฐ๋ณธ๊ฐ’ ๋ณด์กด
  • TLS ์„ค์ •: -Dhttps.protocols=TLSv1.2,TLSv1.3 -Djdk.tls.client.protocols=TLSv1.2,TLSv1.3
  • DNS ์บ์‹œ ํŠœ๋‹: -Dnetworkaddress.cache.ttl=60, -Djava.net.preferIPv4Stack=true
  • ORA-01882 ๋Œ€์‘: -Doracle.jdbc.timezoneAsRegion=false + TZ=Asia/Seoul + tzdata
  • ClaudeToolkitUiApplication.main() ์—์„œ System.setProperty ๋กœ defense-in-depth
  • ClaudeClient: forward proxy (CLAUDE_PROXY_HOST/PORT ๋˜๋Š” HTTPS_PROXY env)
  • ClaudeClient.formatNetworkError(): handshake_failure/PKIX/timeout/unknown host ํ•œ๊ตญ์–ด ๋ณ€ํ™˜
  • /admin/health/claude-api-diagnose ์ง„๋‹จ ์—”๋“œํฌ์ธํŠธ + AdminHealthPage UI

DB ์ž๋™ ์ด๊ด€ / ๋Ÿฐํƒ€์ž„ ์ „ํ™˜ / Oracle ํ˜ธํ™˜

  • DbOverrideConfig: data/db-override.properties ๊ธฐ๋ฐ˜ ๋Ÿฐํƒ€์ž„ DataSource ์˜ค๋ฒ„๋ผ์ด๋“œ
  • POST /admin/db-migration/auto/switch-target / /switch-h2 โ€” ์žฌ์‹œ์ž‘์œผ๋กœ ์šด์˜ DB ์ „ํ™˜
  • GET /admin/db-migration/auto/tables โ€” 19๊ฐœ ๋Œ€์ƒ ํ…Œ์ด๋ธ” ๋ชฉ๋ก ๋…ธ์ถœ
  • POST /admin/db-migration/auto/validate โ€” ๋Œ€์ƒ DB ์ถฉ๋Œ/๊ธฐ์กด ํ–‰์ˆ˜ ์‚ฌ์ „ ๊ฒ€์ฆ
  • Oracle URL ์ž๋™ ํฌ๋งท ๊ฐ์ง€: SID(@host:port:SID) โ†’ Service Name(@//host:port/SVC) fallback
  • SystemHealthController + DataRestController: ํ™œ์„ฑ DB ์ž๋™ ๊ฐ์ง€ โ€” ์ž๋™ ์ด๊ด€ ํ›„ ์‹œ์Šคํ…œ ํ—ฌ์Šค๊ฐ€ ์‹ค์ œ ์šด์˜ DB ์ •๋ณด ํ‘œ์‹œ
  • SourceSelector ํ”„๋กœ์ ํŠธ ์Šค์บ” ์ค‘ ์ƒํƒœ ํด๋ง (๋ถ€ํŒ… ์งํ›„ "Java ํŒŒ์ผ ์—†์Œ" ์˜คํ•ด ์ œ๊ฑฐ)

๊ณ„์ • / ๋น„๋ฐ€๋ฒˆํ˜ธ / ๊ฐ์‚ฌ๋กœ๊ทธ / ํŒŒ์ดํ”„๋ผ์ธ

  • AccountController.me GET โ€” ํ”„๋กœํ•„ prefill
  • SecurityPage: ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ‹€๋ฆด ๋•Œ ๋ช…ํ™•ํ•œ ์—๋Ÿฌ (์ด์ „์—” ํ•ญ์ƒ "์„ฑ๊ณต")
  • PasswordChangePage ์‹ ๊ทœ (/account/password) โ€” 90์ผ ๋งŒ๋ฃŒ ๋ฐฐ๋„ˆ + "๋‹ค์Œ์— ๋ณ€๊ฒฝํ•˜๊ธฐ" ๋ฒ„ํŠผ
  • AuditLogPage ์žฌ์ž‘์„ฑ: ํŽ˜์ด์ง€๋‹น 20๊ฑด ํŽ˜์ด์ง€๋„ค์ด์…˜ + ๊ธฐ๊ฐ„/์‚ฌ์šฉ์ž ํ•„ํ„ฐ + CSV ๋‹ค์šด๋กœ๋“œ
  • DbMigrationGuidePage: ๋Œ€์ƒ ํ…Œ์ด๋ธ” details + ์‚ฌ์ „ ๊ฒ€์ฆ ๊ฒฐ๊ณผ + ๋Ÿฐํƒ€์ž„ ์ „ํ™˜ ๋ฒ„ํŠผ
  • PipelineExecutionPage ์ „๋ฉด ๊ฐœํŽธ: ์ŠคํŠธ๋ฆฌ๋ฐ ์ฒญํฌ + ํƒญ ๋„ค๋น„ + ์ง„ํ–‰์  outputContent DB ์ €์žฅ + 1์ดˆ ํด๋ง ๋ฐฑ์—…
  • PipelineExecutor: setOutputContent setter ์ถ”๊ฐ€ + 300ms/1000์ž throttled ์ €์žฅ
  • WorkspacePage / PipelineExecutionPage / CodeReviewPage: ๋ณต์‚ฌ ๋ฒ„ํŠผ execCommand fallback (HTTP IP ํ™˜๊ฒฝ ๋Œ€์‘)

Claude API / CSRF / ์ด๋ฉ”์ผ

  • SseStreamController: ์ŠคํŠธ๋ฆฌ๋ฐ ์™„๋ฃŒ ํ›„ historyService.save() ํ˜ธ์ถœ (React ๊ฒฝ๋กœ์—์„œ ์ด๋ ฅ ์ €์žฅ ๋ˆ„๋ฝ ๋ฒ„๊ทธ)
  • ReviewHistoryService.save(): SecurityContextHolder ์—์„œ username ์ถ”์ถœํ•ด setUsername ํ˜ธ์ถœ
  • SecurityConfig CSRF ignore ์— /pipelines/**, /email/** ์ถ”๊ฐ€ (๊ธฐ์กด ๋ˆ„๋ฝ)
  • EmailController ์‹ ๊ทœ โ€” POST /email/send (์‰ผํ‘œ/์„ธ๋ฏธ์ฝœ๋ก  ๊ตฌ๋ถ„ ์ตœ๋Œ€ 10๋ช…), POST /email/test
  • EmailModal ๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ โ€” Workspace/Pipeline/CodeReview ๋ชจ๋‹ฌ ๋ฒ„ํŠผ ์—ฐ๊ฒฐ
  • SettingsPage: SMTP ์นด๋“œ (Gmail ์•ฑ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•ˆ๋‚ด + ํ…Œ์ŠคํŠธ ๋ฐœ์†ก)

โœ… v4.2.3 โ€” ๋ฆฌ๋ทฐ ์›Œํฌํ”Œ๋กœ์šฐ (์Šน์ธ/๊ฑฐ์ ˆ + ๋Œ“๊ธ€ ์•Œ๋ฆผ)

์Šคํ‚ค๋งˆ ํ™•์žฅ

  • ReviewHistory: reviewStatus (PENDING/ACCEPTED/REJECTED), reviewedBy, reviewedAt, reviewNote ์ปฌ๋Ÿผ ์ถ”๊ฐ€
  • ReviewComment: parentId ์ปฌ๋Ÿผ ์ถ”๊ฐ€ (๋Œ€๋Œ“๊ธ€ ์ง€์›)

๋ฐฑ์—”๋“œ API

  • POST /history/{id}/review-status โ€” REVIEWER/ADMIN ์ด ๋ฆฌ๋ทฐ ์ด๋ ฅ ์Šน์ธ/๊ฑฐ์ ˆ + ์ž‘์„ฑ์ž์—๊ฒŒ ์•Œ๋ฆผ
  • POST /history/{id}/comments โ€” parentId ํŒŒ๋ผ๋ฏธํ„ฐ ์ง€์› (๋Œ€๋Œ“๊ธ€ โ†’ ๋ถ€๋ชจ ๋Œ“๊ธ€ ์ž‘์„ฑ์ž ์•Œ๋ฆผ)
  • GET /api/v1/review-queue?tab=received|sent โ€” ์—ญํ•  ๊ธฐ๋ฐ˜ ๋ฆฌ๋ทฐ ํ
    • received: REVIEWER/ADMIN โ†’ ํƒ€์ธ์˜ PENDING ์ด๋ ฅ, VIEWER โ†’ ๋ณธ์ธ ์ด๋ ฅ ์ค‘ ๊ฒ€ํ†  ์™„๋ฃŒ๋œ ๊ฒƒ
    • sent: ๋ณธ์ธ์ด ์ž‘์„ฑํ•œ ๋ชจ๋“  ์ด๋ ฅ

UI/UX

  • HistoryPage ์žฌ์ž‘์„ฑ:
    • ํ•„๋“œ ๋งคํ•‘ ์ˆ˜์ • (inputContent/outputContent โ€” ์ด์ „์—” ์ž˜๋ชป๋œ inputText/resultText ์‚ฌ์šฉ)
    • ๋ฆฌ๋ทฐ ์ƒํƒœ ๋ฐฐ์ง€ (์Šน์ธ๋จ/๊ฑฐ์ ˆ๋จ/๊ฒ€ํ†  ๋Œ€๊ธฐ)
    • REVIEWER/ADMIN ์Šน์ธยท๊ฑฐ์ ˆ ๋ฒ„ํŠผ (VIEWER ๋Š” ์ฝ๊ธฐ ์ „์šฉ)
    • ๋Œ“๊ธ€ ์„น์…˜ + ๋Œ€๋Œ“๊ธ€ ํŠธ๋ฆฌ (๋“ค์—ฌ์“ฐ๊ธฐ ๊ตฌ์กฐ)
    • copyToClipboard ์ ์šฉ (HTTP IP ๋ณต์‚ฌ ์ง€์›)
  • ReviewRequestsPage ์žฌ์ž‘์„ฑ:
    • ๋‚ด๊ฒŒ ์˜จ / ๋‚ด๊ฐ€ ์š”์ฒญํ•œ ํƒญ
    • ์—ญํ• ๋ณ„ ๋ฌธ๊ตฌ (REVIEWER/ADMIN vs VIEWER)
    • ์Šน์ธ/๊ฑฐ์ ˆ ํ™•์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ ("์Šน์ธํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?" / "๊ฑฐ์ ˆํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?")
    • ๋…น์ƒ‰ ์Šน์ธ / ๋นจ๊ฐ• ๊ฑฐ์ ˆ ๋ฒ„ํŠผ (REVIEWER/ADMIN ๋งŒ, VIEWER ๋Š” ๐Ÿ”’ ์•ˆ๋‚ด)
  • AdminUsersPage ๋ผ๋ฒจ ๋ณ€๊ฒฝ: ์‚ฌ์šฉ์ž๋ช… โ†’ ์•„์ด๋””, ํ‘œ์‹œ ์ด๋ฆ„ โ†’ ์‚ฌ์šฉ์ž๋ช…

์‚ฌ์ด๋“œ๋ฐ” UX

  • Sidebar section max-height ๊ณ„์‚ฐ: items.length * 36 โ†’ items.length * 40 + 8 (๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ ์ž˜๋ฆผ ํ•ด๊ฒฐ)

๋ฌธ์„œ

  • README.md / docs/index.html ๋ฒ„์ „ ํžˆ์Šคํ† ๋ฆฌ ๊ฐฑ์‹ 

โœ… v4.2.4 โ€” ํŒŒ์ดํ”„๋ผ์ธ ์•ˆ์ •ํ™” (์ŠคํŠธ๋ฆฌ๋ฐ/์ด๋ ฅ/์ปจํ…์ŠคํŠธ ์ „ํŒŒ)

ํŒŒ์ดํ”„๋ผ์ธ ๋‹จ๊ณ„ ๊ฐ„ ์ปจํ…์ŠคํŠธ ์ „ํŒŒ ๋ฒ„๊ทธ

  • PipelineExecutor ๊ฐ€ step.getContext() ๋ฅผ WorkspaceRequest.projectContext ์— ์ €์žฅํ–ˆ์ง€๋งŒ AnalysisService.buildUserMessage() ๊ตฌํ˜„์ฒด๋“ค์ด projectContext ๋ฅผ ๋ฌด์‹œ โ†’ step 2 ๊ฐ€ step 1 ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์ง€ ๋ชปํ•ด ๋™์ผ ํ”„๋กฌํ”„ํŠธ ๋ฐ˜๋ณตํ•˜๋˜ ๋ฒ„๊ทธ
  • PipelineExecutor ๋‘ ๊ฒฝ๋กœ(์ˆœ์ฐจ + ๋ณ‘๋ ฌ) ๋ชจ๋‘์—์„œ stepContext ๋ฅผ userMsg ์•ž์— ์ง์ ‘ prepend ํ•˜๋„๋ก ์ˆ˜์ • โ†’ 'SQL ์ตœ์ ํ™” ํ’€ ์Šคํƒ' ๋“ฑ ์—ฐ์‡„ ํŒŒ์ดํ”„ ์ •์ƒ ๋™์ž‘
  • [Pipeline] ๋‹จ๊ณ„ ์‹คํ–‰: exec=N, step=X, inputLen=A, contextLen=B ๋กœ๊น… ์ถ”๊ฐ€
  • ๋นˆ ์‘๋‹ต ๋ฐฉ์–ด (Claude ๊ฐ€ 0 ์ฒญํฌ๋กœ ๋๋‚˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž ์นœํ™” ๋ฉ”์‹œ์ง€ + WARN ๋กœ๊ทธ)

ํŒŒ์ดํ”„๋ผ์ธ ๊ฒฐ๊ณผ โ†’ ๋ฆฌ๋ทฐ ์ด๋ ฅ ์ €์žฅ ๋ˆ„๋ฝ

  • React ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ›„ PipelineExecutor ๊ฐ€ claudeClient.chatStream() ์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜์—ฌ /stream/init ๊ฒฝ๋กœ์˜ saveHistory() ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Œ
  • PipelineExecutor.saveHistoryForExecution() ์ถ”๊ฐ€ โ€” ๋ชจ๋“  ๋‹จ๊ณ„ ๊ฒฐ๊ณผ๋ฅผ ๋งˆํฌ๋‹ค์šด 1๊ฑด์œผ๋กœ ์กฐ๋ฆฝํ•ด type=PIPELINE ๋กœ ReviewHistory ์ €์žฅ
  • ReviewHistoryService.save() / saveHarness() ๊ฐ€ SecurityContextHolder ์—์„œ username ์ถ”์ถœํ•˜์—ฌ setUsername ํ˜ธ์ถœ (์ด์ „์—” null ์ €์žฅ โ†’ /history ํ•„ํ„ฐ๋ง์—์„œ ํ•ญ์ƒ ์ œ์™ธ)
  • SseStreamController.saveHistory() ๋„ ๋™์ผ ๋ฐฉ์‹ โ€” 3๊ฐœ ๋ถ„๊ธฐ(harness/sql_translate/generic) ๋ชจ๋‘

ํŒŒ์ดํ”„๋ผ์ธ Broken pipe ๋กœ๊ทธ ํญ์ฃผ + max_tokens ์ž˜๋ฆผ

  • GlobalExceptionHandler.isClientDisconnect() โ€” ClientAbortException / Broken pipe / Connection reset ์„ cause chain 10๋‹จ๊ณ„๊นŒ์ง€ ๊ฒ€์‚ฌํ•˜์—ฌ ERROR โ†’ DEBUG ๋กœ ๊ฐ•๋“ฑ + null ๋ฐ˜ํ™˜ (์‘๋‹ต ๋ณธ๋ฌธ ์“ฐ๊ธฐ ์‹œ๋„ ์ž์ฒด ํšŒํ”ผ)
  • PipelineStreamBroker.push() catch (Exception) โ†’ catch (Throwable) ๋กœ ํ™•์žฅ
  • PipelineExecutor ๊ฐ€ chatStream() โ†’ chatStreamWithContinuation(..., 3, ...) ์‚ฌ์šฉ โ€” max_tokens ๋„๋‹ฌ ์‹œ ์ž๋™์œผ๋กœ ์ตœ๋Œ€ 3ํšŒ ์ด์–ด๋ฐ›๊ธฐ (๋‹จ๊ณ„๋‹น ์ตœ๋Œ€ 32K ํ† ํฐ)

๊ธฐํƒ€

  • ReviewHistory ์—”ํ‹ฐํ‹ฐ์— reviewStatus / reviewedBy / reviewedAt / reviewNote ์ปฌ๋Ÿผ ์ถ”๊ฐ€ (PENDING/ACCEPTED/REJECTED)
  • ReviewComment ์—”ํ‹ฐํ‹ฐ์— parentId ์ปฌ๋Ÿผ ์ถ”๊ฐ€ (๋Œ€๋Œ“๊ธ€)

โœ… v4.2.5 โ€” ๋ฆฌ๋ทฐ ์ด๋ ฅ + ๊ถŒํ•œ + UX ์ •๋ฆฌ

๋ฆฌ๋ทฐ ์›Œํฌํ”Œ๋กœ์šฐ ์™„์„ฑ

  • ReviewStatusController ์‹ ๊ทœ: POST /history/{id}/review-status โ€” REVIEWER/ADMIN ๋งŒ ์Šน์ธ/๊ฑฐ์ ˆ ๊ฐ€๋Šฅ, ์ž‘์„ฑ์ž์—๊ฒŒ ์•Œ๋ฆผ ๋ฐœ์†ก
  • ReviewCommentController ์— parentId ํŒŒ๋ผ๋ฏธํ„ฐ ์ง€์› โ€” ๋Œ€๋Œ“๊ธ€ ์ž‘์„ฑ ์‹œ ๋ถ€๋ชจ ๋Œ“๊ธ€ ์ž‘์„ฑ์ž์—๊ฒŒ COMMENT_REPLY ์•Œ๋ฆผ
  • DataRestController.reviewQueue() ์‹ ๊ทœ: GET /api/v1/review-queue?tab=received|sent ์—ญํ•  ๊ธฐ๋ฐ˜ ํ•„ํ„ฐ๋ง (REVIEWER/ADMIN โ†” VIEWER)
  • HistoryPage ์žฌ์ž‘์„ฑ: ํ•„๋“œ๋ช… ๋งคํ•‘ ์ˆ˜์ • (inputContent/outputContent), ๋ฆฌ๋ทฐ ์ƒํƒœ ๋ฐฐ์ง€, ์Šน์ธ/๊ฑฐ์ ˆ ๋ฒ„ํŠผ, ๋Œ“๊ธ€/๋Œ€๋Œ“๊ธ€ ํŠธ๋ฆฌ, copyToClipboard ์ ์šฉ
  • ReviewRequestsPage ์žฌ์ž‘์„ฑ: ๋‚ด๊ฒŒ ์˜จ / ๋‚ด๊ฐ€ ์š”์ฒญํ•œ ํƒญ, ์—ญํ• ๋ณ„ ์•ˆ๋‚ด, ์Šน์ธ/๊ฑฐ์ ˆ confirm ๋‹ค์ด์–ผ๋กœ๊ทธ, ๋…น์ƒ‰/๋นจ๊ฐ• ๋ฒ„ํŠผ ๋ถ„๊ธฐ

๋ณด์•ˆ / ๊ถŒํ•œ / CSRF

  • SecurityConfig CSRF ignore ์— /history/**, /email/**, /pipelines/** ์ถ”๊ฐ€ (์ด์ „์—” /history/*/share, /history/*/comments/** ๋งŒ ์žˆ์–ด์„œ review-status, pipelines/{id}/run, history/{id}/delete ๋“ฑ์ด 405 ๋ฐœ์ƒ)
  • AdminUsersPage ๋ผ๋ฒจ ๋ณ€๊ฒฝ: ์‚ฌ์šฉ์ž๋ช… โ†’ ์•„์ด๋””, ํ‘œ์‹œ ์ด๋ฆ„ โ†’ ์‚ฌ์šฉ์ž๋ช…
  • Sidebar ์„น์…˜ max-height ๊ณ„์‚ฐ: items.length * 36 โ†’ items.length * 40 + 8 (๋งˆ์ง€๋ง‰ ๋ฉ”๋‰ด ์ž˜๋ฆผ ํ•ด๊ฒฐ)

์ด๋ฉ”์ผ ๋ฐœ์†ก + Settings SMTP

  • EmailController ์‹ ๊ทœ: POST /email/send (๋‹ค์ˆ˜ ์ˆ˜์‹ ์ž, ์ตœ๋Œ€ 10๋ช…), POST /email/test (SMTP ๊ฒ€์ฆ)
  • EmailModal ๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ: ์ˆ˜์‹ ์ž ์ถ”๊ฐ€ (์ตœ๋Œ€ 10), ๋ณธ๋ฌธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ, ๋ฐœ์†ก ์‹œ ๋ถ€๋ถ„ ์‹คํŒจ ์•ˆ๋‚ด
  • Workspace/Pipeline/CodeReview ๊ฒฐ๊ณผ ํŽ˜์ด์ง€์— ์ด๋ฉ”์ผ ๋ฐœ์†ก ๋ฒ„ํŠผ ์—ฐ๊ฒฐ
  • SettingsPage SMTP ์นด๋“œ ์‹ ๊ทœ (Gmail ์•ฑ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•ˆ๋‚ด + ํ…Œ์ŠคํŠธ ๋ฐœ์†ก ๋ฒ„ํŠผ)

๋ฆฌ๋ทฐ ์ด๋ ฅ ๋Œ€์‹œ๋ณด๋“œ + ์‚ฌ์šฉ์ž ๊ถŒํ•œ ๋™์  ๋กœ๋”ฉ

  • DataRestController.reviewDashboard() ์‹ ๊ทœ: 1/3/7/30์ผ ๋˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ • ๊ธฐ๊ฐ„ ํŒŒ๋ผ๋ฏธํ„ฐ, ์ƒํƒœ๋ณ„ ์นด์šดํŠธ/% + dailyTrend + byType + byReviewer ์ง‘๊ณ„
  • ReviewDashboardPage ์‹ ๊ทœ (/admin/review-dashboard): ๋„๋„›/๋ง‰๋Œ€/๋ผ์ธ ์ฐจํŠธ + 4์ข… ์Šคํƒฏ์นด๋“œ + ๋ถ„์„ ์œ ํ˜•๋ณ„ / ๋ฆฌ๋ทฐ์–ด๋ณ„ ํ‘œ (recharts)
  • AdminPermissionController.listFeatures() ์‹ ๊ทœ: GET /admin/permissions/features ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ๊ทธ๋ฃนํ•‘ ์‘๋‹ต
  • AdminPermissionsPage ๊ฐ€ features ๋ชฉ๋ก์„ ๋™์  ๋กœ๋“œ โ€” ํ•˜๋“œ์ฝ”๋”ฉ ์ด์ค‘ ๊ด€๋ฆฌ ์ œ๊ฑฐ
  • authStore.login() ์— disabledFeatures fetch ์ถ”๊ฐ€ โ€” ๋กœ๊ทธ์ธ ์งํ›„ ์‚ฌ์ด๋“œ๋ฐ” ๊ถŒํ•œ ํ† ๊ธ€ ์ฆ‰์‹œ ๋ฐ˜์˜ (์ด์ „์—” ์ƒˆ๋กœ๊ณ ์นจ ํ›„์—๋งŒ ์ ์šฉ๋จ)

๋Œ€์‹œ๋ณด๋“œ / DB ์ƒํƒœ / ์„ค์ •

  • SystemHealthController + DataRestController ์˜ /admin/health/data ๊ฐ€ DataSource.getMetaData() ๋กœ ์‹ค์ œ ์šด์˜ DB ์ž๋™ ๊ฐ์ง€ โ€” ์ž๋™ ์ด๊ด€ ํ›„ ์‹œ์Šคํ…œ ํ—ฌ์Šค๊ฐ€ H2/Oracle/MySQL/PostgreSQL ์ •ํ™•ํžˆ ํ‘œ์‹œ
  • data/db-override.properties ํ™œ์„ฑ ์—ฌ๋ถ€๋กœ dbOverrideActive ํ”Œ๋ž˜๊ทธ ๋…ธ์ถœ
  • AdminHealthPage: ์œ ํ˜• ๋ฐฐ์ง€ + ์ œํ’ˆ/URL/๊ณ„์ • + ๋ณด๋ผ์ƒ‰ "๐Ÿ” ์ž๋™ ์ด๊ด€์œผ๋กœ ์ „ํ™˜๋œ ์šด์˜ DB ์‚ฌ์šฉ ์ค‘" ๋ฐฐ๋„ˆ

โœ… v4.2.6 โ€” ์šด์˜ ์•ˆ์ •ํ™” ๋ผ์šด๋“œ (Oracle ํ—ฌ์Šค/ํ•˜๋„ค์Šค/๋Œ€์‹œ๋ณด๋“œ/UX)

Oracle DB ํ—ฌ์Šค์ฒดํฌ ์›Œ์ปค ์ ์œ  ํ•ด์†Œ (์†Œ์Šค ์„ ํƒ๊ธฐ ๋ฉˆ์ถค ์›์ธ)

  • OracleDbHealthIndicator ๊ฐ€ ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค timeout ์—†๋Š” DriverManager.getConnection() ๋กœ Tomcat ์›Œ์ปค ์Šค๋ ˆ๋“œ๋ฅผ 80์ดˆ์”ฉ ์ ์œ ํ•˜๋˜ ๋ฒ„๊ทธ
  • oracle.net.CONNECT_TIMEOUT=3s + oracle.jdbc.ReadTimeout=3s + DriverManager.setLoginTimeout(3) ์œผ๋กœ ๋น ๋ฅธ ์‹คํŒจ ๋ณด์žฅ
  • ๊ฒฐ๊ณผ ์บ์‹ฑ (TTL 60์ดˆ) โ€” ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค connection ์žฌ์ƒ์„ฑ X
  • HarnessCacheService ์˜ ๋‘ Oracle connection (DB ๊ฐ์ฒด ๋ชฉ๋ก/์†Œ์Šค ์กฐํšŒ) ํ˜ธ์ถœ๋„ ๋™์ผ timeout ์ ์šฉ โ€” openOracleConnection() ํ—ฌํผ๋กœ ์ถ”์ถœ
  • application.yml ์— management.endpoint.health.cache.time-to-live: 30s โ€” Spring Actuator ์ž์ฒด ์บ์‹ฑ (์ด์ค‘ ๋ฐฉ์–ด)

์ฝ”๋“œ ๋ฆฌ๋ทฐ ํ•˜๋„ค์Šค 4๋‹จ๊ณ„ ํƒญ ๋ถ„๋ฆฌ

  • HarnessReviewService.analyzeStream() ์ด ๋‹จ๊ณ„ ์‹œ์ž‘ ์ง์ „ sentinel ๋งˆ์ปค [[HARNESS_STAGE:N]] emit (Reviewer/Verifier ๊ฐ€ ๊ฐ๊ฐ 4 sub-section ์„ ๊ฐ€์ ธ ๋‹จ์ˆœ ํ—ค๋” ๋งค์นญ์œผ๋ก  ๋ถˆ์•ˆ์ •)
  • SseStreamController ๊ฐ€ ์ด๋ ฅ ์ €์žฅ ์‹œ ๋งˆ์ปค๋Š” ์ •๊ทœ์‹์œผ๋กœ ์ œ๊ฑฐ โ€” DB ์—๋Š” ๊น”๋”ํ•œ ๋งˆํฌ๋‹ค์šด๋งŒ ์ €์žฅ
  • CodeReviewPage ์ „๋ฉด ์žฌ์ž‘์„ฑ: 5๊ฐœ ํƒญ (1.๋ถ„์„/2.๊ฐœ์„ ์ฝ”๋“œ/3.๊ฒ€ํ† /4.๊ฒ€์ฆ/์ „์ฒด๊ฒฐ๊ณผ)
  • ์ฒญํฌ ํŒŒ์„œ processChunk() โ€” ๋งˆ์ปค๊ฐ€ chunk ๊ฒฝ๊ณ„์— ๊ฑธ์น˜๋Š” ์ผ€์ด์Šค ๋ฐฉ์–ด (accumRef ๋ˆ„์  + ๋งˆ์ง€๋ง‰ 24์ž ๋ณด๋ฅ˜)
  • ํ™œ์„ฑ ์ŠคํŠธ๋ฆฌ๋ฐ ๋‹จ๊ณ„ ์ž๋™ ํƒญ ์ „ํ™˜ + spinner ์ธ๋””์ผ€์ดํ„ฐ
  • ํƒญ๋ณ„ [๋ณต์‚ฌ / MD / PDF / ์ด๋ฉ”์ผ] ๋ฏธ๋‹ˆ๋ฒ„ํŠผ 4์ข… + '์ „์ฒด ๊ฒฐ๊ณผ' ํƒญ์€ 4๋‹จ๊ณ„ ํ•ฉ๋ณธ

๋ฆฌ๋ทฐ ์ด๋ ฅ ๋Œ€์‹œ๋ณด๋“œ ๊ถŒํ•œ ํ†ตํ•ฉ (3๊ณณ ๋“ฑ๋ก ๋ˆ„๋ฝ)

  • AdminPermissionController.FEATURES ์— review-dashboard ์ถ”๊ฐ€
  • PermissionInterceptor.FEATURE_PATHS ์— ๋งคํ•‘ ์ถ”๊ฐ€
  • sidebarMenus.ts ๋ฉ”๋‰ด ํ•ญ๋ชฉ์— featureKey: 'review-dashboard' ๋ถ€์—ฌ โ†’ ํ† ๊ธ€ OFF ์‹œ ์‚ฌ์ด๋“œ๋ฐ” ์ž๋™ ์ˆจ๊น€

๊ธฐํƒ€ UX ๋ฒ„๊ทธ ์ˆ˜์ •

  • RegexPage ์˜ˆ์‹œ ์นฉ์ด navigator.clipboard.writeText ๋งŒ ํ˜ธ์ถœํ•ด์„œ HTTP IP ํ™˜๊ฒฝ์—์„œ silent ์‹คํŒจ โ†’ AnalysisPageTemplate.inputExamples prop ์‹ ๊ทœ, ํด๋ฆญ ์‹œ setInput() ์œผ๋กœ textarea ์ฆ‰์‹œ ์ฑ„์›€
  • ์ •๊ทœ์‹ ์ƒ์„ฑ๊ธฐ์˜ 8๊ฐœ ์˜ˆ์‹œ (ํ•ธ๋“œํฐ/์ฃผ๋ฏผ/์ด๋ฉ”์ผ/์ฃผ์†Œ/์ด๋ฆ„/IP/URL/๋‚ ์งœ) ๊ฐ€ ์ด์ œ ํ•œ ๋ฒˆ ํด๋ฆญ์— ์ž…๋ ฅ์นธ์— ๋“ค์–ด๊ฐ

โœ… v4.2.7 โ€” ํ˜„์‹ค ๋ฒ„๊ทธ ์ •๋ฆฌ + ๋ณด์•ˆ ๊ฐ•ํ™” + ์šด์˜ ํŽธ์˜์„ฑ

์ด๋ฒˆ ๋ผ์šด๋“œ๋Š” ์‚ฌ์šฉ ์ค‘ ๋ˆ„์ ๋œ ํ˜„์‹ค ๋ฒ„๊ทธ๋ฅผ ํ›‘์–ด ๋‚ด๊ณ , ๋ฏธ๋ฌ˜ํ•˜๊ฒŒ ๊ตฌ๋ฉ์ด ๋‚˜ ์žˆ๋˜ ๊ถŒํ•œ ์ฒดํฌ๋ฅผ ์ „๋ฐ˜์ ์œผ๋กœ ์กฐ์—ฌ๋‚ธ ์šด์˜ ํ’ˆ์งˆ ๋ผ์šด๋“œ์ž…๋‹ˆ๋‹ค. 5๊ฐœ ๋‹จ๊ณ„(Phase 1~4) ๋กœ ๋‚˜๋ˆ  ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

Phase 1 โ€” ๋ฒ„๊ทธ & ๋ณด์•ˆ

  • /api/v1/admin/** ์—ญํ•  ๊ฒŒ์ดํŒ… ๋ˆ„๋ฝ ์ˆ˜์ • โ€” /admin/** ๊ทœ์น™์ด /api/v1/admin/** ๋ฅผ ๋งค์นญํ•˜์ง€ ๋ชปํ•ด VIEWER/REVIEWER ๋„ ๊ด€๋ฆฌ์ž API ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋˜ ๊ตฌ๋ฉ์„ SecurityConfig ์— .hasRole("ADMIN") ์œผ๋กœ ์ฐจ๋‹จ
  • FavoriteController.delete ์†Œ์œ ์ž ์ฒดํฌ ์ถ”๊ฐ€ โ€” ๊ธฐ์กด์—” ๋ˆ„๊ตฌ๋“  ๋‚จ์˜ ์ฆ๊ฒจ์ฐพ๊ธฐ๋ฅผ ์ง€์šธ ์ˆ˜ ์žˆ์—ˆ์Œ. ๋ณธ์ธ ์†Œ์œ  ์•„๋‹ˆ๋ฉด HTTP 403 + JSON ์‘๋‹ต์œผ๋กœ ๋ณ€๊ฒฝ
  • /favorites/star ์ค‘๋ณต ์ €์žฅ ๋ฐฉ์ง€ โ€” FavoriteRepository.findByUsernameAndHistoryId + FavoriteService.save() ์—์„œ ๊ธฐ์กด ๋ ˆ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๋กœ์ง
  • ReviewCommentController.deleteComment ์ฃผ์„๊ณผ ๊ตฌํ˜„ ๋ถˆ์ผ์น˜ ์ˆ˜์ • โ€” ์ฃผ์„์—” "๋ณธ์ธ ๋˜๋Š” ADMIN" ์ด๋ผ ์ ํ˜€์žˆ์—ˆ์ง€๋งŒ ์‹ค์ œ๋ก  ๋ณธ์ธ๋งŒ ๊ฐ€๋Šฅํ–ˆ๋˜ ๋ฒ„๊ทธ. HttpServletRequest.isUserInRole("ADMIN") ๋กœ ADMIN ํ—ˆ์šฉ
  • ์•Œ๋ฆผ SSE onerror fallback ํด๋ง ์ง€์†ํ™” โ€” ๊ธฐ์กด์—” setTimeout 1ํšŒ๋งŒ ๋Œ๊ณ  ์˜์›ํžˆ ๋ฉˆ์ถฐ์„œ ์ข… ์•„์ด์ฝ˜ ์นด์šดํŠธ๊ฐ€ ๋ณต๊ตฌ๋˜์ง€ ์•Š๋˜ ๋ฒ„๊ทธ. setInterval ๊ธฐ๋ฐ˜ ์ง€์† ํด๋ง + ์ฃผ๊ธฐ์  SSE ์žฌ์—ฐ๊ฒฐ ์‹œ๋„๋กœ ์ „ํ™˜
  • toggleFavorite ์—ฐ์† ํด๋ฆญ ๊ฒฝํ•ฉ ๊ฐ€๋“œ โ€” togglingIdsRef: Set<number> ๋กœ ๋™์ผ historyId ์— ๋Œ€ํ•œ ์ค‘๋ณต ์š”์ฒญ ์ฐจ๋‹จ
  • CSRF ์ „์ˆ˜ ์ ๊ฒ€ ์™„๋ฃŒ โ€” SecurityConfig.ignoringAntMatchers ์— ์ด๋ฒˆ ์„ธ์…˜์˜ ๋ชจ๋“  state-changing ๊ฒฝ๋กœ๊ฐ€ ์ด๋ฏธ ํฌํ•จ๋ผ ์žˆ์Œ์„ ํ™•์ธ

Phase 2 โ€” UX ๊ณต๋ฐฑ

  • ๋Œ“๊ธ€ @username ๋ฉ˜์…˜ ์‹œ๊ฐ ๊ฐ•์กฐ โ€” renderCommentContent() ๊ฐ€ ๋ณธ๋ฌธ์„ ์ˆœํšŒํ•˜๋ฉฐ ๋ฉ˜์…˜ ํ† ํฐ์„ accent ๋ฐฐ์ง€๋กœ ๋ Œ๋”
  • HistoryPage ๋‹ค์ค‘ ์„ ํƒ ์‚ญ์ œ โ€” "์„ ํƒ N๊ฑด ์‚ญ์ œ" ๋ฒ„ํŠผ (canDelete ์กฐ๊ฑด๋ถ€), Promise.all ๋กœ ๋ณ‘๋ ฌ DELETE, ์„ฑ๊ณต/์‹คํŒจ ๊ฐœ์ˆ˜ ํ† ์ŠคํŠธ ๋ถ„๋ฆฌ
  • FavoritesPage ์ „๋ฉด ์—…๊ทธ๋ ˆ์ด๋“œ โ€” ๊ฒ€์ƒ‰, ์ „์ฒด์„ ํƒ, ๋‹ค์ค‘ ๋‚ด๋ณด๋‚ด๊ธฐ, ๋‹ค์ค‘ ์‚ญ์ œ, ์„ ํƒ ํ•˜์ด๋ผ์ดํŠธ, ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์—†์Œ ๋ถ„๊ธฐ. HistoryPage ์™€ ๋™์ผํ•œ ํŒจํ„ด ์ด์‹
  • ์•Œ๋ฆผ "์ „์ฒด ์‚ญ์ œ" โ€” NotificationRepository.deleteAllByRecipientUsername + POST /notifications/delete-all + ๋“œ๋กญ๋‹ค์šด ํ—ค๋” ๋นจ๊ฐ• ๋ฒ„ํŠผ
  • ๋ชจ๋‹ฌ fade ์• ๋‹ˆ๋ฉ”์ด์…˜ โ€” theme.css ์— modal-overlay-in / modal-body-in keyframe ์ถ”๊ฐ€, ReviewActionDialog + ๋ฆฌ๋ทฐ ์ƒ์„ธ ๋ชจ๋‹ฌ์— ์ ์šฉ

Phase 3 โ€” ์ฝ”๋“œ ํ’ˆ์งˆ & ์„ฑ๋Šฅ

  • utils/date.ts ๊ณตํ†ต ์ถ”์ถœ โ€” formatDate / formatRelative. HistoryPage, ReviewRequestsPage ์˜ ์ค‘๋ณต ํ•จ์ˆ˜ ์ œ๊ฑฐ
  • utils/harnessMarkdown.tsx ์ถ”์ถœ โ€” normalizeBuilderSection / harnessMdComponents / flattenChildren ์„ CodeReviewPage.tsx ์—์„œ ๋ถ„๋ฆฌ โ†’ ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒํƒœ/์ŠคํŠธ๋ฆฌ๋ฐ orchestration ์— ์ง‘์ค‘
  • toolkit.history.max / toolkit.favorites.max ์„ค์ • ์™ธ๋ถ€ํ™” โ€” application.yml + @Value ์ฃผ์ž…. ๊ธฐ๋ณธ๊ฐ’ ์ƒํ–ฅ (history 100โ†’200, favorites 200โ†’500). ํ™˜๊ฒฝ๋ณ€์ˆ˜ TOOLKIT_HISTORY_MAX / TOOLKIT_FAVORITES_MAX ๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ
  • /api/v1/history ยท /api/v1/favorites ํŽ˜์ด์ง€๋„ค์ด์…˜ โ€” ?page=&size= ํŒŒ๋ผ๋ฏธํ„ฐ, X-Total-Count / X-Has-More / X-Page / X-Page-Size ์‘๋‹ต ํ—ค๋”. ๊ธฐ์กด ํ”„๋ก ํŠธ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ๋žตํ•˜๋ฉด backward-compatible
  • ํ”„๋ก ํŠธ "๋” ๋ณด๊ธฐ" ๋ฒ„ํŠผ โ€” HistoryPage / FavoritesPage ์— PAGE_SIZE=50 ๊ธฐ๋ฐ˜ load-more UX

Phase 4 โ€” ๋ฌธ์„œ/๋ฆด๋ฆฌ์ฆˆ

  • README v4.2.6 โ†’ v4.2.7 ๋ฒ„์ „ ๋ฐฐ์ง€ + v4.2.7 ์„น์…˜ ์ถ”๊ฐ€
  • CHANGELOG.md ์‹ ์„ค โ€” Keep a Changelog ํฌ๋งท์œผ๋กœ v4.0 ~ v4.2 ๋ฆด๋ฆฌ์ฆˆ ์ •๋ฆฌ

Phase 5.2 โ€” ์ƒ๋Œ€ ์‹œ๊ฐ„ ํ‘œ์‹œ

  • utils/date.ts ์˜ formatRelative() ๋ฅผ 3๊ฐœ ๊ฒฝ๋กœ์— ์ ์šฉ: ๋Œ“๊ธ€(CommentBox), ์•Œ๋ฆผ ๋“œ๋กญ๋‹ค์šด(TopBar), ์ด๋ ฅ ์นด๋“œ(HistoryPage)
  • ํ‘œ๊ธฐ ์˜ˆ์‹œ: "๋ฐฉ๊ธˆ", "5๋ถ„ ์ „", "2์‹œ๊ฐ„ ์ „", "์–ด์ œ", "3์ผ ์ „", 7์ผ ์ดˆ๊ณผ์‹œ ์ ˆ๋Œ€ ์‹œ๊ฐ
  • hover ์‹œ title ์†์„ฑ์œผ๋กœ ์›๋ณธ ์ ˆ๋Œ€ ์‹œ๊ฐ ๋…ธ์ถœ (์ •๋ฐ€ ํ™•์ธ ๊ฐ€๋Šฅ)
  • ๋ฐฑ์—”๋“œ ReviewCommentController / NotificationController ์‘๋‹ต์— createdAtIso ํ•„๋“œ ์ถ”๊ฐ€ โ€” ๊ธฐ์กด pre-formatted createdAt ์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฉฐ ํ”„๋ก ํŠธ๊ฐ€ ์ƒ๋Œ€ ์‹œ๊ฐ„ ๊ณ„์‚ฐ์šฉ ์›๋ณธ ISO ๋ฅผ ํ•จ๊ป˜ ๋ฐ›๋„๋ก ํ™•์žฅ

Phase 6 โ€” ํ…Œ์ŠคํŠธ ์ธํ”„๋ผ (ํšŒ๊ท€ ๋ฐฉ์ง€ ์•ˆ์ „๋ง)

  • spring-security-test ์˜์กด์„ฑ ์ถ”๊ฐ€ (pom.xml)
  • src/test/resources/application-test.yml โ€” H2 in-memory ๊ฒฉ๋ฆฌ ํ”„๋กœํŒŒ์ผ
  • JUnit ์Šค๋ชจํฌ ํ…Œ์ŠคํŠธ 16๊ฐœ ์ „๋ถ€ green โ€” src/test/java/.../smoke/ - MentionPatternTest (8) โ€” ๋ฉ˜์…˜ ์ •๊ทœ์‹ ํšŒ๊ท€ ๋ฐฉ์ง€ (์ด๋ฉ”์ผ ์ œ์™ธ, ๋‹ค์ค‘ ๋ฉ˜์…˜, ํ† ํฐ ๋ฌธ์ž _/./-, ํ•œ๊ธ€ ๊ฒฝ๊ณ„ ๋“ฑ) - SecuritySmokeTests (7) โ€” @SpringBootTest + MockMvc + @WithMockUser ๋กœ Phase 1 ์˜ ๋ชจ๋“  ๊ถŒํ•œ ๊ฒฝ๋กœ ๊ฒ€์ฆ (VIEWER/REVIEWER/ADMIN ร— admin API ร— history ์‚ญ์ œ) - FavoriteDedupSmokeTest (1) โ€” FavoriteService.save ์ค‘๋ณต ๋ฐฉ์ง€ ํ†ตํ•ฉ ๊ฒ€์ฆ
  • Playwright E2E ํ™•์žฅ โ€” frontend/e2e/app.spec.ts ์— 4๊ฐœ ์ถ”๊ฐ€ ํ…Œ์ŠคํŠธ green - utils/date ์ˆœ์ˆ˜ ๋กœ์ง ๋ธŒ๋ผ์šฐ์ € ๊ฒ€์ฆ (7 ์ผ€์ด์Šค) - @๋ฉ˜์…˜ ์ •๊ทœ์‹ ๋ธŒ๋ผ์šฐ์ € ๊ฒ€์ฆ (4 ์ผ€์ด์Šค) - ๋ผ์šฐํŠธ ๋กœ๋“œ ์ฒดํฌ์— v4.2.7 ์‹ ๊ทœ ๊ฒฝ๋กœ ํฌํ•จ (/favorites, /review-requests, /harness, ?historyId=42 ๋”ฅ๋งํฌ)
  • ํ–ฅํ›„ ๋ฆฌํŒฉํ„ฐ๋ง์‹œ ์ด ํ…Œ์ŠคํŠธ๋“ค์ด ์ž๋™์œผ๋กœ Phase 1 ๋ณด์•ˆ ํšŒ๊ท€๋ฅผ ์žก์•„๋ƒ„

๊ธฐํƒ€ (์„ธ์…˜ ์ค‘ ํ•จ๊ป˜ ์ฒ˜๋ฆฌ๋œ ํ•ญ๋ชฉ)

  • VIEWER ๊ถŒํ•œ์ด ์ƒ์„ฑํ•œ ๋ฆฌ๋ทฐ ์ด๋ ฅ โ†’ REVIEWER/ADMIN ์ „์› "๋Œ€๊ธฐ ์•Œ๋ฆผ" โ€” PendingReviewNotifier ์‹ ์„ค, ReviewHistoryService / SseStreamController / PipelineExecutor 4๊ฐœ ์ €์žฅ ๊ฒฝ๋กœ ๋ชจ๋‘ ํ›…ํ‚น
  • ๋Œ“๊ธ€ @๋ฉ˜์…˜ โ†’ ์•Œ๋ฆผ ๋ฐœํ–‰ โ€” MENTION_PATTERN + AppUserRepository ์กด์žฌ ๊ฒ€์ฆ + Notification(type="MENTION")
  • /api/v1/users/mentions ์—”๋“œํฌ์ธํŠธ โ€” ๋ฉ˜์…˜ ์ž๋™์™„์„ฑ ํ›„๋ณด (๋ชจ๋“  ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž ์ ‘๊ทผ ๊ฐ€๋Šฅ, ๋ฏผ๊ฐํ•„๋“œ ์ œ์™ธ)
  • MentionInput.tsx ๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ โ€” @ ํŠธ๋ฆฌ๊ฑฐ ๋“œ๋กญ๋‹ค์šด, ArrowUp/Down, Enter/Tab ์‚ฝ์ž…, Escape, ์ด๋ฉ”์ผ a@b.com ์€ ๋ฉ˜์…˜ ์•„๋‹Œ ๊ฒƒ์œผ๋กœ ํŒ์ •
  • ์ด๋ ฅ ์ƒ์„ธ ๋ชจ๋‹ฌ โ€” ๋ฆฌ๋ทฐ ์š”์ฒญ ํŽ˜์ด์ง€์—์„œ VIEWER ์ž‘์„ฑ ๋ณธ๋ฌธ์„ ํŒ์—…์œผ๋กœ ํ™•์ธ + ๋ชจ๋‹ฌ ๋‚ด์—์„œ ์Šน์ธ/๊ฑฐ์ ˆ ๊ฐ€๋Šฅ
  • ReviewActionDialog ๊ณต์šฉ ๋‹ค์ด์–ผ๋กœ๊ทธ โ€” ์Šน์ธ/๊ฑฐ์ ˆ ํ™•์ •์‹œ ์„ ํƒ ์ฝ”๋ฉ˜ํŠธ ์ž…๋ ฅ, Ctrl+Enter / Esc ๋‹จ์ถ•ํ‚ค, ReviewNoteCard ๋กœ ๋ชจ๋“  ๊ถŒํ•œ์— ํ”ผ๋“œ๋ฐฑ ํ‘œ์‹œ
  • Favorite ์—”ํ‹ฐํ‹ฐ username / historyId ์ปฌ๋Ÿผ ์ถ”๊ฐ€ โ€” ๊ธฐ์กด ํ•„ํ„ฐ ์ฟผ๋ฆฌ๊ฐ€ NULL ์กฐ๊ฑด์œผ๋กœ ๋นˆ ๋ฐฐ์—ด๋งŒ ๋Œ๋ ค์ฃผ๋˜ ์น˜๋ช…์  ๋ฒ„๊ทธ ์ˆ˜์ •
  • ์•Œ๋ฆผ ๊ฐœ๋ณ„ ์‚ญ์ œ โ€” ๋“œ๋กญ๋‹ค์šด ๊ฐ ํ•ญ๋ชฉ ์šฐ์ธก ์ƒ๋‹จ X ๋ฒ„ํŠผ + POST /notifications/{id}/delete
  • OracleDbHealthIndicator ์ „๋ฉด ์žฌ์ž‘์„ฑ โ€” @PostConstruct + @Scheduled(1h) ๋กœ ํ”„๋กœ๋ธŒ๋ฅผ health() ํ˜ธ์ถœ๊ณผ ์™„์ „ ๋ถ„๋ฆฌ. Tomcat ์›Œ์ปค ์Šค๋ ˆ๋“œ ์ ์œ  ์ œ๊ฑฐ
  • HarnessCacheService.initOnStartup() @PostConstruct ์ „ํ™˜ โ€” Spring ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™” ๋‹จ๊ณ„์—์„œ ์ธ๋ผ์ธ ์‹คํ–‰ํ•˜์—ฌ WAS ๊ฐ€ ์š”์ฒญ์„ ๋ฐ›๊ธฐ ์‹œ์ž‘ํ•  ๋•Œ ์ด๋ฏธ ํ”„๋กœ์ ํŠธ ํŒŒ์ผ / DB ์˜ค๋ธŒ์ ํŠธ ์บ์‹œ๊ฐ€ ๋กœ๋“œ๋œ ์ƒํƒœ ๋ณด์žฅ
  • Dockerfile ๋นŒ๋“œ ๋กœ๊ทธ ์ •๋ฆฌ โ€” dependency:go-offline ์‹คํŒจ ๋กœ๊ทธ๋ฅผ >/dev/null 2>&1 ๋กœ ์™„์ „ ๋ฌต์Œ ์ฒ˜๋ฆฌ + ์ด์œ  ์ฃผ์„
  • ํ•˜๋„ค์Šค "๊ฐœ์„  ์ฝ”๋“œ" ํƒญ "sql" ๋ผ๋ฒจ ๋ผ์ธ ์ œ๊ฑฐ โ€” Claude Builder ๊ฐ€ ํ”„๋กฌํ”„ํŠธ ์˜ˆ์‹œ๋ฅผ ๋”ฐ๋ผ ์ฒซ ์ค„์— sql ์„ ๋ฑ‰๋˜ ์ฆ์ƒ์„ ํ”„๋ก ํŠธ ์ •๊ทœ์‹์œผ๋กœ clean up
  • VIEWER ๊ถŒํ•œ์€ ์ด๋ ฅ ์‚ญ์ œ ์•„์ด์ฝ˜ ๋…ธ์ถœ ์ž์ฒด๋ฅผ ์ œ์™ธ + ๋ฐฑ์—”๋“œ ReviewHistoryController.delete ์—์„œ๋„ isUserInRole ์ฒดํฌ๋กœ 403 ๋ฐ˜ํ™˜

๐Ÿค ๊ธฐ์—ฌ

PR๊ณผ Issue๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค! ๊ธฐ์—ฌ ๊ฐ€์ด๋“œ: CONTRIBUTING.md


๐Ÿ“„ ๋ผ์ด์„ ์Šค

Apache License 2.0

About

AI-powered tools for Oracle DB & Java/Spring enterprise development

Resources

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors