[BE-78] 단계 3 운영 가시성 — 소스 상태 조회 · 소스 레지스트리 백필 API

작업 내용 (설계 의도)

근거 TDD: 20260808-지원관리-확장-tdd.md — “Observability”, “Release Scenario 3-4 소스 레지스트리 초기값 산출”

변경 사항

  1. GET /api/operations/source-registry — 소스별 6종 상태·마지막 전이 시각·연속 비정상 일수·마지막 정상 수집 시각을 조회합니다. PRD Operations “소스 상태 레지스트리 가시성”과 Success Metrics “소스 커버리지 가시성”의 조회 수단입니다.
  2. POST /api/operations/backfills/source-registry — 데이터 마이그레이션 2단계(배치 백필). 대상 30행 미만(NFR-1: 회사 종속형 소스 30개 미만 + 애그리게이터 소수)이라 페이지 순회·청크가 불필요합니다. 이 근거를 코드 주석에 남깁니다 — private-db-schema-convention의 청크 요구는 락 범위 축소가 목적인데, 30행 단일 트랜잭션은 락 영향이 없습니다.
    • registry_status IS NULL인 행만 대상이라 재실행 멱등입니다.
    • 초기값은 seeded_at·disabled_at·job_source_health·어댑터 보유 여부로 계산합니다.
  3. 크로스 컨텍스트 조합 — 응답에 회사명이 필요하므로 companyId 집합으로 배치 조회 1회를 수행합니다(N+1 금지).
  4. OperationApiController.kt에 엔드포인트 2개를 추가합니다. 같은 wave(BE-77)는 presentation/contact만 건드리므로 파일이 겹치지 않습니다.

롤백: 백필은 registry_status를 다시 NULL로 되돌리는 UPDATE로 즉시 복구 가능합니다(30행).

의존

  • BE-70 (소스 레지스트리 상태 도메인)

다이어그램

처리 흐름

sequenceDiagram
    participant Op as 운영자
    participant C as OperationApiController
    participant U as BackfillSourceRegistryUseCase
    participant R as JobSourceRegistryDomainService
    participant H as JobSourceHealthQueryDomainService
    participant Co as CompanyDomainService
    Op->>C: POST /api/operations/backfills/source-registry
    C->>U: execute()
    U->>H: 소스별 health 배치 조회
    U->>R: recalculateAll() — 30행 단일 트랜잭션
    R-->>U: 갱신 건수
    Op->>C: GET /api/operations/source-registry
    C->>R: findAllStatuses()
    C->>Co: findAllBy(companyIds) 배치 1회
    C-->>Op: 소스별 상태 + 회사명

클래스 의존

flowchart LR
    subgraph Presentation["presentation/operation"]
        Api[OperationApiController]
    end
    subgraph Application["application/operation"]
        Backfill[BackfillSourceRegistryUseCase]
        ListS[ListSourceRegistryUseCase]
    end
    subgraph Domain["domain"]
        RDS[JobSourceRegistryDomainService]
        HDS[JobSourceHealthQueryDomainService]
        CDS[CompanyDomainService]
    end
    Api --> Backfill
    Api --> ListS
    Backfill --> RDS
    Backfill --> HDS
    ListS --> RDS
    ListS --> CDS

테스트 케이스

  • 백필 실행 후 registry_status IS NULL인 소스가 0건이다
  • 수집 성공 이력이 있는 소스는 ACTIVE로 초기화된다
  • seeded_at이 NULL인 소스는 DISCOVERED로 초기화된다
  • disabled_at이 설정된 소스는 DISABLED로 초기화된다
  • 어댑터가 없는 플랫폼 소스는 UNSUPPORTED로 초기화된다
  • 연속 비정상 일수가 1 이상인 소스는 TRANSIENT_FAILURE로 초기화된다
  • 백필을 두 번 실행하면 두 번째는 갱신 건수가 0이다 (멱등)
  • 소스 레지스트리 조회에 상태·마지막 전이 시각·회사명이 포함된다
  • 소스 30건 조회 시 회사 조회가 1회만 발생한다 (N+1 방지)
  • 애그리게이터 소스는 companyId·companyName이 null이다
  • 소스가 0건이면 빈 배열을 반환한다 (0건 경계)
  • 기존 운영 조회 API(수집 이력·알림 이력·웹훅 수신) 동작이 변경되지 않는다 (회귀)