유민우 · Tech Notes


링크 치환 및 카운트 추적 로직 개선

🗓️ 11/10/2025 👤 Role: System Architect
FastAPIPostgreSQL

Problem & Condition

캠페인 KPI에 링크 클릭 수를 반영하려면, 캡션 내 URL을 우리 public redirect로 바꾸고 방문 수를 DB에 기록해야 했다.

컴파일 파이프라인은 persona 정책 주입 → 플랫폼 규칙 적용 → 결과 저장 순인데, 링크 치환은 컴파일 결과(텍스트)도 바꾸고 DB에도 row를 남겨야 했다.

기존 persona injector/compile 엔진은 상태 없는 텍스트 변환만 담당했기에, 어디서 DB 세션을 활용해야 할지 결정이 필요했다.

Candidates

1. 사후 처리

Injector/compile 끝난 뒤 compile_variant 반환 결과에서 URL을 다시 돌면서 DB에 tracking 링크 만들고 텍스트 교체.

장점:

  • 기존 파이프라인 건드리지 않음

단점:

  • 엔진이 만든 요약/메트릭과 최종 텍스트가 어긋남
  • replay 시에도 다시 치환해야 해서 일관성 깨짐

2. PersonaInjector 내부에서 처리 시도

persona directives를 주입할 때 URL을 교체하면서 DB row 생성.

장점:

  • persona 정책과 붙어 있어서 자연스러워 보임

단점:

  • Injector는 DB 세션을 모르고 단순 데이터 변환만 수행함
  • 토큰 충돌 검사/저장/에러 처리를 할 수 없어서 구조적으로 불가능

3. TrackingLinkAllocator 계층

링크 발급/저장을 담당하는 allocator 인터페이스를 두고, 컴파일 엔진은 allocator만 호출. DB 세션은 worker가 allocator 구현에 주입.

장점:

  • 엔진은 여전히 순수한 텍스트 처리, DB 지식은 allocator에 국한
  • replay 시에도 동일한 allocator를 주입하면 동일한 링크를 재사용

단점:

  • compile_variant 시그니처, InjectorContext, engine 계층에 allocator 전달 로직을 추가해야 함

Decision

3번 TrackingLinkAllocator 방식을 선택.

엔진에 새 의존성만 주입하면 persona 정책 흐름을 깨지 않으면서 DB 연동 요구를 해결할 수 있음. Allocatorallocate(original_url)만 받으므로 테스트/추후 mock도 쉽고, DB 세션 관리가 worker 쪽에 그대로 남는다.

Effects

  • 링크 치환이 _apply_link_policy 단계에서 실행되며, compile 결과 요약/metrics와 항상 일치
  • TrackingLinkAllocator가 기존 링크를 재사용하도록 로직을 갖추면서 중복 레코드/토큰 발급 문제 감소
  • 캠페인 KPI에서 LINK_CLICKStracking_links.visit_count 기반으로 집계할 수 있게 되어 CTR 산출 준비 완료