diff --git a/.agents/skills/git-commit/SKILL.md b/.agents/skills/git-commit/SKILL.md index 08c65cc..376c72c 100644 --- a/.agents/skills/git-commit/SKILL.md +++ b/.agents/skills/git-commit/SKILL.md @@ -47,8 +47,8 @@ Format: `type(scope): 설명` ## Scope Selection -For the full scope selection table and examples, read `references/scope-guide.md`. -For commit type and scope naming conventions, read `references/commit-conventions.md`. +For the full scope selection table and examples, read `.agents/skills/git-commit/references/scope-guide.md`. +For commit type and scope naming conventions, read `.agents/skills/git-commit/references/commit-conventions.md`. Quick rule: infer domain from changed file paths and directory structure. Use `global` / `ci/cd` / module names only for cross-cutting changes. diff --git a/.agents/skills/java-spring-arch/SKILL.md b/.agents/skills/java-spring-arch/SKILL.md new file mode 100644 index 0000000..44edeba --- /dev/null +++ b/.agents/skills/java-spring-arch/SKILL.md @@ -0,0 +1,65 @@ +--- +name: java-spring-arch +description: Architecture reference for Java + Spring Boot 4.0 projects — Controller/Service/Repository layer responsibilities, @Transactional strategy (readOnly optimization, N+1 prevention), ExpectedException usage, and Entity↔DTO conversion patterns. +--- + +# Java + Spring Boot Architecture Guide + +## Layer Structure + +### Controller +- Role: Request validation, DTO conversion, HTTP response +- Annotations: `@RestController`, `@RequestMapping` +- Validation: `@Valid`, `@Validated` +- Response: Use `CommonApiResponse` wrapper + +### Service +- Role: Business logic, transaction management +- Pattern: interface + implementation +- Transaction: + - Read: `@Transactional(readOnly = true)` + - Write: `@Transactional` +- Dependencies: Inject Repository via constructor injection + +### Repository +- Role: Data access +- JPA: Extend `JpaRepository` +- Avoid N+1: Fetch Join, `@EntityGraph` + +## Transaction Strategy + +### Read-only Optimization +```java +@Transactional(readOnly = true) +public List findStudents() { + return repository.findAll().stream() + .map(StudentResDto::from) + .toList(); +} +``` + +### N+1 Problem Resolution +```java +// ❌ N+1 occurs +repository.findAll(); // 1 query +entity.getRelatedEntities(); // N queries + +// ✅ Fetch Join +@Query("SELECT e FROM Entity e JOIN FETCH e.relatedEntities") +List findAllWithRelated(); +``` + +## Exception Handling + +```java +throw new ExpectedException("학생을 찾을 수 없습니다.", HttpStatus.NOT_FOUND); +``` + +## DTO Conversion Pattern + +```java +// Entity → ResDto (static factory) +public static StudentResDto from(Student student) { + return new StudentResDto(student.getId(), student.getName()); +} +``` \ No newline at end of file diff --git a/.agents/skills/resolve-reviews/SKILL.md b/.agents/skills/resolve-reviews/SKILL.md index f4e78bb..8ebf0eb 100644 --- a/.agents/skills/resolve-reviews/SKILL.md +++ b/.agents/skills/resolve-reviews/SKILL.md @@ -8,7 +8,7 @@ allowed-tools: Bash(bash *get-pr-data.sh:*), Bash(gh api:*), Bash(gh pr view:*), ## Step 1 — Collect PR Data ```bash -bash scripts/get-pr-data.sh +bash .agents/skills/resolve-reviews/scripts/get-pr-data.sh ``` Output files: @@ -105,7 +105,7 @@ gh api "repos///pulls//comments//replies" \ -f body="" ``` -For reply body templates, read `references/reply-formats.md`. +For reply body templates, read `.agents/skills/resolve-reviews/references/reply-formats.md`. ## Step 7 — Cleanup diff --git a/.agents/skills/the-sdk/SKILL.md b/.agents/skills/the-sdk/SKILL.md new file mode 100644 index 0000000..0247174 --- /dev/null +++ b/.agents/skills/the-sdk/SKILL.md @@ -0,0 +1,16 @@ +--- +name: the-sdk +description: Usage guide for the-sdk common library — HTTP request/response logging with UUID Log-ID, CommonApiResponse wrapping, ExpectedException handling, and Swagger auto-configuration. +--- + +# the-sdk Usage Guide + +`com.github.themoment-team:the-sdk:1.5` — the core common library for this project. +Controlled via `sdk.*` settings in `application.yml`. + +## Features + +- **Logging**: Assigns a UUID `Log-ID` to every HTTP request/response; automatic logging +- **Response Wrapper**: Automatically wraps controller return values in `CommonApiResponse`. Use `success()` / `created()` / `error()` factory methods +- **Exception Handler**: Throwing `ExpectedException(message, HttpStatus)` returns a standard error response automatically +- **Swagger**: Auto-configured at `/v3/api-docs` and `/swagger-ui`. Only `/v1/**` paths are documented diff --git a/.agents/skills/write-pr/SKILL.md b/.agents/skills/write-pr/SKILL.md index 4e1e12e..c7cea5a 100644 --- a/.agents/skills/write-pr/SKILL.md +++ b/.agents/skills/write-pr/SKILL.md @@ -21,8 +21,8 @@ cat .github/PULL_REQUEST_TEMPLATE.md ## Step 2 — Determine Labels -Read `references/labels.md` and select 1–2 appropriate labels based on the nature of the changes. -Read `references/commit-conventions.md` for commit type and scope naming rules. +Read `.agents/skills/write-pr/references/labels.md` and select 1–2 appropriate labels based on the nature of the changes. +Read `.agents/skills/write-pr/references/commit-conventions.md` for commit type and scope naming rules. ## Step 3 — Generate PR Content @@ -61,7 +61,7 @@ Ask the user which title to use (present options 1/2/3). Wait for the answer bef Run the creation script with the confirmed title and labels: ```bash -bash scripts/create-pr.sh "" "PR_BODY.md" "," +bash .agents/skills/write-pr/scripts/create-pr.sh "" "PR_BODY.md" "," ``` After creation, display the PR URL. diff --git a/.claude/settings.json b/.claude/settings.json index 0c7ea16..68b2e98 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -26,7 +26,7 @@ "hooks": [ { "type": "command", - "command": ".claude/hooks/preToolUse.sh" + "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/preToolUse.sh" } ] } @@ -37,7 +37,7 @@ "hooks": [ { "type": "command", - "command": ".claude/hooks/postToolUse.sh" + "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/postToolUse.sh" } ] } @@ -45,7 +45,6 @@ }, "enabledPlugins": { "claude-hud@claude-hud": true, - "github@claude-plugins-official": true, "context7@claude-plugins-official": true }, "language": "korean", diff --git a/.claude/skills/java-spring-arch/SKILL.md b/.claude/skills/java-spring-arch/SKILL.md new file mode 100644 index 0000000..44edeba --- /dev/null +++ b/.claude/skills/java-spring-arch/SKILL.md @@ -0,0 +1,65 @@ +--- +name: java-spring-arch +description: Architecture reference for Java + Spring Boot 4.0 projects — Controller/Service/Repository layer responsibilities, @Transactional strategy (readOnly optimization, N+1 prevention), ExpectedException usage, and Entity↔DTO conversion patterns. +--- + +# Java + Spring Boot Architecture Guide + +## Layer Structure + +### Controller +- Role: Request validation, DTO conversion, HTTP response +- Annotations: `@RestController`, `@RequestMapping` +- Validation: `@Valid`, `@Validated` +- Response: Use `CommonApiResponse` wrapper + +### Service +- Role: Business logic, transaction management +- Pattern: interface + implementation +- Transaction: + - Read: `@Transactional(readOnly = true)` + - Write: `@Transactional` +- Dependencies: Inject Repository via constructor injection + +### Repository +- Role: Data access +- JPA: Extend `JpaRepository` +- Avoid N+1: Fetch Join, `@EntityGraph` + +## Transaction Strategy + +### Read-only Optimization +```java +@Transactional(readOnly = true) +public List findStudents() { + return repository.findAll().stream() + .map(StudentResDto::from) + .toList(); +} +``` + +### N+1 Problem Resolution +```java +// ❌ N+1 occurs +repository.findAll(); // 1 query +entity.getRelatedEntities(); // N queries + +// ✅ Fetch Join +@Query("SELECT e FROM Entity e JOIN FETCH e.relatedEntities") +List findAllWithRelated(); +``` + +## Exception Handling + +```java +throw new ExpectedException("학생을 찾을 수 없습니다.", HttpStatus.NOT_FOUND); +``` + +## DTO Conversion Pattern + +```java +// Entity → ResDto (static factory) +public static StudentResDto from(Student student) { + return new StudentResDto(student.getId(), student.getName()); +} +``` \ No newline at end of file diff --git a/.claude/skills/the-sdk/SKILL.md b/.claude/skills/the-sdk/SKILL.md new file mode 100644 index 0000000..0247174 --- /dev/null +++ b/.claude/skills/the-sdk/SKILL.md @@ -0,0 +1,16 @@ +--- +name: the-sdk +description: Usage guide for the-sdk common library — HTTP request/response logging with UUID Log-ID, CommonApiResponse wrapping, ExpectedException handling, and Swagger auto-configuration. +--- + +# the-sdk Usage Guide + +`com.github.themoment-team:the-sdk:1.5` — the core common library for this project. +Controlled via `sdk.*` settings in `application.yml`. + +## Features + +- **Logging**: Assigns a UUID `Log-ID` to every HTTP request/response; automatic logging +- **Response Wrapper**: Automatically wraps controller return values in `CommonApiResponse`. Use `success()` / `created()` / `error()` factory methods +- **Exception Handler**: Throwing `ExpectedException(message, HttpStatus)` returns a standard error response automatically +- **Swagger**: Auto-configured at `/v3/api-docs` and `/swagger-ui`. Only `/v1/**` paths are documented diff --git a/.codex/config.toml b/.codex/config.toml index c5e8511..b35be22 100644 --- a/.codex/config.toml +++ b/.codex/config.toml @@ -1,12 +1,12 @@ -model = "gpt-5.5" -model_reasoning_effort = "high" web_search = "live" - -[approval] -policy = "on-request" - +sandbox_mode = "workspace-write" +project_doc_max_bytes = 32768 +[sandbox_workspace_write] +network_access = true [shell] login_shell_allowed = true - [features] hooks = true +[mcp_servers.context7] +command = "npx" +args = ["-y", "@upstash/context7-mcp"] diff --git a/.codex/hooks.json b/.codex/hooks.json index 37e3a12..52a0bab 100644 --- a/.codex/hooks.json +++ b/.codex/hooks.json @@ -2,12 +2,22 @@ "hooks": { "PreToolUse": [ { - "command": ".codex/hooks/pre-tool-use.sh" + "hooks": [ + { + "type": "command", + "command": "bash -c 'root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; hook=\"$root/.codex/hooks/pre-tool-use.sh\"; if [[ ! -f \"$hook\" ]]; then hook=\"$root/.codex/hooks/dispatcher/pre-tool-use.sh\"; fi; if [[ -f \"$hook\" ]]; then exec bash \"$hook\"; fi; exit 0'" + } + ] } ], "PostToolUse": [ { - "command": ".codex/hooks/post-tool-use.sh" + "hooks": [ + { + "type": "command", + "command": "bash -c 'root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; hook=\"$root/.codex/hooks/post-tool-use.sh\"; if [[ ! -f \"$hook\" ]]; then hook=\"$root/.codex/hooks/dispatcher/post-tool-use.sh\"; fi; if [[ -f \"$hook\" ]]; then exec bash \"$hook\"; fi; exit 0'" + } + ] } ] } diff --git a/.codex/hooks/post-tool-use.sh b/.codex/hooks/post-tool-use.sh index 3c4645a..ff0af24 100755 --- a/.codex/hooks/post-tool-use.sh +++ b/.codex/hooks/post-tool-use.sh @@ -2,6 +2,7 @@ INPUT=$(cat) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" MODULES_DIR="$SCRIPT_DIR/modules" +[[ -d "$MODULES_DIR" ]] || MODULES_DIR="${SCRIPT_DIR%/*}/modules" [[ -d "$MODULES_DIR" ]] || exit 0 @@ -10,4 +11,4 @@ for hook in "$MODULES_DIR"/*/post-tool-use.sh; do echo "$INPUT" | bash "$hook" done -exit 0 \ No newline at end of file +exit 0 diff --git a/.codex/hooks/pre-tool-use.sh b/.codex/hooks/pre-tool-use.sh index 265793f..87dd4d2 100755 --- a/.codex/hooks/pre-tool-use.sh +++ b/.codex/hooks/pre-tool-use.sh @@ -2,6 +2,7 @@ INPUT=$(cat) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" MODULES_DIR="$SCRIPT_DIR/modules" +[[ -d "$MODULES_DIR" ]] || MODULES_DIR="${SCRIPT_DIR%/*}/modules" [[ -d "$MODULES_DIR" ]] || exit 0 @@ -14,4 +15,4 @@ for hook in "$MODULES_DIR"/*/pre-tool-use.sh; do fi done -exit 0 \ No newline at end of file +exit 0