[BE-10] 기존 시설 지역 백필 — 온라인 배치 서비스 + 관리자 엔드포인트

작업 내용 (설계 의도)

변경 사항

기존 Mongo facility 문서를 주소 파싱으로 시/도·시군구 표준코드로 백필한다. 신규 서비스·UseCase 파일과 AdminFacilityApiController만 건드려 BE-06/07과 파일 충돌 없음. 근거 TDD: ../TDD.md FR-3·“실패 경로·동시성·멱등”.

  • domain/facility/service/FacilityRegionBackfillService.kt(신규) — FacilityRepository + RegionResolveGateway + DistributedLock 주입. backfill(pageSize): 락 획득(lock:facility:region-backfill, 실패 시 예외) → findAllForBackfill 페이지 순회 → 각 문서 resolve(address, null)facility.assignRegion(region)save. UNSPECIFIED도 보존, 결정적 재해석으로 멱등. 결과 BackfillResult(updated, unspecified).
  • application/facility/usecase/BackfillFacilityRegionUseCase.kt(신규) — execute(pageSize): BackfillResult, 서비스 위임(10줄).
  • application/facility/dto/BackfillFacilityRegionResult.kt(신규).
  • presentation/facility/controller/AdminFacilityApiController.ktPOST /admin/facilities/backfill-region?pageSize= 추가. 락 실패 시 409. 이 파일 단독 수정자.
  • presentation/facility/dto/response/BackfillFacilityRegionResponse.kt(신규).

롤백

  • 데이터는 멱등이라 재실행으로 수렴. 필요 시 region 필드 $unset mongosh 역스크립트로 원복. 배치는 락으로 중복 방지, 피처 없이 관리자 트리거만 존재(트리거 안 하면 no-op).

의존

  • BE-04, BE-02

다이어그램

처리 흐름

sequenceDiagram
    participant A as Admin
    participant C as AdminFacilityApiController
    participant U as BackfillFacilityRegionUseCase
    participant S as FacilityRegionBackfillService
    participant L as DistributedLock
    participant R as FacilityRepository
    participant G as RegionResolveGateway
    A->>C: POST /admin/facilities/backfill-region
    C->>U: execute(pageSize)
    U->>S: backfill(pageSize)
    S->>L: acquire
    loop 페이지
        S->>R: findAllForBackfill(page)
        S->>G: resolve(address, null)
        S->>R: save(assignRegion)
    end
    S-->>U: BackfillResult

클래스 의존

flowchart LR
    Ctl[AdminFacilityApiController] --> UC[BackfillFacilityRegionUseCase]
    UC --> Svc[FacilityRegionBackfillService]
    Svc --> Repo[FacilityRepository]
    Svc --> Reg[RegionResolveGateway]
    Svc --> Lock[DistributedLock]

테스트 케이스

  • 해석 가능한 주소의 문서는 시/도·시군구 코드가 채워진다
  • 주소 파싱 실패 문서는 UNSPECIFIED로 보존되고 삭제·스킵되지 않는다
  • 동일 데이터에 백필을 재실행해도 결과가 동일하다(멱등)
  • 락 획득 실패(동시 트리거) 시 409로 즉시 중단된다
  • 이미 해석된 문서는 재백필 시 동일 코드로 유지된다
  • 페이지 단위로 순회해 대량 문서에서도 장시간 트랜잭션을 만들지 않는다