[BE-58] 자동 슬롯 생성 스케줄러 (멱등, 향후 14일)

작업 내용 (설계 의도)

변경 사항

근거 TDD: “Possible Solutions 자동 슬롯 생성 A·실패 경로 배치 멱등/부분실패·서버 토폴로지”. 운영시간·휴무 기준으로 매일 향후 14일 예약 가능 회차(Slot)를 자동 생성한다(FR-9). 기존 (facility,date,timeRange) 조합은 skip(멱등), 신규 날짜분만 생성 — V14 UNIQUE와 충돌 없이 재실행 안전(Scenario22).

포함 (전부 신규 파일):

  • domain: FacilityScheduleGateway interface(booking) + FacilitySchedule/WeeklyHours(booking 소유 DTO — facility import 금지) + SlotGenerationDomainService.generate(schedule, windowDays) — 윈도우 내 기존 슬롯 (date,timeRange) Set 조회 후 미존재분만 Slot.create(programId=null, status=OPEN), 생성건수 반환.
  • application: GenerateSlotsUseCase.execute()FacilityScheduleGateway.findSchedulableFacilities() 순회, 시설 단위 try-catch로 부분실패 격리, 시설별 생성/skip 집계 반환.
  • infrastructure: FacilityScheduleGatewayImpl(Mongo FacilityRepository 읽어 운영시간·휴무를 booking DTO로 변환, @Profile("!test-jpa") — FacilityOwnershipGatewayImpl 패턴).
  • presentation: GenerateSlotsScheduler(@Scheduled(cron) 1일1회, McpAnomalyScheduler 패턴) + @ConditionalOnProperty(facility.autoslot.enabled) — 초기 OFF로 대량 생성 사고 방지. windowDays는 설정값(default 14).
  • 시간 ZonedDateTime, 휴무일 skip, 운영시간 없는 요일 skip.

롤백

facility.autoslot.enabled=false로 스케줄러 즉시 정지. 이미 생성된 슬롯은 유지(무해).

의존

  • BE-56 (OperatingHours/Holiday VO)
  • BE-57 (Slot status/create 확장)

다이어그램

처리 흐름

sequenceDiagram
    participant Sch as GenerateSlotsScheduler
    participant U as GenerateSlotsUseCase
    participant G as FacilityScheduleGateway
    participant S as SlotGenerationDomainService
    Sch->>U: execute()
    U->>G: findSchedulableFacilities()
    loop 시설별 (try-catch)
        U->>S: generate(schedule, 14)
        S->>S: 기존(date,timeRange) skip, 신규만 create
    end

클래스 의존

flowchart LR
    Sch[GenerateSlotsScheduler] --> U[GenerateSlotsUseCase]
    U --> Gw[FacilityScheduleGateway]
    U --> SGS[SlotGenerationDomainService]
    SGS --> SlotRepo[SlotRepository]
    GwImpl[FacilityScheduleGatewayImpl] -.->|implements| Gw

테스트 케이스

  • 운영시간 등록된 시설에 향후 14일치 슬롯이 생성된다
  • 같은 14일 윈도우로 재실행 시 기존 (시설,날짜,시간대)는 skip되고 중복 슬롯이 생기지 않는다(멱등)
  • 휴무일로 지정된 날짜에는 슬롯이 생성되지 않는다
  • 브레이크타임 시간대는 슬롯 생성에서 제외된다
  • 한 시설의 DB 오류가 다른 시설 슬롯 생성을 막지 않는다(부분실패 격리)
  • 새 윈도우에 편입된 날짜분만 신규 생성된다
  • facility.autoslot.enabled=false면 스케줄러가 실행되지 않는다