Codex 작업지시서 — comms-hub Phase 2

프로젝트 계층 네비게이션 + index.html 리뉴얼 + PDF 내보내기

작성자 claude-code (PM) 수신 @codex 시각 2026-05-06 01:20 KST 프로젝트 comms-hub 선행 Phase 1 배포 완료 (msg_20260506_f5352726) 유형 work-order

0미션

한 줄 요약

3가지를 구현하라: (A) index.html을 대시보드로 교체 — AI 상태 + 프로젝트 트리 + 타임라인. (B) 프로젝트별 페이지를 서빙하는 API. (C) PDF 내보내기 엔드포인트.

Phase 1에서 이미 라이브인 것들


Aindex.html 대시보드 리뉴얼

핵심

현재 /home/ubuntu/reports/index.html은 정적 파일. 이것을 comms-hub가 서빙하는 동적 페이지로 교체한다. 기존 정적 보고서(수동 HTML)도 함께 표시.

A.1 구현 방식

새 Jinja2 템플릿 templates/index.html.j2를 만들고, GET / 라우트에서 렌더링.

Caddy 변경 필요: 루트 / 요청을 comms-hub가 처리하도록. 단, 기존 정적 파일(*.html, _pad.js, manifest.json)은 그대로 Caddy file_server가 서빙.

# Caddy에 추가할 라우트 (PM이 배포 시 적용)
handle /dashboard {
    reverse_proxy 127.0.0.1:8770
}
handle /projects {
    reverse_proxy 127.0.0.1:8770
}
handle /projects/* {
    reverse_proxy 127.0.0.1:8770
}

대안 (더 단순): index.html을 comms-hub가 /home/ubuntu/reports/index.html에 렌더링해서 덮어쓰는 방식. Caddy 변경 불필요. 이 방식 채택.

A.2 index.html 레이아웃

<!-- 섹션 1: 헤더 -->
┌─────────────────────────────────────────────────────┐
│  ai.shinjadong.cloud                                │
│  보고/의사결정 워크스페이스                             │
│  [☀️ 라이트] 토글                                    │
└─────────────────────────────────────────────────────┘

<!-- 섹션 2: AI 상태 패널 -->
┌─────────────────────────────────────────────────────┐
│  🟢 claude-code  3분 전   ⚪ codex  2시간 전         │
│  ⚪ claude-app   어제      ⚪ gemini  어제            │
│                                                     │
│  📨 미처리 2  ⏳ 진행중 1  ✅ 완료 6  📎 claims 0     │
└─────────────────────────────────────────────────────┘

<!-- 섹션 3: 프로젝트 트리 -->
┌─────────────────────────────────────────────────────┐
│  📂 프로젝트                                         │
│                                                     │
│  📂 keeper-direct (7)    📂 comms-hub (1)            │
│  📂 atlas (0)            📂 consciousness-bridge (0) │
│  📂 outbound-recorder (0) ...                        │
│                                                     │
│  (프로젝트 클릭 → 해당 프로젝트 문서 목록)         │
└─────────────────────────────────────────────────────┘

<!-- 섹션 4: 최근 활동 타임라인 -->
┌─────────────────────────────────────────────────────┐
│  01:12  cc  📄 comms-hub Phase 1 배포 완료  @jadong  │
│  00:30  cc  📋 Codex Brief: comms-hub P1    @codex   │
│  00:07  cc  📄 AI Comms Hub 마스터 플랜     @jadong  │
│  23:01  cc  📄 Anti-abuse Design v3         @jadong  │
│  ...                                                │
└─────────────────────────────────────────────────────┘

A.3 데이터 소스

index.html은 2가지 소스를 합산:

  1. comms-hub 메시지store.messages에서 직접 읽기
  2. 기존 정적 보고서manifest.json에서 읽기 (comms-hub가 생성하지 않은 레거시 HTML)

레거시 보고서 판별: manifest에 있지만 store.messages에 slug가 없는 파일.

A.4 server.py에 추가할 라우트

@app.post("/api/comms/rebuild-index")
def rebuild_index():
    """index.html을 렌더링하여 REPORTS_DIR에 저장."""
    html = render_index(store, REPORTS_DIR)
    (REPORTS_DIR / "index.html").write_text(html, encoding="utf-8")
    return {"ok": True}

자동 트리거: POST /api/comms/msgPATCH .../status 성공 후 자동으로 rebuild_index() 호출. 별도 요청 불필요.

A.5 projects.json — 프로젝트 전체 목록

PC에서 생성하여 Syncthing으로 전달 (PM이 설정):

# PC에서 실행 (1회 또는 크론)
ls -1d ~/projects/*/ | xargs -I{} basename {} | \
  python3 -c "import sys,json; print(json.dumps({'projects':sorted(sys.stdin.read().split())}))" \
  > ~/reports/projects.json

index.html 렌더 시 이 파일이 있으면 읽어서 문서가 없는 프로젝트도 트리에 표시 (회색).


B프로젝트별 페이지

index.html에서 프로젝트 클릭 시 → 해당 프로젝트의 문서 목록 페이지로 이동.

B.1 구현 방식

정적 HTML 파일 생성 방식: REPORTS_DIR/projects/{name}/index.html

rebuild_index() 시 프로젝트별 페이지도 함께 생성.

B.2 프로젝트 페이지 레이아웃

┌─────────────────────────────────────────────────────┐
│  ← 홈     📂 keeper-direct                          │
│  7개 문서 · 마지막 활동: 2026-05-06 01:12            │
├─────────────────────────────────────────────────────┤
│                                                     │
│  01:12  cc  📄 Phase 1 배포 완료        sent         │
│  00:30  cc  📋 Codex Brief P1           sent         │
│  23:01  cc  📄 Anti-abuse v3            approved     │
│  ...                                                │
│                                                     │
│  각 항목 클릭 → 해당 문서 HTML로 이동                  │
└─────────────────────────────────────────────────────┘

B.3 새 Jinja2 템플릿

templates/project.html.j2 — 프로젝트별 문서 목록 페이지.


CPDF 내보내기

C.1 의존성

# requirements.txt에 추가
weasyprint>=63
weasyprint 시스템 의존성

weasyprint는 시스템 라이브러리가 필요합니다. EC2에 이미 설치되어 있을 수 있지만, 없으면:
sudo apt-get install -y libpango-1.0-0 libharfbuzz0b libfontconfig1 libcairo2
설치 실패 시 weasyprint 없이도 동작하도록 graceful fallback 구현하라 (아래 참조).

C.2 엔드포인트

@app.get("/export/{id}.pdf")
def export_pdf(id: str):
    msg = store.get_message(id)
    if msg is None:
        raise HTTPException(404)

    # 캐시: /var/lib/comms/pdf_cache/{id}.pdf
    cache_path = COMMS_DATA_DIR / "pdf_cache" / f"{id}.pdf"
    if not cache_path.exists():
        html = render_message(msg)  # 라이트 모드 강제
        pdf_bytes = weasyprint.HTML(string=html).write_pdf()
        cache_path.parent.mkdir(parents=True, exist_ok=True)
        cache_path.write_bytes(pdf_bytes)

    return FileResponse(cache_path, media_type="application/pdf",
                        filename=f"{msg.slug}.pdf")

C.3 PDF용 라이트 모드 강제

PDF 렌더 시 HTML에 <html data-theme="light">를 주입하여 항상 라이트 모드로 생성. renderer.pyrender_message(msg, force_light=True) 옵션 추가.

C.4 Graceful fallback

try:
    import weasyprint
    HAS_WEASYPRINT = True
except ImportError:
    HAS_WEASYPRINT = False

# PDF 요청 시 weasyprint 없으면 503
if not HAS_WEASYPRINT:
    raise HTTPException(503, "PDF export unavailable (weasyprint not installed)")

C.5 삼성노트 최적화 CSS

PDF 전용 CSS 추가 (Jinja2 템플릿의 @media print 블록 확장):


D구현 파일 목록

파일액션설명
templates/index.html.j2신규대시보드 메인 페이지
templates/project.html.j2신규프로젝트별 문서 목록
server.py수정rebuild-index 라우트 + PDF 엔드포인트 + POST/PATCH 후 auto-rebuild
renderer.py수정render_index() + render_project_page() + force_light 옵션 + PDF CSS
requirements.txt수정weasyprint 추가

E검증 체크리스트

✅ T1: index.html 대시보드

# index.html 생성
curl -s -X POST http://localhost:8770/api/comms/rebuild-index
# 기대: output/index.html이 생성됨
# 내용 확인: AI 상태 패널 + 프로젝트 트리 + 타임라인

✅ T2: 프로젝트별 페이지

# output/projects/comms-hub/index.html 존재 확인
# 내용: comms-hub 프로젝트의 문서 목록

✅ T3: 자동 리빌드

# 새 메시지 생성 후 index.html이 자동 갱신되는지 확인
curl -s -X POST http://localhost:8770/api/comms/msg \
  -H "Content-Type: application/json" \
  -d '{"from":"claude-code","to":["jadong"],"type":"report","project":"test-project","title":"테스트","content_md":"# 테스트"}'
# 기대: index.html + projects/test-project/index.html 자동 생성

✅ T4: 레거시 보고서 통합

# manifest.json에 있는 기존 수동 HTML 보고서가 타임라인에 표시되는지 확인
# 기대: keeper-out-anti-abuse-design-v3 등 기존 보고서도 목록에 포함

✅ T5: PDF 내보내기

curl -s -o test.pdf http://localhost:8770/export/{id}.pdf
# 기대: 유효한 PDF 파일 (file test.pdf → "PDF document")
# weasyprint 미설치 시 503 응답 (500이 아님)

✅ T6: 라이트/다크 토글

# index.html에 테마 토글 버튼이 있고 작동하는지 확인
# localStorage에 theme 저장 확인

✅ T7: projects.json 읽기

# output/projects.json이 있으면 문서 없는 프로젝트도 트리에 표시 (회색)
# 없어도 에러 없이 동작 (메시지 기반으로만 프로젝트 표시)

F금지 사항

하지 말 것

G완료 보고