Glowb Dev Docs
Admin API약기법 검수

정책·법률 준수 검수 개요

캠페인 콘텐츠의 광고 규정 위반 여부를 AI로 검수하는 기능. 정책별로 분리된 계층형 구조입니다.

정책·법률 준수 검수 개요

캠페인 콘텐츠(가이드라인·제출물·광고주 피드백)의 광고 규정 위반 여부를 AI로 검수하는 기능입니다. 판정은 Python(sns-crawler)이, 정책 선택·트리거·저장은 Spring 이 담당합니다.

정책별로 독립 실행·독립 저장됩니다. 한 정책의 실패나 재실행이 다른 정책 결과를 덮어쓰지 않습니다.

범위 — 전체 기획 vs 현재 구현

기능의 상위 개념은 정책·법률 준수 검수이고, 현재 구현·배포된 범위는 일본 광고규정입니다.

정책policyKey적용 방식상태
일본 광고규정 — 약기법(薬機法)·화장품 효능 56항목·의약품등 적정광고기준·경표법(景品表示法)·스텔스 마케팅 규제yakkiho관리자 토글✅ 구현·운영
메타(Meta) 광고 정책 — Meta Advertising StandardsmetaAds인스타그램 캠페인이면 자동 적용✅ 구현
틱톡 광고 정책 — TikTok Advertising PoliciestiktokAds틱톡 캠페인이면 자동 적용✅ 구현
북미 법령(미정)—❌ 미구현

Meta 자동 적용 판별

Meta 는 토글이 없습니다. 캠페인이 인스타그램이면 무조건 적용됩니다.

  1. sns_content_format 이 있으면 그 플랫폼을 따릅니다(타입이 명시된 값이라 우선)
  2. 없으면(멀티 SNS 캠페인) sns 콤마 목록에서 INSTAGRAM 토큰을 찾습니다

Meta 응답의 차이

Meta 는 약기법에 없는 requirements 를 함께 반환합니다. 광고 문구를 고치는 것만으로 해결되지 않는 집행·설정·자격 요건(연령 제한, 사전 승인, 협찬 고지 등)입니다.

requirements[].status 가 unknown 인 것은 위반 확정이 아니라 "설정 확인 필요" 입니다. 캠페인에서 근거를 얻을 수 있는 값(market_country·is_branded_content·compensation_type·has_paid_partnership_label)만 전송하고, 타게팅 최소 연령·특별 광고 카테고리·업종 자격 같은 집행 설정값은 우리가 알 수 없어 보내지 않으므로 그 요건들은 unknown 으로 남습니다.

이 때문에 위반이 하나도 없는 캠페인도 Meta 를 적용하면 low(주의 필요)로 표시됩니다. 버그가 아닙니다 — Meta 는 미충족·미확인 요건이 있으면 pass 를 주지 않습니다.

토글 1개가 일본 광고규정 세트 전체를 켠다. 아래 규정이 항상 함께 적용되며(Python 코어 규정), 개별 법령만 켜고 끄는 옵션은 없습니다. 캡션 검수에만 스텔스 마케팅 규제가 추가로 적용됩니다.

  • 약기법 광고 관련 조항
  • 화장품 효능 56항목(화이트리스트)
  • 의약품등 적정광고기준(본체 + 해설·유의사항)
  • 경표법(우량오인 등)
  • 스텔스 마케팅 규제 (캡션 전용)

여기에 요청마다 롱테일 RAG 청크(기본 30개)가 더해집니다.

결과 저장 구조

정책별 블록으로 저장합니다. 실행한 정책의 키만 생성됩니다.

{
  "regulationRiskResults": {
    "yakkiho": { "status": "high", "violations": [] },
    "metaAds": { "status": "low", "violations": [], "requirements": [] },
    "tiktokAds": { "status": "pass", "violations": [], "requirements": [] }
  }
}

정책별 응답 차이 (Meta vs TikTok)

뼈대(status·summary·violations[]·requirements[]·review_scope·corpus_version·_meta)는 같지만 필드가 갈립니다.

필드MetaTikTok
violations[].rule_id · priority · action✅❌
violations[].verification_required · verification_context_key✅❌
requirements[].rule_id✅❌
review_scope.industry❌✅ (미전송이라 항상 null)
_meta.evidence_bundles❌✅ (검색 묶음 메타데이터 — 정책명 아님, 화면 비표시)

violations[].type 값 집합도 다릅니다.

  • Meta(12): 금지콘텐츠 개인속성 건강웰니스 과장기만 연령제한 타게팅제한 승인필요 협찬고지 자격요건 형식제한 지식재산권 기타
  • TikTok(14): 금지콘텐츠 제한업종 과장기만 차별안전 청소년보호 연령제한 국가제한 타게팅제한 허가서류 협찬고지 랜딩페이지 계정자격 지식재산권 기타

requirements[].type 도 Meta 는 authorization_required·special_ad_category_required·eligibility_required, TikTok 은 certification_required·targeting_restricted·advertiser_eligibility_required·landing_page_required 로 갈립니다. status(met·unmet·unknown)만 공통입니다.

Meta 기준으로 priority 정렬이나 action 분기를 구현했다면 TikTok 에서는 전부 undefined 입니다. type 을 하드코딩 매핑했다면 TikTok 값 8개가 매칭에 실패합니다 — 정책 키별 매핑을 두거나 모르는 값은 원문 그대로 표시하세요.

제출물 검수 조회 응답에도 실린다

스크립트·영상·캡션의 AI 검수 조회 응답에 두 키가 함께 내려갑니다.

{
  "overallStatus": "PASS",
  "regulationRiskResult":  { "status": "high" },
  "regulationRiskResults": { "yakkiho": {...}, "metaAds": {...}, "tiktokAds": {...} }
}
  • GET /ai/influence/contents/ai-review/script/{reviewId}
  • GET /ai/influence/contents/ai-review/{collabNo}/{applicationId}/{itemId} (영상·캡션)

Meta 결과는 단일 키에 실리지 않으므로 정책별 축은 regulationRiskResults 로 렌더해야 합니다.

재검수 중에는 IN_PROGRESS 로 내려간다

재제출로 재검수가 도는 동안에는 직전 완료 결과를 그대로 주지 않는다.

결과 문서에 대상 제출 버전(submissionVersion = TB_CONTENT_SUBMISSION_ITEM.current_version)을 남기고, 조회 시 현재 버전과 비교한다. 저장된 결과가 더 오래됐으면 재검수 중으로 판단한다.

{
  "submissionVersion": 1,
  "reviewState": "IN_PROGRESS",
  "regulationRiskResults": {
    "yakkiho": { "status": "IN_PROGRESS" },
    "metaAds": { "status": "IN_PROGRESS" },
    "tiktokAds": { "status": "IN_PROGRESS" }
  }
}
필드의미
submissionVersion이 결과가 검수한 제출 버전
reviewStateCOMPLETED | IN_PROGRESS

재검수 중이면 양 축의 status 도 함께 IN_PROGRESS 로 내려가고, 이전 버전의 위반 내용은 응답에서 제외된다. 프론트 게이트가 status 만 보고도 로딩 처리를 할 수 있어야 하기 때문이다.

스크립트 검수는 회차(reviewId) 단위라 대상 항목 중 가장 높은 버전을 기준으로 삼는다 — 하나라도 재제출되면 재검수 대상이다.

중간 상태를 문서로 쓰지 않고 조회 시점에 판단한다. 검수 시작 시점에 IN_PROGRESS 문서를 최신본으로 쓰면, 검수가 실패했을 때 직전 정상 결과가 묻히기 때문이다.

전환기 이중 쓰기 — 프론트가 아직 단일 키 regulationRiskResult 를 읽습니다. 전환이 끝날 때까지 약기법 결과는 두 키에 모두 기록됩니다. 단일 키는 정책 하나만 담을 수 있으므로 Meta 결과는 정책별 키에만 저장됩니다.

읽기 폴백 — 이관 이전 문서는 정책별 키가 없습니다. 백필하지 않는 대신 조회 시 단일 키로 폴백하므로 과거 검수 결과도 그대로 보입니다.

검수 대상과 저장 위치

대상트리거저장 위치조회 방법
가이드라인가이드라인 완성(COMPLETED) 시 자동MongoDB guidelines.regulationRiskResult가이드라인 검수 결과 조회 — 어드민 + 기업
스크립트 제출물크리에이터 1차 제출 시 + 크리에이터 AI 검수 재요청 시 기존 AI 스크립트 검수와 병렬 실행ai_script_review_results 문서의 data.regulationRiskResult (병합)GET /ai/influence/contents/ai-review/script/{reviewId} 응답의 regulationRiskResult
영상 제출물크리에이터 2차 제출 시 + 크리에이터 AI 검수 재요청 시 기존 AI 영상 검수와 병렬 실행ai_review_results 문서의 data.regulationRiskResult (병합)GET /ai/influence/contents/ai-review/{collabNo}/{applicationId}/{itemId} 응답의 regulationRiskResult
캡션 제출물크리에이터 2차 제출 시 (영상과 한 세트)ai_review_results (캡션 itemId, 약기법 단독)위와 동일한 API 에 캡션 itemId 로 조회
광고주 피드백 (검수의 검수)광고주 피드백 정식 제출 시regulation_review_results (reviewId + 타입)피드백 검수 결과 조회

제출물(스크립트/영상/캡션) 약기법 결과는 별도 API 가 아니라 기존 AI 검수 조회 API 응답에 regulationRiskResult 필드로 병합되어 내려갑니다. 같은 검수인데 저장소가 갈리면 디버그가 불편하다는 합의에 따른 설계입니다.

크리에이터가 쿼터를 써서 AI 검수를 재요청하는 경로(POST /ai/influence/contents/ai-review/request/script/{reviewId}, .../request/video/{itemId})에서도 동일하게 약기법 검수가 병렬 실행되어 같은 문서에 병합됩니다. 최초 제출 경로와 저장 위치·병합 키가 같으므로 재요청이 이전 결과를 덮어써도 약기법 결과가 사라지지 않습니다.

쿼터 환불은 일반 AI 검수 성공 여부로만 판단합니다 — 약기법만 실패해도 검수 횟수는 차감된 채 유지됩니다(부가 정보이므로).

regulationRiskResult 노출은 조회 경로에 따라 다릅니다.

경로크리에이터(ROLE_USER)
GET /ai/influence/contents/ai-review/result/script/{reviewId}
.../result/video/{itemId} — 크리에이터 전용
✅ 노출
GET /ai/influence/contents/ai-review/script/{reviewId}
.../ai-review/{collabNo}/{applicationId}/{itemId} — 어드민·기업용
❌ 제거

크리에이터 전용 경로는 본인이 제출한 스크립트·영상의 규정 위반 내용을 보고 수정하라고 그대로 내려보냅니다. assertOwner 로 신청 당사자만 통과하므로 남의 검수 결과는 조회되지 않습니다.

검수의 검수(광고주 피드백 약기법 검수)는 여전히 어드민 전용입니다 — 저장소(regulation_review_results)와 API 가 달라 이 경로로는 나가지 않습니다.

엔드포인트별 권한 — /ai/admin/regulation 아래 엔드포인트지만 가이드라인 2개만 기업에 열려 있습니다. 광고주 본인이 작성한 콘텐츠라 결과를 못 받으면 고칠 수가 없기 때문입니다.

엔드포인트권한
GET /{collabNo}/guideline
POST /{collabNo}/guideline/review
어드민 + 기업(본인 캠페인만, 소유권 검증)
토글 조회·변경, 피드백 조회·재실행, 제출물 백필어드민 전용

크리에이터(ROLE_USER)는 어느 쪽도 호출할 수 없습니다.

opt-in 을 나중에 켜면 그 전 제출물에는 약기법 결과가 없습니다. 제출물 약기법은 제출 시 자동 실행뿐이라 소급되지 않습니다. 이미 제출된 건은 제출물 약기법 백필 로 채워 넣으세요.

opt-in 플래그

  • 저장: MariaDB TB_COLLAB.regulation_review_enabled (tinyint(1), 기본 0)
  • 토글: 사용 여부 변경 — 캠페인만 있으면 언제든 설정 가능(가이드라인 문서 불필요)
  • 노출: 캠페인 상세(GET /ai/progress-table/item) 응답의 regulationReviewEnabled 필드

실행 상태 구분 (4상태)

검수 결과 페이로드의 status 로 실행 이력을 구분합니다.

상태의미
(결과 없음 / null)실행된 적 없음
IN_PROGRESS실행 중 (startedAt 포함, 10분 이상 지속되면 실패 간주 후 수동 재실행)
FAILED실패 (error 포함)
high | low | pass완료 — 위반 최고 위험도 기준 판정

판정 결과 형식

{
  "status": "high",
  "summary": "일본 약기법·경품표시법 기준으로 검수한 결과입니다.",
  "violations": [
    {
      "kind": "expression",
      "text": "シミが完全に消える",
      "text_ko": "기미가 완전히 사라진다",
      "type": "효능범위초과",
      "risk": "high",
      "basis": "약기법 제66조 (과대광고 금지)",
      "reason": "화장품 효능 범위를 벗어난 의약품적 효능 표현입니다.",
      "fix": "メラニンの生成を抑え、シミ・そばかすを防ぐ",
      "fix_ko": "멜라닌 생성을 억제해 기미·주근깨를 방지"
    }
  ]
}
  • timeRange: 영상 검수만 — [시작초, 끝초]
  • scene/part: 스크립트 검수만 — 장면 번호 / subtitle·narration·videoScene
  • feedback_id: 피드백 검수만 — 위반을 유발한 TB_CONTENT_FEEDBACK.id

On this page