GET /ai/progress-table/item/{id}
캠페인 진행 항목 조회
캠페인 진행 항목 조회
기업 대시보드용 캠페인 진행 항목을 조회합니다.
기업 승인 전(INVALID_BUSINESS) 광고주도 본인 캠페인을 조회할 수 있습니다. 승인 전이어도 데이터는 정상 반환되며, 응답의 businessApproved 값으로 승인 여부를 분기하세요. 미승인(false) 시 프런트에서 CTA 자리에 "기업승인 진행중" 등을 노출하는 용도입니다. (타인 캠페인 조회는 여전히 403 FORBIDDEN)
HTTP 요청
GET /ai/progress-table/item/{id}
Authorization: Bearer {access_token}Path Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id | long | 예 | 캠페인 ID |
응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "캠페인 진행 상황 항목 조회가 완료되었습니다.",
"data": {
"step": "MATCHING",
"items": [
{
"id": 1,
"creator": "인플루언서A",
"creatorEmail": "influencer_a@example.com",
"influenceId": 12345,
"profileImg": "https://s3.../profile.jpg",
"creatorLink": "https://instagram.com/influencer_a",
"trackingNumber": "1234567890",
"courierCode": "kr.cjlogistics",
"shippedAt": "2026-05-26T18:02:53",
"deliveredAt": "2026-05-27T13:56:22",
"trackingDetail": "{\"lastEvent\":{...},\"events\":{\"edges\":[ ... ]}}",
"uploadUrl": "https://instagram.com/p/xxx",
"file": null,
"aiCheckReady": true,
"matchingStatus": "MATCHED",
"deliveryStatus": "DELIVERED",
"aiCheck": "APPROVED",
"personCheck": "PENDING",
"campaignResult": null,
"recommendReason": "높은 참여율",
"uploadStatus": "UPLOADED",
"quotePrice": 100000,
"currentPrice": 80000,
"collaborationNote": "특별 요청 사항",
"reviewInfo": {
"hasNewSubmission": false,
"reviews": [
{
"reviewRound": 1,
"reviewId": 101,
"status": "APPROVED",
"hasNewSubmission": false,
"submissionItems": []
}
],
"uploadApproved": true,
"finalSubmission": null
},
"followerCount": 50000,
"avgViewCount": 10000,
"rank": "A",
"rankPrice": 100000,
"recentPosts": [
{
"postId": "abc123",
"postLink": "https://instagram.com/p/abc123",
"mediaUrl": "https://video.cdninstagram.com/...",
"mediaType": "VIDEO",
"publishedAt": "2025-01-20T14:30:00Z"
},
{
"postId": "def456",
"postLink": "https://instagram.com/p/def456",
"mediaUrl": "https://scontent.cdninstagram.com/...",
"mediaType": "IMAGE",
"publishedAt": "2025-01-18T10:00:00Z"
}
],
"contractId": 42,
"contractStatus": "SIGNED",
"selectedOptions": [
{
"optionId": 1,
"title": "색상",
"selected": [
{ "choiceId": 11, "value": "아이보리" }
]
}
]
}
],
"isLegacy": false,
"totalCount": 10,
"eliminatedCount": 2,
"eliminatedPercentage": 20.0,
"campaignDetails": {
"no": "123",
"businessId": "business_001",
"thumbnailImagePath": "https://s3.../thumbnail.jpg",
"productImagePath": "https://s3.../product.jpg",
"productImagePaths": ["https://s3.../product1.jpg"],
"snsType": "INSTAGRAM",
"contentFormat": "REEL",
"category": "BEAUTY",
"campaignType": "SEEDING",
"campaignSubStep": "CREATOR_RECRUIT",
"guidelineStatus": "COMPLETED",
"productName": "상품명",
"charge": "100000",
"currency": "KRW",
"recruitCount": "10",
"recruitmentStartDate": "2024-01-01 00:00:00",
"recruitmentEndDate": "2024-01-31 23:59:59",
"campaignContractType": "STANDARD",
"currentPriceRate": 80.0,
"quotePriceRate": 125.0
},
"budgetSummary": {
"totalBudget": 1000000,
"usedCredit": 300000,
"refundAmount": 700000,
"lockedCount": 3,
"status": "ACTIVE"
},
"deficitLock": {
"engaged": true,
"amount": 300000,
"status": "LOCKED",
"threshold": 800000,
"sumLockedNormal": 500000,
"policyEnabled": true
},
"guidelineCompletedAt": "2025-02-15T14:30:00",
"campaignCompletedAt": "2025-03-20T18:45:10",
"managers": [
{
"managerNo": 42,
"name": "홍길동",
"phone": "01000000000",
"email": "manager@example.com",
"isDefault": true
}
],
"paymentStatus": "PAID",
"businessApproved": false,
"canEditGuideline": false
}
}Response 스키마
ProgressTableWithCampaignResponse
| 필드명 | 타입 | 설명 |
|---|---|---|
step | string | 진행 단계 ("MATCHING" | "EXECUTING") |
items | ProgressItemExceptBidPriceResponse[] | 진행 항목 목록 |
isLegacy | boolean | 레거시 여부 |
totalCount | int | 전체 항목 수 |
eliminatedCount | int | 탈락 항목 수 |
eliminatedPercentage | double | 탈락률 (%) |
campaignDetails | CampaignFullResponseDto | 캠페인 상세 정보 |
budgetSummary | BudgetSummaryDto | 캠페인 예산 요약 (SaaS 캠페인만) |
deficitLock | DeficitLockResponseDto | 80% 부족분 lock 스냅샷. 모달 진입 전 FE 분기 처리용. 상세는 부족분 lock 조회 참조. SaaS 이전 캠페인은 engaged=false, policyEnabled=false |
guidelineCompletedAt | datetime | 가이드라인 완성일. 가이드라인 미완성 시 null |
campaignCompletedAt | datetime | 캠페인 완료일 (campaignSubStep = CAMPAIGN_COMPLETED 로 최초 전환된 시각). 아직 완료되지 않았거나 백필 대상이 아닌 레거시 건은 null |
managers | BusinessManagerResponseDto[] | 캠페인 담당자 목록(N:M, 동등). 담당자 미지정 시 빈 배열 |
paymentStatus | string | null | 결제 상태. UNPAID / PAYMENT_PENDING / PAID 또는 null (트래킹 대상 아님). 도출 규칙은 아래 참고 |
businessApproved | boolean | 캠페인 소유자(광고주)의 기업 승인(계약 체결) 여부. 계약 상태(contractSignStatus)가 SIGNED / EXCEPTION 이면 true, NONE / PENDING 이면 false. 용도는 상단 안내 참고 |
canEditGuideline | boolean | 광고주가 현재 가이드라인을 수정할 수 있는지 여부 (FE 수정 버튼 노출용). 모집 단계(CREATOR_RECRUIT/CREATOR_MATCHING)에서는 어드민이 수정 허용을 켠 경우에만 true (1회용: 광고주가 완성본을 한 번 저장하면 소진되어 다시 false, 어드민 재허용 필요). 콘텐츠 제작 단계 이후에는 false, 가이드라인 미생성 시 false |
ProgressItemExceptBidPriceResponse
| 필드명 | 타입 | 설명 |
|---|---|---|
id | long | 항목 ID |
creator | string | 크리에이터 이름 |
creatorEmail | string | 크리에이터 이메일 |
influenceId | long | 인플루언서 ID |
profileImg | string | 프로필 이미지 URL |
creatorLink | string | 크리에이터 링크 |
trackingNumber | string | 운송장 번호 |
courierCode | string | 택배사 코드(kr.xxx) 또는 기타 한글명/OTHER. 미입력 시 null |
shippedAt | string | 배송 시작(집화) 시각. 추적 전/불가 시 null |
deliveredAt | string | 배송 완료 시각. 완료 전 null |
trackingDetail | string(JSON) | 배송조회 전체 응답(타임라인). 미조회 시 null. 구조는 배송 상세조회 문서 참고 |
uploadUrl | string | 업로드 URL |
file | string | 파일 URL |
aiCheckReady | boolean | AI 체크 준비 상태 |
matchingStatus | string | 매칭 상태 |
deliveryStatus | string | 배송 상태 |
aiCheck | string | AI 검수 상태 |
personCheck | string | 담당자 검수 상태 |
campaignResult | string | 캠페인 결과 URL |
recommendReason | string | 추천 이유 |
uploadStatus | string | 업로드 상태 |
quotePrice | long | 견적 가격 |
currentPrice | long | 현재 가격 |
collaborationNote | string | 협업 노트 |
reviewInfo | ReviewInfo | 검수 정보 |
followerCount | long | 팔로워 수 |
avgViewCount | long | 평균 조회수 |
rank | string | 랭크 (A/B/C 등) |
rankPrice | int | 랭크별 가격 |
recentPosts | PostMediaDto[] | 최근 게시물 미디어 (최대 3개) |
contractId | long | 전자계약서 ID (계약서 미발송 시 null) |
contractStatus | string | 전자계약 상태 (DRAFT, SENT, OPENED, FILLED, OTP_VERIFIED, SIGNED). 계약서 미발송 시 null |
selectedOptions | array | 캠페인 제공 옵션 — 크리에이터가 선택한 값 (그룹별로 묶음). 옵션 정의는 GET /ai/campaign/{collabNo}/provided-options, 정책은 캠페인 제공 옵션 개요 참고. 옵션 미정의/미선택 시 빈 배열 |
PostMediaDto
| 필드명 | 타입 | 설명 |
|---|---|---|
postId | string | 게시물 ID |
postLink | string | 게시물 링크 |
mediaUrl | string | 미디어 URL (video_url 또는 images 중 첫 번째) |
mediaType | string | 미디어 타입 (VIDEO 또는 IMAGE) |
publishedAt | datetime | 게시일 |
recentPosts는 PostgreSQL의 post 테이블에서 조회됩니다.
video_url이 있으면mediaType: VIDEO로 반환video_url이 없으면images의 첫 번째 이미지를mediaType: IMAGE로 반환
BusinessManagerResponseDto
| 필드명 | 타입 | 설명 |
|---|---|---|
managerNo | long | 담당자 번호 |
name | string | 담당자 이름 |
phone | string | 담당자 연락처 |
email | string | 담당자 이메일 |
isDefault | boolean | 기본 담당자 여부 |
BudgetSummaryDto (SaaS 캠페인만 반환)
| 필드명 | 타입 | 설명 |
|---|---|---|
totalBudget | int | 캠페인 총 예산 (CAMPAIGN_DEPOSIT 합계) |
usedCredit | int | 사용(LOCKED) 금액 합계 |
refundAmount | int | 환급 가능 금액 (totalBudget - usedCredit) |
lockedCount | long | 잠금된 건수 |
status | string | 상태 ("ACTIVE") |
budgetSummary는 SaaS 캠페인(collabNo >= saasNum)에서만 반환됩니다.
레거시 캠페인은 null이 반환됩니다.
[TASK-071 2026-05-26] guidelineCompletedAt 출처 변경:
- 주 출처: MongoDB
GuidelineDocument.completedAt(v1/v2/v4 publish 시 자동 set, 운영자 정정 가능) - Fallback (legacy): 위 값이 없으면
Collab.recruitment_start_date - 가이드라인 상태가
COMPLETED가 아니면 fallback 도 시도하지 않고null반환
campaignCompletedAt은 TB_COLLAB.campaign_completed_at 컬럼 값입니다.
PATCH /ai/admin/campaigns/{campaignNo}/substep?substep=CAMPAIGN_COMPLETED를 호출해 최초로CAMPAIGN_COMPLETED상태가 되는 순간 서버 시각(LocalDateTime.now())으로 기록됩니다.- 이미 값이 있으면 재호출해도 덮어쓰지 않습니다 (최초 완료 시각 유지).
- 기존 완료 캠페인은
FinalSubmission.submitted_at중 MAX 값으로 일회성 백필되어 있습니다. 최종 제출물이 전혀 없는 레거시 완료 건은null입니다.
paymentStatus 도출 규칙
TB_CAMPAIGN_PAYMENT_VERIFICATION행이 존재하면 그 행의payment_status값을 그대로 반환합니다.- admin 이 캠페인 단계 변경 API(
PATCH /ai/admin/campaigns/{campaignNo}/step) 로UNPAID/PAYMENT_PENDING/PAID처리한 캠페인은 모두 행이 존재합니다.
- admin 이 캠페인 단계 변경 API(
- 행이 없으면
null— 결제 트래킹 대상 아님 (CandyPay 정상 결제 흐름은 verification 행을 만들지 않음).
PAYMENT_PENDING 캠페인은 같은 응답에서 items 가 빈 배열로 반환됩니다 (영업 결제 대기 중 인원 노출 차단).
예산 관련 에러 응답
매칭 상태를 PROPOSAL로 변경할 때 예산 검증 실패 시 발생하는 에러입니다.
| 상태 코드 | 에러 코드 | 설명 |
|---|---|---|
| 400 | NEED_CAMPAIGN_DEPOSIT | 캠페인 예산이 부족합니다. 추가 입금이 필요합니다. |
| 400 | INSUFFICIENT_GLOBAL_CREDIT | 기업 크레딧이 부족합니다. 크레딧을 충전해주세요. |
| 403 | PROPOSAL_STATUS_CHANGE_NOT_ALLOWED | 제안 상태의 크리에이터는 기업에서 상태를 변경할 수 없습니다. 관리자에게 문의해주세요. |
| 404 | BUDGET_NOT_FOUND | 캠페인 예산 정보를 찾을 수 없습니다. |
| 400 | BUDGET_ALREADY_LOCKED | 이미 예산이 예약되어 있습니다. |
| 400 | BUDGET_ALREADY_UNLOCKED | 이미 예산이 취소되었습니다. |
NEED_CAMPAIGN_DEPOSIT 발생 시: 캠페인 예산 추가 입금 API (POST /ai/payments/collab/confirm)를 호출하세요.
INSUFFICIENT_GLOBAL_CREDIT 발생 시: 크레딧 충전 API (POST /ai/payments/credit/confirm)를 먼저 호출하세요.