Glowb Dev Docs
SaaS API캠페인 일정

트리거 기반 일정 재설계

캠페인 일정의 후속 단계 마감일을 트리거 이벤트로 재산정하는 모델

트리거 기반 일정 재설계

개요: 캠페인 일정의 후속 단계 마감일이 명시적 트리거 이벤트 발화 시점에 시트 명세대로 재산정되는 모델로 전환되었습니다. 트리거 발화 시점에 해당 단계 endDate를 "당일"로 고정하고, 이후 단계들의 endDate를 산정식대로 갱신합니다. 광고주 화면(CampaignSchedule)과 크리에이터 화면(ApplicationSchedule) 모두 같은 트리거에서 일관되게 갱신됩니다.

발화 anchor 정책 (2026-05-22 Lucy/Daniel/BeomSu 합의)

  • endDate는 산정식 마감일만 의미 — 트리거 발화는 단계 종료 신호일 뿐, 트리거 phase 자체의 endDate건드리지 않음
  • 후속 phase는 발화 시점(now)을 anchor로 cascade 재산정 — 신청자 발화 시점이 늦으면 후속 phase 마감도 자연스럽게 늦춰짐
  • 완료 시각 기록(completedDate/isCompleted)은 본 작업 범위 밖 (인프라만 있고 미활용)

트리거 전체 흐름

[T0] 가이드라인 완성
  └─ 모집/선정/계약 endDate 초기 세팅 (모집: 국내 +5일 / 해외 +7일)

[선정 (PROPOSAL)]
  └─ ApplicationSchedule 최초 생성 (setProposalSchedules)
  └─ EXCLUSION_SELECTION endDate는 그대로 (마감일 유지) — 후속 phase만 발화 anchor cascade
  └─ 광고주가 계약서 발송 → 계약 전송 트리거 별도

[계약 전송] ContractService.sendContracts
  └─ CONTRACT_CREATION endDate = 전송 시점 + 1일 (시트 "당일 +1일")
  └─ 후속 phase 발화 anchor cascade

[T1-A] 운송장 입력 (배송형)
  └─ DRAFT_SUBMISSION endDate = 운송장 입력 + 4영업일 (토 포함, 일 제외)
  └─ 후속 스크립트/영상 제출 마감 재산정

[T1-B] 신청자 계약 서명완료 (비배송형)
  └─ CONTRACT_CREATION endDate는 그대로 (계약 전송 트리거에서 set한 값 유지)
  └─ 후속 phase: 서명 시점 anchor cascade — 신청자 첫 제출 마감 등

[T2] 스크립트 검수완료 (재제출 후 검수완료 포함)
  └─ SCRIPT_REVIEW endDate는 그대로 → 영상 제출 마감만 검수완료 시점 anchor 재산정

[T3] 영상 검수완료 (재제출 후 검수완료 포함)
  └─ VIDEO_PRODUCTION endDate는 그대로 → 업로드/정산 재산정

[T4] 영상 등 대시보드 업로드 완료
  └─ UPLOAD_APPROVAL endDate는 그대로 → SETTLEMENT만 업로드일 + 20영업일 내 마지막 목요일

[재제출 트리거]
  ├─ [T2-R] 스크립트 반려: 재제출 요청일 +1일 (크리에이터 재제출 마감)
  ├─ [T3-R] 영상 반려: 재제출 요청일 +2일(첫 피드백) / +3일(재피드백)
  └─ [T4-R] 최종 재요청: 재제출 요청일 +1일 (FINAL_RESUBMISSION_DEADLINE)

본 트리거 (T0~T4)

T0 — 가이드라인 완성

광고주가 "가이드라인 생성 완료" 버튼을 누른 시점에 초기 일정이 세팅됩니다.

항목산정식비고
모집 (RECRUITMENT)가이드 완성일 + Collab.recruitmentDays 영업일 (기본 4영업일, 관리자 1-10 선택)국내/해외 분기 제거 (2026-05-22 Sam 합의, 영업일 통일). Collab.recruitmentEndDate 갱신
광고주 선정 (EXCLUSION_SELECTION)startDate = 모집 종료 + 1영업일 ("리스트 오픈일"), endDate = startDate + 2영업일모집 종료 다음 영업일에 리스트 오픈
계약 작성 (CONTRACT_CREATION)당일 +1일 (캘린더, 다른 cascade는 기존 유지)
이후 phase시트 산정식 (applyPhaseDuration)RECRUITMENT 다음부터 순차

가이드라인 재완료(수정) 시 일정 재계산 스킵 — Lucy 요청: 이미 GuidelineStatus == COMPLETED인 상태에서 completeGuideline()이 다시 호출되는 케이스(운영/영업 측 실수로 모집 도중 가이드라인 수정·재완료)에는 T0 트리거를 발화하지 않습니다. 진입 직전 상태를 캡처해 wasAlreadyCompleted=true이면 일정 재계산을 스킵합니다.

진입점: ContentGuidelineService.completeGuideline() 끝부분 호출: CampaignScheduleService.recalculateSchedulesFromGuidelineComplete(collabNo) (단, wasAlreadyCompleted == false일 때만)


T1-A — 운송장 번호 입력 (배송형 한정)

광고주가 운송장 번호를 입력하면 배송 anchor가 잡히고 후속 일정이 산정됩니다.

항목산정식
임시 배송완료일운송장 입력일(=배송시작일) + 배송영업일 4일 (토 포함, 일 제외)
CampaignSchedule.DRAFT_SUBMISSION.endDate임시 배송완료일
스크립트 제출 마감 (2회검수)배송완료일 + 3일 (= 운송장 +4+3)
영상 제출 마감 (1회검수)배송완료일 + 4일 (= 운송장 +4+4)
신청자 측ApplicationSchedule.SCRIPT_SUBMISSION_DEADLINE 또는 CONTENT_SUBMISSION_DEADLINE 동일 산정

임시 정책 (배송조회 API 미구현): 실제 배송완료 추적이 없는 상태라 Jay 합의(2026-05-20)에 따라 운송장 입력일 + 4영업일을 임시 배송완료일로 사용합니다. 배송조회 API 도입 시 anchor를 실제 배송완료일로 교체하면 됩니다 (TODO 주석 표시됨).

진입점: ApplicationDeliveryService.saveOrUpdateTracking() 호출: CampaignScheduleService.recalculateSchedulesFromTracking() + ApplicationScheduleService.recalculateSchedulesFromTracking()


T1-B — 신청자 계약 서명완료 (비배송형 한정)

비배송형 캠페인은 배송지 입력이 없으므로 신청자 계약 서명완료 시점이 본 체인 시작점입니다.

항목산정식
CampaignSchedule.CONTRACT_CREATION.endDate건드리지 않음 (계약 전송 트리거에서 set한 "전송 +1일" 마감일 유지)
스크립트 제출 마감 (2회검수)서명완료 + 3일 (캘린더)
영상 제출 마감 (1회검수)서명완료 + 4일 (캘린더)
후속 phase서명 시점 anchor + 시트 산정식

비배송형의 경우 선정 시점에 setProposalSchedules로 임시 산정된 첫 제출 마감을 계약 서명완료 시점에 정확히 재산정합니다. 시트 명세 "계약 서명완료 + 가이드라인 발송 기준"과 일치.

진입점: ContractService.submitSignature() (ApplicationContract 서명 처리 직후) 호출: CampaignScheduleService.recalculateSchedulesFromContractSigned() + ApplicationScheduleService.recalculateAfterContractSigned()


계약 전송 트리거

광고주가 계약서를 발송하는 시점이 CONTRACT_CREATION 단계 anchor입니다.

항목산정식
CampaignSchedule.CONTRACT_CREATION.endDate전송 시점 + 1일 (시트 "계약 작성 = 당일 +1일")
후속 phase전송 시점 anchor + 시트 산정식 cascade

신청자별 다발 전송 시 시간 순서 보장으로 마지막 전송 +1일이 자연 max 수렴.

진입점: ContractService.sendContracts() (계약서 발송 직후) 호출: CampaignScheduleService.recalculateSchedulesFromContractSent(campaignNo)


T2 — 스크립트 검수완료 (재제출 후 검수완료 포함)

광고주가 1차(스크립트) 검수를 승인한 시점.

항목산정식
CampaignSchedule.SCRIPT_REVIEW.endDate검수완료 당일
영상 제출 마감검수완료 + 4일 (캘린더)
신청자 측ApplicationScheduleService.setContentSubmissionAfterScriptApproval() 기존 흐름

진입점: ContentSubmissionService.addFeedbackOrApprove() 승인 분기 (reviewRound == 1 + ReviewStatus.APPROVED) 호출: CampaignScheduleService.recalculateSchedulesFromScriptReview()


T3 — 영상 검수완료 (재제출 후 검수완료 포함)

광고주가 2차(영상) 검수를 승인한 시점.

항목산정식
CampaignSchedule.VIDEO_PRODUCTION.endDate검수완료 당일
업로드 (UPLOAD)광고주 지정 — 검수완료 + 10일 이내 선택 가능
후속 phase (정산 등)시트 산정식
신청자 측광고주가 업로드 일자 지정 시 setUploadAllowedDate() 호출됨

진입점: ContentSubmissionService.addFeedbackOrApprove() 승인 분기 (reviewRound == 2 + ReviewStatus.APPROVED) 호출: CampaignScheduleService.recalculateSchedulesFromVideoReview()


T4 — 모든 최종제출물 업로드 완료 (시트 갱신 2026-05-21)

신청자가 본인에게 요구된 모든 최종제출물 타입(영상 + 캡션 + 해시태그 + 스크린샷 등, Collab.finalSubmissionTypes 기준)을 대시보드에 업로드 완료한 시점.

항목산정식
CampaignSchedule.UPLOAD_APPROVAL.endDate모든 타입 업로드 완료 당일
정산 (SETTLEMENT)마지막 최종제출물 업로드일 + 20영업일 내 마지막 목요일
신청자 측ApplicationSchedule.SETTLEMENT_DEADLINE 동일 산정

시트 변경 (2026-05-21) — "모든"의 의미: 캠페인 전체 신청자가 아니라 한 신청자가 제출해야 할 여러 최종제출물 타입(보통 3~4종)이 전부 완료된 시점을 뜻함. Collab.finalSubmissionTypes에 정의된 필수 타입 모두 제출 = 신청자 본인의 정산 트리거 발화. 정산 산정도 "최종 업로드일" → "마지막 (타입의) 최종제출물 업로드일" 기준.

정산 산정 특수 규칙 (Jay 합의): addBusinessDays(uploadDate, 20) 결과에서 가장 가까운 이전 목요일로 snap. BusinessDayCalculator.lastThursdayWithinBusinessDays(uploadDate, 20) 신규 유틸 사용.

진입점: FinalSubmissionService.saveOrSubmit() (isSubmit=true 분기) 호출: CampaignScheduleService.recalculateSchedulesFromFinalUpload() + ApplicationScheduleService.setSettlementDeadline()


재제출 트리거 (T2-R / T3-R / T4-R)

광고주가 피드백을 입력하고 반려하면 트리거가 발화됩니다 (피드백 = 재요청 동일 흐름).

T2-R — 스크립트 반려·재제출

항목산정식
캠페인 측CampaignSchedule.SCRIPT_REVIEW.delayReasonsSCRIPT_RESUBMISSION_DELAY +1일 누적
신청자 재제출 마감SCRIPT_SUBMISSION_DEADLINE = 재제출 요청일 +1일 (캘린더)
기업 검수 마감FEEDBACK_DEADLINE = 재제출일 +2영업일

진입점: ContentSubmissionService.addFeedbackOrApprove() 반려 분기 (reviewRound == 1) 호출: CampaignScheduleService.recalculateSchedulesFromScriptResubmission()


T3-R — 영상 반려·재제출

항목산정식
캠페인 측CampaignSchedule.VIDEO_PRODUCTION.delayReasonsVIDEO_RESUBMISSION_DELAY 누적
신청자 재제출 마감 (첫 피드백)CONTENT_SUBMISSION_DEADLINE = 재제출 요청일 +2일
신청자 재제출 마감 (재피드백)CONTENT_SUBMISSION_DEADLINE = 재제출 요청일 +3일
기업 검수 마감FEEDBACK_DEADLINE = 재제출일 +2영업일

본 작업에서 보완된 부분: 기존 코드는 1차 스크립트 재제출 시에만 SCRIPT_RESUBMISSION_DELAY를 자동 기록하고 2차 영상 재제출 시에는 지연 사유가 누락되어 있었습니다. TASK-071에서 VIDEO_RESUBMISSION_DELAY 신규 enum + recordResubmissionDelayByReviewRound()로 1차/2차 모두 처리하도록 일반화했습니다.

진입점: ContentSubmissionService.addFeedbackOrApprove() 반려 분기 (reviewRound == 2) 호출: CampaignScheduleService.recalculateSchedulesFromVideoResubmission(collabNo, applicationId, isFirstFeedback)


T4-R — 최종제출물 재요청 (시트 갱신 2026-05-21: 후순위)

광고주가 최종 제출물을 재요청한 시점 (피드백이 아닌 단순 재요청).

시트 변경 (2026-05-21): 최종제출물 재제출이 트리거 체인에서 정산 트리거(T3/T4) 이후 후순위로 이동. 즉 정상 흐름은 "영상 검수완료 → 업로드 → 모든 최종제출물 업로드 완료(정산 트리거)"이고, 최종제출물 재요청은 그 이후 발생 가능한 부가 흐름으로 재배치됨.

항목산정식
캠페인 측CampaignSchedule.UPLOAD_APPROVAL.delayReasonsFINAL_RESUBMISSION_DELAY +1일 누적
신청자 재제출 마감FINAL_RESUBMISSION_DEADLINE = 재요청 요청일 +1일
검수없음 (재요청 → 재제출 단순 흐름)

진입점: FinalSubmissionService.createReRequest() 호출: CampaignScheduleService.recalculateSchedulesFromFinalReRequest() + ApplicationScheduleService.setFinalResubmissionDeadline()


캠페인 유형별 트리거 체인 (시트 명세 매핑)

유형T1T2T3T4
배송 + 2회검수T1-A: 배송지 입력 → 스크립트 +3일 / 검수 2영업일스크립트 검수완료 → 영상 +4일영상 검수완료 → 업로드 (광고주 지정 +10일 이내)업로드 → 정산 +20영업일 내 마지막 목요일
배송 + 1회검수T1-A: 배송지 입력 → 영상 +4일 / 검수 2영업일영상 검수완료 → 업로드업로드 → 정산
비배송 + 2회검수T1-B: 계약 서명 → 스크립트 +3일스크립트 검수완료 → 영상 +4일영상 검수완료 → 업로드업로드 → 정산
비배송 + 1회검수T1-B: 계약 서명 → 영상 +4일영상 검수완료 → 업로드업로드 → 정산

영업일 정의 (단계별 상이)

단계영업일 정의메서드
일반 (검수, 정산 등)월~금 (토·일 제외)BusinessDayCalculator.addBusinessDays() / endOfBusinessDays()
배송 (DRAFT_SUBMISSION)일요일만 제외 (토요일 포함)BusinessDayCalculator.addDaysExcludingSunday()
정산 (SETTLEMENT)20영업일 + 마지막 목요일 snapBusinessDayCalculator.lastThursdayWithinBusinessDays()

신규 데이터 모델

ScheduleDelayType enum 신규 값

Type설명용도
VIDEO_RESUBMISSION_DELAY영상 재제출로 인한 지연T3-R 트리거 (2차 영상 반려 시)
FINAL_RESUBMISSION_DELAY최종 제출물 재요청으로 인한 지연T4-R 트리거

ApplicationSchedulePhase enum 신규 값

Phase설명용도
FINAL_RESUBMISSION_DEADLINE최종제출물 재제출 마감T4-R 신청자 측 마감
SETTLEMENT_DEADLINE정산 마감T4 신청자 측 마감

CampaignPhase.CONTRACT_CREATION 변경

기존 durationDays = 2 (캘린더 2일) → durationDays = 1 (캘린더 1일). CampaignScheduleService.applyPhaseDuration()의 하드코딩도 함께 변경(endOfCalendarDays(start, 1)).


본 트리거 ↔ 코드 매핑 요약

Trigger캠페인 진입점신청자 mirror
T0 가이드라인 완성recalculateSchedulesFromGuidelineComplete(collabNo)(선정 전이라 신청자 없음)
T1-A 운송장 입력recalculateSchedulesFromTracking(collabNo)recalculateSchedulesFromTracking(application)
T1-B 계약 서명완료recalculateSchedulesFromContractSigned(collabNo, applicationId)recalculateAfterContractSigned(application)
T2 스크립트 검수완료recalculateSchedulesFromScriptReview(collabNo, applicationId)setContentSubmissionAfterScriptApproval(application) (기존 흐름)
T3 영상 검수완료recalculateSchedulesFromVideoReview(collabNo, applicationId)setUploadAllowedDate(application, submission) (광고주 일자 지정 시)
T4 영상 업로드 완료recalculateSchedulesFromFinalUpload(collabNo, applicationId)setSettlementDeadline(application, uploadDate)
T2-R 스크립트 반려recalculateSchedulesFromScriptResubmission(collabNo, applicationId)setSubmissionDeadlineFromFeedback() (기존 흐름)
T3-R 영상 반려recalculateSchedulesFromVideoResubmission(collabNo, applicationId, isFirstFeedback)setSubmissionDeadlineFromFeedback() (기존 흐름)
T4-R 최종 재요청recalculateSchedulesFromFinalReRequest(collabNo, applicationId)setFinalResubmissionDeadline(application)

예시 — 배송형 2회검수 캠페인 전체 흐름

2026-05-01 (금)  T0 가이드라인 완성
  → 모집 endDate = 2026-05-06 (수, 국내 +5일)
  → 선정 endDate = 2026-05-08 (금, +2영업일)
  → 계약 endDate = 2026-05-09 (토, +1일)

2026-05-08 (금)  광고주 선정 (PROPOSAL)
  → ApplicationContract 자동 생성 (status=PENDING)
  → ApplicationSchedule.SCRIPT_SUBMISSION_DEADLINE 임시 산정

2026-05-09 (토)  신청자 계약 서명완료
  → 배송형이므로 T1-B 발화 X (T1-A 대기)

2026-05-11 (월)  광고주 운송장 입력 (T1-A)
  → 임시 배송완료일 = 5/11 + 4영업일(토 포함, 일 제외) = 2026-05-15 (금)
  → CampaignSchedule.DRAFT_SUBMISSION.endDate = 2026-05-15
  → SCRIPT_SUBMISSION_DEADLINE = 2026-05-18 (월, 배송완료 +3일)
  → ApplicationSchedule도 동일 산정

2026-05-18 (월)  크리에이터 스크립트 제출 + 광고주 검수완료 (T2)
  → CampaignSchedule.SCRIPT_REVIEW.endDate = 2026-05-18
  → CONTENT_SUBMISSION_DEADLINE = 2026-05-22 (목, 검수완료 +4일)

2026-05-22 (목)  크리에이터 영상 제출 + 광고주 검수완료 (T3)
  → CampaignSchedule.VIDEO_PRODUCTION.endDate = 2026-05-22
  → 광고주 업로드 일자 지정 가능 (2026-05-22 ~ 2026-06-01, +10일 이내)

2026-05-25 (일)  광고주가 업로드 일자 지정 (2026-05-28)
  → setUploadAllowedDate, ApplicationSchedule.UPLOAD_ALLOWED_DATE 갱신

2026-05-28 (수)  크리에이터 최종 업로드 완료 (T4)
  → CampaignSchedule.UPLOAD_APPROVAL.endDate = 2026-05-28
  → SETTLEMENT 마감 = 2026-06-19 (목, 20영업일 내 마지막 목요일)
  → ApplicationSchedule.SETTLEMENT_DEADLINE 동일 산정

회귀 방지 / 호환성

  • CampaignSchedule.endDate 값은 트리거 발화 시 갱신되지만, 컬럼 의미·기존 소비자 동작은 변경 없음 — Aligo 발송 스케줄러(AligoSchedulerService .toLocalDate().equals(today) 필터), PaymentPendingCampaignItemDto(CONTRACT_CREATION endDate), TASK-056/057 happy path 응답 모두 정상 동작
  • 불변 원칙은 original* 컬럼에만 적용CampaignSchedule.originalEndDate / ApplicationSchedule.originalDeadline은 최초 1회만 세팅 후 변경 없음 (TASK-056/057 도입, 지연 측정 기준점)
  • 트리거 발화 시 갱신되는 값: CampaignSchedule.endDate / ApplicationSchedule.deadline
  • 트리거 결과 시간 컴포넌트 정규화 — 트리거 발화 시각(예: 10:44:41.177993)이 deadline에 그대로 노출되던 문제를 보완. 모든 트리거 결과(CampaignSchedule.endDate, ApplicationSchedule.deadline)는 LocalDate.atTime(23, 59, 59)로 정규화되어 저장됨
  • 기존 진행 중 캠페인은 다음 트리거 발화 시점부터 새 정책 적용 (백필 불필요)
  • 신규 DB 컬럼 추가 없음 — endDate/deadline 그대로 사용, triggerStatus 같은 별도 컬럼 도입 안 함 (Daniel/Lucy 합의)

검수 마감 응답 fallback 매핑 (CampaignApplicationService)

CampaignApplicationService에서 신청자별 검수 마감을 응답에 노출할 때 ApplicationSchedule row가 없으면 CampaignSchedule로 fallback. 매핑 의미 주의:

응답 필드1순위 (ApplicationSchedule)fallback (CampaignSchedule)
scriptReviewDeadlineSCRIPT_REVIEW_DEADLINECampaignPhase.SCRIPT_REVIEW ("스크립트 검수 및 제작 허용")
contentReviewDeadlineCONTENT_REVIEW_DEADLINECampaignPhase.VIDEO_PRODUCTION ("제작물 검수 및 업로드 허용")

CampaignPhase.VIDEO_PRODUCTION은 enum 이름이 "영상 제작"으로 헷갈리지만 한글 라벨은 "제작물 검수"입니다. fallback 매핑 자체는 의미상 정확.

fallback 발동 빈도를 줄이기 위해 ContentSubmissionService.batchSubmit 경로에 setReviewDeadline 호출을 추가 — 일괄 제출 시점에 ApplicationSchedule.SCRIPT_REVIEW_DEADLINE / CONTENT_REVIEW_DEADLINE row가 항상 생성/갱신됩니다 (단건 submit 경로엔 이미 호출되고 있었음).

응답 필드 guidelineCompletedAt 와 화면 표시 정책(예상 완료일 산정 등)은 Campaign Schedule API 페이지의 Response 스키마 섹션 참고.

On this page