backend-claude-code 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.claude/settings.json +42 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +35 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +33 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +32 -0
  5. package/.mcp.json +19 -0
  6. package/CLAUDE.md +126 -0
  7. package/README.md +142 -0
  8. package/agents/code-reviewer.md +84 -0
  9. package/agents/database-reviewer.md +91 -0
  10. package/agents/java-build-resolver.md +127 -0
  11. package/agents/java-performance-reviewer.md +262 -0
  12. package/agents/planner.md +99 -0
  13. package/agents/security-reviewer.md +119 -0
  14. package/agents/tdd-guide.md +189 -0
  15. package/bin/cli.js +144 -0
  16. package/commands/db-migrate.md +134 -0
  17. package/commands/dev-build.md +72 -0
  18. package/commands/dev-coverage.md +73 -0
  19. package/commands/dev-fix.md +75 -0
  20. package/commands/dev-plan.md +501 -0
  21. package/commands/dev-review.md +144 -0
  22. package/commands/dev-run.md +385 -0
  23. package/commands/dev-test.md +89 -0
  24. package/commands/dev-verify.md +95 -0
  25. package/commands/dev.md +45 -0
  26. package/commands/git-commit.md +112 -0
  27. package/commands/git-issue.md +74 -0
  28. package/commands/git-pr.md +184 -0
  29. package/commands/git-push.md +28 -0
  30. package/package.json +24 -0
  31. package/rules/architecture.md +33 -0
  32. package/rules/coding-style.md +113 -0
  33. package/rules/controller-patterns.md +63 -0
  34. package/rules/dto-patterns.md +76 -0
  35. package/rules/entity-patterns.md +70 -0
  36. package/rules/error-handling.md +56 -0
  37. package/rules/hooks.md +73 -0
  38. package/rules/repository-patterns.md +75 -0
  39. package/rules/security.md +101 -0
  40. package/rules/service-patterns.md +70 -0
  41. package/rules/testing.md +174 -0
  42. package/skills/api-design/SKILL.md +523 -0
  43. package/skills/architecture-decision-records/SKILL.md +179 -0
  44. package/skills/database-migrations/SKILL.md +429 -0
  45. package/skills/hexagonal-architecture/SKILL.md +276 -0
  46. package/skills/java-coding-standards/SKILL.md +236 -0
  47. package/skills/jpa-patterns/SKILL.md +218 -0
  48. package/skills/postgres-patterns/SKILL.md +147 -0
  49. package/skills/springboot-patterns/SKILL.md +255 -0
  50. package/skills/springboot-security/SKILL.md +241 -0
  51. package/skills/springboot-tdd/SKILL.md +236 -0
@@ -0,0 +1,112 @@
1
+ ---
2
+ description: "Quick commit with natural language file targeting — describe what to commit in plain English"
3
+ argument-hint: "[target description] (blank = all changes)"
4
+ ---
5
+
6
+ # Smart Commit
7
+
8
+ > Adapted from PRPs-agentic-eng by Wirasm. Part of the PRP workflow series.
9
+
10
+ **Input**: $ARGUMENTS
11
+
12
+ ---
13
+
14
+ ## Phase 1 — ASSESS
15
+
16
+ ```bash
17
+ git status --short
18
+ ```
19
+
20
+ If output is empty → stop: "Nothing to commit."
21
+
22
+ Show the user a summary of what's changed (added, modified, deleted, untracked).
23
+
24
+ ---
25
+
26
+ ## Phase 2 — INTERPRET & STAGE
27
+
28
+ Interpret `$ARGUMENTS` to determine what to stage:
29
+
30
+ | Input | Interpretation | Git Command |
31
+ |---|---|---|
32
+ | *(blank / empty)* | Stage everything | `git add -A` |
33
+ | `staged` | Use whatever is already staged | *(no git add)* |
34
+ | `*.ts` or `*.py` etc. | Stage matching glob | `git add '*.ts'` |
35
+ | `except tests` | Stage all, then unstage tests | `git add -A && git reset -- '**/*.test.*' '**/*.spec.*' '**/test_*' 2>/dev/null \|\| true` |
36
+ | `only new files` | Stage untracked files only | `git ls-files --others --exclude-standard \| grep . && git ls-files --others --exclude-standard \| xargs git add` |
37
+ | `the auth changes` | Interpret from status/diff — find auth-related files | `git add <matched files>` |
38
+ | Specific filenames | Stage those files | `git add <files>` |
39
+
40
+ For natural language inputs (like "the auth changes"), cross-reference the `git status` output and `git diff` to identify relevant files. Show the user which files you're staging and why.
41
+
42
+ ```bash
43
+ git add <determined files>
44
+ ```
45
+
46
+ After staging, verify:
47
+ ```bash
48
+ git diff --cached --stat
49
+ ```
50
+
51
+ If nothing staged, stop: "No files matched your description."
52
+
53
+ ---
54
+
55
+ ## Phase 3 — COMMIT
56
+
57
+ Craft a single-line commit message in imperative mood:
58
+
59
+ ```
60
+ {type}: {description}
61
+ ```
62
+
63
+ Types:
64
+ - `feat` — New feature or capability
65
+ - `fix` — Bug fix
66
+ - `refactor` — Code restructuring without behavior change
67
+ - `docs` — Documentation changes
68
+ - `test` — Adding or updating tests
69
+ - `chore` — Build, config, dependencies
70
+ - `perf` — Performance improvement
71
+ - `ci` — CI/CD changes
72
+
73
+ Rules:
74
+ - Imperative mood ("add feature" not "added feature")
75
+ - Lowercase after the type prefix
76
+ - No period at the end
77
+ - Under 72 characters
78
+ - Describe WHAT changed, not HOW
79
+
80
+ ```bash
81
+ git commit -m "{type}: {description}"
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Phase 4 — OUTPUT
87
+
88
+ Report to user:
89
+
90
+ ```
91
+ Committed: {hash_short}
92
+ Message: {type}: {description}
93
+ Files: {count} file(s) changed
94
+
95
+ Next steps:
96
+ - git push → push to remote
97
+ - /git pr → create a pull request
98
+ - /code-review → review before pushing
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Examples
104
+
105
+ | You say | What happens |
106
+ |---|---|
107
+ | `/git commit` | Stages all, auto-generates message |
108
+ | `/git commit staged` | Commits only what's already staged |
109
+ | `/git commit *.ts` | Stages all TypeScript files, commits |
110
+ | `/git commit except tests` | Stages everything except test files |
111
+ | `/git commit the database migration` | Finds DB migration files from status, stages them |
112
+ | `/git commit only new files` | Stages untracked files only |
@@ -0,0 +1,74 @@
1
+ ---
2
+ description: GitHub 이슈 생성 — bug_report 또는 feature_request 템플릿으로 이슈를 만든다
3
+ argument-hint: [bug | feat] <제목>
4
+ ---
5
+
6
+ # Create Issue
7
+
8
+ GitHub 이슈를 생성합니다.
9
+
10
+ **입력**: $ARGUMENTS
11
+ - `bug <제목>` — 버그 리포트 이슈
12
+ - `feat <제목>` — 기능 요청 이슈
13
+ - 타입 생략 시 대화로 결정
14
+
15
+ ---
16
+
17
+ ## Step 1 — 타입과 제목 파악
18
+
19
+ `$ARGUMENTS`에서 첫 단어로 타입(`bug` / `feat`)을 판별하고, 나머지를 제목으로 사용한다.
20
+ 둘 다 없으면 사용자에게 타입과 제목을 묻는다.
21
+
22
+ ## Step 2 — 내용 작성
23
+
24
+ 현재 컨텍스트(변경된 파일, 오류 메시지, 대화 내용)를 바탕으로 이슈 본문을 작성한다.
25
+
26
+ **bug** 인 경우:
27
+ ```
28
+ ## 버그 설명
29
+ <현상 요약>
30
+
31
+ ## 재현 절차
32
+ 1.
33
+ 2.
34
+
35
+ ## 기대 동작
36
+ <기대값>
37
+
38
+ ## 실제 동작
39
+ <실제값>
40
+
41
+ ## 로그 / 스택 트레이스
42
+ <관련 로그>
43
+
44
+ ## 환경
45
+ - Spring Boot 버전:
46
+ - Java 버전:
47
+ ```
48
+
49
+ **feat** 인 경우:
50
+ ```
51
+ ## 목적
52
+ <왜 필요한지>
53
+
54
+ ## 도메인 / 레이어
55
+ - [ ] Controller / Service / Repository / Domain / 인프라
56
+
57
+ ## 제안하는 해결책
58
+ <구현 방향>
59
+
60
+ ## 인수 조건
61
+ - [ ]
62
+ - [ ]
63
+ ```
64
+
65
+ ## Step 3 — 이슈 생성
66
+
67
+ ```bash
68
+ gh issue create \
69
+ --title "<제목>" \
70
+ --body "<본문>" \
71
+ --label "<bug|enhancement>"
72
+ ```
73
+
74
+ 생성된 이슈 URL을 출력한다.
@@ -0,0 +1,184 @@
1
+ ---
2
+ description: "Create a GitHub PR from current branch with unpushed commits — discovers templates, analyzes changes, pushes"
3
+ argument-hint: "[base-branch] (default: main)"
4
+ ---
5
+
6
+ # Create Pull Request
7
+
8
+ > Adapted from PRPs-agentic-eng by Wirasm. Part of the PRP workflow series.
9
+
10
+ **Input**: `$ARGUMENTS` — optional, may contain a base branch name and/or flags (e.g., `--draft`).
11
+
12
+ **Parse `$ARGUMENTS`**:
13
+ - Extract any recognized flags (`--draft`)
14
+ - Treat remaining non-flag text as the base branch name
15
+ - Default base branch to `main` if none specified
16
+
17
+ ---
18
+
19
+ ## Phase 1 — VALIDATE
20
+
21
+ Check preconditions:
22
+
23
+ ```bash
24
+ git branch --show-current
25
+ git status --short
26
+ git log origin/<base>..HEAD --oneline
27
+ ```
28
+
29
+ | Check | Condition | Action if Failed |
30
+ |---|---|---|
31
+ | Not on base branch | Current branch ≠ base | Stop: "Switch to a feature branch first." |
32
+ | Clean working directory | No uncommitted changes | Warn: "You have uncommitted changes. Commit or stash first. Use `/git commit` to commit." |
33
+ | Has commits ahead | `git log origin/<base>..HEAD` not empty | Stop: "No commits ahead of `<base>`. Nothing to PR." |
34
+ | No existing PR | `gh pr list --head <branch> --json number` is empty | Stop: "PR already exists: #<number>. Use `gh pr view <number> --web` to open it." |
35
+
36
+ If all checks pass, proceed.
37
+
38
+ ---
39
+
40
+ ## Phase 2 — DISCOVER
41
+
42
+ ### PR Template
43
+
44
+ Search for PR template in order:
45
+
46
+ 1. `.github/PULL_REQUEST_TEMPLATE/` directory — if exists, list files and let user choose (or use `default.md`)
47
+ 2. `.github/PULL_REQUEST_TEMPLATE.md`
48
+ 3. `.github/pull_request_template.md`
49
+ 4. `docs/pull_request_template.md`
50
+
51
+ If found, read it and use its structure for the PR body.
52
+
53
+ ### Commit Analysis
54
+
55
+ ```bash
56
+ git log origin/<base>..HEAD --format="%h %s" --reverse
57
+ ```
58
+
59
+ Analyze commits to determine:
60
+ - **PR title**: Use conventional commit format with type prefix — `feat: ...`, `fix: ...`, etc.
61
+ - If multiple types, use the dominant one
62
+ - If single commit, use its message as-is
63
+ - **Change summary**: Group commits by type/area
64
+
65
+ ### File Analysis
66
+
67
+ ```bash
68
+ git diff origin/<base>..HEAD --stat
69
+ git diff origin/<base>..HEAD --name-only
70
+ ```
71
+
72
+ Categorize changed files: source, tests, docs, config, migrations.
73
+
74
+ ### PRP Artifacts
75
+
76
+ Check for related PRP artifacts:
77
+ - `.claude/PRPs/reports/` — Implementation reports
78
+ - `.claude/PRPs/plans/` — Plans that were executed
79
+ - `.claude/PRPs/prds/` — Related PRDs
80
+
81
+ Reference these in the PR body if they exist.
82
+
83
+ ---
84
+
85
+ ## Phase 3 — PUSH
86
+
87
+ ```bash
88
+ git push -u origin HEAD
89
+ ```
90
+
91
+ If push fails due to divergence:
92
+ ```bash
93
+ git fetch origin
94
+ git rebase origin/<base>
95
+ git push -u origin HEAD
96
+ ```
97
+
98
+ If rebase conflicts occur, stop and inform the user.
99
+
100
+ ---
101
+
102
+ ## Phase 4 — CREATE
103
+
104
+ ### With Template
105
+
106
+ If a PR template was found in Phase 2, fill in each section using the commit and file analysis. Preserve all template sections — leave sections as "N/A" if not applicable rather than removing them.
107
+
108
+ ### Without Template
109
+
110
+ Use this default format:
111
+
112
+ ```markdown
113
+ ## Summary
114
+
115
+ <1-2 sentence description of what this PR does and why>
116
+
117
+ ## Changes
118
+
119
+ <bulleted list of changes grouped by area>
120
+
121
+ ## Files Changed
122
+
123
+ <table or list of changed files with change type: Added/Modified/Deleted>
124
+
125
+ ## Testing
126
+
127
+ <description of how changes were tested, or "Needs testing">
128
+
129
+ ## Related Issues
130
+
131
+ <linked issues with Closes/Fixes/Relates to #N, or "None">
132
+ ```
133
+
134
+ ### Create the PR
135
+
136
+ ```bash
137
+ gh pr create \
138
+ --title "<PR title>" \
139
+ --base <base-branch> \
140
+ --body "<PR body>"
141
+ # Add --draft if the --draft flag was parsed from $ARGUMENTS
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Phase 5 — VERIFY
147
+
148
+ ```bash
149
+ gh pr view --json number,url,title,state,baseRefName,headRefName,additions,deletions,changedFiles
150
+ gh pr checks --json name,status,conclusion 2>/dev/null || true
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Phase 6 — OUTPUT
156
+
157
+ Report to user:
158
+
159
+ ```
160
+ PR #<number>: <title>
161
+ URL: <url>
162
+ Branch: <head> → <base>
163
+ Changes: +<additions> -<deletions> across <changedFiles> files
164
+
165
+ CI Checks: <status summary or "pending" or "none configured">
166
+
167
+ Artifacts referenced:
168
+ - <any PRP reports/plans linked in PR body>
169
+
170
+ Next steps:
171
+ - gh pr view <number> --web → open in browser
172
+ - /code-review <number> → review the PR
173
+ - gh pr merge <number> → merge when ready
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Edge Cases
179
+
180
+ - **No `gh` CLI**: Stop with: "GitHub CLI (`gh`) is required. Install: <https://cli.github.com/>"
181
+ - **Not authenticated**: Stop with: "Run `gh auth login` first."
182
+ - **Force push needed**: If remote has diverged and rebase was done, use `git push --force-with-lease` (never `--force`).
183
+ - **Multiple PR templates**: If `.github/PULL_REQUEST_TEMPLATE/` has multiple files, list them and ask user to choose.
184
+ - **Large PR (>20 files)**: Warn about PR size. Suggest splitting if changes are logically separable.
@@ -0,0 +1,28 @@
1
+ # Git Commit & Push
2
+
3
+ 변경사항을 커밋하고 원격 저장소에 푸시합니다.
4
+
5
+ ## 실행 순서
6
+
7
+ 1. `git status`로 변경 파일 확인
8
+ 2. `git diff --staged` + `git diff`로 변경 내용 파악
9
+ 3. `git log --oneline -5`로 최근 커밋 스타일 확인
10
+ 4. 변경사항에 맞는 커밋 메시지 작성 (Semantic Commit)
11
+ 5. 관련 파일 스테이징 후 커밋
12
+ 6. 현재 브랜치로 push
13
+
14
+ ## 규칙
15
+
16
+ - 커밋 메시지는 Semantic Commit 형식 (`feat:`, `fix:`, `refactor:`, `chore:` 등)
17
+ - 서명 스킵 (`--no-verify`) 금지 — 훅 실패 시 원인 수정
18
+ - `.env`, 시크릿 파일 커밋 금지
19
+ - `git add .` 대신 파일명 지정으로 스테이징
20
+ - force push 금지
21
+ - Co-Authored-By 태그 포함:
22
+ ```
23
+ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
24
+ ```
25
+
26
+ ## 완료 기준
27
+
28
+ `git log --oneline -1`로 커밋 확인 + push 성공 메시지 확인.
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "backend-claude-code",
3
+ "version": "1.0.0",
4
+ "description": "Java/Spring Boot 프로젝트를 위한 Claude Code 설정 패키지",
5
+ "bin": {
6
+ "backend-claude-code": "./bin/cli.js"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ "agents/",
11
+ "rules/",
12
+ "commands/",
13
+ "skills/",
14
+ ".claude/",
15
+ ".mcp.json",
16
+ ".github/",
17
+ "CLAUDE.md"
18
+ ],
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "keywords": ["claude-code", "spring-boot", "java", "backend"],
23
+ "license": "MIT"
24
+ }
@@ -0,0 +1,33 @@
1
+ ---
2
+ paths:
3
+ - "**/*.java"
4
+ ---
5
+ # Architecture
6
+
7
+ Spring Boot 3.x (Jakarta namespace) 표준 레이어드 아키텍처.
8
+
9
+ ```
10
+ src/main/java/com/{company}/{app}/
11
+ ├── web/ # REST controllers (@RestController)
12
+ ├── service/ # 비즈니스 로직 (@Service, @Transactional)
13
+ ├── repository/ # JPA + QueryDSL 데이터 접근
14
+ ├── domain/
15
+ │ ├── entity/ # JPA 엔티티
16
+ │ ├── enums/ # 공유 열거형
17
+ │ └── value/ # Value objects
18
+ ├── dto/ # 요청/응답 DTO (*Dtos.java 내 static inner record)
19
+ └── global/
20
+ ├── config/ # Spring 설정
21
+ ├── security/ # 인증/인가
22
+ ├── error/ # 예외 및 핸들러
23
+ └── util/ # 공통 유틸리티
24
+ ```
25
+
26
+ ## 레이어 책임
27
+
28
+ | 레이어 | 책임 | 금지 사항 |
29
+ |--------|------|----------|
30
+ | Controller | HTTP 매핑, 입력 검증, 응답 포맷 | 비즈니스 로직 |
31
+ | Service | 비즈니스 로직, 트랜잭션 | 직접 HTTP 처리 |
32
+ | Repository | 데이터 접근, 쿼리 | 비즈니스 로직 |
33
+ | Entity | 도메인 상태 | 외부 DTO 의존 |
@@ -0,0 +1,113 @@
1
+ ---
2
+ paths:
3
+ - "**/*.java"
4
+ ---
5
+ # Java Coding Style
6
+
7
+ > This file extends [common/coding-style.md](../common/coding-style.md) with Java-specific content.
8
+
9
+ ## 포매팅
10
+
11
+ - **google-java-format** 또는 **Checkstyle** (Google 또는 Sun 스타일) 강제 적용
12
+ - 파일당 하나의 공개 최상위 타입
13
+ - 일관된 들여쓰기: 2 또는 4 스페이스 (프로젝트 표준에 맞춤)
14
+ - 멤버 순서: 상수, 필드, 생성자, 공개 메서드, protected, private
15
+
16
+ ## 불변성
17
+
18
+ - 값 타입에는 `record` 선호 (Java 16+)
19
+ - 기본적으로 필드를 `final`로 표시 — 필요한 경우에만 가변 상태 사용
20
+ - 공개 API에서 방어적 복사 반환: `List.copyOf()`, `Map.copyOf()`, `Set.copyOf()`
21
+
22
+ ```java
23
+ // GOOD — 불변 값 타입
24
+ public record OrderSummary(Long id, String customerName, BigDecimal total) {}
25
+
26
+ // GOOD — final 필드, setter 없음
27
+ public class Order {
28
+ private final Long id;
29
+ private final List<LineItem> items;
30
+
31
+ public List<LineItem> getItems() {
32
+ return List.copyOf(items);
33
+ }
34
+ }
35
+ ```
36
+
37
+ ## 명명 규칙
38
+
39
+ 표준 Java 관례 준수:
40
+ - `PascalCase` — 클래스, 인터페이스, 레코드, 열거형
41
+ - `camelCase` — 메서드, 필드, 매개변수, 지역 변수
42
+ - `SCREAMING_SNAKE_CASE` — `static final` 상수
43
+ - 패키지: 모두 소문자, 역방향 도메인 (`com.example.app.service`)
44
+
45
+ ## 모던 Java 기능
46
+
47
+ 명확성을 향상시키는 경우 모던 언어 기능 사용:
48
+ - **Records** — DTO 및 값 타입 (Java 16+)
49
+ - **Sealed classes** — 닫힌 타입 계층 (Java 17+)
50
+ - **Pattern matching** `instanceof` — 명시적 캐스트 불필요 (Java 16+)
51
+ - **Text blocks** — 여러 줄 문자열 (SQL, JSON 템플릿) (Java 15+)
52
+ - **Switch expressions** — 화살표 구문 (Java 14+)
53
+ - **Pattern matching in switch** — sealed 타입 완전 처리 (Java 21+)
54
+
55
+ ```java
56
+ // 패턴 매칭 instanceof
57
+ if (shape instanceof Circle c) {
58
+ return Math.PI * c.radius() * c.radius();
59
+ }
60
+
61
+ // Sealed 타입 계층
62
+ public sealed interface PaymentMethod permits CreditCard, BankTransfer, Wallet {}
63
+
64
+ // Switch 표현식
65
+ String label = switch (status) {
66
+ case ACTIVE -> "Active";
67
+ case SUSPENDED -> "Suspended";
68
+ case CLOSED -> "Closed";
69
+ };
70
+ ```
71
+
72
+ ## Optional 사용법
73
+
74
+ - 결과가 없을 수 있는 finder 메서드에서 `Optional<T>` 반환
75
+ - `map()`, `flatMap()`, `orElseThrow()` 사용 — `isPresent()` 없이 `get()` 절대 금지
76
+ - `Optional`을 필드 타입이나 메서드 매개변수로 사용 금지
77
+
78
+ ```java
79
+ // GOOD
80
+ return repository.findById(id)
81
+ .map(ResponseDto::from)
82
+ .orElseThrow(() -> new OrderNotFoundException(id));
83
+
84
+ // BAD — 매개변수로 Optional
85
+ public void process(Optional<String> name) {}
86
+ ```
87
+
88
+ ## 오류 처리
89
+
90
+ - 도메인 오류에는 unchecked 예외 선호
91
+ - `RuntimeException`을 확장하는 도메인별 예외 생성
92
+ - 최상위 핸들러 외에는 `catch (Exception e)` 지양
93
+ - 예외 메시지에 컨텍스트 포함
94
+
95
+ ```java
96
+ public class OrderNotFoundException extends RuntimeException {
97
+ public OrderNotFoundException(Long id) {
98
+ super("Order not found: id=" + id);
99
+ }
100
+ }
101
+ ```
102
+
103
+ ## Streams
104
+
105
+ - 변환에 스트림 사용; 파이프라인을 짧게 유지 (최대 3-4 연산)
106
+ - 가독성이 있을 때 메서드 참조 선호: `.map(Order::getTotal)`
107
+ - 스트림 연산에서 부작용 방지
108
+ - 복잡한 로직은 복잡한 스트림 파이프라인보다 루프 선호
109
+
110
+ ## 참고
111
+
112
+ skill: `java-coding-standards` — 예시가 포함된 전체 코딩 표준
113
+ skill: `jpa-patterns` — JPA/Hibernate 엔티티 설계 패턴
@@ -0,0 +1,63 @@
1
+ ---
2
+ paths:
3
+ - "**/controller/**/*.java"
4
+ - "**/web/**/*.java"
5
+ ---
6
+ # Controller 패턴
7
+
8
+ ## 클래스 구조
9
+
10
+ ```java
11
+ @RestController
12
+ @RequestMapping("/api/v1/{domain}")
13
+ @RequiredArgsConstructor
14
+ @Validated
15
+ public class FooController {
16
+ private final FooService fooService;
17
+ }
18
+ ```
19
+
20
+ ## 응답 포맷
21
+
22
+ 공통 래퍼 없이 DTO 직접 반환.
23
+
24
+ ```java
25
+ // 조회
26
+ public FooDtos.FooResponse getFoo(...) { ... }
27
+
28
+ // 생성
29
+ @ResponseStatus(HttpStatus.CREATED)
30
+ public FooDtos.FooResponse createFoo(...) { ... }
31
+
32
+ // 삭제 / 본문 없는 수정
33
+ @ResponseStatus(HttpStatus.NO_CONTENT)
34
+ public void deleteFoo(...) { ... }
35
+ ```
36
+
37
+ ## Validation
38
+
39
+ - `@Validated` 클래스 레벨 선언
40
+ - Request record 필드: `@NotBlank`, `@NotNull`, `@Positive`, `@PositiveOrZero`
41
+ - nullable 필드 조건부 검증: `@AssertTrue` 메서드로 처리
42
+
43
+ ```java
44
+ public record FooUpdateRequest(String title) {
45
+ @AssertTrue(message = "title must not be blank")
46
+ public boolean hasNonBlankTitleWhenPresent() {
47
+ return title == null || !title.isBlank();
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## 페이지네이션 파라미터
53
+
54
+ ```java
55
+ @RequestParam(defaultValue = "1") @Positive int page,
56
+ @RequestParam(defaultValue = "20") @Positive int size
57
+ ```
58
+
59
+ ## 금지 사항
60
+
61
+ - 컨트롤러에 비즈니스 로직 작성 금지
62
+ - `@Autowired` 필드 주입 금지
63
+ - 엔티티 직접 반환 금지
@@ -0,0 +1,76 @@
1
+ ---
2
+ paths:
3
+ - "**/dto/**/*.java"
4
+ ---
5
+ # DTO 패턴
6
+
7
+ ## 파일 구조
8
+
9
+ 한 도메인의 모든 DTO는 `dto/FooDtos.java` 한 파일 안에 static inner record로 정의한다.
10
+
11
+ ```java
12
+ public class FooDtos {
13
+
14
+ public record CreateRequest(
15
+ @NotBlank String title,
16
+ Integer duration
17
+ ) {
18
+ public Foo toEntity(String id, String ownerId) {
19
+ return new Foo(id, ownerId, title, duration);
20
+ }
21
+ }
22
+
23
+ public record UpdateRequest(String title) {
24
+ @AssertTrue(message = "title must not be blank")
25
+ public boolean hasNonBlankTitleWhenPresent() {
26
+ return title == null || !title.isBlank();
27
+ }
28
+ }
29
+
30
+ public record FooResponse(
31
+ String id,
32
+ String title,
33
+ FooStatus status
34
+ ) {
35
+ public static FooResponse from(Foo foo) {
36
+ return new FooResponse(foo.getId(), foo.getTitle(), foo.getStatus());
37
+ }
38
+ }
39
+
40
+ public record FooListResponse(
41
+ List<FooResponse> items,
42
+ long total,
43
+ int page,
44
+ int size,
45
+ boolean hasMore
46
+ ) {
47
+ public static FooListResponse of(List<FooResponse> items, long total, int page, int size) {
48
+ return new FooListResponse(items, total, page, size, (long) page * size < total);
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ ## 변환 메서드 규칙
55
+
56
+ | 메서드 | 용도 |
57
+ |--------|------|
58
+ | `from(Entity)` | 단일 엔티티 → DTO |
59
+ | `fromDetail(Entity, ...)` | 연관 데이터 포함한 상세 조회 |
60
+ | `toEntity(...)` | Request DTO → 엔티티 |
61
+
62
+ ## 네이밍 컨벤션
63
+
64
+ | 용도 | 이름 |
65
+ |------|------|
66
+ | 생성 요청 | `CreateRequest` |
67
+ | 수정 요청 | `UpdateRequest` |
68
+ | 단건 응답 | `FooResponse` |
69
+ | 목록 응답 | `FooListResponse` |
70
+ | 상세 응답 | `FooDetailResponse` |
71
+
72
+ ## 금지 사항
73
+
74
+ - DTO에서 엔티티 import 금지 (toEntity 제외)
75
+ - record 대신 class 사용 금지
76
+ - 응답 DTO에 비즈니스 로직 작성 금지