Pack 1 집계 스크립트 자동화 가이드
ADR 0012 S1 및 0017 후속. 다음 3개 aggregator 를 Cloud Scheduler + Cloud Functions 경유로 하루 1회 자동 실행한다.
scripts/aggregate-docgen-stats.ts— docgenEvents →stats.docgen.*scripts/aggregate-related-memories-stats.ts— relatedMemoriesEvents →stats.relatedMemories.*(ADR 0017 V2 필드 포함)scripts/aggregate-embedding-coverage.ts— legacyDocuments →stats.embedding.*(ADR 0017 · #580)
1. 현 상태 (2026-04-24)
- 3 스크립트 모두 수동 실행 —
NODE_PATH=apps/web/node_modules npx tsx scripts/aggregate-*.ts - Firebase Admin 초기화 완료 (scripts/lib/admin.ts)
- 30일 롤링 윈도우 (docgen · relatedMemories) · 순간 스냅샷 (embedding coverage)
제약:
- 수동 실행 → 집계 간극 발생 시 대시보드 데이터 stale
- Cloud Functions 으로 승격 시 실행 환경 제약 (파일시스템 접근 없음, 60s 타임아웃)
2. 권장 아키텍처
옵션 A: Cloud Functions scheduled
Cloud Scheduler (cron "0 4 * * *" KST)
→ Pub/Sub topic: pack1-stats-aggregate
→ Cloud Function: aggregateStats (Gen2)
→ 내부에서 aggregate-docgen-stats 로직 호출
→ 내부에서 aggregate-related-memories-stats 로직 호출
장점: 한 스케줄러로 두 집계 동시 실행. 실패 시 알림 단일 경로. 단점: Cloud Functions Gen2 메모리 · 타임아웃 설정 필요. 다 테넌트 순회 시 540s 상한 접근.
옵션 B: GitHub Actions scheduled workflow
.github/workflows/aggregate-stats.yml
- cron: "0 19 * * *" # UTC 19:00 = KST 04:00
- firebase-admin credentials via GitHub Secret
- NODE_PATH=apps/web/node_modules npx tsx scripts/aggregate-*.ts
장점: 기존 스크립트 그대로 재사용. Cloud 환경 설정 최소. 단점: GH Actions 실행 시간 제한 (6h), 시크릿 관리 부담.
옵션 C (권장): 옵션 A 의 간소화
- 단일 Cloud Function
aggregatePack1Stats(Gen2, 540s, 1GB) - 내부에서 두 집계 로직 순차 실행
- 실패 시 Sentry/Slack 알림 (기존
infraHardening네임스페이스 활용)
3. Cloud Function 스켈레톤 (미구현, 후속 PR)
// functions/src/aggregate-pack1-stats.ts
import { onSchedule } from "firebase-functions/v2/scheduler";
import { getFirestore, FieldValue } from "firebase-admin/firestore";
export const aggregatePack1Stats = onSchedule(
{
schedule: "0 4 * * *", // KST 04:00
timeZone: "Asia/Seoul",
memory: "1GiB",
timeoutSeconds: 540,
retryCount: 2,
},
async () => {
const db = getFirestore();
const tenants = await db.collection("tenants").get();
for (const t of tenants.docs) {
await aggregateDocgenForTenant(t.id, db);
await aggregateRelatedMemoriesForTenant(t.id, db);
await aggregateEmbeddingCoverageForTenant(t.id, db);
}
},
);
주의: scripts/lib/admin.ts 와 Cloud Functions SDK 초기화 방식이 다름 → 로직 추출 리팩터 필요 (packages/pack1-stats 로 승격 검토).
4. 배포 순서
- 관측 페이즈 (현재): 수동 실행, 1주 1회
- Cloud Functions 이전 PR: 옵션 C 구현, Functions emulator 로 검증
- 알림 연결 PR: 실패 시
ops-console감사 로그 + Slack webhook - Gone: 수동 스크립트는
scripts/유지 (재인덱싱·긴급 복구용)
5. 경보 임계값 (pack1-metrics.md 참조)
- docgen: template_invalid > 5% · render_failed > 1% · avgElapsedMs > 3000ms
- relatedMemories: C 캐시 재평가 3 조건 (CTR / weight / cancel)
Cloud Function 내부에서 임계 초과 시 ops-console alerts 컬렉션에 write.