following-the-architecture
Use when adding, moving, or renaming code in this repository, or deciding which module and package something belongs in
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when adding, moving, or renaming code in this repository, or deciding which module and package something belongs in
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use when adding, changing, or reviewing HTTP API controllers, request and response DTOs, ApiResponse payloads, JSON field names, or response nesting in this repository
Use when writing a commit message or naming a branch in this repository
Use when opening a pull request or writing a PR description in this repository
| name | following-the-architecture |
| description | Use when adding, moving, or renaming code in this repository, or deciding which module and package something belongs in |
bootstrap → web, external-in, external-out, persistence, core
web → core
external-out → core
persistence → core
core → (없음)
core에 Spring·JPA·Jackson import가 등장하면 잘못된 위치다.
어댑터끼리는 서로 의존하지 않는다. web은 persistence를 직접 부르지 않고 core의 포트를 통한다.
모든 모듈이 <모듈 루트>.<도메인> 으로 나뉜다. 현재 도메인은 auth, user. 레이어(entity, adapter, usecase, port)로 먼저 나누지 않고, 도메인 안에서는
평평하게 둔다.
src/test도 같은 규칙을 따른다. 여러 도메인이 함께 쓰는 테스트 픽스처만 모듈 테스트 루트에 둔다 (core/src/test/.../core/Fakes.kt).
도메인에 속하지 않는 것만 별도 패키지를 쓴다 — web.common(응답·예외), web.config, web.security, persistence.config.
두 도메인이 함께 쓰는 타입은 공용 패키지를 만들지 말고 더 근본이 되는 도메인에 둔다. Provider는 core.auth에 있고 core.user가 import한다.
한 도메인의 같은 종류를 한 파일에 모은다. 예외를 개별 파일로 흩뜨리지 않는다.
<도메인>UseCases.kt 유스케이스 인터페이스 + 커맨드/결과
<도메인>Gateways.kt 나가는 포트
<도메인>Exceptions.kt 도메인 예외 전부
<도메인>Dtos.kt 요청·응답 DTO
클래스가 하나뿐인 파일은 그 클래스 이름을 파일명으로 쓴다. ktlint가 강제한다.
core의 유스케이스 구현은 ...Service, 나가는 포트 구현은 ...Adapter다. 유스케이스에 Spring 애노테이션을 달지 않고, 빈 등록은 bootstrap의
CoreBeansConfig가 생성자 주입으로 한다.
/api/v1/<도메인 복수형> — user 도메인 → /api/v1/usersApiResponse<T>. ResponseEntity는 예외 핸들러만 쓴다following-api-contract을 따른다@AuthUserId, @RequestBodyfrom() / toCommand()에서 한다성공은 ApiResponse.ok(data) 또는 ApiResponse.empty(). 성공 message는 항상 "OK"이고, 엔드포인트마다 다른 성공 문구를 넣지 않는다.
실패는 GlobalExceptionHandler가 예외 타입별로 상태 코드를 정한다. 실패에 200을 반환하는 경로는 없다. 새 도메인 예외를 만들면 핸들러에 매핑을 추가한다 — 빠뜨리면 500으로 나간다.
인증 실패 응답에는 고정 문구를 쓴다. 예외 메시지에 라이브러리 내부 정보가 담길 수 있으므로 클라이언트로 내보내지 않고 로그에만 남긴다.
/api/** 의 모든 핸들러는 인증이 필요하다. 공개하려면 @PublicEndpoint를 붙인다. 새 엔드포인트는 아무것도 하지 않아도 보호된다.
OpenAPI의 bearer 표기는 AuthenticationInterceptor.isPublic을 공유하므로 문서를 따로 손대지 않는다.
@EntityScan, @EnableJpaRepositories는 basePackages = ["com.challa.persistence"] 형태로 쓴다. 메인 설정과 테스트 설정 모두.
basePackageClasses = [UserEntity::class]는 그 클래스의 패키지만 스캔한다. 도메인을 나누는 순간 다른 도메인의 엔티티가 등록되지 않고, 컴파일은 통과하고 테스트만 깨진다.
ddl-auto: update라 새 @Entity는 테이블을 자동 생성한다. 마이그레이션 도구가 없으므로 컬럼 삭제·타입 변경은 반영되지 않는다. 기존 컬럼을 바꿔야 하면 PR에 수동 DDL을 적는다.