-
Notifications
You must be signed in to change notification settings - Fork 4
[global] AGENTS.md SOT 재구성 및 CLAUDE.md import 적용 #323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
9135dbe
75a197b
8caf9b1
266070c
4c716a8
8a067f9
85bb227
93c88c1
e5eeef1
c08dfa4
cc24200
9a32871
66986d1
f7eb910
bc81e19
6c12801
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Comment Rules | ||
|
|
||
| Write comments only when the logic is not self-evident. Do NOT add excessive comments. | ||
|
|
||
| ## When to write | ||
|
|
||
| - Non-obvious business rules or domain constraints | ||
| - Workarounds for specific bugs or framework quirks | ||
| - Hidden invariants that a future reader could not infer from the code | ||
|
|
||
| ## When NOT to write | ||
|
|
||
| - Restating what well-named identifiers already convey | ||
| - Narrating step-by-step what the code does | ||
| - Marking referenced tickets, callers, or the current task (those belong in the commit/PR description) | ||
|
|
||
| ```kotlin | ||
| // WRONG — restates the obvious | ||
| // Find student by id | ||
| val student = studentRepository.findById(id).orElseThrow { ... } | ||
|
|
||
| // CORRECT — surfaces a non-obvious constraint | ||
| // NEIS API returns 0 instead of null for "no allergy", so treat 0 as absent. | ||
| val allergy = response.allergyCode.takeIf { it != 0 } | ||
| ``` |
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. kotest-guide 같은 스킬이 존재하는데 충돌하는 것 같습니다. 테스트 컨벤션을 rule로 정의한다면 차라리 path 프론트매터를 추가하는게 좋을 것 같습니다. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Testing Rules | ||
|
|
||
| ## Framework | ||
|
|
||
| Use **Kotest `DescribeSpec` + MockK + JUnit 5** with the **Given-When-Then** structure. | ||
|
|
||
| ## Naming | ||
|
|
||
| Test names are written in Korean. Use `describe("클래스명 클래스의")` for the top-level scope. | ||
|
|
||
| ```kotlin | ||
| class StudentServiceImplTest : DescribeSpec({ | ||
| describe("StudentServiceImpl 클래스의") { | ||
| context("execute 메서드를 호출할 때") { | ||
| it("학생을 조회한다") { | ||
| // Given | ||
| val id = 1L | ||
| every { studentRepository.findById(id) } returns Optional.of(student) | ||
|
|
||
| // When | ||
| val result = service.execute(id) | ||
|
|
||
| // Then | ||
| result.id shouldBe id | ||
| } | ||
| } | ||
| } | ||
| }) | ||
| ``` | ||
|
|
||
| ## Structure | ||
|
|
||
| - **Given**: prepare data, configure mocks (`every { } returns ...`) | ||
| - **When**: invoke the system under test | ||
| - **Then**: assert results (`shouldBe`, `shouldThrow<T>`, `verify { }`) |
|
snowykte0426 marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,99 +2,57 @@ | |
|
|
||
| ## Project Overview | ||
|
|
||
| DataGSM is a Spring Boot REST API service providing school information (students, clubs, meals, schedules) for Gwangju Software Meister High School. The system uses Google OAuth2 authentication with JWT token and API key management. | ||
| DataGSM is a Spring Boot REST API server that exposes Gwangju Software Meister High School data (students, clubs, meals, timetable, etc.). It provides Google OAuth2 (JWT) authentication for internal clients and API-Key authentication for external public APIs. | ||
|
|
||
| ## Tech Stack | ||
|
|
||
| - **Backend**: Kotlin, Spring Boot 4.0, Spring Security, Spring Data JPA | ||
| - **Database**: MySQL (main data), Redis (caching, sessions) | ||
| - **Query & Integration**: QueryDSL for complex queries, OpenFeign for external APIs | ||
| - **Serialization**: Jackson 3.0 for JSON processing | ||
| - **Testing**: Kotest + MockK + JUnit 5 (Given-When-Then style) | ||
| - **Language / Framework**: Kotlin 2.3.10, Spring Boot 4.0.3, Spring Security, Spring Data JPA | ||
|
ZaMan0806 marked this conversation as resolved.
|
||
| - **Build**: Gradle (Java 25 toolchain), multi-module | ||
| - **Database**: MySQL (main), Redis (cache, session) | ||
| - **Query / Integration**: QueryDSL, OpenFeign | ||
| - **Serialization**: Jackson 3.0 | ||
| - **Testing**: Kotest (`DescribeSpec`) + MockK + JUnit 5 | ||
|
|
||
| ## Project Structure (Multi-module) | ||
| ## Project Structure | ||
|
|
||
| ``` | ||
| datagsm-server/ | ||
| ├── datagsm-common/ # Shared library (Entity, DTO, Repository, Config, Health API) | ||
| ├── datagsm-common/ # Shared Entity/DTO/Repository/Config, Health API (library module) | ||
| ├── datagsm-oauth-authorization/ # OAuth2 authentication, account lifecycle (signup, password reset) | ||
| ├── datagsm-oauth-userinfo/ # OAuth2 UserInfo endpoint (external clients) | ||
| ├── datagsm-openapi/ # Public read-only API (students, clubs, NEIS) | ||
| └── datagsm-web/ # Web service API (user features, admin features, Excel) | ||
| ├── datagsm-oauth-userinfo/ # OAuth2 UserInfo endpoint (for external clients) | ||
| ├── datagsm-openapi/ # External public API (API-Key auth) | ||
| │ # Domains: student, club, project, webhook, neis | ||
| └── datagsm-web/ # Web service API (includes Excel processing) | ||
| # Domains: account, auth, application, client, student, club, project, utility | ||
| ``` | ||
|
|
||
| Each module follows: `controller/`, `service/`, `repository/`, `entity/`, `dto/` | ||
| Each module follows the `controller/ → service/ → repository/` layering with `entity/` and `dto/` packages per domain. | ||
|
|
||
| **Note**: `/v1/health` endpoint is provided by `HealthController` in `datagsm-common/global/controller/` and is shared across all modules. | ||
| **Key Paths** | ||
|
|
||
| ## Commands | ||
| - The `/v1/health` endpoint is served by `HealthController` in `datagsm-common` and is shared across all runnable modules. | ||
| - Shared entities: `datagsm-common/src/main/kotlin/team/themoment/datagsm/common/domain/` | ||
| - Global exception handling: `datagsm-common/src/main/kotlin/team/themoment/datagsm/common/global/common/error/` | ||
| - API response: controllers return DTOs directly — `the-sdk`'s `ResponseBodyAdvice` automatically wraps them in `CommonApiResponse`. Use `CommonApiResponse<Nothing>` explicitly only when no data is returned (e.g. delete operations). Exception responses are wrapped by `GlobalExceptionHandler`. | ||
|
|
||
| - Build: `./gradlew build` | ||
| - Test: `./gradlew test` | ||
| - Format: `./gradlew ktlintFormat` | ||
| - Run: `./gradlew :<module>:bootRun` | ||
| ## Runnable Modules | ||
|
|
||
| ## Coding Conventions | ||
| Modules launched via `./gradlew :<module>:bootRun`: `datagsm-oauth-authorization`, `datagsm-oauth-userinfo`, `datagsm-openapi`, `datagsm-web`. (`datagsm-common` is a library module and is not run directly.) | ||
|
|
||
|
snowykte0426 marked this conversation as resolved.
Comment on lines
+38
to
41
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gradle 사용법을 재차 알려줄 필요는 없을 것 같습니다 |
||
| ### Kotlin Style | ||
| ## Detailed Rules (`.claude/rules/`) | ||
|
|
||
| - Prefer `val` over `var`. Use `var` only when reassignment is strictly required. | ||
| - Always use constructor injection — never `@Autowired` field injection. | ||
| - Use Kotlin null-safety features (`?.`, `?:`) instead of `!!`. | ||
| - Do NOT add excessive comments — only where logic is not self-evident. | ||
| The following rule files are auto-loaded when working on related code: | ||
|
|
||
| ### DTO Annotations | ||
|
|
||
| - Jackson: always use `@field:` target — never `@param:` (e.g., `@field:JsonProperty("user_name")`) | ||
| - Swagger/OpenAPI: | ||
| - Request DTOs (`*ReqDto`): use `@param:Schema` | ||
| - Response DTOs (`*ResDto`): use `@field:Schema` | ||
|
|
||
| ### API Conventions | ||
|
|
||
| - 1–2 query params: use `@RequestParam`; 3+ or with validation: use `@ModelAttribute` + DTO | ||
| - `@RequestBody` variable: `reqDto`; `@ModelAttribute` query: `queryReq` | ||
| - `@Transactional` must be at **method level only** — never class level | ||
| - Read operations: `@Transactional(readOnly = true)` / Write operations: `@Transactional` | ||
| - Use `CommonApiResponse` wrapper for all API responses | ||
|
|
||
| ### Logging | ||
|
|
||
| - English only — verb-led sentences | ||
| - SLF4J `{}` placeholder only — no Kotlin string interpolation, no colon separators | ||
| - Correct: `logger().info("Deleted {} expired API keys", deletedCount)` | ||
| - Wrong: `logger().error("에러 발생: $message")` or `logger().error("Failed: {}", msg)` | ||
|
|
||
| ### Exception Handling | ||
|
|
||
| - Use `ExpectedException` directly — do NOT subclass it | ||
| - Message: Korean (합쇼체) + period, no dynamic data (IDs, names, variables) | ||
| - Correct: `ExpectedException("학생을 찾을 수 없습니다.", HttpStatus.NOT_FOUND)` | ||
| - Wrong: `ExpectedException("학생 ID: $id 없음", HttpStatus.NOT_FOUND)` | ||
|
|
||
| ### Commit Conventions | ||
|
|
||
| Format: `type(scope): 설명` | ||
|
|
||
| - Types: `add` / `update` / `fix` / `refactor` / `ci/cd` / `docs` / `test` / `merge` | ||
| - Scope: domain name (`auth`, `student`, `club`, `application`, etc.) — NOT module names | ||
| - Cross-cutting only: `global`, `ci/cd`, or module names (`web`, `openapi`, `oauth`) | ||
| - Description: Korean, no period | ||
|
|
||
| ## Key Practices | ||
|
|
||
| ### JPA | ||
|
snowykte0426 marked this conversation as resolved.
|
||
| - Avoid N+1 problems — use Fetch Join or `@EntityGraph` | ||
| - Use `@Transactional(readOnly = true)` for read operations | ||
|
|
||
| ### Testing | ||
| - Write Kotest tests for business logic | ||
| - Use Kotest `DescribeSpec` with `describe/context/it` blocks | ||
| - Use MockK for mocking; Given-When-Then structure inside `it` blocks | ||
| - Test names in Korean: `describe("클래스명 클래스의")`, `describe("메서드명 메서드는")` | ||
| - `kotlin-style.md` — `val/var`, constructor injection, null safety | ||
| - `dto-annotations.md` — Jackson/Swagger `@field:` vs `@param:` targets | ||
| - `api-conventions.md` — `@RequestParam` vs `@ModelAttribute`, DTO naming, `@Transactional` placement | ||
| - `logging.md` — English only, SLF4J `{}` placeholder, no colon separators | ||
| - `exception.md` — `ExpectedException` usage and message format | ||
| - `testing.md` — Kotest `DescribeSpec` + MockK + Given-When-Then structure | ||
| - `comments.md` — when to write comments (only for non-obvious logic) | ||
| - `commit-conventions.md` — commit `type(scope): description` rules (scope = domain name) | ||
|
|
||
|
snowykte0426 marked this conversation as resolved.
|
||
| ## Notes | ||
|
|
||
| - This project uses Java 25 for Gradle builds | ||
| - Always check `.gitignore` and `.geminiignore` when suggesting file changes | ||
| - When analyzing code, consider the multi-module structure | ||
| - Always check `.gitignore` before proposing file changes. | ||
| - When analyzing code, consider the multi-module structure and inter-module dependencies (`datagsm-common` is the base for every runnable module). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,55 +1,5 @@ | ||
| ## Project Overview | ||
| @AGENTS.md | ||
|
|
||
| School information API server for Gwangju Software Meister High School (students, clubs, meals, schedules) | ||
| ## Claude Code Specific | ||
|
|
||
| ## Module Structure | ||
|
|
||
| - datagsm-common: Shared Entity/DTO/Repository, Health API | ||
| - datagsm-oauth-authorization: OAuth2 authentication, account lifecycle (signup, password reset) | ||
| - datagsm-oauth-userinfo: OAuth2 UserInfo endpoint (external clients) | ||
| - datagsm-openapi: Public read-only API (students, clubs, NEIS integration) | ||
| - datagsm-web: Web service API (user features, admin features, Excel processing) | ||
|
|
||
| **Note**: `/v1/health` endpoint is provided by `HealthController` in `datagsm-common` module and is shared across all modules. | ||
|
|
||
| ## Commands | ||
|
|
||
| - Build: `./gradlew build` | ||
| - Test: `./gradlew test` | ||
| - Format: `./gradlew ktlintFormat` | ||
| - Run: `./gradlew :<module>:bootRun` (modules: `datagsm-oauth-authorization`, `datagsm-openapi`, `datagsm-oauth-userinfo`, `datagsm-web`) | ||
|
|
||
| ## Tech Stack | ||
|
|
||
| Kotlin, Spring Boot 4.0, Spring Data JPA, QueryDSL, Redis, MySQL | ||
|
|
||
| ## Coding Rules | ||
|
|
||
| - Controller → Service → Repository pattern | ||
| - Use constructor injection | ||
| - Test: Kotest + MockK (Given-When-Then) | ||
| - Do NOT add excessive comments - only add comments where logic is not self-evident | ||
|
|
||
| Detailed rules are split into `.claude/rules/`: | ||
| - `dto-annotations.md` — `@field:` vs `@param:` rules for Jackson and Swagger | ||
| - `logging.md` — English-only, SLF4J `{}` placeholders, no colon separators | ||
| - `exception.md` — `ExpectedException` usage and message format | ||
| - `kotlin-style.md` — `val/var`, constructor injection, null safety | ||
| - `api-conventions.md` — `@RequestParam` vs `@ModelAttribute`, DTO naming, `@Transactional` placement | ||
| - `commit-conventions.md` — commit type/scope rules | ||
|
|
||
| ## Context Compaction Rules | ||
|
|
||
| Priority order when compressing conversation history: | ||
| 1. Project Overview (module structure) | ||
| 2. Common Mistakes section | ||
| 3. DTO Annotations rules | ||
| 4. Commit/PR conventions | ||
| 5. Tech Stack | ||
| 6. Reduce: Commands, Key Paths | ||
|
|
||
| ## Key Paths | ||
|
|
||
| - Common Entity: `datagsm-common/src/main/kotlin/.../domain/` | ||
| - Exception Handler: `datagsm-common/.../global/common/error/` | ||
| - API Response: Use `CommonApiResponse` wrapper | ||
| - `.claude/rules/`의 세부 규칙은 Claude Code가 작업 컨텍스트에 맞춰 자동 로드합니다. 자동 로드된 규칙과 충돌하는 코드를 발견하면 단순 수정에 그치지 말고 규칙 파일에 누락된 항목이 있는지 점검하고 보완을 제안하세요. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 사용자 상호작용 규칙에 따른다고 하셨는데 사실 이해가 되지 않습니다. 해당 내용도 한국어로 유지할 이유가 있을까요 |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pr 코멘트 달때 규칙인가요?