68 lines
6.8 KiB
Markdown
68 lines
6.8 KiB
Markdown
# 코드 컨벤션
|
|
|
|
## 파일 생성 규칙
|
|
- 새 기능은 가능하면 `modules/{도메인명}Controller` 단위로 패키지를 만들고 그 아래에 `service`, `mapper`, `dto`, `vo`를 필요한 만큼만 추가한다.
|
|
- 요청 검증이나 JSON 바인딩이 필요하면 `form` 패키지를 함께 만든다.
|
|
- 클래스명은 역할이 바로 드러나게 `도메인명 + 역할` 형식을 유지한다. 예: `ApiService`, `ApiMapper`, `ApiVo`
|
|
- Mapper 인터페이스를 추가하면 같은 이름의 XML을 `src/main/resources/mapper/{도메인경로}` 아래 함께 만든다.
|
|
- 단순 예시 코드와 운영 코드는 섞지 말고 패키지로 분리한다.
|
|
- 설정성 클래스는 `config` 하위 역할별 패키지에 둔다. 예: `config.jwt`, `config.exception`, `config.properties`
|
|
|
|
## DTO/VO/Form 규칙
|
|
- `Dto`는 각 Controller 에서 Service, Mapper 로 전달하는 파라미터 성격의 값 객체로 정의한다.
|
|
- `Dto`는 요청 처리에 필요한 저장, 수정, 로그 적재 같은 작업 파라미터를 담는 용도로 우선 사용한다.
|
|
- `Vo`는 Mapper 에서 Service, Controller 로 반환하는 값 객체로 정의한다.
|
|
- `Vo`는 Mapper 조회 결과를 담을 수 있고, Service 에서 비즈니스 로직 처리 후 필요한 데이터를 가공해서 Controller 로 반환하는 용도로 사용한다.
|
|
- `Form`은 Controller 입력 검증과 요청 바인딩 전용으로 두고, `@Valid` 와 Jakarta Validation 어노테이션을 우선 사용한다.
|
|
- 현재 코드처럼 DTO/VO는 Lombok `@Getter`, 필요한 경우에만 `@Setter`를 사용한다.
|
|
- Form 안에는 DTO 변환 메서드를 둘 수 있다. 예: `userDto()`, `fileUploadDto()`
|
|
- DTO 안에 연관된 다른 DTO 변환이 꼭 필요할 때만 최소한의 보조 메서드를 둔다.
|
|
- 외부 응답에 노출되면 안 되는 내부 필드는 응답에 사용될 수 있는 객체에서 `@JsonIgnore`로 숨긴다.
|
|
- Form 에서 DTO 로 변환할 때는 검증과 `trim()`, 기본값 치환까지 같이 처리하는 현재 패턴을 우선 따른다.
|
|
- 목록 조회 API 는 특별한 사유가 없으면 기본적으로 페이징을 적용하고, 검색 Form/Dto 는 `PageRequest`, 목록 응답 Vo 는 `PageResponse` 를 상속한다.
|
|
|
|
## Swagger/OpenAPI 문서화 규칙
|
|
- 신규 또는 수정되는 Controller, Form, VO에는 Swagger 테스트 편의성을 위한 설명을 반드시 남긴다.
|
|
- Controller 클래스에는 `@Tag`를 사용해 API 그룹명과 설명을 작성한다.
|
|
- Controller 메서드에는 `@Operation`으로 `summary`와 `description`을 작성한다.
|
|
- `@RequestBody` Form 클래스에는 클래스 레벨 `@Schema(description = "...")`를 작성한다.
|
|
- `@ModelAttribute` 검색 Form 필드에도 `@Schema`를 작성해 Swagger query parameter 설명과 예시가 보이게 한다.
|
|
- Form 필드에는 `@Schema`로 `description`, `example`을 작성한다.
|
|
- 필수 입력값은 Jakarta Validation 어노테이션과 `@Schema(requiredMode = Schema.RequiredMode.REQUIRED)`를 함께 사용한다.
|
|
- 코드값 필드는 허용 값을 `description`에 명시한다. 예: `userType: A 관리자, T 교사, S 학생`, `withdrawStatus: N 정상, P 탈퇴대기, Y 탈퇴완료`.
|
|
- VO 클래스에는 클래스 레벨 `@Schema(description = "...")`를 작성한다.
|
|
- VO 필드에는 `@Schema`로 응답 값의 의미를 작성한다.
|
|
- 토큰, 임시 비밀번호처럼 Swagger 테스트에 필요한 응답 필드는 VO에 명시하되 `description`에 용도를 적는다.
|
|
- 비밀번호, DB 조회용 내부 식별자, `resultCode`처럼 외부 응답에 노출하지 않는 필드는 `@JsonIgnore`를 사용하고 필요하면 `@Schema(hidden = true)`도 함께 사용한다.
|
|
- 클라이언트가 직접 전달하지 않는 내부 계산 필드나 서버 전용 getter는 `@Schema(hidden = true)`로 숨긴다.
|
|
- 페이징 요청에서 클라이언트는 `page`, `size`만 전달하고, `limit`, `offset`은 Swagger에 노출하지 않는다.
|
|
- 페이징 응답의 `rowStartNum`처럼 계산 방식이 필요한 값은 프론트 사용 방법까지 `description`에 남긴다.
|
|
|
|
## Mapper/MyBatis 규칙
|
|
- Mapper 메서드명은 SQL 동작이 드러나도록 `select`, `insert`, `update` 접두어를 사용한다.
|
|
- 삭제가 물리 삭제가 아니라 상태 변경이면 `delete` 대신 목적이 드러나는 `update...Canceled`, `update...DelYn` 같은 이름을 우선한다.
|
|
- Mapper XML `namespace`는 인터페이스의 전체 경로와 정확히 일치시킨다.
|
|
- XML의 `id`는 Mapper 메서드명과 동일하게 맞춘다.
|
|
- 조회 결과 타입은 `resultType`, 저장/수정 파라미터는 DTO 필드명과 매핑되는 프로퍼티명을 그대로 사용한다.
|
|
- Mapper XML 안 SQL 블록 시작부 주석은 현재 코드처럼 `/*Mapper.method*/` 형식을 유지한다.
|
|
- Mapper XML 위치는 `src/main/resources/mapper/**/*.xml` 이다.
|
|
- `map-underscore-to-camel-case: true` 설정으로 DB 컬럼 `user_idx` 는 Java 필드 `userIdx` 로 자동 매핑된다.
|
|
- `useGeneratedKeys`, `keyProperty` 를 사용하는 insert 가 있으므로 신규 PK 생성 테이블은 현재 패턴을 먼저 확인한다.
|
|
- 상태 집계나 이력성 데이터는 단건 update 외에 이벤트 로그 insert 가 같이 필요한지 확인한다.
|
|
|
|
## Java/Spring 코드 스타일
|
|
- Java 코드는 현재 프로젝트 스타일에 맞춰 탭/들여쓰기와 import 정렬을 유지한다.
|
|
- Lombok은 반복 보일러플레이트 제거에만 절제해서 사용한다.
|
|
- 로그는 `Slf4j`를 사용하고 반복문 내부 대량 출력은 지양한다.
|
|
- 새로운 기능은 가능하면 역할이 드러나는 패키지로 분리한다.
|
|
- 생성자 주입을 기본으로 하고 필드 주입은 추가하지 않는다.
|
|
- Service 에서 DB 상태를 바꾸는 메서드는 필요한 범위에서 `@Transactional`을 사용하고, 조회 전용은 `readOnly = true`를 우선 검토한다.
|
|
- 문자열 입력값은 현재 코드처럼 필요한 지점에서 `trim()` 처리하고, null 가능성 여부를 먼저 확인한다.
|
|
|
|
## Controller/Service 규칙
|
|
- Controller 는 요청/응답 조립과 인증 주체 확인에 집중하고, DB 처리나 복잡한 계산은 Service 로 넘긴다.
|
|
- Controller 응답은 `ResponseEntity<ApiResponse<T>>` 를 기본으로 사용한다. 파일 다운로드처럼 바이너리 응답이 필요한 경우만 예외로 둔다.
|
|
- Controller 에서는 `@RequestBody`, `@PathVariable`, `@RequestHeader`, `@CookieValue` 를 명시적으로 선언해 요청 출처를 드러낸다.
|
|
- 인증 사용자 확인은 모듈 구현에 따라 `HttpSession` 또는 `SecurityContextHolder` 를 사용하므로 기존 방식을 먼저 맞춘다.
|
|
- 목록 조회는 Controller 에서 `@ModelAttribute` 검색 Form 을 받고, Service 에서 `totalCount` 와 목록을 조회한 뒤 `PageResponse#setPaging(...)` 으로 페이징 정보를 채운다.
|