init: 클린 아키텍처 백엔드
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
# adapter:outbound:notification — 설계 결정 참조
|
||||
|
||||
알림(email/Slack 등) 아웃바운드 어댑터 모듈. 패키지 루트:
|
||||
`dev.caskeleton.adapter.outbound.notification`. `:adapter:outbound:support` 에 의존해 공유
|
||||
correlation / fail-open 의존성 로깅을 재사용한다.
|
||||
|
||||
허용/금지 의존 정책은 `src/build.gradle` 의
|
||||
`allowedProjectDependencies['adapter:outbound:notification']` 항목이 SSOT 다(이 모듈은 아직
|
||||
별도 CLAUDE.md 를 두지 않았다). 이 문서는 코드 주석에서 덜어낸 **설계 결정의 근거**를 모아둔
|
||||
참조용 기록이다.
|
||||
|
||||
## 모듈 개요
|
||||
|
||||
application-core 포트 뒤에 두는 **선택형** 알림 어댑터다. `@ConditionalOnProperty` 로 게이팅되고
|
||||
기본 비활성이다. 이 모듈이 기본 제공하는 프로바이더는 `email/google`(`GoogleEmailProvider` /
|
||||
`GoogleEmailClient`)과 `slack/webhook`(`SlackWebhookProvider` / `SlackClient`)이며, 실제 연동
|
||||
client 는 포킹 프로젝트가 채우는 seam 이다.
|
||||
|
||||
## (channel, providerId) 복합 키 + fan-out
|
||||
|
||||
`RoutingNotifier` 는 `(channel, providerId)` 복합 키로 프로바이더를 등록한다 — 채널 내 중복
|
||||
`providerId` 는 생성 시점에 실패한다. 라우트당 providerId 목록을 주면 fan-out(모든 프로바이더
|
||||
호출)이 된다. 각 프로바이더는 이미 `FailOpenNotificationProvider` 로 감싸져 있어 한 곳의 실패가
|
||||
다른 곳을 막지 않고, 그래서 fan-out 루프에 try/catch 가 필요 없다. `FailOpenNotificationProvider
|
||||
.send` 가 `throws` 를 선언하지 않는 건 이 루프를 try/catch 없이 예외-free 로 증명하기 위함이다.
|
||||
|
||||
## 중앙 fail-open 합성 + 라우팅 바인딩
|
||||
|
||||
`NotificationConfig` 가 모든 프로바이더를 `FailOpenNotificationProvider` 로 중앙에서 감싼다(→
|
||||
`:adapter:outbound:support` 의 `FailOpenDependencyLogger` 로 WARN 로깅). 라우팅은
|
||||
`app.notification.routes.<channel>.<route>=<providerId>[,<providerId>]`. 프로바이더는
|
||||
`channel()`+`providerId()` 로 키잉된 `NotificationProvider` 빈으로 기여한다(예:
|
||||
`GoogleEmailProvider`, `SlackWebhookProvider`). `GoogleEmailClient`/`SlackClient` 는 포크가
|
||||
구현하는 seam 이며 실패는 데코레이터가 fail-open 처리한다.
|
||||
Reference in New Issue
Block a user