init: 클린 아키텍처 백엔드
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
# AGENTS.md
|
||||
|
||||
## 프로젝트 정체성
|
||||
|
||||
이 저장소는 단순한 예제 블로그 애플리케이션이 아니라, Java 21 + Spring Boot 4.0.0 + Gradle 멀티모듈 기반의 Clean Architecture 템플릿이다.
|
||||
|
||||
기본 패키지는 `dev.caskeleton`이며, 예시 도메인은 production 모듈이 아니라 `sample-portfolio` 모듈(WorkLog 엔지니어링 작업 기록 게시판)에 격리한다. 새 프로젝트를 시작할 때는 도메인 이름, 패키지, 엔티티, 유스케이스를 교체할 수 있지만, 모듈 경계와 의존성 방향은 유지해야 한다.
|
||||
|
||||
## Prime Directive
|
||||
|
||||
에이전트는 속도보다 아키텍처 보존을 우선한다.
|
||||
|
||||
동작하는 코드라도 HARD-STOP 조건을 하나라도 위반하면 완료된 작업이 아니다.
|
||||
|
||||
HARD-STOP 8개 항목의 SSOT 는 `.agents/plugins/ca-superpowers/rules/clean-architecture.md` §HARD-STOP 이다. 이 문서는 목록 사본을 유지하지 않는다 — 불일치 시 SSOT 파일이 우선한다. (항상 로드되는 요약 사본은 root `CLAUDE.md` Prime Directive 에 있다.)
|
||||
|
||||
## Superpowers Workflow
|
||||
|
||||
이 프로젝트에서 에이전트는 관련 Superpowers 스킬을 먼저 확인하고, 작업 성격에 맞는 스킬을 사용한다. 사용자 지시와 이 `AGENTS.md`가 로컬 프로젝트의 최상위 규칙이며, Superpowers는 그 규칙을 실행하기 위한 작업 방식이다.
|
||||
|
||||
사용 가능한 주요 스킬과 트리거:
|
||||
|
||||
- `superpowers:using-superpowers`: 대화나 작업을 시작할 때 관련 스킬을 확인한다.
|
||||
- `superpowers:brainstorming`: 기능 설계, 구조 변경, 동작 변경, 새 문서 정책 수립 전에 사용한다.
|
||||
- `superpowers:writing-plans`: 승인된 설계가 있고 작업이 여러 단계로 나뉠 때 사용한다.
|
||||
- `superpowers:executing-plans`: 작성된 계획을 현재 세션에서 순차 실행할 때 사용한다.
|
||||
- `superpowers:subagent-driven-development`: 계획을 작업 단위로 나누어 독립 에이전트에게 맡길 때 사용한다.
|
||||
- `superpowers:dispatching-parallel-agents`: 서로 독립적인 조사나 구현을 병렬로 진행할 때 사용한다.
|
||||
- `superpowers:test-driven-development`: 기능 추가와 버그 수정을 테스트 우선으로 진행할 때 사용한다.
|
||||
- `superpowers:systematic-debugging`: 버그, 실패한 테스트, 예상 밖 동작을 다룰 때 사용한다.
|
||||
- `superpowers:verification-before-completion`: 완료, 수정됨, 통과함을 주장하기 전에 사용한다.
|
||||
- `superpowers:requesting-code-review`: 의미 있는 구현을 마친 뒤 병합 또는 PR 전에 사용한다.
|
||||
- `superpowers:receiving-code-review`: 리뷰 피드백을 적용하기 전에 사용한다.
|
||||
- `superpowers:finishing-a-development-branch`: 구현과 검증이 끝난 브랜치를 정리할 때 사용한다.
|
||||
- `superpowers:using-git-worktrees`: 격리된 작업 공간이 필요할 때 사용한다.
|
||||
- `superpowers:writing-skills`: 스킬을 만들거나 수정할 때 사용한다.
|
||||
|
||||
## Harness 정책 SSOT
|
||||
|
||||
- `.harness/manifest.yaml`: Java 21 / Spring Boot 4.0.0 프로젝트 identity와 task packet 진입점
|
||||
- `.harness/project/modules.yaml`: 19개 leaf의 ID, 소스 경로, Gradle path, 허용 edge, focused command
|
||||
- `.harness/core/risk-policy.yaml`: change-surface 기반 risk 분류
|
||||
- `.harness/core/evidence-policy.yaml`: risk별 evidence/review profile
|
||||
- `.harness/core/review-policy.yaml`: orchestration, option/counterargument, human-only commit 정책
|
||||
- `.harness/core/report-policy.yaml`: concise/durable report와 citation self-grep 정책
|
||||
|
||||
작업 시작 시 task packet을 한 번 resolve하고 stable packet/rule hash를 재사용한다. overlay나 관련
|
||||
hash가 바뀔 때만 다시 resolve하거나 rule 전문을 재정독한다. 파일 수는 risk 분류 기준이 아니다.
|
||||
commit 정책은 모든 플랫폼에서 `human-only`이며 agent는 stage/commit/amend/push하지 않는다.
|
||||
|
||||
## LLM Wiki 캡처 워크플로우
|
||||
|
||||
구현, 아키텍처, 빌드, 테스트, 런타임, 문서 워크플로우 변경처럼 의미 있는 작업을 끝낸 뒤에는 최종 응답 전에 LLM Wiki 기록을 갱신한다.
|
||||
|
||||
기준 vault:
|
||||
|
||||
```text
|
||||
/home/donghyeon/workspace/ai-tool/llm-wiki-private/
|
||||
```
|
||||
|
||||
에이전트는 해당 vault의 `AGENTS.md`, `CLAUDE.md`, `rules/`, `.agents/`, `.claude/`, `.codex/` 지침을 확인한 뒤 작성한다. ca-tmpl 내부의 상세 실행 규칙은 `.agents/plugins/ca-superpowers/rules/llm-wiki-capture.md`를 따른다.
|
||||
|
||||
필수 순서:
|
||||
|
||||
1. `/home/donghyeon/workspace/ai-tool/llm-wiki-private/raw/branch-notes/<branch-name>.md`를 생성하거나 갱신한다.
|
||||
2. 구현 내용, 변경 파일, 의사결정, 검증 명령, 실패/차단 사항, 증거 등급을 branch-note에 기록한다.
|
||||
3. 실제로 파생 자료가 있으면 다음 raw 문서를 생성하거나 갱신한다.
|
||||
- `raw/errors/`: 오류, 실패한 테스트, 샌드박스/도구 문제, 재발 가능한 트러블슈팅
|
||||
- `raw/interviews/`: 이 작업에서 정직하게 뽑을 수 있는 면접 질문
|
||||
- `raw/blog-topics/`: 채용공고가 아닌 구현·설계·트러블슈팅 기반 블로그 글감
|
||||
4. 파생 문서는 `## Parent`에서 branch-note로 upward link하고, branch-note의 `## Cluster / 묶음`에는 파생 문서 wikilink를 되돌려 적는다.
|
||||
5. canonical 추출 요청이 없는 한 `wiki/blog/`, `wiki/interview/`, `wiki/portfolio/`, `wiki/concepts/`, `wiki/projects/`를 바로 만들지 않는다.
|
||||
|
||||
파생 문서가 필요 없을 때도 그냥 생략하지 말고, branch-note의 cluster 섹션에 "없음" 또는 "추출할 별도 글감 없음"처럼 판단 결과를 남긴다.
|
||||
|
||||
## 강제 수준
|
||||
|
||||
이 문서는 에이전트와 개발자가 따라야 할 작업 규칙을 정의하지만, 그 자체로 빌드나 테스트를 실패시키는 자동 강제 장치는 아니다.
|
||||
|
||||
이 프로젝트의 규칙은 세 단계로 관리한다.
|
||||
|
||||
1. `AGENTS.md`: 에이전트와 개발자가 따라야 할 아키텍처, 작업 순서, 검증 원칙을 정의한다.
|
||||
2. ArchUnit/Gradle/Test: 모듈 의존성, 계층 침범, 설정 바인딩, 동작 회귀를 자동으로 탐지한다.
|
||||
3. Code Review/CI: 문서와 자동 검증이 놓친 설계 품질, 운영 위험, 템플릿 일관성을 최종 확인한다.
|
||||
|
||||
에이전트는 `AGENTS.md`를 따라 작업해야 하며, 현업 수준의 스켈레톤 완성도는 반드시 자동 검증과 리뷰로 보강해야 한다.
|
||||
|
||||
## 모듈 책임
|
||||
|
||||
19개 leaf 모듈의 ID, 실제 소스 경로, Gradle path, 허용 의존성, focused test 명령은
|
||||
`.harness/project/modules.yaml`이 SSOT다. 이 문서는 leaf 목록을 복제하지 않고 family 책임만
|
||||
정의한다. 작업 파일에서는 가장 가까운 `src/**/CLAUDE.md`를 함께 읽는다.
|
||||
|
||||
- `domain-core`: 순수 도메인 모델, 불변식, 이벤트, port. Spring/JPA/transport/IO 타입 금지.
|
||||
- `application-core`: command, use case, application policy, transaction port, application 예외.
|
||||
inbound DTO, persistence entity, adapter 타입 금지.
|
||||
- `adapter:inbound:*`: HTTP/gRPC/GraphQL/WebSocket transport, DTO, validation, 인증·인가 매핑,
|
||||
error mapping. repository 직접 호출과 비즈니스 정책 금지.
|
||||
- `adapter:outbound:persistence-*`: JPA/PostgreSQL 또는 MongoDB persistence 구현과 mapping,
|
||||
migration/vendor 동작. 유스케이스 정책 금지.
|
||||
- 그 밖의 `adapter:outbound:*`: support, messaging, cache, notification, object storage,
|
||||
file server, HTTP client, identifier 능력을 port 뒤에서 구현한다. adapter 간 허용 edge는
|
||||
registry만 따른다.
|
||||
- `shared-contract`: skeleton-wide 운영 계약. business/domain 개념 저장 금지.
|
||||
- `sample-portfolio`: 샘플/fixture consumer. production leaf가 의존하면 안 된다.
|
||||
- `app-bootstrap`: Spring Boot entrypoint와 composition root. 비즈니스 유스케이스 금지.
|
||||
|
||||
## 의존성 방향
|
||||
|
||||
family 수준 기본 방향:
|
||||
|
||||
```text
|
||||
app-bootstrap -> adapter:inbound:* -> application-core -> domain-core
|
||||
app-bootstrap -> adapter:outbound:* -> application-core -> domain-core
|
||||
runtime modules -> shared-contract
|
||||
sample-portfolio -> registered runtime leaves (fixture consumer only)
|
||||
```
|
||||
|
||||
개별 edge는 `.harness/project/modules.yaml`의 `allowed_dependencies`가 유일한 목록이다.
|
||||
Gradle 의존성 검증도 같은 registry를 읽는다. root 문서나 기억에서 leaf edge를 추론하지 않는다.
|
||||
|
||||
## 기능 개발 프로토콜
|
||||
|
||||
새 기능이나 동작 변경은 다음 순서로 진행한다.
|
||||
|
||||
1. 요구사항을 읽고 소유 계층을 판단한다.
|
||||
2. 구조나 동작이 바뀌면 `superpowers:brainstorming`으로 설계를 먼저 확정한다.
|
||||
3. 여러 단계의 작업이면 `docs/superpowers/specs/`에 설계 문서를 남긴다.
|
||||
4. 구현 전 `docs/superpowers/plans/`에 실행 계획을 작성한다.
|
||||
5. 동작 변경은 테스트를 먼저 작성한다.
|
||||
6. 새 비즈니스 개념은 `domain-core`에 먼저 둔다.
|
||||
7. 유스케이스는 `application-core` command와 use case/service method로 표현한다.
|
||||
8. 외부 연동은 registry가 가리키는 `adapter:outbound:*` leaf에서 port 구현으로 추가한다.
|
||||
9. endpoint는 마지막에 해당 `adapter:inbound:*` leaf에서 얇게 연결한다.
|
||||
10. focused test를 먼저 돌리고, 가능한 경우 전체 Gradle test를 돌린다.
|
||||
11. LLM Wiki branch-note와 필요한 파생 raw 문서를 갱신한다.
|
||||
12. 완료 응답에는 변경 파일, 검증 결과, Wiki capture 결과를 포함한다.
|
||||
|
||||
## 테스트 전략
|
||||
|
||||
계층별 테스트 기준:
|
||||
|
||||
- `domain-core`: Spring 없이 순수 unit test로 도메인 규칙을 검증한다.
|
||||
- `application-core`: fake/in-memory port를 사용해 유스케이스 흐름을 검증한다.
|
||||
- `adapter:inbound:*`: transport validation, auth mapping, status/response contract를 검증한다.
|
||||
- `adapter:outbound:persistence-*`: persistence mapping, repository adapter, vendor/migration 동작을 검증한다.
|
||||
- 그 밖의 `adapter:outbound:*`: external capability adapter contract를 검증한다.
|
||||
- `app-bootstrap/settings`: configuration binding, validation, logging 설정을 검증한다.
|
||||
|
||||
검증 원칙:
|
||||
|
||||
- 완료를 주장하기 전에 `superpowers:verification-before-completion`을 사용한다.
|
||||
- 실행한 명령과 결과를 최종 응답에 적는다.
|
||||
- 테스트를 실행하지 못했다면 이유와 남은 위험을 솔직히 적는다.
|
||||
|
||||
권장 절차:
|
||||
|
||||
```bash
|
||||
cd src
|
||||
python3 ../.harness/validators/resolve_task.py <task-overlay.json>
|
||||
# resolved packet의 focused_commands를 실행
|
||||
./gradlew test
|
||||
./gradlew check # check 가 verifyCleanArchitectureDependencies + verifyEnvKeys 2종을 전이 실행한다 (src/build.gradle)
|
||||
./gradlew verifyCleanArchitectureDependencies
|
||||
./gradlew verifyPublicPathSnapshot
|
||||
./gradlew verifyEnvKeys
|
||||
```
|
||||
|
||||
19개 leaf의 정확한 focused test 명령은 `.harness/project/modules.yaml`과 resolved task packet을
|
||||
따른다. root 문서에 별도 명령 목록을 복제하지 않는다.
|
||||
|
||||
## 설정과 런타임
|
||||
|
||||
설정 규칙:
|
||||
|
||||
- secrets를 코드, 테스트 fixture, 문서 예시에 하드코딩하지 않는다.
|
||||
- 새 설정 그룹은 typed settings class로 만든다.
|
||||
- 흩어진 `@Value`보다 configuration properties와 settings class를 선호한다.
|
||||
- `.env.local`은 로컬 오버라이드로 취급한다.
|
||||
- `application.yml`은 환경별로 안전한 기본값과 명확한 placeholder만 담는다.
|
||||
- 새 settings class를 만들면 binding/validation 테스트를 추가한다.
|
||||
|
||||
Docker/runtime 규칙:
|
||||
|
||||
- Dockerfile 변경 시 build context와 runtime env 요구사항을 함께 확인한다.
|
||||
- container 안에서 필요한 profile, port, env var를 문서나 예시 설정에 반영한다.
|
||||
- local-only 경로와 운영 경로를 섞지 않는다.
|
||||
|
||||
## 템플릿 재사용 체크리스트
|
||||
|
||||
이 저장소를 새 프로젝트 시작점으로 사용할 때:
|
||||
|
||||
1. `src/settings.gradle`의 `rootProject.name`을 새 프로젝트명으로 바꾼다.
|
||||
2. Java package `dev.caskeleton`을 새 organization/project package로 바꾼다.
|
||||
3. `CaSkeletonApplication` 이름을 새 애플리케이션 이름으로 바꾼다.
|
||||
4. production 모듈에는 목표 도메인의 entity, repository port, use case, adapter만 추가하고, 예시 코드는 `sample-portfolio`에 격리한다.
|
||||
5. 모듈 이름과 경계는 유지한다.
|
||||
6. Docker image/application 이름을 새 프로젝트 기준으로 수정한다.
|
||||
7. `.env`, `.env.local`, `application.yml`의 예시 값을 새 런타임 요구사항에 맞춘다.
|
||||
8. README와 운영 문서를 새 프로젝트 설명으로 갱신한다.
|
||||
9. 전체 테스트를 실행한다.
|
||||
|
||||
```bash
|
||||
cd src
|
||||
./gradlew test
|
||||
```
|
||||
|
||||
## 금지된 지름길
|
||||
|
||||
에이전트는 다음을 하지 않는다.
|
||||
|
||||
- `domain-core`에 Spring/JPA annotation 추가
|
||||
- controller에서 repository 직접 호출
|
||||
- application method가 web request DTO를 인자로 받게 만들기
|
||||
- application이나 domain에서 JPA entity 반환
|
||||
- mapper에 비즈니스 정책 넣기
|
||||
- filter/config/settings class에 유스케이스 넣기
|
||||
- 요청 범위 밖의 대규모 리팩터링
|
||||
- 사용자 변경사항 되돌리기
|
||||
- 명시적 요청 없는 destructive git command 실행
|
||||
- 테스트 미실행 상태에서 "완료"라고 말하기
|
||||
|
||||
## 작업 보고 규칙
|
||||
|
||||
최종 응답에는 다음을 포함한다.
|
||||
|
||||
- 변경한 파일
|
||||
- 핵심 변경 내용
|
||||
- 실행한 검증 명령
|
||||
- 실패하거나 실행하지 못한 검증
|
||||
- LLM Wiki branch-note와 파생 문서 캡처 결과
|
||||
- 남은 위험 또는 후속 작업
|
||||
|
||||
짧은 작업이라도 검증 여부는 생략하지 않는다.
|
||||
Reference in New Issue
Block a user