[BE-30A] 어댑터 SPI 겸용 디스패치 — (platform, sourceType) 키 일반화

상태: 설계 완료 (designed). 근거 TDD: 20260727-jobkorea-dual-source-type-tdd.md “인터페이스 시그니처”. BE-02 계약 amend: 현재 코드에 posting 도메인·SPI 미구현. BE-02가 이 시그니처로 구현되거나, 이미 구현됐다면 이 티켓이 supports(platform)supports(platform, sourceType)로 수정한다.

작업 내용 (설계 의도)

근거 TDD: 20260727-jobkorea-dual-source-type-tdd.md

변경 사항

겸용 플랫폼(JOBKOREA)은 어댑터가 2개(JRS 회사 종속형 + www 애그리게이터)이고 능력(SourceCapabilities)·규약 정책·파서가 서로 다릅니다. 기존 SPI가 platform 단독 키(supports(platform)·capabilitiesOf(platform)·adapters.first { supports(platform) })라 겸용을 라우팅할 수 없습니다. 디스패치·능력 조회를 (platform, sourceType) 복합 키로 일반화합니다.

  • SourcePlatformAdapter.supports(platform, sourceType): Boolean — 어댑터가 자기 플랫폼×유형을 선언.
  • SourcePlatformAdapter.capabilities: SourceCapabilities — 능력을 어댑터 인스턴스가 보유(플랫폼당 1개 가정 제거).
  • JobSourceGatewayImpl.collect(descriptor)adapters.first { it.supports(descriptor.platform, descriptor.sourceType) }. when(platform) 분기 없음(OCP 유지).
  • JobSourceGateway.capabilitiesOf(platform, sourceType) — 겸용 플랫폼의 두 능력을 유형으로 구분. categoriesOf(platform)은 애그리게이터 어댑터에만 위임(회사 종속형은 emptyList()).
  • 미지원 조합 요청 시 명시적 예외(기존 규칙 유지).

롤백: 시그니처 변경이므로 코드 revert. 데이터 영향 없음.

의존

  • BE-30 (JobPlatform 지원 집합·SourceType 겸용)
  • BE-02 (posting 도메인·SPI·CollectionDescriptor·SourceCapabilities — 미구현 시 이 시그니처로 구현)

다이어그램

처리 흐름

sequenceDiagram
    participant C as 수집 서비스
    participant G as JobSourceGatewayImpl
    participant A as 어댑터 목록
    C->>G: collect(descriptor)
    G->>A: first { supports(platform, sourceType) }
    A-->>G: 매칭 어댑터 (JRS 또는 www)
    G->>A: fetchList(descriptor)
    A-->>G: Fetched / Failed

클래스 의존

flowchart LR
    Gateway[JobSourceGatewayImpl] --> SPI[SourcePlatformAdapter]
    SPI --> Cap[SourceCapabilities]
    Gateway --> Desc[CollectionDescriptor]
    Desc --> Platform[JobPlatform]
    Desc --> SType[SourceType]

테스트 케이스

  • (JOBKOREA, COMPANY_BOUND) descriptor가 JRS 회사 종속형 어댑터로 라우팅된다
  • (JOBKOREA, AGGREGATOR) descriptor가 www 애그리게이터 어댑터로 라우팅된다
  • 단일 유형 플랫폼(INCRUIT, COMPANY_BOUND)이 정확히 해당 어댑터로 라우팅된다
  • 지원 어댑터가 없는 조합(GREENHOUSE, AGGREGATOR) 요청은 명시적 예외를 던진다
  • capabilitiesOf(JOBKOREA, COMPANY_BOUND)capabilitiesOf(JOBKOREA, AGGREGATOR)가 서로 다른 능력을 반환한다
  • categoriesOf(JOBKOREA)가 애그리게이터 어댑터의 카테고리를 반환하고, 회사 종속형만 있는 플랫폼은 빈 목록을 반환한다