[BE-01] alerting 도메인 계약 (엔티티·VO·인터페이스·도메인 서비스)

작업 내용 (설계 의도)

변경 사항

신규 alerting 지원 도메인의 순수 도메인 계약과 오케스트레이션 로직을 확립한다. 후행 티켓 전원이 이 계약을 참조하는 연관 병목이므로 한 티켓으로 묶는다. 근거 TDD: ../TDD.md §Detail Design·§상태 전이·§인터페이스 시그니처. 근거 ADR: ADR-003·ADR-004.

신규 domain/alerting 패키지에 작성:

  • 엔티티 Alert(Aggregate Root, private constructor + create/reconstitute 팩토리, private var 필드, 기본값 금지). 상태 전이 메서드 attachAnalysis·markDelivered·markDeliveryFailed, 질의 프로퍼티. 도메인 이벤트를 @Transient 리스트에 적재 → pullDomainEvents().
  • enum AlertStatus(RAISED/ANALYZED/FALLBACK/DELIVERED/DELIVERY_FAILED, canTransitTo 캡슐화), AlertSource(LATENCY/OVERSELL/DEPLOYMENT/SELF_CHECK), AlertSeverity(INFO/WARN/CRITICAL, discordColor()).
  • VO AlertSignal(endpoint/source/severity, cooldownKey(env)), IncidentAnalysis(errorType/causeEstimation/remediation/included, fallback() 팩토리), TelemetrySnapshot, IncidentContext.
  • interface TelemetryQueryGateway·IncidentAnalysisGateway(gateway), AlertRepository·AlertCooldownRepository(repository) — 시그니처는 TDD 확정본.
  • event AlertProcessingRequestedEvent(alertId)·AlertDeliveryReadyEvent(alertId, title, body, source, severity, env)(common DomainEvent 구현).
  • service AlertDomainServiceraise(command)(쿨다운 tryAcquire → 미획득 시 null, 획득 시 Alert 저장 + 처리이벤트 발행), process(alertId)(telemetry 조회 → LLM analyze, 실패 시 fallback → attachAnalysis → 발송이벤트 발행), selfCheck()(INFO heartbeat 발송이벤트). 검증·전이는 Entity/enum에 위임, execute 규칙 준수.
  • 시간은 ZonedDateTime, Clock 주입·시간 인자 금지(엔티티 내부 해결).

롤백: 순수 신규 패키지 — revert로 제거, 기존 코드 무영향.

의존

  • 없음 (wave 1)

다이어그램

클래스 의존

flowchart LR
    DS["AlertDomainService"] --> AR["AlertRepository"]
    DS --> CD["AlertCooldownRepository"]
    DS --> TG["TelemetryQueryGateway"]
    DS --> IG["IncidentAnalysisGateway"]
    DS --> EP["DomainEventPublisher"]
    DS --> E["Alert (Entity)"]
    E --> ST["AlertStatus"]
    E --> AN["IncidentAnalysis"]

테스트 케이스

  • 쿨다운을 획득하면 RAISED Alert가 저장되고 AlertProcessingRequestedEvent가 발행된다.
  • 쿨다운을 획득하지 못하면 Alert가 생성되지 않고 null을 반환한다(억제).
  • process에서 LLM 분석이 성공하면 상태가 ANALYZED로 전이되고 analysis.included=true가 된다.
  • process에서 IncidentAnalysisGateway가 예외를 던지면 fallback 분석으로 FALLBACK 상태가 되고 발송 이벤트는 여전히 발행된다.
  • DELIVERED 상태에서 재발송 전이 시 InvalidAlertStateException을 던진다.
  • AlertSignal.cooldownKey(env)가 alerting:cooldown:{env}:{endpoint}:{source}:{severity} 형식을 정확히 생성한다.
  • AlertSeverity.discordColor()가 severity별 색상을 반환한다(critical/warn/info 구분).