Repository navigation
[FBE-14] dev 환경 CI/CD 파이프라인 고도화 및 AI 기반 개발 환경 구축 #6
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: dev
Are you sure you want to change the base?
Changes from all commits
15db9eb
482f058
bffc182
4d9ad07
fa74403
0ff8abe
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,36 @@ | ||
| --- | ||
| description: Add a domain-specific ErrorCode to the target FRAMEY service following project conventions. | ||
| argument-hint: "<service> <error-description>" | ||
| allowed-tools: Read, Grep, Glob, Edit, Write | ||
| --- | ||
|
|
||
| # Add ErrorCode | ||
|
|
||
| $ARGUMENTS에 지정된 도메인의 ErrorCode를 추가한다. | ||
|
|
||
| ## 절차 | ||
|
|
||
| ### 1. 대상 확인 | ||
| - 대상 서비스(member/collage/archive)를 확인한다. | ||
| - 추가할 오류 상황과 적절한 HttpStatus를 파악한다. | ||
| - 불명확하면 사용자에게 질문한다. | ||
|
|
||
| ### 2. 기존 코드 분석 | ||
| - 대상 서비스의 기존 `{Domain}ErrorCode` enum이 있는지 확인한다 — 있으면 항목만 추가한다. | ||
| - 형식 참조: `framey-common/framey/common/exception/CommonErrorCode.java` | ||
| - 동일한 의미의 기존 코드가 있는지 확인해 중복 생성을 방지한다. | ||
|
|
||
| ### 3. ErrorCode 생성 또는 추가 | ||
| - 위치: 해당 서비스의 exception 패키지 (`framey.{domain}.exception`) | ||
| - `framey.common.response.ErrorCode` 인터페이스 구현 | ||
| - 코드 형식: `{도메인 약자}-###` (예: `MB-001`, `CL-001`, `AR-001`) | ||
| - 한국어 메시지 + `HttpStatus` 지정 | ||
| - `@Getter` + `@RequiredArgsConstructor` 패턴 사용 | ||
|
|
||
| ### 4. 금지 사항 | ||
| - `framey-common`의 `CommonErrorCode`에 도메인 전용 코드를 추가하지 않는다 — 공통 모듈 수정은 사용자 승인 필요. | ||
| - 문자열 하드코딩 예외 메시지를 코드에 직접 쓰지 않는다. | ||
|
|
||
| ### 5. 결과 보고 | ||
| - 생성/수정한 파일 | ||
| - 추가한 에러 코드 목록 (코드, 메시지, HttpStatus) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| --- | ||
| description: Analyze which services will be redeployed on dev push based on changed files and paths-filter rules. | ||
| argument-hint: "(optional) <description-of-changes>" | ||
| allowed-tools: Read, Grep, Glob, Bash | ||
| --- | ||
|
|
||
| # Deploy Check | ||
|
|
||
| 현재 변경 사항이 dev 배포 시 어떤 서비스를 재배포하는지 분석한다. | ||
|
|
||
| ## 절차 | ||
|
|
||
| ### 1. 변경 파일 수집 | ||
| - `git status` / `git diff --name-only`로 변경된 파일 목록을 확인한다. | ||
|
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. 마지막 성공 배포를 기준으로 변경 파일을 수집해 주세요. 변경 사항을 커밋한 뒤 실행하면
|
||
|
|
||
| ### 2. 배포 트리거 판별 | ||
| `.github/workflows/dev-deploy.yaml`의 paths-filter 규칙으로 판별한다. | ||
|
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. 실제 배포 대상 선정 규칙을 참조해 주세요. 이 workflow에는 paths-filter가 없습니다.
|
||
|
|
||
| - **공유 모듈 변경 시 전 서비스 재배포**: | ||
| - `framey-common/**`, `framey-web/**`, `framey-monitoring/**` | ||
| - `build.gradle`, `settings.gradle`, `gradle/**` | ||
| - **서비스별 트리거**: | ||
| - `framey-application/member-service/**` → member-dev (포트 8081) | ||
| - `framey-application/collage-service/**` → collage-dev (포트 8082) | ||
| - `framey-application/archive-service/**` → archive-dev (포트 8083) | ||
| - **인프라 트리거**: | ||
| - `framey-infrastructure/swagger-dev/**` → swagger-dev | ||
| - `framey-infrastructure/nginx/**` → nginx | ||
|
|
||
| ### 3. 결과 보고 | ||
| - 재배포 대상 서비스 목록 | ||
| - 공유 모듈 변경 여부 (변경 시 전체 재배포 경고) | ||
| - 배포 후 `/actuator/health` 헬스체크 대상 포트 | ||
| - 주의 사항: `main`은 배포 워크플로우 없음 — `dev` push 시에만 배포됨 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| --- | ||
| description: Implement a new API in the specified FRAMEY service following project architecture conventions, including tests and validation. | ||
| argument-hint: "<service> <api-description>" | ||
| allowed-tools: Read, Grep, Glob, Edit, Write, Bash | ||
| --- | ||
|
|
||
| # New API Implementation | ||
|
|
||
| $ARGUMENTS에 지정된 API를 구현한다. | ||
|
|
||
| ## 절차 | ||
|
|
||
| ### 1. 대상 확인 | ||
| - 대상 서비스(member/collage/archive)를 확인한다. | ||
| - 구현할 API의 요구사항을 분석한다. | ||
| - 대상 서비스 또는 요구사항이 불명확하면 사용자에게 질문한다. | ||
|
|
||
| ### 2. 기존 코드 분석 | ||
| - CLAUDE.md의 아키텍처 규칙을 확인한다. | ||
| - 대상 서비스의 기존 패키지 구조와 구현 패턴을 분석한다. | ||
| - 재사용 가능한 Entity, DTO, Repository, Service를 확인한다. | ||
| - 기존 코드의 중복 구현을 방지한다. | ||
| - 다른 서비스 및 공유 모듈을 임의로 수정하지 않는다. | ||
|
|
||
| ### 3. 관련 Skill 적용 | ||
| 다음 Skill의 규칙을 확인하고 적용한다. | ||
|
|
||
| 필수: | ||
| - `.claude/skills/api-design/SKILL.md` | ||
| - Controller, Service, DTO 구현 규칙 | ||
|
|
||
| 필요한 경우: | ||
| - `.claude/skills/domain-design/SKILL.md` | ||
| - Entity 생성 또는 변경이 필요한 경우 | ||
| - `.claude/skills/persistence/SKILL.md` | ||
| - Repository 구현이 필요한 경우 | ||
| - `.claude/skills/inter-service-communication/SKILL.md` | ||
| - 외부 또는 도메인 간 통신이 필요한 경우 | ||
|
|
||
| ### 4. 구현 계획 수립 | ||
| - API의 HTTP Method와 Endpoint를 확인한다. | ||
| - Request 및 Response 구조를 정의한다. | ||
| - 생성 및 수정이 필요한 파일을 식별한다. | ||
| - 기존 코드와의 중복 여부를 검토한다. | ||
| - 아키텍처 변경 또는 다른 모듈 수정이 필요한 경우 사용자 승인을 받는다. | ||
| - 요구사항이 명확하고 기존 구조 내에서 구현 가능한 경우 바로 진행한다. | ||
|
|
||
| ### 5. API 구현 | ||
| 1. 기존 코드 재사용 여부 판단 | ||
| 2. 필요한 DTO 정의 | ||
| 3. 필요한 경우 Domain 구현 또는 수정 | ||
| 4. 데이터 접근이 필요한 경우 Repository Port 및 Adapter 구현 | ||
| 5. Service 비즈니스 로직 구현 | ||
| 6. Controller 구현 | ||
| 7. 도메인 ErrorCode 및 BusinessException 적용 | ||
| 8. 기존 프로젝트 규칙에 따른 API 문서화 | ||
|
|
||
| ### 6. 테스트 | ||
| - Controller 테스트 작성 | ||
| - Service 테스트 작성 | ||
| - 필요한 경우 Repository 통합 테스트 작성 | ||
| - 성공 및 실패 시나리오 검증 | ||
| - 기존 테스트에 영향을 주는 변경 사항 확인 | ||
|
|
||
| ### 7. 검증 | ||
| - 대상 서비스의 Gradle check 작업을 실행한다. | ||
| - 검증에 실패하면 원인을 분석하고 수정 후 재검증한다. | ||
| - 동일한 오류가 반복되거나 작업 범위 밖의 문제가 발견되면 사용자에게 보고한다. | ||
| - 테스트를 실행하지 못한 경우 성공했다고 보고하지 않는다. | ||
| - 검증을 위해 다른 서비스나 공유 모듈을 임의로 수정하지 않는다. | ||
|
|
||
| ### 8. 결과 보고 | ||
| - 생성 및 수정한 파일 목록 | ||
| - 구현한 API 목록 (HTTP Method, Endpoint) | ||
| - 작성한 테스트 및 실행 결과 | ||
| - 아키텍처 규칙 준수 여부 | ||
| - 해결되지 않은 문제 및 추가 검토 사항 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| --- | ||
| name: api-design | ||
| description: Controller, Service, DTO implementation rules for FRAMEY services. Apply when implementing API endpoints. | ||
| --- | ||
|
|
||
| # API Design | ||
|
|
||
| ## Controller | ||
| - `@RestController` + `@RequestMapping` 사용 | ||
| - 반환형은 `ResponseEntity<ApiResponse<T>>` — raw Entity, `Map` 직접 반환 금지 | ||
| - 비즈니스 로직 작성 금지 — Service로 위임 | ||
| - `try-catch`로 예외 응답을 만들지 않는다 — `CommonExceptionHandler`가 처리 | ||
| - 입력 검증은 `@Valid` + DTO 제약 어노테이션 사용 | ||
| - 인증된 사용자 정보는 `@AuthUser`로 주입 | ||
| - Swagger 어노테이션(`@Operation`, `@ApiResponse` 등)은 Controller에 직접 붙이지 않고 별도 문서화 인터페이스(예: `{Domain}ApiDocs`)에 선언하고 Controller가 구현하게 하여 Controller를 깔끔하게 유지한다. | ||
|
|
||
| ### Controller 작성 규칙 | ||
| - 성공 응답은 `ApiResponse`의 static 메서드를 static import한다. **데이터 없음**: `success(SuccessCode)`, **데이터 있음**: `successWithData(SuccessCode, data)`. `SuccessCode`는 `framey.common.response.SuccessCode` enum (OK, CREATED, UPDATED, DELETED). | ||
| - 메서드 파라미터는 `final`로 선언한다. | ||
| - PathVariable/RequestBody/AuthUser 순서는 기존 패턴을 따른다. | ||
|
|
||
| 예시: | ||
| ```java | ||
| @DeleteMapping("/{productId}") | ||
| public ResponseEntity<ApiResponse<Void>> deleteProduct( | ||
| @AuthUser final Long memberId, | ||
| @PathVariable final Long productId | ||
| ) { | ||
| productService.deleteProduct(memberId, productId); | ||
| return ResponseEntity.ok(success(SuccessCode.DELETED)); | ||
| } | ||
|
|
||
| @GetMapping("/{productId}") | ||
| public ResponseEntity<ApiResponse<GetMemberProductResponse>> getMemberProduct( | ||
| @AuthUser final Long memberId, | ||
| @PathVariable final Long productId | ||
| ) { | ||
| GetMemberProductResponse product = productService.findMemberProduct(memberId, productId); | ||
| return ResponseEntity.ok(successWithData(SuccessCode.OK, product)); | ||
| } | ||
| ``` | ||
|
|
||
| ## Service | ||
| - `@Service` + `@RequiredArgsConstructor` 생성자 주입 (`final` 필드) | ||
| - 조회 전용 메서드는 `@Transactional(readOnly = true)` | ||
| - 데이터 변경 메서드는 쓰기 가능한 `@Transactional` | ||
| - 오류는 `BusinessException` + 도메인 `ErrorCode`로 던진다 | ||
| - 조회 결과가 없을 때는 `orElseThrow(() -> new BusinessException(XxxErrorCode.NOT_FOUND))` 패턴 사용 | ||
| - Entity → Result 변환은 `map(XxxResult::from)` 등 Result의 static factory로 수행 | ||
|
|
||
| 예시: | ||
| ```java | ||
| public MemberInfo getProfile(final Long memberId) { | ||
| return memberRepository.findById(memberId) | ||
| .map(MemberInfo::from) | ||
| .orElseThrow(() -> new BusinessException(MemberErrorCode.MEMBER_NOT_FOUND)); | ||
| } | ||
| ``` | ||
|
|
||
| ## DTO Mapping | ||
| - Controller는 Request DTO를 Application Command로 변환한다. | ||
| - Service는 Application Command를 입력받아 비즈니스 로직을 수행한다. | ||
| - Service는 Application Result를 반환한다. | ||
| - Controller는 Application Result를 Response DTO로 변환한다. | ||
| - Service는 Controller 전용 DTO에 의존하지 않는다. | ||
| - Entity를 Controller에 전달하거나 API 응답으로 직접 반환하지 않는다. | ||
|
|
||
| ### Response DTO 작성 규칙 | ||
| - Java `record` 사용. | ||
| - DTO 필드에 `@Schema(description = ..., requiredMode = Schema.RequiredMode.REQUIRED)`를 붙여 Swagger 스키마를 정의한다 (DTO 수준의 `@Schema`는 허용 — Controller의 운영 어노테이션과는 구분). | ||
| - Result → Response 변환은 DTO 내부의 static factory `from(final XxxResult result)`으로 수행한다. | ||
|
|
||
| 예시: | ||
| ```java | ||
| @Schema(description = "사용자 정보 응답") | ||
| public record MemberResponse( | ||
| @Schema(description = "사용자 ID", requiredMode = Schema.RequiredMode.REQUIRED) Long memberId, | ||
| @Schema(description = "닉네임", requiredMode = Schema.RequiredMode.REQUIRED) String nickname | ||
| ) { | ||
| public static MemberResponse from(final MemberResult result) { | ||
| return new MemberResponse(result.memberId(), result.nickname()); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Exception | ||
| - 비즈니스 오류는 `BusinessException` + 도메인별 `ErrorCode` enum으로 던진다. | ||
| - 도메인 `ErrorCode`는 각 서비스 모듈의 exception 패키지에 생성한다 (`{도메인 약자}-###`, `framey.common.response.ErrorCode` 구현). 형식 참조: `CommonErrorCode.java`. | ||
| - Controller/Service에서 `try-catch`로 응답을 만들지 않는다 — `CommonExceptionHandler`가 처리한다. | ||
|
|
||
| ## 참조 | ||
| - 응답 래퍼: `framey-common/framey/common/response/ApiResponse.java` | ||
| - 예외: `framey-common/framey/common/exception/BusinessException.java` | ||
| - 공통 에러 코드 형식: `framey-common/framey/common/exception/CommonErrorCode.java` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| --- | ||
| name: domain-design | ||
| description: Entity and domain model rules for FRAMEY services. Apply when creating or modifying entities. | ||
| --- | ||
|
|
||
| # Domain Design | ||
|
|
||
| ## Entity | ||
| - 프로젝트 `BaseEntity`를 상속한다 (없으면 생성 전 사용자에게 확인) | ||
| - Entity 간 불필요한 양방향 연관관계를 생성하지 않는다 — 필요한 방향만 단방향 | ||
| - 다른 도메인(서비스)의 Entity/Repository를 직접 참조하지 않는다 — 다른 도메인 식별자는 ID 값으로만 참조 | ||
| - `@Setter` / `@Data` 사용 금지 — 상태 변경은 의도 있는 도메인 메서드로 수행 | ||
| - 생성은 생성자 또는 정적 팩터리 메서드로 제한한다 | ||
|
|
||
| ## 패키지 | ||
| - 새 Entity는 해당 서비스(`framey.{domain}`)의 domain 패키지에 배치 | ||
| - 도메인별 `ErrorCode` enum은 서비스 내 exception 패키지에 배치 |
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.
참조 파일 경로를 수정해 주세요.
지정한 경로에는 파일이 없습니다. 실제 경로는
framey-common/src/main/java/framey/common/exception/CommonErrorCode.java입니다. (raw.githubusercontent.com).claude/skills/api-design/SKILL.md의 Line 92–94에도src/main/java를 추가해 주세요.