스키마 v3 적합성 전수조사

조사된 쿼리 31개 × 3개 관점(쿼리 · 코드관리 · 확장성) · 2026-07-29 · 대상: schema-structure-v3.html · 쿼리 출처: available-queries.md(Category A~E) · schema-structure.md(§5 시그널) · v2(Q1~Q10) · 반응관측
19
지원 — 스키마만으로 가능
5
조건부 — 미정 항목에 의존
3
불가 — 입력 소실(진짜 갭)
4
의도된 폐기 — v2가 죽임
출처별 판정 분포 — 31개 Category A · 직통 매핑 3 지원 Category B · KOL 승률 3 의도된 폐기 — winRate·계정 시계열 제거 Category C · 내러티브 1 지원 · 1 조건부(라벨 생성 미정) Category D · 모멘텀 1 지원 · 2 조건부(토큰 시세는 도메인 밖) Category E · 계보·크로스 3 지원 — E-1 대폭 강화 · E-3 신규 §5 시그널 로직 3 · 1 · 1(Trust Divergence) · 1 폐기 v2 Q1~Q10 7 · 1 · 2(Q4 인프라지문 · Q10 이미지해시) 반응 관측 1 구조 지원 지원 조건부 불가(입력 소실) 의도된 폐기(v2 결정)
불가 3건은 전부 "자리는 있는데 그 소셜/필드를 수집 대상에서 뺐다"가 원인 — 스키마 결함이 아니다
한 줄 결론

쿼리 표현력은 적합하다(31개 중 19 지원, 불가 7개 중 4개는 v2가 의도적으로 죽인 것). 그러나 "최적"이라고는 말할 수 없다 — 모델링 건전성 점검에서 결함 3건이 나왔고(§⑤), 성능은 실데이터 없이 판단 불가다.

쿼리 관점 갭 3개는 전부 같은 원인이다 — "입력을 담을 자리는 있는데 그 소셜/필드를 수집 대상에서 뺐다". 모델링 관점 갭 3개는 다른 원인이다 — "어디에 두는지·누가 SoT인지를 안 정했다".

⚠ 범위 한계 — "전수조사"가 실제로는 부분조사였다

이 조사는 쿼리 31개(Category A~E · §5 시그널 · v2 Q1~Q10 · 반응관측)만 대조했고, structural-idea-matching.html구조 축 88개는 보지 않았다. 합치면 119축이다.

88축을 별도로 훑은 결과(v3 §④·§⑥·§⑭ 반영):

주의 — structural-idea-matching 은 규칙상 "데이터 유무만 표시, 유효성 평가 안 함" 이라 "데이터가 있어도 구조상 무의미" 는 걸러내지 못한다. 그리고 그 축들은 채택 목록이 아니라 검증 대기열이다(research-findings).

이 조사의 범위 변경 이력

초판(§①~④)은 쿼리 커버리지만 봤다 — "조사된 쿼리가 이 스키마로 돌아가나". 엔티티 경계·문서 크기·SoT 중복·참조 갱신 규칙·컬렉션 분할 실익 같은 모델링 관점은 빠져 있었다. §⑤가 그 점검이며, 그 결과 §⑥의 대안 판정 2건도 수정됐다.

① 쿼리 전수 대조 31개

Category A · 엔티티 직통 매핑

쿼리판정근거 · v3에서 달라진 점
A-1 토큰 → 연관 콘텐츠지원 content_token_links{tokenAddress}contents. v2가 배열을 엣지로 바꿔 1홉 늘었지만 as-of 절단이 가능해진 대가
A-2 콘텐츠 → 파생 토큰지원 같은 엣지 역방향. idx(contentKey, linkedAt)
A-3 계정 → 포트폴리오지원 정확도↑ v3가 creatorId숫자 id로 확정 → 핸들 리네임 시 누락되던 것이 사라짐. TikTok·GitHub은 재할당까지 있어 기존 handle 기준이면 다른 계정이 섞였을 케이스

Category B · 알파 시그널 & KOL 발굴

쿼리판정근거
B-1 승률≥0.7 S급 계정의 실시간 샤우팅의도된 폐기 v2가 quantMetrics.winRate·tier 제거 — "정의상 미래 성과"라 마스터에 두면 look-ahead
B-2 하이프 주도자가 진짜 알파콜러인가의도된 폐기 동일 사유. 승률 없이 "이 계정이 이전에 몇 개 토큰에 붙었나"(Q3)로 대체 가능하나 같은 질문은 아님
B-3 팔로워 급증 Z-Score 선행 탐지의도된 폐기 v2가 account_metrics_ts 제거 — "관측대상 = 조작대상"(팔로워는 매수 가능)
v3 문서의 누락 — 폐기 사실이 기록돼 있지 않다

v1 available-queries.md는 Category B를 "퀀트 관점에서 가장 가치가 높은" 경로로 명시했다. 그런데 v2가 그 입력(winRate·계정 시계열)을 제거하면서 3개 경로가 통째로 죽었고, v3는 이를 언급하지 않는다. 나중에 이 문서를 읽는 사람이 "왜 B가 안 되지"에서 막힌다. → v3 §⑩에 "폐기된 쿼리" 항목 추가 필요.

Category C · 내러티브 & 메타 테마

쿼리판정근거
C-1 라벨 클러스터 토큰 바스켓조건부 entities[] 자리는 v2가 만들었으나 라벨 생성 방법이 미정(v2가 스스로 명시). v3도 해결 안 함
C-2 플랫폼별 영향력 비교지원 platform 필드 + tokens 시총으로 그룹 비교. 비교 대상이 토큰 시총이라 소셜 지표 통일이 애초에 불필요 — v3의 metrics 통일 철회가 이 쿼리를 깨지 않음을 확인

Category D · 시계열 모멘텀 & 시세 교차

쿼리판정근거
D-1 바이럴 속도 상위 1% 발굴지원 v3가 ContentMetricSnapshot을 되살려 Δ 계산 가능. 단 관측 주기가 미정(§⑩) — "15분 Δ"를 재려면 그보다 촘촘해야 함
D-2 시세 스파이크 원인 역추적조건부 토큰 가격 시계열이 이 스키마 밖(기존 TokenPriceTracker 도메인). 크로스 도메인 조인이 전제인데 v3가 그 의존을 명시하지 않음
D-3 소셜-시총 다이버전스조건부 D-2의 의존 + metricRanks 코호트 정의 미정. 소셜 지표는 raw로 두고 백분위로 비교하는 v3 결론과는 정합

Category E · 다중 홉 계보 & 크로스 플랫폼

쿼리판정근거
E-1 인용 계보 · 밈 파생 트리지원 대폭 강화 v2는 "fetcher가 인용 원본 id를 안 담는 게 병목"이라 했으나, audit 실측에서 X quoted_tweet이 최상위와 키 집합 100% 동일하고 author까지 완전 프로필 → 추가 fetch 0회로 2단계 전개. v3에서 가장 많이 좋아진 경로
E-2 지갑 ↔ 크로스플랫폼 엔티티지원 accounts.knownWallets[] 유지 + AF는 쿼리 시점 조인. 단 deployer 미수집은 v1이 지적한 그대로 남음
E-3 코-멘션 네트워크지원 신규 v3가 mentions[]를 L1 공통축으로 승격 → IG·TikTok·X 3개 소셜에서 동작. 이전엔 X 하나뿐이었고 그마저 미저장

§5 시그널 로직 schema-structure.md

시그널판정근거
5.1-a Δt_meme (원본→첫 트윗 시차)조건부 rootContentId가 필요한데 v2의 "순번 미저장" 원칙상 root도 질의 시점 파생이 자연스럽다. 파생 규칙이 미정
5.1-b Δt_token → isPreMinedHype지원 tokens.createdAt − contents.core.publishedAt. 양쪽 다 immutable이라 look-ahead safe
5.2 Sybil/Rug 위험도지원 신생계정 = accounts.createdAt(v3가 채움률 표로 정리 — IG만 구조적 부재) + 동시인용 급증 = Q2 경쟁밀도
5.3 narrativeDepth지원 genealogy.parentContentId 재귀. E-1과 같은 근거로 강화됨
5.4 Trust Divergence불가 두 겹으로 막힘 — ①v1이 이미 "산출식 정의 부재"로 판정 불가 ②도메인 신뢰도 입력(urlscanScore·certValidFrom)이 website 계열에 있는데 v3가 그 소셜을 다루지 않음(§②-1)
5.5 I_total (승률가중 바이럴 강도)의도된 폐기 winRate 의존 → Category B와 함께 죽음

v2 Q1~Q10

쿼리판정근거
Q1 as-of 순번(몇 번째 토큰인가)지원idx(contentKey, linkedAt)
Q2 동시 경쟁 밀도지원동일 인덱스 · 윈도우 상한이 T라 look-ahead 없음
Q3 계정의 시리얼 발행 횟수지원 정확도↑idx(creatorId, publishedAt). A-3과 같은 이유로 숫자 id 확정이 정확도를 올림
Q4 같은 인프라로 뿌린 토큰 수(공장 규모)불가 🔴 fingerprint.trackingIds유일한 공급원이 website fetcher인데 v3에 website가 없음(§②-1)
Q5 인용 계보 깊이지원E-1·5.3과 동일
Q6 링크 살아있나/삭제됐나/없었나지원 fetchStatus 6종 + v3의 moderation 축(removedBy·archived·unavailable)이 "삭제 주체"까지 구분
Q7 코호트 AF 자금 집중도지원links가 코호트를 만들고 AF는 쿼리 시점 조인
Q8 소셜 상위인데 AF 하위(괴리)지원발행 시각 윈도우 코호트 + 두 백분위 차
Q9 소재(엔티티) 포화도조건부C-1과 동일 — entities[] 자리만 있고 라벨 생성 미정
Q10 토큰 이미지 ↔ 프로필 이미지 동일성불가 🔴 audit이 미디어 URL을 대부분 skipcontents.imageHash 계산 입력이 없음(§②-2)

반응 관측

쿼리판정근거
t_c ~ t_0 반응 궤적
토큰 발행 전 구간의 깨끗한 참여 궤적
구조 지원 ContentMetricSnapshotcontent_key 기준이라 토큰과 무관하게 관측 가능하고, content_token_links.linkedAt으로 t_0 이후 오염 구간을 잘라낼 수 있다. 다만 "fetch → 모니터링" 수집 방식 전환이 전제인데 그건 스키마 문제가 아니다

② 발견된 갭 진짜 문제 5건

②-1 🔴 website(도메인) 축이 스키마에 반영되지 않았다 — 최대 갭

[정정] 초판은 이를 "audit이 빠뜨렸다"로 적었으나 틀렸다. REFINEMENT-WORKFLOW.md의 객체 모델 표는 website를 "(별개) 프로젝트 자체 홈, 소셜 객체 아님"으로 의도적으로 3객체 밖에 분류해 뒀다. 즉 소셜 audit 대상이 아닌 게 맞다. 진짜 문제는 그 "별개 축"을 스키마 v3가 반영하지 않은 것이다.

코드의 SocialSourceType에는 'website'실재하고, website.fetcher.ts는 이미 17개 필드를 수집한다:

// urlscan
certValidFrom · certIssuer · urlscanScore · brands · scanTime
ip · asn · asnName · server · country · city
technologies · bodyHashes · globalNames · trackingIds · urlscanLinkDomains
// RDAP — 도메인 등록일 3필드

객체 모델이 "별개"로 분류했으므로 Creator/Content/Venue 어디에도 안 들어가는 게 맞다. 그런데 v3는 그 별개 축을 위한 자리를 만들지 않았다 — platform 코드(ig·yt·tt·x·rd·gh·tg)에도 없고 컬렉션도 없다. 샘플 디렉터리에 website.json이 없어 관측량조차 모른다.

파급: v2가 신설한 fingerprint.trackingIds(Q4 공장 규모)와 §5.4 Trust Divergence의 유일한 공급원이 이 fetcher다. v2는 contents.fingerprint로 자리를 만들었는데, v3가 contents를 3객체 기준으로 재정의하면서 website가 그 안에 안 들어간다는 사실을 반영하지 않았다.

→ 조치는 소셜 audit이 아니라 §⑥(d) Infra 객체 신설이다. 객체 모델이 이미 "별개"라고 말했으므로 4번째 객체를 인정하는 게 그 분류와 정합한다. 다만 필드 목록 확정에는 website fetcher 산출 조사가 선행돼야 한다.

참고: information-inventory가 이미 "F only 17건 — 수집하는데 담을 자리가 없다"로 이 필드들을 지목했고, v2가 fingerprint 필드로 자리를 만들었다. 이제 반대 상황이다 — 자리는 있는데 소셜 정의가 없다.

②-2 🔴 audit의 미디어 skip이 v2 Q10을 죽였다

v2 Q10은 tokens.imageHash ≈ contents.imageHash사전 공모 정황을 잡는 쿼리다(pump.fun 이미지 불변 + authority 소각 92% 실측이 전제).

그런데 audit은 미디어 URL을 대부분 skip했다 — perceptual hash 인프라가 없다는 일관된 사유였다:

소셜미디어 필드audit 결정
instagramdisplayUrl·videoUrlskip
xextendedEntities.mediaskip
githubavatar·originalAvatarUrlskip
tiktokslideshowImageLinks[]keep — 유일

판단: 두 결정 모두 각자 맥락에선 옳다. 충돌은 "인프라가 없으니 안 담는다"와 "이 쿼리를 하려면 담아야 한다"가 서로를 모르는 상태에서 생겼다. → 해상도: URL만 담고 해시는 나중에(저장비용 작음) 또는 Q10을 명시적으로 보류. 지금처럼 조용히 불가인 게 최악이다.

②-3 🔴 v3 설계 버그 — platform 키가 한 문서에 두 번

v3 §⑤ 구조 예시가 같은 문서에 platform두 가지 의미로 쓴다:

contents {
  platform: "x",                              // ① 소셜 구분 문자열platform: { x: { conversationId, … } },     // ② L2 네임스페이스 객체
}

같은 키를 덮어쓴다. 순수한 작성 실수이며 반드시 이름을 갈라야 한다 — 예: platform(구분) + ext 또는 platformData(네임스페이스).

②-4 🟡 METRIC_SPEC은 있는데 L1 매핑 레지스트리가 없다

v3는 지표에 대해서만 "소셜 차이를 아는 파일은 하나"를 정했다(METRIC_SPEC). 그런데 L1 공통축(text.primary·links·form·genealogy…) 매핑도 똑같이 소셜별 지식이다. v3는 그걸 표로만 정의하고 어디에 구현할지 정하지 않았다.

→ 그대로 두면 fetcher마다 매핑 코드가 흩어지고, 지표는 레지스트리로 모으면서 나머지는 흩뜨리는 비일관 상태가 된다. ContentGenerator(소셜별 · URL 1건당 1개)를 같은 위치에 두는 게 맞다.

이 조사에서는 처음에 CORE_MAP 이라 불렀으나, 실제로 1 URL → N 객체 생성이라 v3 §⑬ 에서 ContentGenerator 로 확정했다.

②-5 🟡 폐기된 쿼리가 문서에 없다

Category B 3개 + §5.5 = 4개 경로가 v2 결정으로 죽었다(winRate·account_metrics_ts 제거). 타당한 폐기지만 어디에도 기록돼 있지 않다 — v1 문서는 여전히 B를 "가장 가치 높은 카테고리"라고 말한다.

→ v3 §⑩에 "폐기된 쿼리와 사유" 표를 추가해야 한다. 안 그러면 나중에 같은 쿼리를 다시 설계하려다 입력이 없어 막힌다.

③ 코드 관리 측면

항목평가내용
레지스트리 패턴적합 기존 SocialFetcherRouter.classify() + fetcher별 handles[]같은 모양. 소셜 지식을 한 곳에 가두고 나머지는 타입으로만 다룸. 단 ②-4의 L1 매핑 레지스트리 누락
BaseModel 일관성적합 time-series를 포기한 결정 덕에 모든 컬렉션이 buildSchema+timestamps+트랜잭션 규칙을 동일하게 따름 — 예외 컬렉션이 없음
polymorphic Mixed주의 스키마 검증이 사라지는 구간. 레지스트리가 곧 검증기 역할을 해야 하므로 METRIC_SPEC에 없는 키가 들어오면 경고하는 장치가 필요
sourceType enum 규모주의 v1 5종 → v2 14종 → audit 후 20종+. 코드 SocialSourceType은 현재 14종이라 이미 어긋나 있음. enum 확장이 코드 반영 단계의 첫 작업
platform vs sourceType 중복정당 platformsourceType에서 파생 가능하지만, 코호트 인덱스({platform, observed_at})를 위한 의도적 비정규화. 단 ②-3의 키 충돌은 별개 문제
3층(core/L2/data) 유지비낮음 audit 결과 L2가 얇게 나왔다(소셜당 1~4필드). 대부분 L1에 흡수돼 소셜별 분기 코드가 적음

④ 확장성 측면

새 소셜 추가 비용

단계변경비용
컬렉션없음 — contents/accounts/venues/스냅샷 그대로0
enumsourceType에 타입 추가
매핑ContentGenerator + METRIC_SPEC에 항목 1개씩
L2ext.<코드> 네임스페이스 추가 — 다른 소셜과 충돌 없음0
인덱스필요 시 partial index

새 객체 종류 추가

Venue를 추가하며 이미 한 번 검증됐다 — 컬렉션 1개 신설 + contents.venueKey 참조로 끝났고 기존 구조를 안 건드렸다. Telegram처럼 Venue만 있는 소셜도 같은 틀에 들어간다(Creator·Content가 비는 것이 자연스러움).

확장성의 실제 약점 — 소셜이 아닌 축

구조가 잘 버티는 건 "또 다른 소셜"이다. 반대로 website처럼 성격이 다른 소스(계정도 콘텐츠도 아니고 도메인 인프라)는 지금 3객체 모델(Creator/Content/Venue)에 깔끔히 안 들어간다 — ②-1이 발생한 구조적 이유이기도 하다.

website는 Venue에 가깝지만(장소성) 멤버·개설자가 없고, Creator에 가깝지만(주체성) 게시물이 없다. → 4번째 객체 Infra(도메인)를 인정하거나, Venue를 "주체가 아닌 귀속점"으로 넓게 재정의해야 한다.

⑤ 모델링 점검 쿼리와 별개 — 구조 자체의 건전성

초판에서 본 것초판에서 빠졌던 것
쿼리 31개의 표현 가능성문서 크기 성장 — raw가 붙어 다니는 비용
인덱스 존재 여부쓰기 패턴 — 같은 콘텐츠 재fetch 시 무엇이 덮이나
컬렉션 간 홉 수SoT 중복 — 같은 사실이 두 곳에 있는가
참조 갱신 규칙 — 마스터를 언제 갱신하나
컬렉션 분할의 실익 — 규모 대비

실질 개선 후보 3건

⑤-1 🔴 contents.data(무손실 raw)가 문서에 붙어 있다

X 트윗은 author 33키 + quoted_tweet 전체가 들어가 문서 하나가 수십 KB가 된다. MongoDB는 문서 단위 I/O라 목록 조회에서 안 쓰는 raw까지 읽힌다 (projection으로 필드는 뺄 수 있어도 캐시·스토리지 효율은 그대로 손해).

content_raw 별도 컬렉션으로 분리. contents는 가벼워지고 raw는 재해석이 필요할 때만 읽는다.

원인: v3 §③이 L3를 "인덱스 없음"이라고만 적고 어디에 사는지는 정하지 않았다. raw 보존의 가치(audit 내내 반복된 교훈 — 절단된 덤프 때문에 alt·isSlideshow·author.id를 놓쳤다)는 그대로 유지된다.

⑤-2 🔴 fetchStatuslinks.status가 같은 사실을 두 곳에 둔다

v2 Q6("링크가 살아있나/삭제됐나/애초에 없었나")은 links{observedAt ≤ T} → status로 답한다. 그런데 v3는 contents.fetchStatus도 뒀다 — 어느 쪽이 SoT인지 정하지 않았다.

더 큰 문제: contents.observedAt단수다. 재fetch 시 덮어쓰면 ok → deleted 전이를 못 본다. "지금 상태"만 남고 "언제 죽었나"가 사라진다 — v2의 관측 로그(소급 불가) 원칙과 충돌한다.

→ 상태 이력은 links(또는 스냅샷)에만 두고, contents.fetchStatus최신값 캐시임을 명시한다.

⑤-3 🔴 sourceType → 객체종류 → 컬렉션 매핑이 없다

audit은 소셜을 Creator / Content / Venue 3객체로 정리했고, 라우터는 URL에서 sourceType을 낸다. 그런데 둘의 연결 고리가 v3에 통째로 빠져 있다.

x_profile    → Creator → accounts
x_tweet      → Content → contents
x_community  → Venue   → venues
github_owner → Creator → accounts
github_repo  → Content → contents
tiktok_shortlink → ?        // 해석 전엔 객체 종류를 모른다

sourceType마다 objectType을 선언하고, 그것이 저장 컬렉션을 결정하도록 규칙을 명시해야 한다. shortlink처럼 해석 전엔 종류를 모르는 타입의 처리(보류 큐 or 해석 후 배정)도 같이 정한다.

재검토 후보 2건

⑤-4 🟡 core. 래핑의 실익이 약하다

초판은 이 문제를 대안 (c)에서 "취향 문제"로 넘겼는데 얕은 판단이었다.

기대했던 이득실제
L2와 이름 충돌 방지L2는 이미 ext.<코드>로 격리돼 있어 효과 없음
의미 그룹이 드러남문서 가독성 — 유일한 실익
비용모든 인덱스·쿼리에 core. prefix + typegoose 중첩 클래스 정의

평면 + L2 네임스페이스가 더 단순하다. 되돌리기 쉬운 결정이므로 코드 반영 전에 확정한다.

⑤-5 🟡 venues 별도 컬렉션의 실익

규모: X community 137 · reddit subreddit 161건. accounts와 필드가 거의 같고 (createdAt·description·metrics·creatorId), 개설자가 accounts를 가리켜 크로스 컬렉션 참조가 생긴다.

초판에서 분리를 정당화한 근거는 "독자 상태를 갖고 여러 콘텐츠가 공유한다"였는데, 그건 accounts도 마찬가지라 분리 사유가 되지 못한다.

accountskind: user | org | venue로 통합하면 참조가 같은 컬렉션 안에서 닫힌다.

단 관계는 분명히 다르다 — Creator는 authored-by, Venue는 posted-in. 관계가 다르니 필드·인덱스는 분리하되, 컬렉션까지 나눌 필요가 있나는 별개 질문이고 이 규모에선 아닐 수 있다.

기록만 2건

#항목내용
⑤-6accounts 마스터 갱신 규칙 부재 contents.author{} 스냅샷이 콘텐츠마다 쌓인다(같은 계정이 1000개 콘텐츠에 나오면 1000번). as-of 정확성 때문에 중복 저장은 의도된 것이지만, 언제 accounts 마스터를 갱신하는지 규칙이 없다. → "더 최신 observedAt이면 갱신" 같은 규칙 필요
⑤-73홉이 v1 원칙과 어긋남 v1은 "1~2홉 이내에서 $lookup 배제"를 원칙으로 세웠는데, A-3(계정→포트폴리오)은 accounts → contents → links → tokens3홉이다. as-of 요구(배열→엣지 전환) 때문에 불가피하나 원칙과 실제가 어긋난 상태가 기록돼 있지 않다
"최적인가"에 대한 답
관점상태
쿼리 표현력확인됨 31개 중 19 지원, 불가 7개 중 4개는 의도된 폐기
모델링 건전성결함 3건 raw 분리 · SoT 중복 · sourceType 매핑
성능판단 불가 실데이터 카디널리티·문서 크기 분포·인덱스 선택도 미측정

"최적"을 주장하려면 최소한 실데이터로 문서 크기 분포와 주요 쿼리 explain을 봐야 하는데, 그건 코드 반영 이후에나 가능하다.

⑥ 더 나은 구조가 있나 대안 4개 검토

대안장점기각/채택 사유
(a) 3객체를 social_entities 하나로 통합
entityType: creator|content|venue
"이 토큰에 붙은 모든 소셜 엔티티"가 1회 조회. 소셜마다 있는 객체가 달라도(TG=venue only) 균일 전면 통합은 기각 — 라이프사이클이 다르다. creator는 재사용(여러 콘텐츠가 공유)이고 content는 1회성이다. 무엇보다 Q3·A-3 같은 계정 단위 질문이 accounts를 독립 주체로 요구한다.
단 부분 통합은 검토accounts + venueskind로 합치는 안은 유효하다(§⑤-5). 규모가 작고(venue 300건 수준) 필드가 유사하며 개설자 참조가 같은 컬렉션 안에서 닫힌다
(b) 엣지를 배열로 되돌리기
tokens.contentRefs[]
홉 1개 감소 기각 — v2가 이미 기각한 이유가 유효: 배열 원소에 시각이 없어 as-of 절단(Q1·Q2)이 불가능. 그게 이 도메인의 핵심 요구
(c) core를 flatten
text_primary 등 평면 키
모든 인덱스·쿼리의 core. prefix 제거 + typegoose 중첩 클래스 불필요 판정 수정 · 채택 검토 — 초판은 "취향 문제"로 넘겼으나 §⑤-4에서 재검토한 결과 기대했던 이득(L2와 이름 충돌 방지)이 실제로는 없다(L2가 이미 ext.<코드>로 격리됨). 남는 실익은 문서 가독성뿐이고 비용은 계속 든다 → 평면 + L2 네임스페이스가 더 단순
(d) 4번째 객체 Infra 신설
domain/website 계열
②-1을 구조적으로 해소. fingerprint·RDAP·cert가 자기 자리를 가짐 검토 권장 — 유일하게 지금 구조를 실제로 개선하는 대안. 다만 website audit이 선행돼야 필드 목록이 나온다

⑦ 조치 목록 티어별 — 앞 티어가 뒤 티어의 전제

Tier 1 · 코드 반영 전 필수 2026-07-30 전건 확정

확정 내용 — v3 문서에 반영됨
#결정v3 위치
1content_raw 별도 컬렉션 — _id(=contentKey)만 두고 보조 인덱스 없음(id 로만 조회)§③ L3
2상태 이력의 SoT 는 links. contents.fetchStatus최신값 캐시로 명시§⑧
3SOURCE_TYPE_OBJECT(상수 맵, objectType 분류) + ContentGenerator(_id 추출·fan-out) — C 안§⑩
4platform(구분 문자열) + ext(L2 네임스페이스)로 키 분리§③·§⑤·§⑦

3번에서 기각한 대안 — 상수 맵 하나로 전부: fan-out 구조를 표현 못 함. 각 fetcher 가 선언: fetcher 가 "가져오기 + 변환" 두 일을 하고, 지표만 레지스트리로 모으는 비일관.

#조치이유출처
1content_raw 분리 무손실 raw가 contents에 붙어 있어 목록 조회마다 수십 KB를 같이 읽는다. 나중에 옮기면 전량 마이그레이션이 필요§⑤-1
2상태 SoT 확정
fetchStatus vs links.status
같은 사실이 두 곳에 있고 observedAt이 단수라 ok → deleted 전이가 소실된다 — v2 관측로그 원칙 위반§⑤-2
3sourceType → objectType → 컬렉션 매핑 정의 라우터 산출과 3객체 모델의 연결 고리가 통째로 없다. shortlink처럼 해석 전엔 종류를 모르는 타입 처리도 포함§⑤-3
4platform 키 충돌 수정 한 문서에 같은 키가 두 의미로 존재 — 그대로 옮기면 즉시 데이터 손실§②-3

Tier 2 · 구조 선택 결정만 하면 되는 것

#조치이유출처
5core. 유지 vs 평면화기대했던 이득이 없음이 확인됨. 되돌리기 쉬우나 코드 반영 후엔 비싸진다§⑤-4
6venues 별도 vs accounts 통합규모 300건 · 필드 유사 · 크로스 컬렉션 참조 발생§⑤-5
7ContentGenerator 명시지표만 레지스트리로 모으고 L1 매핑은 표로만 둔 비일관§②-4
8accounts 갱신 규칙author 스냅샷은 쌓이는데 마스터를 언제 갱신하는지 미정§⑤-6

Tier 3 · 문서 정합 구조 변경 없음

#조치이유출처
9"폐기된 쿼리" 표 추가Category B 3개 + §5.5가 조용히 죽어 있음. v1은 여전히 B를 "가장 가치 높은"이라 말함§②-5
10Q10 처리 결정
URL만 담기 vs 명시 보류
지금은 "조용히 불가"라 최악§②-2
113홉 현황 기록v1 "1~2홉" 원칙과 실제가 어긋난 상태가 미기록§⑤-7
보류 — 인덱스 설계 지금 결정 불필요

인덱스는 구조를 바꾸지 않는 순수 추가라 코드 반영 시점에 정해도 된다. 다만 조사 중 나온 항목이라 잊지 않도록 기록만 남긴다.

항목내용
content_token_links의 tokenAddress 진입 v2가 명시한 건 (contentKey, linkedAt) 하나인데 반대 방향 진입이 여럿이다 — A-1(토큰→콘텐츠) · Q6(links{tokenAddress=Y, observedAt ≤ T}) · Q7(코호트 구성). links는 핫 경로(Q1·Q2·A-1·A-2·Q6·Q7·Q8이 전부 여기를 침)라 (tokenAddress, linkedAt)가 없으면 collscan
contents 인덱스 조합 미정 접근 패턴이 최소 4가지 — creatorId+publishedAt(Q3) · platform+publishedAt(코호트) · sourceType · genealogy.parentContentId(계보 재귀)
A-3의 $in 폭발 계정이 콘텐츠 1000개를 쓰면 links 조회가 1000키 $in. 3홉 구조상 불가피하므로 페이징·청킹 규칙을 정해야 함
문제 아님(확인) 스냅샷의 {platform, observed_at}은 등가+범위라 ESR 규칙상 올바른 순서다. 단 플랫폼 무관 시간 범위 스캔이 필요하면 {observed_at}이 별도로 필요

Tier 4 · 선행 조사 필요 지금 결정 불가

#조치이유출처
12website 소셜 audit → Infra 객체 검토 Q4·§5.4의 유일한 공급원. 쿼리 관점 최대 갭이지만 audit 1회가 선행돼야 필드 목록이 나옴§②-1 · §⑥(d)
13telegram auditVenue 전용 소셜의 요구사항이 아직 미반영v3 §⑩
14미정 3건 확정
관측 주기 · 백분위 코호트 · entities 라벨 생성
조건부 5개(C-1·D-1·D-3·5.1-a·Q9)가 전부 여기 걸림. 실험이 필요하지 결정으로 풀 수 없음v3 §⑩
15실데이터 성능 측정"최적" 주장의 전제 — 문서 크기 분포 + 주요 쿼리 explain. 코드 반영 이후에만 가능§⑤ 결론

정직한 한계