Glowb Dev Docs
Admin APIAdmin Dashboard API

데모(목업) 후보 — 프론트 연동 가이드

모집 에이전트가 발굴한 비가입자를 리스트 관리·광고주 대시보드에 노출하는 dummyItems 연동

데모(목업) 후보 — 프론트 연동 가이드

모집 에이전트가 인스타그램에서 발굴한 비가입자 크리에이터를 캠페인 리스트에 목업으로 올리는 기능입니다. 어드민에서는 데모임을 표기하고, 광고주 화면에서는 표기 없이 일반 신청자와 똑같이 보여야 합니다.

광고주 화면에 데모 표기 금지. 광고주 대시보드에서 dummyItemsitems구분 없이 자연스럽게 렌더해야 합니다. 뱃지·툴팁·회색 처리 등 데모임을 드러내는 표기를 넣지 마세요. 어드민에서만 표기합니다.

왜 별도 배열인가

데모 후보는 실제 신청(TB_CAMPAIGN_APPLICATION)이 아니라 별도 테이블(TB_CAMPAIGN_DEMO_APPLICANT)에 있습니다. 우리 회원이 아니라 influence_id(NOT NULL FK)를 채울 수 없기 때문입니다.

그 결과 신청 테이블에는 이 후보의 행이 아예 없습니다. 계약·정산은 모두 신청 행을 기준으로 동작하므로, 이 후보들을 구조적으로 집을 수 없습니다 — 막는 코드가 따로 있는 게 아니라, 집을 대상이 존재하지 않습니다.

선정/예비/제외

데모도 선정·예비·제외 상태를 가질 수 있습니다. 실제 신청자와 같은 API 를 씁니다 — 프런트가 데모와 신청을 나눠 호출하지 않습니다. itemIds 에 실제 신청 ID 와 데모 ID(1억 오프셋)를 섞어 보내도 됩니다 — 서버가 오프셋을 보고 갈라 각각 처리합니다.

하는 일엔드포인트
선정POST /ai/progress-table/items/bulk/proposal-with-charge
예비·제외·대기PUT /ai/progress-table/items/bulk/user/matching-status (reserved/eliminated/waiting)
단건 변경PUT /ai/progress-table/items/{id}/user/matching-status (waiting/matched/reject 만)
POST /ai/progress-table/items/bulk/proposal-with-charge
{ "collabId": 3126, "itemIds": [18539, 100000012] }

선정은 크레딧이 움직이는 경로입니다. proposal-with-charge 는 예산 부족 시 자동 충전 (forceCharge 기본 true)까지 합니다. 데모는 이 계산에서 완전히 빠집니다 — 선정 표시만 하고 크레딧은 1원도 건드리지 않습니다. 데모만 보내면 "데모 후보 N건 선정 처리했습니다. (크레딧 변동 없음)" 으로 응답합니다.

선정 상태는 표시용입니다. 데모도 선정/예비/제외 상태를 가질 수 있지만(selectionStatus), 실제 신청과 달리 부수효과가 없습니다. 실제 신청은 SELECTED 가 되면 매칭·배송 테이블이 생기고 ELIMINATED 면 예산이 UNLOCK 되는데, 데모는 그 어느 것도 일으키지 않습니다 — 목업이 계약·배송·예산을 건드리면 안 되기 때문입니다. 즉 "화면에 그렇게 보인다"는 뜻일 뿐입니다.

응답의 dummyItems[].applicationId는 렌더 편의를 위해 만들어 넣은 값이지 실제 신청 ID가 아닙니다. 아래 ID 규칙을 참고하세요.

ID 규칙 — 신청 ID와 겹치지 않는다

dummyItemsitems동일한 구조라 같은 컴포넌트로 그대로 렌더할 수 있습니다. ID는 1억(100,000,000) 오프셋을 더해 내려가므로 실제 신청 ID와 겹치지 않습니다. 한 목록에 이어 붙여도 key 충돌이 없습니다. (신청 ID는 현재 1만대)

어드민 dummyItems[].applicationId광고주 dummyItems[].id
100000000 + 데모 PK동일
판별id >= 100000000 이면 데모동일

데모 ID를 신청 상세 조회 API에 쓰지 마세요. 신청 ID가 아니라 데모 테이블 PK에 오프셋을 더한 값이라, 개별 신청을 조회하는 API(GET .../applications/{id} 등)에 넣으면 404가 납니다. 단, 데모를 지원하도록 만든 API에는 받은 값을 그대로 넘기면 됩니다 (서버가 오프셋을 해석): 삭제·노출, 벌크 수정, 그리고 아래 선정/예비/제외(진행테이블 matching-status·proposal-with-charge)까지. 계약·검수는 데모에 존재하지 않습니다.

1. 어드민 — 리스트 관리 응답

GET /ai/admin/dashboard/{campaignNo}/list 응답에 dummyItems가 추가됩니다. items동일한 ListItemDto 구조라 기존 행 컴포넌트를 그대로 재사용할 수 있습니다.

{
  "campaign": { "...": "..." },
  "items": [ { "applicationId": 18539, "influenceName": "홍길동", "...": "..." } ],
  "dummyItems": [
    {
      "applicationId": 100000012,
      "appliedAt": "2026-07-15T18:20:11",
      "adminVisible": false,
      "sourceType": "AI_RECOMMENDED",
      "influenceNo": null,
      "influenceName": "creator_jp_1",
      "influenceProfileImage": null,
      "influenceTel": null,
      "influenceEmail": null,
      "influenceRankScore": "300000",
      "followerCount": "12400",
      "averageViewCount": "8300",
      "autoCategories": ["뷰티", "라이프스타일"],
      "recommendReason": "뷰티 카테고리 릴스 비중이 높고 ...",
      "flags": [],
      "currentPrice": 250000,
      "quotePrice": 300000,
      "matchScore": null,
      "latestNegotiationId": null,
      "contractWritten": null,
      "defaultUnitPrice": null,
      "previouslyCollaborated": false,
      "previouslyExposed": false,
      "recentPosts": []
    }
  ],
  "remainBusinessCredit": 1200000,
  "veteranPercentage": 40.0
}

데모 행에서 비는 값 — 비가입자라 우리 DB에 없는 정보입니다.

필드이유
applicationId100000000 + 데모 PK실제 신청이 아님. 삭제·노출 API에만 사용
influenceNonull회원이 아님
influenceName인스타 username실명을 모름
snsUrl인스타 프로필 링크데모 행에 저장된 account_link. 진행 API 병합에 의존하지 않는다
influenceTel, influenceEmailnull연락처를 모름
influenceRankScore예상가(원) 문자열에이전트 산정값. 불가 시 null
currentPrice, quotePrice, defaultUnitPrice, latestProposedPrice어드민이 입력한 값초기엔 null. 가격 벌크로 4종 모두 수정 가능
recommendReason에이전트 LLM 초안어드민이 벌크 수정으로 다듬는다
matchScorenull매칭 점수는 신청에만 있음
latestNegotiationStatus 등 협상 상태·계약 필드null데모는 협상·계약이 존재할 수 없다. 제안가(latestProposedPrice)는 협상 이력 없이 값만 보관한다
recentPosts최근 게시물 최대 3개크롤 DB(PG public.post)를 account_id로 조회해 채운다. 실제 신청자와 동일
flags어드민이 입력한 비고 칩리스트 벌크의 flags 로 편집. 초기엔 빈 배열
sourceType"AI_RECOMMENDED"에이전트 발굴

신청이 하나도 없는 캠페인(items: [])에서도 dummyItems는 정상 반환됩니다.

2. 기업(광고주) — 캠페인 대시보드 응답

GET /ai/progress-table/item/{id} 응답에 dummyItems가 추가됩니다. items와 완전히 동일한 shape이라 같은 컴포넌트로 그대로 렌더할 수 있습니다.

{
  "step": "MATCHING",
  "items": [ { "id": 18539, "creator": "홍길동", "matchingStatus": "waiting", "...": "..." } ],
  "dummyItems": [
    {
      "id": 100000012,
      "creator": "creator_jp_1",
      "profileImg": null,
      "creatorEmail": null,
      "influenceId": null,
      "creatorLink": "https://www.instagram.com/creator_jp_1/",
      "matchingStatus": "waiting",
      "flags": [],
      "followerCount": 12400,
      "avgViewCount": 8300,
      "recommendReason": "뷰티 카테고리 릴스 비중이 높고 ...",
      "rankPrice": 300000,
      "quotePrice": 300000,
      "currentPrice": 250000,
      "recentPosts": [],
      "trackingNumber": null,
      "deliveryStatus": null,
      "aiCheck": null,
      "personCheck": null,
      "uploadStatus": null
    }
  ]
}

렌더 규칙

  • items와 이어 붙여 하나의 목록으로 보여줍니다. 순서는 프런트 판단(뒤에 붙이는 것을 권장).
  • 데모임을 드러내는 표기를 넣지 않습니다.
  • 진행 상태 필드(deliveryStatus, aiCheck, personCheck, uploadStatus, 배송 관련)는 모두 null입니다. 실제 신청이 아니므로 계약·배송·검수가 없습니다. 기존 항목의 "아직 진행 전" 표시와 동일하게 처리하세요.
  • matchingStatus는 어드민이 정한 선정 상태를 실제 신청과 같은 규칙으로 매핑한 값입니다(SELECTEDmatched 등). 상태를 안 정했으면 "waiting".
  • creatorEmail, influenceIdnull입니다. 이 값에 의존하는 로직이 있다면 방어가 필요합니다.
  • followerCount, avgViewCount, recommendReason, rankPrice, quotePrice, currentPrice, recentPosts실제 신청과 동일하게 채워집니다. 데모라고 비어 있지 않습니다.
  • recentPosts는 크롤 DB에서 가져오므로 크롤 이력이 없는 계정은 빈 배열일 수 있습니다. 수기 등록 후보는 크롤 대상이 아니라 등록 시 직접 넣은 값이 쓰입니다(수기 입력분이 크롤 조회보다 우선).
  • profileImg는 어드민이 넣지 않으면 null입니다 — 비회원이라 자동으로 가져올 원천이 없습니다 (실제 신청자는 회원 프로필에서 옵니다). 넣으려면 업로드 URL 발급으로 올린 뒤 수기 등록의 profileImage 에 담거나, 등록 후 리스트 벌크의 profileImage 로 수정하세요. 비어 있으면 기본 아바타로 처리합니다.

adminVisible = true인 데모만 내려갑니다. 결제미완(PAYMENT_PENDING) 캠페인과 신청자 숨김 모드에서는 items와 마찬가지로 dummyItems도 빈 배열입니다.

레거시(구사스) 캠페인(isLegacy: true)도 동일하게 내려갑니다. 캠페인 종류에 따라 응답 형태가 달라지지 않으므로 프런트는 isLegacy를 따질 필요가 없습니다. dummyItems는 항상 존재하고, 담긴 데모가 없으면 빈 배열입니다.

3. 데모 후보 관리 API

엔드포인트 상세는 각 문서를 참고하세요.

하는 일문서
후보 모달에서 고른 비가입자를 데모로 담기POST .../demo-applicants
인스타 링크만으로 벌크 등록 + 자동 채움POST .../demo-applicants/bulk-links
광고주 노출 on/offPATCH .../demo-applicants/{demoId}/visible
데모 후보 삭제DELETE .../demo-applicants/{demoId}

삭제·노출 API 의 {demoId} 에는 dummyItems[].applicationId그대로 넣습니다 — 오프셋은 서버가 해석하므로 프런트에서 뺄셈하지 마세요.

4. 데모 후보 수정 — 기존 벌크 API 를 그대로 씁니다

신규 엔드포인트가 없습니다. 프런트가 신청과 데모를 나눠 호출하지 않도록, 지금 쓰는 벌크 API 에 데모 ID 를 그대로 넣으면 서버가 오프셋을 보고 알아서 데모 테이블로 보냅니다.

기존 API데모에 적용되는 항목
PATCH .../applications/prices/bulk가격 4종 — 희망가 defaultUnitPrice, 제안가 proposedPrice, 기준가 quotePrice, 노출가 currentPrice
PATCH .../{campaignNo}/list수기 등록으로 넣은 값 전부 — 이름 username, 링크 accountLink, 프로필이미지 profileImage, 팔로워 followerCount, 조회수 reelsAvgViews, 적합도 matchScore, fitScore, 예상가 estimatedPrice, 노출가 currentPrice, 카테고리 categoryTags, 추천사 recommendReason, 비고칩 flags, 최근게시물 recentPosts, 노출 adminVisible
{
  "items": [
    { "applicationId": 18539,     "currentPrice": 200000 },
    { "applicationId": 100000012, "defaultUnitPrice": 350000, "proposedPrice": 320000, "quotePrice": 300000, "currentPrice": 250000 }
  ]
}

위 요청에서 18539 는 실제 신청으로, 100000012 는 데모로 갑니다. 프런트는 구분 없이 한 번에 보내면 됩니다.

데모에 없는 항목(계약서·지불방식·유저풀 추가·선정 상태)은 조용히 무시됩니다. 데모는 계약·정산이 존재하지 않기 때문입니다. 가격·노출·추천사만 반영됩니다.

수기 등록으로 넣을 수 있는 값은 전부 리스트 벌크로 고칠 수 있습니다. 오타 하나 때문에 지우고 다시 만들 필요가 없습니다. 단 가격 4종 중 희망가·제안가·기준가는 가격 벌크 쪽입니다(위 표).

categoryTags·flags·recentPosts배열 전체 교체입니다 — 개별 항목에 id 가 없습니다.

추천사(recommendReason)는 리스트 관리 벌크에만 있습니다. 가격 벌크(prices/bulk)에는 추천사 필드가 없으므로, 추천사를 고치려면 PATCH .../{campaignNo}/list 를 쓰세요. 값이 없던 후보에 새로 넣는 것도 같은 방식입니다.

비고 칩(flags)도 데모에서 저장·조회됩니다. 리스트 관리 벌크의 flags 로 실제 신청자와 동일하게 편집하세요. 응답도 동일한 InfluenceFlagDto 모양이라 같은 컴포넌트로 렌더할 수 있습니다. 추천사(recommendReason)와 비고 칩(flags)은 서로 다른 것이니 혼동하지 마세요.

데모 비고는 배열 전체 교체 방식입니다. 실제 신청자의 칩은 TB_INFLUENCE_FLAG 행이라 개별 id 가 있지만, 데모 비고는 데모 행의 JSON 이라 id 가 없습니다. 수정·삭제는 원하는 최종 상태의 배열을 통째로 보내세요. 빈 배열 [] 을 보내면 전부 삭제됩니다.

데모 비고는 캠페인별입니다. 실제 비고 칩은 크리에이터 전역 속성이라 캠페인을 넘나들지만, 데모 비고는 그 데모 행에 종속됩니다. 같은 계정을 두 캠페인에 데모로 담으면 비고는 각각 관리됩니다.

알려진 제약

일본 캠페인에 한국 크리에이터가 섞일 수 있습니다. 모집 에이전트 파이프라인에 nation 필터가 미구현이라 수집 단계에서 국가가 걸러지지 않습니다. 백엔드에서 막을 수 없으므로, 어드민이 데모로 담을 때 눈으로 확인해야 합니다.

On this page