댓글 시스템 외부 셋업 가이드 (Firebase)

댓글 시스템 외부 셋업 가이드 (Firebase)

이 문서는 운영자가 직접 해야 할 외부 셋업 작업을 정리합니다. 대부분의 작업은 GitHub Actions로 자동화되어 있어 운영자는 service account 키 발급 + GitHub Secrets 등록 + admin claim 설정 3가지만 하면 됩니다.

단일 출처:

  • 에이전트: .claude/agents/comments-policy-auditor.md
  • 하네스: scripts/validate-comments-policy.py
  • Rules: firestore.rules
  • Indexes: firestore.indexes.json
  • CLI 설정: firebase.json
  • 자동 배포: .github/workflows/firebase-deploy.yml
  • Config: _data/firebase.yml

자동화된 부분 (운영자가 안 해도 됨)

GitHub Actions 워크플로우 .github/workflows/firebase-deploy.yml가 master push 시점에 자동으로:

  • Firestore Rules 배포 (firestore.rules → Firebase)
  • Composite Indexes 배포 (firestore.indexes.json → Firebase)
  • 사전에 validate-comments-policy.py 정책 검증 통과 시에만 실행

이후 Rules/Indexes 변경은 git commit → push 한 번으로 자동 반영. 운영자가 콘솔에 들어갈 필요 없음.

단, 워크플로우가 작동하려면 GitHub Secrets에 FIREBASE_SERVICE_ACCOUNT 등록이 한 번 필요. 아래 1단계.


1. Firebase Service Account 키 발급 + GitHub Secrets 등록 (필수, 1회, 5분)

1-A. service account 키 발급

  1. https://console.firebase.google.com/project/spemer-blog-dfc3d/settings/serviceaccounts/adminsdk 접속
  2. 새 비공개 키 생성 클릭
  3. 키 생성 확인 → JSON 파일 다운로드 (spemer-blog-dfc3d-firebase-adminsdk-xxxxx.json 같은 이름)
  4. ⚠️ 이 파일은 절대 git에 commit 금지. .gitignore에 이미 차단 패턴 등록됨

1-B. GitHub Secrets 등록

  1. https://github.com//spemer.github.io/settings/secrets/actions 접속
  2. New repository secret 클릭
  3. Name: FIREBASE_SERVICE_ACCOUNT
  4. Secret: 위 다운로드한 JSON 파일 전체 내용 그대로 붙여넣기
  5. Add secret

1-C. 첫 배포 트리거

GitHub 웹에서 Actions 탭 → Firebase Firestore Deploy 워크플로우 → Run workflow 클릭. 또는 firestore.rules 작은 수정 후 push.

검증

배포 완료 후 Firebase Console > Firestore Database > Rules 탭에서 본 repo의 firestore.rules 내용이 정확히 반영됐는지 확인. Indexes 탭에서도 3개 인덱스 활성 상태 확인.


1-수동. (선택) GitHub Actions 안 쓰고 콘솔 직접 배포

Service account 발급이 부담스럽거나 한 번만 배포할 거면 콘솔 직접 가능:

Firestore Rules

  1. https://console.firebase.google.com/project/spemer-blog-dfc3d 접속
  2. 빌드Firestore DatabaseRules
  3. 기존 Rules 삭제 → repo의 firestore.rules 전체 내용 붙여넣기 → 게시

Composite Indexes

  • 첫 댓글 조회 시 브라우저 콘솔에 인덱스 생성 URL 자동 표시 → 클릭 → 만들기

검증 (Firestore > Rules > 시뮬레이터)

  • comments 컬렉션에 인증 없이 read → status == 'approved'만 허용
  • 익명 user가 다른 uid로 write → 차단
  • user가 status: 'approved'로 직접 write → 차단 (반드시 pending)

2. 운영자 admin custom claim 설정 (필수, 1회, 5분)

운영자(본인)가 댓글을 승인/거부/삭제하려면 admin: true claim이 필요. Firestore Rules가 request.auth.token.admin == true 검사.

repo에 scripts/set-firebase-admin.js 스크립트 미리 작성됨. 그대로 실행하면 됨.

사전 작업: 본인 UID 확인

  1. https://blog.spemer.com 댓글 시스템에 Google 로그인 (또는 로컬 환경)
  2. Firebase Console → AuthenticationUsers
  3. 본인 Google 계정의 사용자 UID 복사

권장: Firebase Cloud Shell 실행 (보안 부담 0)

  1. https://console.firebase.google.com/project/spemer-blog-dfc3d 우측 상단 Cloud Shell 아이콘(>_) 클릭
  2. repo clone 또는 본 스크립트 내용 복사:
    curl -O https://raw.githubusercontent.com/<your-org>/spemer.github.io/master/scripts/set-firebase-admin.js
    npm install firebase-admin --silent
    node set-firebase-admin.js <YOUR_UID>
    
  3. 출력 ✓ admin claim 부여 완료 확인
  4. 본인 계정 로그아웃 → 재로그인 (token 새로고침 시 claim 반영)

대안: 로컬 Node.js 실행

  1. https://console.firebase.google.com/project/spemer-blog-dfc3d/settings/serviceaccounts/adminsdk 에서 키 다운로드
  2. export GOOGLE_APPLICATION_CREDENTIALS=<다운로드한 JSON 경로>
  3. cd <repo>
  4. npm install firebase-admin
  5. node scripts/set-firebase-admin.js <YOUR_UID>
  6. (보안) JSON 파일 즉시 삭제

검증

  1. 본인 Google 계정 재로그인 후 댓글 작성
  2. Firebase Console > Firestore > comments 컬렉션 → 본인 댓글 document 클릭
  3. status 필드를 approved로 직접 수정 → 성공하면 admin claim 적용 완료

3. App Check + reCAPTCHA v3 활성화 (강력 권장 — spam 차단)

Anonymous Auth는 bot도 쉽게 사용 가능. App Check로 클라이언트 검증 추가 필요.

절차

  1. https://www.google.com/recaptcha/admin/create 접속
  2. 라벨: blog-spemer-com-comments
  3. reCAPTCHA 유형: v3 선택
  4. 도메인 추가:
    • blog.spemer.com
    • localhost (로컬 테스트용)
  5. 제출 → 표시되는 사이트 키 복사
  6. Firebase Console → 좌측 메뉴 빌드App Check
  7. 앱 등록 → blog-spemer-com 웹 앱 선택
  8. reCAPTCHA v3 공급자 선택 → 위에서 복사한 사이트 키 붙여넣기
  9. 저장
  10. 제품별 적용 탭에서:
    • Authentication → 시행(Enforced) 설정 (배포 후 1주 정도 모니터링 후 enforce 권장)
    • Cloud Firestore → 시행(Enforced) 설정

코드 적용 (선택)

App Check 활성화 후 _includes/comments-firebase.html에 다음 추가:

import { initializeAppCheck, ReCaptchaV3Provider } from
  "https://www.gstatic.com/firebasejs/12.14.0/firebase-app-check.js";

const appCheck = initializeAppCheck(app, {
  provider: new ReCaptchaV3Provider("<사이트 키>"),
  isTokenAutoRefreshEnabled: true,
});

App Check site key는 공개 노출 OK (apiKey와 동일하게 클라이언트 식별자). _data/firebase.ymlappCheckSiteKey 필드 추가해서 관리 가능.


4. 운영 모더레이션 흐름 (즉시 노출 + 사후 모니터링)

정책

모든 댓글이 status: 'approved'로 즉시 저장 → 페이지에 실시간 노출. 운영자는 사후에 부적절 댓글을 발견 시 처리.

새 댓글이 들어오면

  1. 독자 댓글 작성 → Firestore comments 컬렉션에 status: 'approved'로 저장
  2. 페이지에 실시간 노출 (다른 독자도 즉시 볼 수 있음)
  3. 운영자는 별도 작업 없음

부적절 댓글 발견 시 운영자 처리

  1. Firebase Console → Firestore > comments → 해당 document 클릭
  2. 다음 중 하나:
    • status: 'rejected'로 수정 — 작성자만 볼 수 있음 (조용한 거부, 작성자는 자기 댓글 그대로 보임)
    • document 삭제 — 영구 제거 (가장 단호)
  3. admin custom claim 있는 운영자만 가능

주기적 모니터링 권장

  • 매일 1회 Firebase Console에서 신규 댓글 검토 (1-2분)
  • spam/욕설/광고 댓글 즉시 처리
  • 트래픽 늘면 Cloud Functions로 운영자 이메일 알림 자동화 검토

spam 위험 완화 (즉시 노출 채택 시 강력 권장)

  • App Check + reCAPTCHA v3 활성화 (Section 3) — bot 자동 차단
  • honeypot 필드 — 이미 코드에 기본 포함
  • 트래픽 증가 시 익명 댓글만 pending 처리하는 단계적 강화 검토

향후 자동화 (선택)

  • Cloud Functions로 부적절 키워드 자동 감지 + 즉시 rejected
  • 운영자 알림 (이메일/Slack)
  • admin UI 자체 구축 (/admin/comments/)

5. 데이터 모델 (참고)

/comments/{commentId}:

{
  postSlug: "ileach-cs-review",
  lang: "ko" | "en",
  name: "독자 이름",
  body: "댓글 본문 (max 2000자)",
  createdAt: serverTimestamp,
  uid: "<Firebase Auth user ID>",
  authMethod: "anonymous" | "google",
  photoURL: null | "https://...",
  status: "approved" | "rejected"
}

Firestore Rules로 강제되는 제약:

  • name max 30자, body max 2000자
  • uid는 request.auth.uid와 일치해야 함 (위조 차단)
  • create 시 status는 반드시 approved (즉시 노출 정책)
  • read: approved 댓글은 모두 / rejected는 본인 또는 admin
  • update: 본인은 body/name만, admin은 status 포함 모든 필드
  • delete: 본인 또는 admin

5b. Firestore Composite Index 자동 생성 (첫 댓글 query 시점)

댓글 query는 postSlug + lang + status + createdAt(desc) 복합 조건이라 Firestore composite index 필요. 사이트 배포 후 첫 페이지 로드 시 Firebase가 자동으로 콘솔 에러 + 인덱스 생성 URL을 제공:

  1. 사용자가 댓글 페이지 방문 → 브라우저 콘솔에 다음과 유사한 에러 표시:
    [comments] snapshot failed FirebaseError: The query requires an index.
    You can create it here: https://console.firebase.google.com/project/spemer-blog-dfc3d/firestore/indexes?create_composite=...
    
  2. URL 클릭 → Firebase Console로 이동 → 인덱스 만들기 자동 양식 채워짐
  3. 만들기 클릭 → 1-2분 대기 → 인덱스 활성화
  4. 페이지 새로고침 → 댓글 정상 로드

이 단계는 한 번만 하면 됨. 이후 모든 댓글 query는 동일 인덱스 사용.

미리 생성하고 싶다면:

  • Firebase Console → Firestore Database → Indexes 탭 → 인덱스 만들기
  • 컬렉션 ID: comments
  • 필드:
    • postSlug ASC
    • lang ASC
    • status ASC
    • createdAt DESC
  • 만들기

6. 검증 자동화

배포 전 다음 명령으로 정책 자동 점검:

python3 scripts/validate-comments-policy.py --all

점검 영역:

  • Firebase config 무결성 (apiKey, projectId 등)
  • Firestore Rules 무결성 (status=pending 강제, default deny 등)
  • secret key 누설 검출
  • XSS 방어 (innerHTML 금지)
  • 광고-댓글 인접 차단
  • spam 차단 (honeypot)
  • 접근성 (label, aria-live)

CRITICAL 발견 시 BLOCK (커밋/배포 차단).


7. 정책 변경 추적

Google UGC / AdSense / Helpful Content 정책은 수시 갱신. 30일마다 다음 URL 재확인:

  • https://developers.google.com/search/docs/essentials/spam-policies
  • https://support.google.com/adsense/answer/1348688
  • https://developers.google.com/search/docs/fundamentals/creating-helpful-content

재확인 후 scripts/validate-comments-policy.pyPOLICY_LAST_CHECKED 상수 갱신.