website 파이프라인 — 이벤트에서 저장까지

토큰 이벤트가 들어와 contents 에 저장될 때까지 무엇을 거치는지 한 장에 그린다. 단계마다 어디까지 정해졌는지를 색으로 구분한다.

렌더 2026-08-11 · 분류는 website-kinds.html, 추출 규격은 website-content-mapping.html, 결정 기록은 qna/website.md

1파이프라인 한 장

본선은 위에서 아래로 흐르고, 오른쪽으로 빠지는 것은 거기서 끝나는 갈래다. 테두리가 실선이면 정해지고 구현까지 된 것, 파선이면 정했는데 아직 코드가 없는 것, 흐린 채움이면 제안 단계다.

website URL 하나가 거치는 전 과정

⑥번 HTML GET 부터가 추출 규격 문서가 다루는 범위다. 그 위의 다섯 단계는 어느 문서에도 그려진 적이 없었다.

확정 · 구현됨확정 · 미구현제안
① token.flow 이벤트SolTrackerApiSdk 로 URL 4종을 받는다website · twitter · telegram · discord구현됨② SocialFetcherRouter담당 소셜을 못 찾은 URL 이 web 으로 떨어진다website 6,264건 · 전체의 24.1%구현됨③ PSL 교정apex 계산을 Public Suffix List 로 바꾼다grok.me 46종이 한 키로 합쳐져 있다 · 19.1%제안④ 단축링크 해제 (G-18)tokenInfo 경계에서 한 번 푼다t.co 실측 4/4 가 301 로 풀렸다미구현⑤ 종류 판정 — 목록 + 토큰명 대조툴 13 · 소셜 26 · 디렉터리 7 · 참조 94토큰명이 도메인에 있나 (정밀도 88.9%)제안⑥ HTML GET 1회최대 3MB · 이미 받고 있다실측 180 도메인 중 124 응답 · 69%구현됨⑦ 표준 8종 파싱 → 패턴 캐스케이드R1 로그인벽 → R2 SPA → R3 미기입 → R4 공통문구→ R5 제목·요약 → R6 제목만확정⑧ 필드별 체인 + RSS 보정칸마다 순서가 다르다 · text 누적 82.3%빈 칸이 있을 때만 피드 1회확정⑨ RDAP · urlscan — 도메인 지문web_site 에만 부른다 · 셋 다 무료731일+ · hasTracking · techCount 가 여기서구현됨툴 · 소셜은 여기서 끝도메인이 남의 것이라 호출해도 얻는 게 없다16.7% · 사유만 기록한다P4~P7 은 Content 를 안 만든다site_wide · gated · unseen · placeholderplaceholder 만 그 자체가 신호다⑩ ContentInputplatformKey 정규화 URLtext · publishedAt · mediaUrls 페이지 정보data{} 도메인 지문 17필드 domain · domainCreatedAt · registrar techCount · hasTracking · …오늘 확정tokens.web{} 폐기지문이 Content.data 로 가면서자리가 없어졌다fingerprints 는 image: 만 남긴다오늘 확정⑪ SocialGraphWritercontents + token_links

세 곳에서 갈라진다. ⑤에서 툴과 소셜이 호출 없이 빠지고(16.7%), ⑦에서 P4~P7 이 Content 없이 사유만 남기고, ⑨에서 도메인 지문은 web_site 에만 붙는다.

끝까지 가서 Content 가 되는 것은 P1~P3링크 1,219건 · 배정 대상의 55.0% 다.

2단계별 결정과 상태

각 단계가 무엇을 정했고, 근거가 어디 있고, 구현이 어디까지 됐는지다.

단계 15개

§1 그림이 열한 칸인데 이 표가 열다섯 줄인 것은, 그림에서 한 칸에 묶은 것을 여기서는 결정 단위로 폈기 때문이다.

#단계무엇을 정했나상태근거숫자
1이벤트 수신 · URL 4종token.flow 를 받아 SolTrackerApiSdkwebsite·twitter·telegram·discord 를 얻는다. 이벤트 payload 에 이 네 필드가 없어 외부 호출이 불가피하다.확정 · 구현됨social-record.processor.ts호출 1회/토큰
2라우팅 · web catch-all호스트 조회표에서 담당 소셜을 못 찾은 URL 이 SocialPlatform.WEB 으로 떨어진다. WebsiteFetcher.hosts 가 비어 있는 이유다 — 웹은 호스트를 소유하지 않는다.확정 · 구현됨social-fetcher.router.ts:47website 6,264건 · 전체의 24.1%
3PSL 교정apex 도메인 계산을 하드코딩 6개에서 Public Suffix List 로 바꾼다. grok.me 46종 · vercel.app 26종처럼 주인이 다른 서브도메인이 한 키로 합쳐진다.제안이번 조사토큰링크의 19.1% 가 잘못 묶임
4단축링크 해제tokenInfo 경계에서 한 번 풀고 아래로는 canonical 만 흘린다. maxRedirects:0 으로 홉을 직접 돌며 사설 대역을 차단한다.확정 · 미구현G-18 (decisions.md)t.co 실측 4/4 가 301 로 풀림
5종류 판정 1단 — 목록툴 13 · 소셜 26 · 디렉터리 7 · 참조 상위 94 를 목록으로 건다. 툴과 소셜은 여기서 끝난다 — 도메인이 남의 것이라 지문도 페이지도 그 토큰을 말하지 않는다.제안website-kinds.html §1목록 140개로 16.7% 를 호출 전에 처리
6종류 판정 2단 — 토큰명 대조토큰 이름이 도메인 문자열에 있으면 자기 사이트로 본다. 외부 호출이 0회다.제안이번 조사정밀도 88.9% · 토큰사이트 46.9% 적중
7HTML 받기페이지를 평범한 GET 으로 받는다(최대 3MB). 이미 하고 있고, 지금은 OG 세 개만 뽑고 본문을 버린다.확정 · 구현됨website.fetcher.ts:175실측 180 도메인 중 124 응답 · 69%
8표준 8종 파싱og · jsonld · article · twitter · meta · canonical · rss · oembed전부 먼저 읽는다. 중간에 끊으면 “있는데 사이트 공통 문구” 인지 알 수 없다.확정 · 구현됨probe-website-extract.pyog 80.6% · jsonld 54.2%
9패턴 판정 — 캐스케이드R1 로그인벽 → R2 SPA → R3 미기입 → R4 사이트공통 → R5 제목·요약 → R6 제목만. 못 쓰는 경우를 먼저 걸러낸다.확정 · 구현됨website-content-mapping.html §5P1~P3 이 링크의 55.0%
10필드별 체인칸마다 시도 순서가 다르다. text 는 OpenGraph 가 압도하는데 published 는 JSON-LD 가 이긴다.확정 · 구현됨〃 §2체인 다섯 · text 누적 82.3%
11RSS 보정text_bodypublished 가 빈 경우에만 도메인당 1회 피드를 받아 URL 로 대조한다. P1·P2 는 호출이 0회 그대로다.확정 · 구현됨〃 §2 · Q10피드 24개 · 요약까지 22개
12도메인 지문 — RDAP · urlscanweb_site 에만 부른다. 셋 다 무료다. 세 시간분할 일관 신호가 여기서 나온다 (731일+ · hasTracking · techCount 4개+).확정 · 구현됨website.fetcher.ts · urlscan.client.ts커버 RDAP 81.7% · urlscan 53%
13ContentInput 조립platformKey정규화 URL 이다. 페이지 정보는 최상위로, 도메인 지문 17필드는 data{} 간다. ContentDataInput 의 정의가 “조회축이 아닌 값” 이라 정확히 맞는다.확정 · 구현됨오늘 확정 · Q11지문 66B/토큰
14tokens.web{} 폐기쓰지 않는다. 지문이 Content.data 로 가면서 자리가 없어졌다. fingerprints[] 에서도 domain: 을 빼고 image: 만 남긴다.확정 · 미구현오늘 확정 · Q11token.model.ts:154 제거 대상
15소유권 판정본문에서 계약 주소를 대조해 match · other · placeholder · none · unseen 다섯으로 가른다. other사칭 확정이다.제안Q6 · Q7tnos.global 26건이 전부 사칭

구현까지 된 것이 9개, 정했는데 코드가 없는 것이 2개, 제안 단계가 4개다. 제안 넷 중 셋(③ PSL · ⑤ 종류 판정 1·2단)은 외부 호출을 줄이는 쪽이라 없어도 파이프라인은 돌지만, 없으면 호출이 늘고 grok.me 46종이 한 도메인으로 세어진다.

3착수 전에 닫아야 하는 것

그리면서 답이 없어 비워둔 자리다. 구현을 실제로 막는 것부터 적는다.

미확정 5건

1번이 그림에 직접 구멍을 낸다 — ⑨번 상자에서 나가는 화살표를 어디로 그릴지가 이것에 달렸다.

#무엇이왜 막나어떻게 닫나
1P4~P7 에서도 도메인 지문을 받나Content 를 안 만드는데 RDAP·urlscan 을 부를 것인가. 부르면 저장할 자리가 없고, 안 부르면 그 토큰의 도메인 나이를 영영 못 본다.web_site 이면서 P4~P7 인 경우가 몇 건인지 세어 정한다
2종류 판정기를 어디에 두나1단은 classify() 가 순수·무료라 맞는데, 2단은 토큰명이 필요해서 ParsedUrl 로는 안 된다.Generator 진입 시점으로 내리거나, classify() 의 입력을 넓힌다
3tags 를 계약에서 뺄지ContentInput.tags 는 필수 배열인데 실측 커버리지가 P1 에서만 절반이다.빈 배열로 두고 P1 에서만 채운다 — 다만 “안 채운 것” 과 “없는 것” 이 구분 안 된다
4web_site 안의 참조 비중목록에 없는 참조가 web_site 로 떨어진다. thaipbs.or.th 13건이 실제로 그랬다.657개 도메인을 훑어야 한다 — qna/website.md Q3 이 열려 있다
5google.com 66건검색 결과 · docs. · sites. 가 섞여 있고 G-4 의 검색 규칙과 겹친다.66건의 내부 구성을 본다 — Q5 가 열려 있다

이 그림이 담지 못하는 것 둘.

첫째, 실패 경로가 없다. 403 봇 차단이 조사에서 74건이었고 사이트가 죽는 경우도 16곳 중 5곳이었다. 재시도 정책은 FetchStatusretryUnconverged 가 이미 다루지만 website 종류별로 무엇이 재시도 대상인지는 안 정했다.

둘째, 다른 7소셜과의 관계가 없다. 단축링크를 풀면 목적지가 인스타그램일 수 있고(실측 4건 중 1건), 그러면 website 가 아니라 그쪽 fetcher 로 넘어가야 한다. 그 되돌아가는 화살표가 이 그림에 없다.

단계 정의는 scaffold/render-website-pipeline.py 상수이고, 숫자는 같은 폴더의 JSON 에서 읽는다. 데이터가 바뀌면 그림의 숫자도 따라간다.