@roottale/analytics-runtime
v0.2.0
Published
RootTale analytics runtime (ADR-0038) — Consent Mode v2 fail-closed tag loader, consent banner, and first-party data-track beacon. Framework-agnostic strings + optional React drop-in (<RootTaleAnalytics>).
Maintainers
Readme
@roottale/analytics-runtime
ADR-0038 plane ① (외부 트래커 주입) + 동의(Consent Mode v2 fail-closed) + plane ②
(first-party 비콘) 의 프레임워크/DB 무관 런타임. 문자열만 산출하므로
cms-renderer-astro·cms-renderer-next 가 동일하게 mount 한다.
⚠️ 주입 규칙
set:html / dangerouslySetInnerHTML 로 주입한 <script> 는 실행되지 않는다.
본 패키지 함수는 JS 본문 또는 HTML 마크업 만 반환하고, 렌더러가 JS 는
실제 <script> 엘리먼트로 감싼다.
- Astro:
<script is:inline set:html={js} /> - Next:
<script dangerouslySetInnerHTML={{ __html: js }} />
head 주입 (순서 중요)
renderConsentBootstrap()— 가장 먼저. Consent Mode v2 default 전부 denied.renderLoaderScript(manifest)— 태그 로더. 동의 update 전 미발화(fail-closed).
import {
buildManifest,
renderConsentBootstrap,
renderLoaderScript,
} from "@roottale/analytics-runtime";
const manifest = buildManifest({ siteId, tags }); // tags = SiteAnalyticsTagsRepo.listForSite()
const bootstrap = renderConsentBootstrap();
const loader = renderLoaderScript(manifest);body 주입
renderConsentBannerMarkup(opts)— 배너 HTML(컨테이너로 주입). 기본 숨김.renderConsentBannerScript()— 배너 동작 JS(선택→updateConsent+localStorage).renderBeaconScript({ collectUrl, siteId })— plane ②data-trackdispatcher. cookieless·anonymized 라 동의 게이트 없이 동작(ADR-0038 §2).
Astro mount 예시 (web-front/src/layouts/BaseLayout.astro)
---
import {
buildManifest, renderConsentBootstrap, renderLoaderScript,
renderConsentBannerMarkup, renderConsentBannerScript, renderBeaconScript,
} from "@roottale/analytics-runtime";
const { manifest, siteId, collectUrl, privacyUrl } = Astro.props;
const bootstrap = renderConsentBootstrap();
const loader = renderLoaderScript(manifest);
const beacon = renderBeaconScript({ collectUrl, siteId });
const bannerJs = renderConsentBannerScript();
---
<head>
<script is:inline set:html={bootstrap} />
<script is:inline set:html={loader} />
<!-- ...기존 SEO 메타... -->
</head>
<body>
<slot />
<Fragment set:html={renderConsentBannerMarkup({ privacyUrl })} />
<script is:inline set:html={bannerJs} />
<script is:inline set:html={beacon} />
</body>[slug].astro 가 getBuildClient() 로 site.id/site.tenantId 를 얻고,
SiteAnalyticsTagsRepo(db, tenantId).listForSite(siteId) → buildManifest →
BaseLayout props 로 전달.
상태 (ADR-0038)
- ✅ 로직·산출물·동의 배너·비콘 dispatcher (본 패키지, 단위 테스트)
- ⏳ web-front mount (workspace dep 등록 =
pnpm install후 BaseLayout 주입) - ⏳ plane ②
/collect엔드포인트 (tenant-api + CF Analytics Engine) - ⏳ plane ③ GA4/GSC ETL +
getWeeklyVisitors()
