주요업무 1 · 2번

차세대 CMS 재구축

콘텐츠가 들어와 화면에 걸리기까지

CMS의 고객은 시청자가 아니라 운영자다. 그들의 화폐는 시간이다.

티빙 현행을 진단한 문서가 아니라 “제가 만든다면”의 목표 설계 초안이며, 기간·목표치는 전부 가정입니다.

§0. 용어 풀이 (이 문서에서 쓰는 약어)

약어원어
CMSContent Management System콘텐츠를 등록·가공·검수·편성·노출하는 내부 운영 시스템
인제스트Ingest외부에서 받은 영상·메타데이터를 시스템 안으로 받아들여 가공하는 과정
메타데이터Metadata콘텐츠를 설명하는 데이터. 제목·줄거리·출연진·장르·등급·썸네일 등
EPGElectronic Program Guide실시간 채널의 편성표. "언제 무슨 프로그램이 방송되는가"(시간축)
카탈로그Catalog서비스 화면의 어느 영역에 콘텐츠를 노출할지 정하는 분류(공간축)
에셋Asset실제 미디어 파일. 원본·인코딩본·자막·썸네일 등
렌디션Rendition원본을 화질·코덱별로 변환한 결과물
트랜스코딩Transcoding원본 영상을 화질·코덱별로 변환해 다양한 기기에서 재생 가능하게 만드는 것
DRMDigital Rights Management콘텐츠 불법 복제를 막는 암호화·권한 기술 (Widevine·FairPlay·PlayReady)
MTSMedia Transcoding System트랜스코딩을 수행하는 시스템 (※ 아래 TMS와 혼동 주의)
TMSTranslation Management System다국어 메타·자막의 기계번역 초벌을 전문 번역·감수 워크플로우로 관리하는 시스템 (Phrase·Smartling 등)
CDNContent Delivery Network영상을 사용자 가까운 서버에서 전송해 속도를 높이는 배포망
CDCChange Data CaptureDB 변경 로그를 실시간으로 뽑아 다른 저장소에 흘려보내는 기술
Strangler Fig레거시를 한 번에 갈아엎지 않고, 새 시스템으로 조금씩 감싸며 대체하는 재구축 패턴
HITLHuman-in-the-LoopAI가 초안을 만들고 사람이 최종 승인하는 구조
리드타임Lead Time콘텐츠를 수급한 시점부터 서비스에 노출되기까지 걸린 시간
북극성 지표North Star Metric조직이 함께 바라보는 단 하나의 핵심 성공 지표
가드레일 지표Guardrail Metric북극성을 좇다가 망가지면 안 되는 품질·안정성 지표

§1. 도메인 정의 — 경계와 "내부 고객"

1-1. CMS는 무엇을 책임지는가

CMS는 콘텐츠가 회사 밖에서 들어와 시청자 화면에 걸리기까지의 전 과정을 책임진다. 재생·스트리밍은 CMS의 일이 아니다. CMS는 "무엇을, 어떤 정보와 함께, 언제, 어디에 노출할 것인가" 를 결정·기록·전달한다.

도식을 탭하면 확대해서 볼 수 있습니다

1-2. CMS의 고객은 시청자가 아니다

이 문서 전체를 관통하는 명제입니다.

CMS의 고객은 내부 콘텐츠 운영자입니다. 그들의 화폐는 시간입니다.

그러므로 CMS의 성공은 MAU가 아니라 운영자의 작업 리드타임·자동화 처리율로 잽니다.

물론 그게 개선되면 신작이 더 빨리·더 정확한 메타와 함께 노출되어 시청 경험에 기여합니다. 하지만 Platform Product Lead가 직접 움직이는 지표는 내부 고객 지표입니다.

내부 고객하는 일이 사람의 "시간"이 어디로 새는가
콘텐츠 운영자(MD)메타 등록·검수, 썸네일 선정, 카탈로그 배치반복 입력, 엑셀 왕복, 오타 재작업
편성 담당실시간 채널 편성, FAST 채널 구성EPG-카탈로그 이중 입력, 급편 대응
권리(라이선스) 담당계약 조건 입력, 서비스 윈도우 관리만료 임박 콘텐츠 수동 추적, 지역 제한 누락
QC 담당영상·자막 품질 검수전수 검사 불가, 샘플링 의존
글로벌 운영다국어 메타·자막 관리언어별 누락 추적 불가, 번역 발주 수작업

1-3. 미디어 CMS가 반드시 푸는 여섯 가지 난제

아래는 티빙 현행에 대한 진단이 아닙니다. 미디어 CMS라면 규모·시대와 무관하게 마주치는 도메인 보편의 난제입니다.

이 문서의 설계 결정은 전부 이 여섯 개 중 하나에 대한 답입니다. TVING 1세대와 BTV NCMS에서 팀과 함께 겪은 문제들이기도 합니다.

#난제왜 어려운가이 문서의 답
N1원본과 조회 저장소의 동기화정합성 기준(원본)과 조회 성능(색인)은 요구가 상반된다§2-2 CDC 스트리밍
N2외부 연동의 실패 처리트랜스코딩·DRM·CDN은 실패가 일상. 재시도·보상이 필요§2-2 워크플로우 엔진
N3대량 메타 입력의 확장성카탈로그가 커지면 인력이 선형으로 늘어난다§2-1 원칙 4, §5-1 AI 초안
N4편성(시간축)과 노출(공간축)의 이원성목적이 다른 두 분류 체계. 합치면 급편·FAST에서 터진다§3-2 결정 ②
N5다국어 확장언어를 컬럼으로 두면 국가 추가마다 스키마가 바뀐다§3-2 결정 ①
N6라이선스(권리) 관리문서에만 있으면 만료 콘텐츠가 노출되는 사고가 난다§3-1 RIGHTS_WINDOW, §4-5

§2. To-Be 목표 아키텍처

2-1. 설계 원칙 다섯 가지

#원칙구체적으로답하는 난제
1원본과 조회를 분리하되 CDC로 잇는다배치가 아니라 변경 로그 스트리밍. 조회 장애가 원본을 오염시키지 않음N1
2편성(시간축)과 노출(공간축)을 분리하고 매핑 계층으로 연결EPG와 카탈로그는 목적이 다른 두 분류 체계N4
3공통 메타 + 오버레이언어·테넌트·지역별 차이를 컬럼 추가가 아닌 오버레이 행으로 흡수N5
4AI는 초안, 사람은 승인 (HITL)자동화율만 좇다 품질이 무너지지 않도록 승인 게이트를 남긴다N3
5외부 연동은 워크플로우 엔진이 소유재시도·보상·타임아웃을 화면 코드가 아니라 오케스트레이터가 책임N2

2-2. 목표 구성도

도식을 탭하면 확대해서 볼 수 있습니다

위 구성도의 워크플로우 오케스트레이션(Temporal) 박스 안 네 개 워크플로우(W1~W4)는 각각 하나의 durable workflow입니다. 아래에서 개별 내부 흐름을 풀어 봅니다. 공통 골격은 같습니다 — activity 단위 재시도는 엔진이, 확정 실패의 보상·사람 호출은 워크플로우가 소유합니다(§2-1 원칙 5).

2-2-1. 검수 워크플로우 (W1) — 인제스트 게이트

외부에서 들어온 파일이 신뢰할 수 있는지, 트랜스코딩에 자원을 쓰기 전에 걸러내는 자동 관문입니다. 값비싼 다운스트림(트랜스코딩·AI·번역)을 오염된 입력으로부터 보호합니다.

도식을 탭하면 확대해서 볼 수 있습니다

핵심: 검증은 전부 자동이고, 사람은 확정 실패일 때만 호출됩니다.

일시적 네트워크·I/O 오류는 Temporal이 activity 단위로 재시도해 사람 손을 타지 않고, 스펙 위반처럼 되돌릴 수 없는 실패만 재업로드 요청으로 넘깁니다. 이 게이트가 §6 상태기계의 VALIDATING → REJECTED 전이를 만듭니다.

2-2-2. 트랜스코딩 워크플로우 (W2) — 장기 실행 + 보상

몇 시간짜리 외부 연동이 실패를 일상으로 겪는 구간입니다. 난제 N2의 정중앙이자, §8-2에서 Temporal을 채택한 이유 그 자체입니다.

도식을 탭하면 확대해서 볼 수 있습니다

핵심: "MTS가 6시간째에 죽었다. 어디까지 됐고 뭘 되돌려야 하나?" — 이 질문에 답하려면 상태를 엔진이 들고 있어야 합니다(§8-2).

실패 시 보상 트랜잭션이 이미 만들어진 부분 렌디션과 CDN 오브젝트를 되돌려, 다음 재시도가 깨끗한 상태에서 시작하게 합니다. 자막 초안(STT)은 트랜스코딩과 병렬로 돌아 리드타임을 줄입니다.

2-2-3. 메타 보강 워크플로우 (W3) — AI 초안 + 환각 게이트

대량 메타 입력을 사람이 선형으로 감당할 수 없다는 난제 N3에 대한 답입니다. AI가 초안을 만들되, 승인은 사람이라는 원칙(§2-1 원칙 4)이 여기서 구조로 박힙니다.

도식을 탭하면 확대해서 볼 수 있습니다

핵심: AI는 approved=false 초안까지만 만들고, 도장은 사람이 찍습니다(§5-1).

source·approved 두 플래그가 §4-3 자동화 처리율 쿼리의 분모·분자를 만들고, 환각 방지 게이트에서 걸린 초안은 사람에게 가기 전에 재생성 루프로 되돌아갑니다. 반려는 §6 상태기계의 IN_REVIEW → META_DRAFTED 전이입니다.

2-2-4. 다국어 워크플로우 (W4) — 오버레이 + TMS

언어를 컬럼이 아니라 오버레이 행으로 흡수하는 데이터 모델(§3-2 결정 ①, 난제 N5) 위에서 도는 워크플로우입니다. 국가 추가가 스키마 변경이 아니라 데이터 삽입이 되게 합니다.

도식을 탭하면 확대해서 볼 수 있습니다

핵심: 대상 언어는 권리(rights_window)가 결정합니다.

일본에 서비스 윈도우가 열린 콘텐츠에만 ja-JP 오버레이를 만들어, 팔지도 않을 지역의 번역을 낭비하지 않습니다. MT 초벌은 TMS의 전문 번역·감수를 대체가 아니라 가속하는 용도이며, 결과는 §4-6의 "다국어 메타 누락" 쿼리로 상시 감시됩니다.

2-3. 이 구성도를 한 문장으로

"수급된 콘텐츠가 워크플로우 엔진의 관리 아래 AI 초안을 얻고, 사람의 승인 게이트를 통과한 뒤, CDC를 타고 조회 저장소로 흘러 서비스에 걸린다."

여기서 되돌리기 어려운 결정은 셋입니다 — 데이터 모델(§3), 편성/노출의 분리(§3-2), 승인 게이트를 어디에 둘 것인가(§5-1).

나머지는 나중에 바꿀 수 있습니다. 그래서 이 셋에만 제가 직접 들어갑니다.


§3. 데이터 모델 (ERD)

3-1. 핵심 엔티티 관계

도식을 탭하면 확대해서 볼 수 있습니다

3-2. 설계 결정 세 가지 — 왜 이렇게 나눴는가

CONTENT_META를 별도 테이블로 분리 (다국어 오버레이) — 난제 N5

content 테이블에 title_ko, title_en, title_ja 컬럼을 두면 언어를 추가할 때마다 스키마를 바꿔야 한다. 로케일을 **행(row)**으로 만들면 언어 추가가 데이터 삽입이 된다. 글로벌 확장이 스키마 마이그레이션을 유발하지 않는다.

또한 source(HUMAN / AI_DRAFT / MT)와 approved 플래그가 AI 초안과 사람 승인을 같은 테이블에서 구분하게 해준다. 이 두 컬럼이 §4-3의 자동화 처리율 쿼리를 계산 가능하게 만드는 핵심이다.

SCHEDULE_SLOT(편성)과 CATALOG_NODE(노출)를 분리하고 선택적으로 매핑 — 난제 N4

편성은 시간축이고 카탈로그는 공간축이다. 하나의 에피소드가 오늘 밤 채널에 편성되면서 동시에 홈 화면 "지금 뜨는" 행에 노출될 수 있다. 두 개념을 한 테이블에 억지로 합치면 FAST 채널이나 급편 대응에서 반드시 터진다.

type_attributesjsonb로 (콘텐츠 타입 이질성 흡수)

시리즈·영화·숏클립·라이브는 공통 필드(제목·등급)를 빼면 구조가 전혀 다르다. 타입별 테이블을 만들면 조인 지옥, 컬럼을 다 합치면 NULL 밭이 된다. 공통은 컬럼, 이질적인 건 JSONB로 두고 타입별 검증 스키마를 애플리케이션이 강제한다.

TVING 1세대에서 원본 Oracle과 서비스용 MongoDB를 분리했던 이유가 바로 이 유연 스키마 요구였습니다.

지금은 PostgreSQL의 jsonb가 그 역할을 하면서도 트랜잭션 정합성을 함께 가져갈 수 있습니다. 같은 문제를, 10년 뒤의 도구로 다시 푸는 셈입니다.


§4. DB 샘플 쿼리

PostgreSQL 방언. 실행 가능한 DB가 없으므로 문법과 의도를 보여주는 용도입니다.

4-1. 북극성 지표 — 수급→노출 리드타임을 단계별로 분해

-- 무엇을 답하는가: "콘텐츠 하나가 들어와서 화면에 걸리기까지 어느 단계에서 시간을 잡아먹는가"
-- 이 쿼리가 재구축 전후 비교의 기준선(baseline)이 된다.
WITH step_duration AS (
    SELECT
        j.content_id,
        s.step_name,
        EXTRACT(EPOCH FROM (s.finished_at - s.started_at)) / 3600 AS hours
    FROM ingest_job j
    JOIN ingest_step s ON s.job_id = j.job_id
    WHERE s.result = 'OK'
      AND j.started_at >= NOW() - INTERVAL '90 days'
)
SELECT
    step_name,
    COUNT(*)                                             AS 처리건수,
    ROUND(AVG(hours)::numeric, 2)                        AS 평균시간,
    ROUND(PERCENTILE_CONT(0.5)  WITHIN GROUP (ORDER BY hours)::numeric, 2) AS p50,
    ROUND(PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY hours)::numeric, 2) AS p95
FROM step_duration
GROUP BY step_name
ORDER BY 평균시간 DESC;

p95를 함께 보는 이유: 평균만 보면 "3시간이면 끝나네"로 읽히지만, 상위 5%가 40시간씩 걸린다면 운영자는 그 꼬리 때문에 야근합니다. 개선 대상은 평균이 아니라 꼬리입니다.

4-2. 전체 리드타임 — 수급부터 노출까지

-- 무엇을 답하는가: "북극성 지표의 현재 값은 얼마인가" (월별 추이)
SELECT
    DATE_TRUNC('month', c.acquired_at)                   AS 월,
    COUNT(*)                                             AS 노출건수,
    ROUND(AVG(EXTRACT(EPOCH FROM (c.published_at - c.acquired_at)) / 86400)::numeric, 2) AS 평균_리드타임_일,
    ROUND(PERCENTILE_CONT(0.95) WITHIN GROUP (
        ORDER BY EXTRACT(EPOCH FROM (c.published_at - c.acquired_at)) / 86400
    )::numeric, 2)                                       AS p95_리드타임_일
FROM content c
WHERE c.published_at IS NOT NULL
  AND c.acquired_at  >= NOW() - INTERVAL '12 months'
GROUP BY 1
ORDER BY 1;

4-3. 자동화 처리율 — AI 초안이 사람 수정 없이 승인된 비율

-- 무엇을 답하는가: "AI가 만든 초안 중 사람이 손대지 않고 통과시킨 비율은?"
-- 분모: AI 초안이 붙은 검수 과제 / 분자: 사람이 수정하지 않은 건
-- 주의: 이 값만 좇으면 검수를 대충 하게 된다 → 반드시 4-4(재작업률)와 함께 본다.
SELECT
    task_type,
    COUNT(*) FILTER (WHERE ai_drafted)                            AS ai초안_건수,
    COUNT(*) FILTER (WHERE ai_drafted AND NOT modified_by_human)  AS 무수정_승인,
    ROUND(
        100.0 * COUNT(*) FILTER (WHERE ai_drafted AND NOT modified_by_human)
              / NULLIF(COUNT(*) FILTER (WHERE ai_drafted), 0)
    , 1)                                                          AS 자동화율_pct
FROM review_task
WHERE completed_at >= NOW() - INTERVAL '30 days'
GROUP BY task_type
ORDER BY 자동화율_pct DESC;

4-4. 가드레일 — 노출 후 메타가 다시 수정된 콘텐츠 (재작업률)

-- 무엇을 답하는가: "빨리 내보냈는데 나중에 고친 건 얼마나 되는가"
-- 속도 지표(리드타임)를 좇다 품질이 무너지는지 감시하는 가드레일.
SELECT
    DATE_TRUNC('week', c.published_at)                   AS 주차,
    COUNT(DISTINCT c.content_id)                         AS 노출건수,
    COUNT(DISTINCT m.content_id) FILTER (
        WHERE m.updated_at > c.published_at + INTERVAL '1 hour'
    )                                                    AS 사후수정_건수,
    ROUND(
        100.0 * COUNT(DISTINCT m.content_id) FILTER (
            WHERE m.updated_at > c.published_at + INTERVAL '1 hour'
        ) / NULLIF(COUNT(DISTINCT c.content_id), 0)
    , 1)                                                 AS 재작업률_pct
FROM content c
LEFT JOIN content_meta m ON m.content_id = c.content_id
WHERE c.published_at >= NOW() - INTERVAL '12 weeks'
GROUP BY 1
ORDER BY 1;

4-5. 정합성 검증 — 라이선스가 만료됐는데 아직 노출 중인 콘텐츠

-- 무엇을 답하는가: "지금 이 순간 계약 위반 상태로 노출되는 콘텐츠가 있는가"
-- 사고가 나면 법무·계약 리스크. 권리를 시스템으로 옮겨야 하는 이유 그 자체.
SELECT
    c.content_id,
    m.title,
    t.iso_code                    AS 지역,
    rw.ends_at                    AS 권리_만료시각,
    NOW() - rw.ends_at            AS 초과_경과
FROM content c
JOIN content_meta  m  ON m.content_id  = c.content_id AND m.locale = 'ko-KR'
JOIN rights_window rw ON rw.content_id = c.content_id
JOIN territory     t  ON t.territory_id = rw.territory_id
WHERE c.status   = 'PUBLISHED'
  AND rw.ends_at < NOW()
  AND NOT EXISTS (        -- 같은 지역에 유효한 다른 윈도우가 없을 것
      SELECT 1 FROM rights_window rw2
      WHERE rw2.content_id   = c.content_id
        AND rw2.territory_id = rw.territory_id
        AND rw2.ends_at      > NOW()
  )
ORDER BY 초과_경과 DESC;

엑셀로 관리하면 이 질문에 답할 수가 없습니다. 답할 수 없는 질문은 사고가 나야 발견됩니다.

4-6. 운영 조회 — 다국어 메타가 누락된 노출 콘텐츠

-- 무엇을 답하는가: "글로벌 서비스 중인데 해당 언어 메타가 없는 콘텐츠는?"
-- 글로벌 운영자의 대표적 pain point. 사람 눈으로 찾으면 반드시 새어나간다.
SELECT
    c.content_id,
    km.title                                             AS 한국어_제목,
    t.iso_code                                           AS 서비스_지역,
    req.locale                                           AS 필요_언어
FROM content c
JOIN rights_window rw ON rw.content_id = c.content_id
JOIN territory     t  ON t.territory_id = rw.territory_id
CROSS JOIN LATERAL (
    -- 지역별로 요구되는 로케일 (실제로는 territory_locale 매핑 테이블에서 읽는다)
    SELECT CASE t.iso_code WHEN 'JP' THEN 'ja-JP' WHEN 'US' THEN 'en-US' END AS locale
) req
LEFT JOIN content_meta km ON km.content_id = c.content_id AND km.locale = 'ko-KR'
LEFT JOIN content_meta tm ON tm.content_id = c.content_id
                          AND tm.locale    = req.locale
                          AND tm.approved  IS TRUE
WHERE c.status      = 'PUBLISHED'
  AND rw.ends_at    > NOW()
  AND req.locale   IS NOT NULL
  AND tm.meta_id   IS NULL          -- 승인된 해당 언어 메타가 없음
ORDER BY t.iso_code, km.title;

§5. 서비스 흐름도 (시퀀스)

5-1. 시나리오 A — 배급사 콘텐츠 인제스트 (해피 패스 + 실패 보상)

도식을 탭하면 확대해서 볼 수 있습니다

승인 게이트(11~13번)가 이 설계의 심장입니다.

AI는 여기까지만 옵니다. 도장은 사람이 찍습니다. modified_by_human 한 컬럼이 "AI가 얼마나 쓸 만한가"를 매일 측정 가능하게 만듭니다.

5-2. 시나리오 B — 급편(急編) 대응: 편성 변경이 노출까지 자동 전파

도식을 탭하면 확대해서 볼 수 있습니다

이 시퀀스의 핵심은 5번과 8번입니다.

5번 — 권리 서비스가 편성 저장을 거부할 수 있다는 것. 난제 N6에 대한 답입니다.

8번 — 편성 변경이 이벤트로 흘러 카탈로그에 자동 전파된다는 것. 난제 N4에 대한 답입니다.


§6. 상태 전이 — 콘텐츠 라이프사이클

도식을 탭하면 확대해서 볼 수 있습니다

6-1. 이 상태기계가 만드는 지표

상태 전이여기서 나오는 지표
RECEIVED → PUBLISHED 총 소요북극성 — 수급→노출 리드타임
META_DRAFTED → APPROVED 무수정 통과 비율자동화 처리율
IN_REVIEW → META_DRAFTED 반려 횟수AI 초안 품질
TRANSCODE_FAILED 진입 빈도연동 안정성 (가드레일)
PUBLISHED → EXPIRED 자동 전이율권리 사고 방지율

상태를 잘 나누면 지표가 공짜로 나옵니다.

반대로 상태를 status = '진행중' 하나로 뭉개면, 어느 단계가 느린지 영원히 알 수 없습니다.


§7. 동선 — 목표 상태의 운영자 경험

7-1. 콘텐츠 운영자의 하루 (To-Be)

도식을 탭하면 확대해서 볼 수 있습니다

점수는 "그 작업이 얼마나 할 만한가"(1=고통, 5=쾌적)를 뜻합니다.

검수(4점)를 5점으로 만들려 하지 않는 것이 의도입니다. 검수는 사람이 판단해야 하는 일이고, 마찰이 0이 되면 아무도 제대로 보지 않습니다.

자동화의 목표는 사람을 빼는 것이 아니라, 사람을 더 중요한 판단에 쓰는 것입니다.

7-2. 운영자 화면 동선

도식을 탭하면 확대해서 볼 수 있습니다

7-3. 시청자 동선 — CMS가 어디에 기여하는가

CMS는 시청자를 직접 만나지 않는다. 하지만 시청자가 겪는 모든 마찰의 뿌리에 CMS가 있다.

도식을 탭하면 확대해서 볼 수 있습니다

경영진에게 설명할 인과 사슬:

수급→노출 리드타임이 줄면 → 신작·화제작이 더 빨리, 더 정확한 메타와 함께 걸린다 → 초기 시청 전환이 오른다.

메타 품질이 오르면 → 검색 성공률·추천 정확도가 오른다 → 체류시간에 기여한다.

다만 CMS 리더가 MAU를 직접 약속하지는 않습니다. 우리가 움직이는 건 사슬의 앞단입니다.


§8. 솔루션 후보 비교 — 빌드 vs 바이

8-0. 이 결정을 누가 어떻게 내리는가 (프로세스 관점)

아래 8-1~8-5는 "무엇을 빌드/바이할지"의 결론입니다. 그 전에 **"이 결정을 누가 내리는가"**를 먼저 밝힙니다. Platform Product Lead의 역할을 오해하지 않기 위해서입니다.

빌드/바이는 Product Lead가 혼자 정해 개발팀에 내리는 지시가 아닙니다. PM이 판단 프레임을 소유하고, 엔지니어링과 함께 내려, 근거를 문서(ADR)로 남기는 공동 결정입니다. PM이 도구까지 정해 던지면 개발팀은 자기가 고르지 않은 선택에 주인의식을 갖지 못하고, 애초에 기술 실현가능성·운영부담은 PM이 정확히 잴 수도 없습니다.

이 결정은 두 층위로 나뉘고, 층위마다 주인이 다릅니다.

층위예시리드Product Lead의 몫
역량(capability)코어를 소유할까 vs 상용 CMS를 살까 (§8-1)Product Lead가 프레임 소유차별화·TCO·전략 판단을 주도
도구(tool)워크플로우를 Temporal이냐 Airflow냐 (§8-2)엔지니어링/아키텍트가 리드판단 기준만 정렬, 세부는 위임

상위(전략) 층위일수록 PM이 프레임을 쥐고, 하위(기술 도구) 층위일수록 엔지니어링에 위임합니다. §8-5의 판단 기준 한 문장 — "경쟁 우위가 되는 도메인은 빌드, 남들도 똑같이 쓰는 인프라는 바이" — 이것이 PM이 제공하는 의사결정 프레임이지, 특정 제품명이 아닙니다.

활동Product Lead엔지니어링
문제·요구사항·우선순위 정의책임(A)기여(C)
비즈니스 가치·TCO·차별화 판단책임(A)기여(C)
기술 실현가능성·공수·운영부담 산정기여(C)책임(A)
구체 도구 선정·PoC정보공유(I)책임(A)
결정 마감·문서화(ADR)책임(A)기여(C)

부임 직후 특히 주의: 신임 리더가 빌드/바이를 탑다운으로 던지는 것은, §12에서 스스로 경계한 "현행도 모르면서 설계를 확정하는" 실수와 같습니다.

그래서 아래 후보 비교는 결정문이 아니라 대화의 출발점입니다. 부임 후 팀과 함께 이 프레임을 현행에 대어 교정합니다.

8-1. CMS 코어 — 상용 헤드리스 CMS를 쓸 것인가

후보강점약점미디어 OTT 적합성판단
Contentful성숙한 SaaS, 다국어·로케일 1급 지원, CDN 내장콘텐츠 모델이 "문서/웹" 중심, 미디어 에셋·권리 윈도우·EPG 개념 없음. 엔트리 과금 급증낮음
Strapi (OSS)셀프호스팅, 커스터마이징 자유, 비용 낮음결국 우리가 다 만듦. 대규모 워크플로우·감사 취약
Sanity실시간 협업 편집, 유연 스키마웹 콘텐츠 중심. 대량 인제스트 파이프라인 아님낮음
Adobe Experience Manager엔터프라이즈 DAM·워크플로우고비용, 무겁고 느린 변경 주기
자체 구축권리 윈도우·EPG·카탈로그·인제스트가 도메인 그 자체초기 개발 비용·기간높음

판단: CMS 코어는 빌드(자체 구축)입니다.

이유는 하나입니다 — 미디어 CMS의 난제(§1-3의 N4·N6)는 범용 헤드리스 CMS의 도메인이 아닙니다.

범용 CMS를 쓰면 결국 그 위에 우리 도메인을 얹느라 두 배로 일합니다. 티빙 규모에서는 코어를 소유하는 편이 총비용이 낮습니다.

다만 "직접 만든다"가 "다 만든다"는 뜻은 아닙니다. 아래 주변부는 사는 게 맞습니다.

8-2. 워크플로우 오케스트레이션 — 인제스트 파이프라인의 심장 (난제 N2)

후보성격재시도·보상가시성학습곡선판단
Temporal코드로 쓰는 durable workflow. 상태를 엔진이 보존★★★ (내장, 보상 트랜잭션)★★★ (Web UI에 실행 이력)중~상채택
Apache Airflow배치 DAG 스케줄러★★ (태스크 재시도)★★★△ (배치엔 좋으나 이벤트 기반 인제스트엔 부적합)
AWS Step Functions서버리스 상태머신★★★★★○ (AWS 종속, 복잡 분기에서 JSON 지옥)
자체 큐 + 상태 컬럼익숙함✕ (직접 구현)✕ (BTV·야나두에서 이게 결국 부채가 됨)

Temporal을 고르는 이유: 인제스트는 몇 시간짜리 장기 실행 + 외부 시스템 실패가 일상인 프로세스입니다.

"트랜스코딩이 6시간째인데 MTS가 죽었다. 어디까지 됐고 뭘 되돌려야 하나?" — 이 질문에 답하려면 상태를 엔진이 들고 있어야 합니다.

자체 큐로 시작하면 재시도·타임아웃·보상 로직을 결국 우리가 다시 짓게 됩니다. 야나두와 BTV에서 본 반복되는 부채입니다.

8-3. 원본→조회 저장소 동기화 (난제 N1)

후보지연원본 침습도운영 부담판단
Debezium + Kafka (CDC)초 단위낮음 (WAL 읽기)중 (Kafka 운영)채택
애플리케이션 이중 쓰기즉시높음 (정합성 깨짐 위험)✕ (분산 트랜잭션 문제)
배치 ETL분~시간낮음✕ (노출 지연이 배치 주기에 묶임)
AWS DMS초~분낮음○ (AWS 종속, 변환 유연성 낮음)

BTV에서 Kafka로 Oracle 데이터를 Elasticsearch에 스트리밍 적재했던 구조와 동일한 발상입니다. 도구만 Debezium·OpenSearch로 현대화한 것입니다.

핵심 이점은 속도가 아니라 격리입니다. 조회 저장소가 죽어도 원본은 무사하고, 되살리면 로그부터 다시 따라옵니다.

8-4. AI 메타데이터 자동화 — 공고 우대사항 직격 (난제 N3)

과제후보 솔루션빌드/바이비고
자막 초안 (STT)OpenAI Whisper (자체 호스팅) / AWS Transcribe / Google STT바이 + 자체 후처리한국어 정확도·고유명사(배우·작품명) 사전 보정이 관건
장면·인물 태깅AWS Rekognition Video / Google Video Intelligence / 자체 비전 모델바이인물 DB만 자체 구축(출연진 마스터와 연결)
줄거리 요약·장르 추론Claude / GPT (API)바이프롬프트·검증 파이프라인은 자체. 환각 방지 게이트 필수
기계번역 초벌DeepL / Google Translate / LLM바이TMS와 결합. 상세는 번역관리 TMS 비교
품질 검수(QC)자체 규칙 + LLM 판정하이브리드난이도 최상 → 후반 단계

AI 원칙 — 드래프트는 AI, 승인은 사람.

자동화율을 KPI로 걸면 조직은 반드시 검수를 대충 하게 됩니다. 그래서 자동화율 옆에는 항상 재작업률·결함율이 짝으로 붙습니다(§10).

야나두에서 AI 도입을 확산할 때도 중단 기준을 먼저 정하고 시작했습니다. 채택률이 오르는데 재작업·롤백이 함께 오르면 롤아웃을 멈추는 규칙입니다.

8-5. 빌드/바이 한눈에

도식을 탭하면 확대해서 볼 수 있습니다

판단 기준 한 문장: 경쟁 우위가 되는 도메인 지식은 빌드, 남들도 똑같이 쓰는 인프라는 바이.

권리 윈도우 로직을 잘 만든다고 아무도 칭찬하지 않지만, 그게 틀리면 회사가 소송을 당합니다. 반면 Kafka를 직접 만들면 그냥 시간 낭비입니다.


§9. 실행 로드맵 — Strangler Fig 전환

9-1. Phase 0 — 목표를 확정하기 위해 무엇을 실측하는가

이 문서는 초안입니다. 부임 후 첫 과제는 이 초안을 밀어붙이는 게 아니라, 현행을 실측해 초안을 교정하는 것입니다.

도식을 탭하면 확대해서 볼 수 있습니다

우선순위 매트릭스 — 계산식은 영향도 = 월간 빈도 × 건당 소요시간 × 오류 발생 시 비용 계수.

아래 수치는 전부 예시(가정) 이며, 실측으로 채운다. 점의 위치도 실측 후 이동한다.

작업월 빈도(가정)건당(분, 가정)오류 계수영향도자동화 난이도
메타 등록·보강2,000121.536,000중 (AI 초안)
다국어 메타 작성1,200201.228,800중 (MT+검수)
썸네일 선정2,00051.010,000하 (자동 추출)
EPG-카탈로그 매핑600152.018,000상 (규칙 정의)
QC 검수800253.060,000상 (샘플→전수)
권리 만료 추적300105.015,000하 (규칙+알림)
도식을 탭하면 확대해서 볼 수 있습니다

읽는 법: 좌상단(즉시 착수)은 난이도가 낮고 영향도가 큰 영역입니다. 권리 만료 추적·썸네일 자동 추출이 첫 quick win 후보이고, QC 검수는 영향이 가장 크지만 난이도도 최상이라 후반의 전략 과제로 미룹니다.

9-2. 왜 빅뱅이 아닌가

재구축하는 동안에도 콘텐츠 수급과 편성은 하루도 멈출 수 없습니다.

빅뱅은 이론상 깔끔하지만, 무중단이 전제인 미디어 플랫폼에서는 리스크가 너무 큽니다.

그래서 신규·저위험 도메인부터 새 시스템으로 감싸며 레거시를 서서히 대체합니다. BTV NCMS에서 레거시 190여 개 메뉴를 먼저 분석해 전환 범위·순서를 정의하고 단계적으로 오픈했던 방식 그대로입니다.

도식을 탭하면 확대해서 볼 수 있습니다

9-3. 전환 중 트래픽 경로 (카나리)

도식을 탭하면 확대해서 볼 수 있습니다

양방향 동기화는 전환 기간에만 존재하는 임시 구조입니다. 영구화되면 그 자체가 새 부채가 됩니다.

그래서 각 도메인 이관마다 "양방향 동기화를 언제 끊을 것인가"를 시작 전에 못박습니다.

9-4. 일정 (부임 후 18개월, 전부 가정)

도식을 탭하면 확대해서 볼 수 있습니다

⚠️ 이 일정은 전부 가정입니다. 실제 기간은 Phase 0의 실측 결과와 조직 규모에 따라 재산정합니다.

9-5. 각 Phase의 종료 조건 (Exit Criteria)

Phase이걸 만족해야 다음으로만족 못하면
0 진단baseline 지표 5종 측정 완료 + 버릴 기능 목록 합의기간 연장. 측정 없이 설계 확정 금지
1 파사드Gateway 경유 트래픽 100% + 오류율 baseline 이하전환 착수 금지
2 저위험카나리 100% 2주 무사고 + 양방향 동기화 해제롤백 후 원인 분석
3 코어리드타임 목표 달성 + 가드레일 악화 없음롤백. 다음 도메인 착수 금지
4 소멸기존 시스템 트래픽 0, 30일 유지잔여 의존 추적

§10. 성과지표 체계

10-1. 지표 트리

도식을 탭하면 확대해서 볼 수 있습니다

10-2. 지표 정의표

지표유형정의 (분모/분자)측정 방법
수급→노출 리드타임북극성published_at - acquired_at, p50·p95§4-2 쿼리
단계별 소요시간입력ingest_step 구간별 duration§4-1 쿼리
자동화 처리율입력분모=AI초안 건 / 분자=사람 무수정 승인 건§4-3 쿼리
운영자 1인당 처리량입력월 처리 콘텐츠 수 ÷ 운영자 FTE작업 로그
셀프서비스 비율입력개발 티켓 없이 운영자가 완결한 작업 비율티켓 시스템 조인
재작업률가드레일노출 1시간 후 메타가 수정된 콘텐츠 비율§4-4 쿼리
권리 위반 노출가드레일만료 후에도 노출 중인 콘텐츠 수 (목표: 0)§4-5 쿼리
인제스트 실패율가드레일재시도 소진으로 REJECTED된 비율상태기계

10-3. 중단 기준 (미리 정해두는 것)

확산 전에 멈출 조건을 먼저 정합니다. 이걸 나중에 정하면 아무도 멈추자고 말하지 못합니다.

조건조치
재작업률이 baseline 대비 +5%p 초과AI 초안 자동 승인 범위 축소, 원인 분석
권리 위반 노출 1건이라도 발생즉시 해당 도메인 롤백. 사후 검토 필수
카나리 구간 오류율이 기존 대비 1.5배 초과라우팅 100% 기존으로 즉시 복귀
리드타임은 개선됐는데 인제스트 실패율 상승속도 개선분을 성공으로 인정하지 않음