← 목록으로
2026-03-01plans

OKR 콘텐츠 자동 집계 구현 계획

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: KR3-1(콘텐츠 편수)/KR2-2(활성채널)/KR3-3(브랜드채널) 수동 입력 완전 제거, 시스템 자동 집계 구현

Architecture: content-os DB에 content_sites 중앙 집계 테이블 추가. 각 사이트 배포 스크립트에서 발행 수 UPDATE. okr-collector가 SUM/COUNT 쿼리로 자동 집계.

Tech Stack: Turso(LibSQL), Node.js, TypeScript, okr-collector.ts


현황 분석

5개 사이트 블로그 소스 현황

사이트블로그 DB발행 수
apppro.krapppro-kr Turso DB~40편
KoreaAI Hubcontent/blog/ MDX 파일~10편
richbukae.comcontent/blog/ MDX 파일~7편
ai-architect-globalcontent/blog/ MDX 파일~9편
prompt-shopcontent/guides/ MDX 파일~3편
  • content-os blog_posts: 발행 0개 (apppro.kr 블로그 = WordPress blog.apppro.kr, 별도)
  • koreaai-hub DB: subscribers/newsletter_issues만 있음 (블로그 테이블 없음)
  • 핵심 문제: 분산된 소스 → 단일 자동 집계 불가

선택한 설계: content_sites 중앙 집계 테이블

각 사이트 배포/발행 시 → content_sites 테이블 UPDATE → okr-collector SUM

Task 1: content-os DB에 content_sites 테이블 생성

Files:

  • Create: projects/content-orchestration/migrations/add-content-sites.sql

Step 1: SQL 마이그레이션 파일 작성

CREATE TABLE IF NOT EXISTS content_sites (
  site TEXT PRIMARY KEY,
  display_name TEXT NOT NULL,
  published_count INTEGER NOT NULL DEFAULT 0,
  is_active INTEGER NOT NULL DEFAULT 1,
  last_published_at INTEGER,
  last_synced_at INTEGER,
  updated_at INTEGER NOT NULL DEFAULT (unixepoch())
);

-- 초기 데이터 시딩 (현재 수동 카운트 반영)
INSERT OR REPLACE INTO content_sites (site, display_name, published_count, is_active, last_synced_at, updated_at) VALUES
  ('apppro-kr',       'apppro.kr 블로그',        40, 1, unixepoch(), unixepoch()),
  ('koreaai-hub',     'KoreaAI Hub 블로그',       10, 1, unixepoch(), unixepoch()),
  ('richbukae',       'richbukae.com 블로그',      7, 1, unixepoch(), unixepoch()),
  ('ai-architect',    'AI Architect Global 블로그', 9, 1, unixepoch(), unixepoch()),
  ('prompt-shop',     'prompt-shop /guides',       3, 1, unixepoch(), unixepoch());

Step 2: content-os DB에 실행

turso db shell content-os < projects/content-orchestration/migrations/add-content-sites.sql

Expected: 테이블 생성 + 5개 row 삽입

Step 3: 확인

turso db shell content-os "SELECT site, published_count, is_active FROM content_sites;"

Expected: 5개 사이트 row, 총 published_count = 69

Step 4: Commit

git add projects/content-orchestration/migrations/add-content-sites.sql
git commit -m "feat: add content_sites table for OKR auto-aggregation"

Task 2: okr-collector.ts 수정 — KR3-1/KR2-2/KR3-3 자동 집계

Files:

  • Modify: projects/jarvis-system/apps/worker/src/okr-collector.ts

Step 1: CONTENT_OS_DB_URL/TOKEN 환경변수 추가 Worker .env 파일에 추가:

CONTENT_OS_DB_URL=libsql://content-os-migkjy.aws-ap-northeast-1.turso.io
CONTENT_OS_DB_TOKEN=<token>

turso db tokens create content-os 로 토큰 생성

Step 2: okr-collector.ts — content-os DB 연결 추가

// content-os DB 연결 (OKR 콘텐츠 집계용)
import { createClient } from '@libsql/client';

let _contentOsClient: ReturnType<typeof createClient> | null = null;
function getContentOsClient() {
  if (!_contentOsClient) {
    const url = process.env.CONTENT_OS_DB_URL;
    const authToken = process.env.CONTENT_OS_DB_TOKEN;
    if (!url || !authToken) throw new Error('CONTENT_OS_DB_URL/TOKEN not set');
    _contentOsClient = createClient({ url, authToken });
  }
  return _contentOsClient;
}

async function queryContentOs(query: string): Promise<number> {
  try {
    const client = getContentOsClient();
    const result = await client.execute(query);
    const row = result.rows[0];
    const val = (row as any)?.value ?? (row as any)?.cnt ?? 0;
    return Number(val) || 0;
  } catch (err) {
    console.error('[OKR] content-os query failed:', err);
    return 0;
  }
}

Step 3: KR3-1, KR2-2, KR3-3 collector를 manualCollector에서 자동 집계로 교체

{
  krId: 'KR3-1',
  configKey: 'content_published',
  collect: async () => {
    const value = await queryContentOs(
      "SELECT SUM(published_count) as value FROM content_sites WHERE is_active = 1"
    );
    return { value, raw: { source: 'content_sites', query: 'SUM(published_count)' } };
  },
},
{
  krId: 'KR2-2',
  configKey: 'content_channels',
  collect: async () => {
    const value = await queryContentOs(
      "SELECT COUNT(*) as value FROM content_sites WHERE is_active = 1"
    );
    return { value, raw: { source: 'content_sites', query: 'COUNT active sites' } };
  },
},
{
  krId: 'KR3-3',
  configKey: 'brand_channel_reach',
  collect: async () => {
    const value = await queryContentOs(
      "SELECT COUNT(*) as value FROM content_sites WHERE is_active = 1"
    );
    return { value, raw: { source: 'content_sites', query: 'COUNT active sites' } };
  },
},

Step 4: Worker 빌드 + 재시작

cd projects/jarvis-system/apps/worker
npm run build
# Worker 프로세스 재시작 (기존 프로세스 종료 후)

Step 5: 즉시 수동 collectAll 트리거 + 결과 확인

turso db shell kanban "SELECT id, current_value FROM okr_key_results WHERE id IN ('KR3-1','KR2-2','KR3-3');"

Expected: KR3-1=69, KR2-2=5, KR3-3=5

Step 6: Commit + Push

git add projects/jarvis-system/apps/worker/src/okr-collector.ts projects/jarvis-system/apps/worker/.env
git commit -m "feat: auto-aggregate KR3-1/KR2-2/KR3-3 from content_sites table"
git pull --rebase origin main && git push

Task 3: 각 사이트 배포 시 content_sites 자동 업데이트 스크립트

Files:

  • Create: scripts/sync-content-count.sh
#!/bin/bash
# 사용법: ./scripts/sync-content-count.sh <site> <count>
# 예: ./scripts/sync-content-count.sh apppro-kr 41

SITE=$1
COUNT=$2
if [ -z "$SITE" ] || [ -z "$COUNT" ]; then
  echo "Usage: $0 <site> <count>"
  exit 1
fi

turso db shell content-os "UPDATE content_sites SET published_count = $COUNT, last_synced_at = unixepoch(), updated_at = unixepoch() WHERE site = '$SITE';"
echo "✅ content_sites[$SITE] = $COUNT"

향후 각 사이트 블로그 발행 시:

./scripts/sync-content-count.sh koreaai-hub 11  # 새 글 발행 후 수동 호출

→ okr-collector 6시간 이내 자동 반영 (또는 즉시 collectAll 트리거)

Step 1: 스크립트 생성 + 실행 권한

chmod +x scripts/sync-content-count.sh

Step 2: Commit

git add scripts/sync-content-count.sh
git commit -m "feat: add sync-content-count.sh for content_sites update"
git pull --rebase origin main && git push

Task 4: Worker .env에 CONTENT_OS_DB_TOKEN 추가

Step 1: token 생성

turso db tokens create content-os

Step 2: Worker .env 업데이트

CONTENT_OS_DB_URL=libsql://content-os-migkjy.aws-ap-northeast-1.turso.io
CONTENT_OS_DB_TOKEN=<생성된 토큰>

Step 3: Worker 재시작 확인

curl -s http://127.0.0.1:5555/status | python3 -m json.tool

완료 기준

  • content_sites 테이블 생성 + 초기 데이터 5개 row
  • KR3-1 자동 집계: SUM(published_count) = 69
  • KR2-2 자동 집계: COUNT(active sites) = 5
  • KR3-3 자동 집계: COUNT(active sites) = 5
  • okr_key_results에 자동 반영 확인
  • 수동 UPDATE okr_key_results 명령 더 이상 불필요

주의사항

  • KR4-3 (평균 소요일): 타임스탬프 혼용 버그 → 자동화 불가, manualCollector 유지
  • KR1-x, KR2-1, KR2-3, KR3-2: 외부 플랫폼 API 연동 필요 → 별도 Phase 2 과제
  • content-os DB token은 .env에만 저장, git commit 금지
plans/2026/03/01/okr-auto-content-collector.md