280 lines
9.5 KiB
Markdown
280 lines
9.5 KiB
Markdown
---
|
|
title: ""
|
|
source_type: "report"
|
|
status: "draft"
|
|
confidence: "unknown"
|
|
derived_from:
|
|
- "wiki/projects/<canonical-project-doc>"
|
|
- "raw/branch-notes/<optional-branch-note>"
|
|
related_projects:
|
|
- "ca-tmpl"
|
|
audience: "self"
|
|
purpose: "big-picture-understanding"
|
|
last_reviewed: ""
|
|
status_label: "draft"
|
|
---
|
|
|
|
# {{title}}
|
|
|
|
> 이 문서는 이해를 위한 derived report입니다.
|
|
> SSOT는 `raw/branch-notes/`와 `wiki/projects/`의 canonical 문서입니다.
|
|
> 이 문서는 ca-tmpl 전체 구조를 사람이 읽고 설명할 수 있도록 재구성합니다.
|
|
|
|
---
|
|
|
|
## 0. Reading Guide
|
|
|
|
### 이 문서는 무엇을 설명하는가
|
|
|
|
`<ca-tmpl 전체 구조, 목표, 핵심 계약, 구현 상태를 설명한다.>`
|
|
|
|
### 먼저 읽어야 할 사람
|
|
|
|
- `<ca-tmpl의 큰 그림이 아직 안 잡힌 사람>`
|
|
- `<branch-note를 읽기 전에 전체 지도가 필요한 사람>`
|
|
- `<Clean Architecture skeleton의 운영 계약이 왜 필요한지 이해하려는 사람>`
|
|
|
|
### 이 문서를 읽고 답할 수 있어야 하는 질문
|
|
|
|
- ca-tmpl은 무엇인가?
|
|
- 왜 도메인 기능을 제거했는가?
|
|
- 왜 운영 계약이 skeleton의 중심인가?
|
|
- 왜 branch-note가 많은가?
|
|
- 각 branch-note는 전체 skeleton의 어느 영역을 책임지는가?
|
|
- 현재 구현된 것과 아직 문서만 있는 것은 무엇인가?
|
|
|
|
### SSOT
|
|
|
|
- Canonical:
|
|
- `wiki/projects/<canonical-project-doc>`
|
|
- Raw / branch notes:
|
|
- `raw/branch-notes/<optional-branch-note>`
|
|
|
|
### 이 문서의 한계
|
|
|
|
- 이 문서는 SSOT가 아니다.
|
|
- 구현 상태는 작성일 기준이다.
|
|
- 세부 결정은 각 branch-note와 canonical 문서를 확인해야 한다.
|
|
|
|
---
|
|
|
|
## 1. 이 프로젝트는 무엇인가
|
|
|
|
### 한 문장 정의
|
|
|
|
> ca-tmpl은 `<새 백엔드 프로젝트를 시작할 때 반복적으로 필요한 운영 계약>`을 Clean Architecture 구조로 미리 고정해두는 skeleton이다.
|
|
|
|
### 하지 않는 것
|
|
|
|
- 특정 비즈니스 도메인을 제공하지 않는다.
|
|
- 특정 adapter를 무겁게 기본 탑재하지 않는다.
|
|
- raw branch-note에서 곧바로 blog/interview/portfolio로 파생하지 않는다.
|
|
- 운영 실패, 로그, trace, API envelope, module boundary를 프로젝트마다 임의로 재결정하지 않는다.
|
|
|
|
### 제공하는 것
|
|
|
|
- module/package boundary
|
|
- structured API response
|
|
- operational error category
|
|
- exception ownership
|
|
- boundary validation / mapper contract
|
|
- structured logging / tracing
|
|
- env-driven runtime configuration
|
|
- repository capability contract
|
|
- adapter failure mapping
|
|
- architecture test / contract test
|
|
- sample domain fixture
|
|
|
|
### 왜 skeleton인가
|
|
|
|
`<도메인 기능 자체보다, 도메인을 얹었을 때 동일한 운영 계약과 아키텍처 경계를 유지하는 구조가 목적이기 때문이다.>`
|
|
|
|
---
|
|
|
|
## 2. 이 프로젝트가 해결하는 핵심 문제
|
|
|
|
### 문제 1. 프로젝트마다 실패 처리 방식이 달라지는 문제
|
|
|
|
- 어떤 프로젝트는 validation 실패를 400으로 반환한다.
|
|
- 어떤 프로젝트는 같은 실패를 500으로 반환한다.
|
|
- 어떤 프로젝트는 raw exception message를 client에게 노출한다.
|
|
- 결과적으로 운영, 디버깅, API contract가 흔들린다.
|
|
|
|
### 문제 2. Clean Architecture 경계가 문서에만 남고 코드에서 무너지는 문제
|
|
|
|
- controller가 JPA entity를 직접 반환한다.
|
|
- application layer가 Spring/JPA 구현체를 직접 import한다.
|
|
- domain이 framework annotation을 알게 된다.
|
|
- adapter끼리 직접 참조하면서 순환 결합이 생긴다.
|
|
|
|
### 문제 3. 관측성 정보가 일관되지 않은 문제
|
|
|
|
- requestId가 없는 로그가 남는다.
|
|
- traceId와 correlationId 의미가 branch마다 다르다.
|
|
- 장애 발생 시 어떤 요청에서 어떤 dependency 실패가 났는지 추적하기 어렵다.
|
|
|
|
### 문제 4. 테스트가 구현 세부만 검증하고 계약 위반을 잡지 못하는 문제
|
|
|
|
- unit test는 통과하지만 architecture boundary가 깨진다.
|
|
- API response schema drift가 생겨도 release 전에 감지하지 못한다.
|
|
- contract violation이 warning-only로 남는다.
|
|
|
|
---
|
|
|
|
## 3. 전체 구조 요약
|
|
|
|
| 영역 | 역할 | 왜 필요한가 |
|
|
| ------------------- | --------------------------------------------------- | --------------------------------------------------- |
|
|
| domain-core | 순수 domain model, value object, domain rule | framework와 adapter로부터 business invariant를 보호 |
|
|
| application-core | use case, command/query, port, policy validation | business flow와 외부 구현체 사이의 경계 유지 |
|
|
| adapter-web | HTTP DTO, controller, validation, response mapper | 외부 HTTP 요청을 application contract로 변환 |
|
|
| adapter-persistence | JPA/RDBMS 저장소 구현, entity, mapper | persistence 기술을 application port 뒤로 숨김 |
|
|
| adapter-outbound | HTTP client, messaging, cache, notification adapter | 외부 dependency 세부 구현을 격리 |
|
|
| shared-contract | envelope, error code, header/log/metric registry | skeleton-wide operational contract 공유 |
|
|
| app-bootstrap | Spring Boot entrypoint, DI wiring, runtime config | composition root로 runtime module을 조립 |
|
|
| sample-portfolio | skeleton contract 검증용 fixture | 실제 domain 없이 contract를 검증 |
|
|
|
|
---
|
|
|
|
## 4. 핵심 흐름
|
|
|
|
### 4.1 Request 처리 흐름
|
|
|
|
```text
|
|
HTTP Request
|
|
→ adapter-web Request DTO
|
|
→ request validation
|
|
→ mapper
|
|
→ application Command/Query
|
|
→ use case
|
|
→ domain model / domain rule
|
|
→ output port
|
|
→ adapter-persistence or adapter-outbound
|
|
→ response mapper
|
|
→ structured envelope
|
|
```
|
|
|
|
### 4.2 Error 처리 흐름
|
|
|
|
```text
|
|
Exception or failure
|
|
→ layer-specific exception ownership
|
|
→ operational error mapping
|
|
→ error.code / error.category / retryable
|
|
→ structured envelope
|
|
→ structured log
|
|
→ trace correlation
|
|
```
|
|
|
|
### 4.3 Domain Feature 추가 흐름
|
|
|
|
```text
|
|
presentation request/response DTO
|
|
→ request mapper
|
|
→ application command/query
|
|
→ use case
|
|
→ input port / output port
|
|
→ domain model / value object / domain rule
|
|
→ persistence model / repository adapter
|
|
→ response mapper
|
|
→ contract test
|
|
→ architecture rule
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 주요 계약 묶음
|
|
|
|
| 계약 영역 | 담당 branch | 설명 | 현재 상태 |
|
|
| ---------------------------- | -------------------------- | ---------------------------------------------- | ---------- |
|
|
| error / observability | `raw/branch-notes/<...>` | error category, envelope, log/trace 기반 | `<status>` |
|
|
| API contract | `raw/branch-notes/<...>` | versioning, pagination, headers, idempotency | `<status>` |
|
|
| boundary validation / mapper | `raw/branch-notes/<...>` | DTO → command/query → domain 변환 경계 | `<status>` |
|
|
| module/package blueprint | `raw/branch-notes/<...>` | Gradle multi-module, package responsibility | `<status>` |
|
|
| transaction / concurrency | `raw/branch-notes/<...>` | transaction boundary, lock, retry, idempotency | `<status>` |
|
|
| sample fixture | `raw/branch-notes/<...>` | skeleton contract 검증용 sample domain | `<status>` |
|
|
| architecture enforcement | `raw/branch-notes/<...>` | ArchUnit / Gradle dependency guardrail | `<status>` |
|
|
|
|
---
|
|
|
|
## 6. 현재 구현 상태
|
|
|
|
| 영역 | 상태 | 근거 | 남은 위험 |
|
|
| -------- | ------------------------------------------------------------------------ | -------------------- | --------- |
|
|
| `<영역>` | `<decision-only / documented-only / local-verified / pending / unknown>` | `<문서/코드/테스트>` | `<위험>` |
|
|
|
|
### 상태 값 정의
|
|
|
|
| 상태 | 의미 |
|
|
| --------------- | ----------------------------------- |
|
|
| decision-only | 결정은 있으나 구현/검증은 아직 없음 |
|
|
| documented-only | 문서상 계약만 있음 |
|
|
| local-verified | 로컬 코드/테스트로 검증됨 |
|
|
| pending | 아직 착수 전 또는 잔여 작업 존재 |
|
|
| unknown | 근거 부족으로 판단 불가 |
|
|
|
|
---
|
|
|
|
## 7. 큰 그림에서 가장 중요한 설계 판단
|
|
|
|
### 판단 1. `<판단 이름>`
|
|
|
|
- 결정:
|
|
- 이유:
|
|
- 대안:
|
|
- 선택하지 않은 이유:
|
|
- 근거:
|
|
- 남은 리스크:
|
|
|
|
### 판단 2. `<판단 이름>`
|
|
|
|
- 결정:
|
|
- 이유:
|
|
- 대안:
|
|
- 선택하지 않은 이유:
|
|
- 근거:
|
|
- 남은 리스크:
|
|
|
|
---
|
|
|
|
## 8. 내가 설명할 수 있어야 하는 문장
|
|
|
|
### 30초 설명
|
|
|
|
`<ca-tmpl을 30초 안에 설명하는 문장>`
|
|
|
|
### 2분 설명
|
|
|
|
`<면접/리뷰/동료 설명에서 말할 수 있는 설명>`
|
|
|
|
### 깊게 질문받았을 때
|
|
|
|
**Q. 왜 도메인 기능을 제거했나?**
|
|
A. `<답변>`
|
|
|
|
**Q. 왜 sample-portfolio가 필요한가?**
|
|
A. `<답변>`
|
|
|
|
**Q. 왜 shared-contract가 필요한가?**
|
|
A. `<답변>`
|
|
|
|
**Q. 왜 architecture test가 필요한가?**
|
|
A. `<답변>`
|
|
|
|
---
|
|
|
|
## 9. 아직 이해가 부족한 부분
|
|
|
|
| 질문 | 왜 헷갈리는가 | 확인할 문서 | 확인할 코드 |
|
|
| ---- | ------------- | ----------- | ----------- |
|
|
| | | | |
|
|
|
|
---
|
|
|
|
## 10. 다음에 읽을 문서
|
|
|
|
- `wiki/reports/ca-tmpl/01-module-boundary-report`
|
|
- `wiki/reports/ca-tmpl/02-operational-error-observability-report`
|
|
- `wiki/reports/ca-tmpl/03-api-contract-report`
|
|
- `wiki/reports/ca-tmpl/04-boundary-validation-mapper-report`
|