Admin APIAdmin Dashboard API
GET /ai/admin/dashboard/{campaignNo}/list
리스트 관리 조회
리스트 관리 조회
캠페인 신청 목록을 조회합니다. adminVisible 값과 무관하게 전체 신청을 조회합니다.
캠페인 정보, 인플루언서 정보, 매칭 정보, 단가 협상 상태, 계약서 정보를 모두 포함합니다.
응답에는 items 외에 dummyItems(모집 에이전트가 발굴한 비가입자 데모 후보)가 함께 내려갑니다.
items와 동일한 ListItemDto 구조이고 applicationId는 1억 오프셋이 붙어 실제 신청과 겹치지 않습니다.
데모도 선정/예비/제외를 할 수 있으나 표시용이라 계약·정산 같은 부수효과는 없습니다. 필드와 렌더 규칙은
데모(목업) 후보 — 프론트 연동 가이드를 참고하세요.
HTTP 요청
GET /ai/admin/dashboard/{campaignNo}/list
Authorization: Bearer {access_token}Path Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
campaignNo | long | 예 | 캠페인 번호 |
Query Parameters
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
influenceName | String | 아니오 | 인플루언서 이름 검색어. 부분 일치 + 대소문자 무시. 미지정 시 전체 신청을 반환 |
인플루언서 이름 검색 (influenceName)
- 인플루언서 이름에 검색어가 포함된 신청만
items로 반환합니다 (부분 일치, 대소문자 무시). veteranPercentage(고인물%)는 검색 필터와 무관하게 전체 신청자 기준으로 계산됩니다 (캠페인 단위 지표).remainBusinessCredit,bizName등 캠페인/기업 단위 값도 검색과 무관하게 동일하게 반환됩니다.
응답
성공 응답 (200 OK)
{
"status": 200,
"code": null,
"message": "리스트 관리 조회 성공",
"data": {
"campaign": {
"no": "123",
"businessId": "business123",
"thumbnailImagePath": "https://...",
"productImagePath": "https://...",
"snsType": "INSTAGRAM",
"contentFormat": "REELS",
"category": "BEAUTY",
"campaignType": "PRODUCT",
"campaignSubStep": "CREATOR_MATCHING",
"nation": "KR",
"productName": "여름 뷰티 캠페인",
"charge": "500000",
"currency": "KRW",
"recruitCount": "10",
"recruitmentStartDate": "2025-01-01 00:00:00",
"recruitmentEndDate": "2025-01-31 00:00:00",
"showPrice": true,
"listMode": "MANUAL"
},
"remainBusinessCredit": 1500000,
"bizName": "글로우비 주식회사",
"veteranPercentage": 42.8,
"exchangeRate": 9.0,
"adminSelectionApprovalEnabled": false,
"items": [
{
"applicationId": 35,
"appliedAt": "2025-01-15T10:30:00",
"adminVisible": true,
"sourceType": "SELF_APPLIED",
"selectionStatus": "WAITING",
"businessSelectionStatus": null,
"pendingSelectionApproval": false,
"influenceNo": 123,
"influenceName": "크리에이터A",
"influenceProfileImage": "https://...",
"influenceTel": "010-1234-5678",
"influenceEmail": "creator@email.com",
"influenceRankScore": "A",
"followerCount": "15200",
"averageViewCount": "3500",
"adjustedEngagementRate": 4.6282,
"currentPrice": 500000,
"quotePrice": 600000,
"adminMemo": "우수 크리에이터",
"latestNegotiationId": 1,
"latestProposedPrice": 500000,
"latestNegotiationStatus": "PENDING",
"negotiationRespondedAt": null,
"contractWritten": true,
"contractNote": "O 계약완료",
"paymentMethod": "현금",
"contractWrittenAt": "2025-01-20T14:00:00",
"matchScore": 0.87,
"autoCategories": ["뷰티", "스킨케어", "리뷰"],
"defaultUnitPrice": 450000,
"previouslyCollaborated": true,
"previouslyExposed": true,
"previouslyListed": true,
"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"
}
]
}
]
}
}응답 필드 설명
data 객체
| 필드 | 타입 | 설명 |
|---|---|---|
campaign | Object | 캠페인 정보. 캠페인 국가 nation(ISO 3166-1 alpha-2, 예: KR/JP/VN) 포함 |
remainBusinessCredit | Integer | 기업 잔여 크레딧 |
bizName | String | 기업명 |
veteranPercentage | Double | 고인물% — 신청자 중 고인물 크리에이터 비율 (소수점 1자리). 70% 이상이면 추가 모집 필요 신호 |
exchangeRate | BigDecimal | null | 캠페인 환율 (외화 1단위당 KRW, 예: JPY 9.0). 미설정 시 null. FE는 제안가 = 희망가(defaultUnitPrice) × 환율로 계산하고, null이면 제안가를 -로 표기 |
adminSelectionApprovalEnabled | Boolean | 선정의 선정 게이트 ON/OFF. true면 기업의 선정이 관리자 승인 후 확정된다. 관리자 전용 필드로, 기업/크리에이터 대상 API에는 노출되지 않는다. |
items | Array | 신청 목록 |
캠페인 국가 (campaign.nation)
TB_COLLAB.nation원본값은 코드와 한글명이 혼재(KR/한국,JP/일본)합니다.- 응답에서는
NationUtils.toIsoCode()로 ISO 3166-1 alpha-2 코드(KR,JP,VN등)로 정규화해 내려줍니다. - 매핑되지 않은 값은 대문자/trim만 적용해 그대로 반환하며, 원본이 비어있으면
null을 반환합니다.
items 배열 내 각 항목
| 필드 | 타입 | 설명 |
|---|---|---|
applicationId | Long | 신청 ID |
appliedAt | LocalDateTime | 신청일 |
adminVisible | Boolean | 기업 대시보드 노출 여부 |
sourceType | String | 신청 경로 (SELF_APPLIED, ADMIN_ADDED, AI_RECOMMENDED) |
selectionStatus | String | 선정 상태 (WAITING, SELECTED, RESERVED, REJECTED, ELIMINATED, PROPOSAL, EXPOSURE_CANDIDATE) — 실제(확정) 상태. EXPOSURE_CANDIDATE(노출 후보)는 관리자 전용이라 기업·크리에이터 응답에는 대기로 마스킹되어 나갑니다 |
businessSelectionStatus | String | 기업 시점 임시 선정 상태 (선정의 선정 게이트 ON 전용, 게이트 OFF면 null). 기업이 선정을 제안했지만 관리자 승인 전인 상태를 나타낸다. 관리자 전용, 기업/크리에이터에는 노출되지 않는다. |
pendingSelectionApproval | Boolean | 관리자 선정 승인 대기 여부. 게이트 ON에서 기업이 선정을 제안한 뒤 관리자 승인 전이면 true. 관리자 전용, 기업/크리에이터에는 노출되지 않는다. |
influenceNo | Integer | 인플루언서 번호 |
influenceName | String | 인플루언서 이름 |
influenceProfileImage | String | 프로필 이미지 URL |
snsUrl | String | SNS 프로필 링크. 실제 신청은 CampaignApplication.snsAccountLink, 데모 후보는 등록 시 입력한 accountLink. 크리에이터가 잘못 입력했으면 리스트 관리 벌크 업데이트의 accountLink 로 정정한다 |
influenceTel | String | 전화번호 |
influenceEmail | String | 이메일 |
influenceRankScore | String | 랭크 점수 |
followerCount | String | 팔로워 수. Instagram OAuth 연동 데이터(SocialAccount) 우선, 없으면 크롤링 데이터(PostgreSQL)에서 조회 |
averageViewCount | String | 평균 조회수. Instagram OAuth 연동 데이터 우선, 없으면 크롤링 데이터에서 조회. 네이버 플랫폼은 avgViews, 그 외는 reelsAvgViews 사용 |
adjustedEngagementRate | Double | 보정 참여율(%). PostgreSQL influencer_profile.adjusted_engagement_rate 원본값. 미산정 계정은 null. 아래 보정 참여율 참고 |
currentPrice | Long | 글특가 (광고주에게 노출되는 가격). 기준가 x (1 + 수수료율) 만원올림 |
quotePrice | Long | 기존가 (기준 가격). 글특가 x 1.5 만원올림 |
matchScore | Double | AI 매칭 점수 (벡터 코사인 유사도, 0~1). TB_APPLICATION_MATCHING.match_score에서 조회 |
autoCategories | Array<String> | AI 자동 카테고리 목록. PostgreSQL influencer_profile.auto_category_categories를 , 구분 파싱 |
adminMemo | String | 비고 (ApplicationMatching.recommendReason) |
latestNegotiationId | Long | 최근 단가 협상 ID |
latestProposedPrice | Long | 최근 제안 가격 |
latestNegotiationStatus | String | 협상 상태 (PENDING, ACCEPT, REJECT) |
negotiationRespondedAt | LocalDateTime | 협상 응답 시간 |
contractWritten | Boolean | 계약서 작성 여부 |
contractNote | String | 계약서 비고 |
paymentMethod | String | 지불 방식 |
contractWrittenAt | LocalDateTime | 계약서 작성 시간 |
defaultUnitPrice | Long | 크리에이터 희망 단가 |
previouslyCollaborated | Boolean | 기협업 여부 (scope 내 이전 캠페인에서 SELECTED된 적 있음). scope는 스코핑 규칙 참조 |
previouslyExposed | Boolean | 기노출 여부 (scope 내 이전 캠페인에서 adminVisible=true 였던 적 있음) |
previouslyListed | Boolean | 기리스트 여부 (scope 내 이전 캠페인 리스트/신청에 올라온 적 있음, selectionStatus 무관) |
recentPosts | Array<PostMediaDto> | 최근 게시물 미디어 (최대 3개) |
보정 참여율
adjustedEngagementRate는 크롤링 PostgreSQL의 influencer_profile.adjusted_engagement_rate 값을 반올림 없이 그대로 내려줍니다.
- 단위: 퍼센트(%). 예를 들어
4.6282는 4.6282% 를 뜻합니다.followerCount·averageViewCount와 달리 문자열이 아니라 숫자 타입입니다. - 조회 기준:
is_current = true인 프로필을 신청자의sns_account_link로 매칭합니다. - 데이터 소스 예외:
followerCount/averageViewCount는 Instagram OAuth 연동 데이터(SocialAccount)가 있으면 그쪽을 우선합니다. 반면adjustedEngagementRate는 크롤링 PostgreSQL 에만 존재하는 값이라 연동 여부와 무관하게 항상 PostgreSQL 프로필에서 채웁니다. null인 경우: 매칭되는 프로필이 없거나, 프로필은 있어도 참여율이 아직 산정되지 않은 계정. 전체 프로필 중 약 1/3 만 값이 채워져 있으므로 프런트는null처리를 반드시 넣어야 합니다.
recentPosts 배열 내 각 항목 (PostMediaDto)
| 필드 | 타입 | 설명 |
|---|---|---|
postId | String | 게시물 ID |
postLink | String | 게시물 링크 |
mediaUrl | String | 미디어 URL (video_url 또는 images 중 첫 번째) |
mediaType | String | 미디어 타입 (VIDEO 또는 IMAGE) |
publishedAt | OffsetDateTime | 게시일 |
recentPosts 조회 로직
- PostgreSQL의
post테이블에서account_link로 최근 게시물 3개를 조회합니다. video_url이 있으면mediaType: VIDEO로 반환video_url이 없으면images의 첫 번째 이미지를mediaType: IMAGE로 반환
기협업/기노출/기리스트 스코핑 규칙 (에이전시 광고주)
- 세 판정(
previouslyCollaborated/previouslyExposed/previouslyListed)은 모두 동일한 scope 안의 다른 캠페인(현재 캠페인 제외)을 대상으로 계산합니다. - 일반 광고주: scope = 캠페인 소유 계정(
TB_COLLAB.id) 하나 → 기존 "기업 기준"과 동일. - 에이전시 광고주(
TB_BUSINESS.agency_id가 있는 계정): scope = 같은 에이전시에 소속된 전 계정의 캠페인. 예를 들어 한 에이전시가 BOM·Bodiance 두 브랜드 계정을 운영하면, 두 브랜드의 캠페인을 하나의 scope로 묶어 판정합니다. - 에이전시 소속 계정 목록이 비어있으면 소유 계정 하나로 안전 폴백합니다(회귀 없음).
- 타 캠페인 불러오기(cross-campaign) 응답은 이 규칙과 무관하며 변경되지 않았습니다.
기협업자 (previouslyCollaborated) 판별 로직
- scope 내 다른 캠페인에서
SELECTED상태였던 크리에이터이면true - 현재 캠페인의 SELECTED는 제외 (자기 자신 캠페인)
- 이전 캠페인 중 하나라도 SELECTED였으면 기협업자로 표시
기노출자 (previouslyExposed) 판별 로직
- scope 내 다른 캠페인에서 신청 건의
adminVisible이true였던 적이 있으면true selectionStatus(SELECTED 등) 와는 무관하게 단순히 기업 대시보드에 노출(공개)된 이력이 있는지로 판단- 현재 캠페인은 제외
기리스트 (previouslyListed) 판별 로직
- scope 내 다른 캠페인의 리스트/신청에 한 번이라도 올라온 적 있으면
true selectionStatus무관 (WAITING/SELECTED/RESERVED/REJECTED/ELIMINATED/PROPOSAL 어떤 상태든 신청 이력이 있으면 해당)- 현재 캠페인은 제외
- 관계: 기리스트 ⊃ 기노출 ⊃ 기협업 (기리스트가 가장 넓은 범위)
- 어느 캠페인에서 리스트/노출됐는지 상세 목록은 기리스트/기노출 상세 조회 API로 조회
고인물% (veteranPercentage) 계산 로직
- 고인물 정의: 현재 모집 중인 캠페인(CREATOR_RECRUIT, CREATOR_MATCHING) 중 70% 이상에 직접 신청(SELF_APPLIED) 한 크리에이터
- 고인물%: 해당 캠페인 신청자 중 고인물 크리에이터가 차지하는 비율
- ADMIN_ADDED, AI_RECOMMENDED로 추가된 건은 고인물 판별 대상에서 제외
- 고인물% ≥ 70% → 추가 모집 필요 신호