댓글 시스템 외부 셋업 가이드 (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 키 발급
- https://console.firebase.google.com/project/spemer-blog-dfc3d/settings/serviceaccounts/adminsdk 접속
- 새 비공개 키 생성 클릭
- 키 생성 확인 → JSON 파일 다운로드 (
spemer-blog-dfc3d-firebase-adminsdk-xxxxx.json같은 이름) - ⚠️ 이 파일은 절대 git에 commit 금지.
.gitignore에 이미 차단 패턴 등록됨
1-B. GitHub Secrets 등록
- https://github.com/
/spemer.github.io/settings/secrets/actions 접속 - New repository secret 클릭
- Name:
FIREBASE_SERVICE_ACCOUNT - Secret: 위 다운로드한 JSON 파일 전체 내용 그대로 붙여넣기
- 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
- https://console.firebase.google.com/project/spemer-blog-dfc3d 접속
- 빌드 → Firestore Database → Rules 탭
- 기존 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 확인
- https://blog.spemer.com 댓글 시스템에 Google 로그인 (또는 로컬 환경)
- Firebase Console → Authentication → Users 탭
- 본인 Google 계정의 사용자 UID 복사
권장: Firebase Cloud Shell 실행 (보안 부담 0)
- https://console.firebase.google.com/project/spemer-blog-dfc3d 우측 상단 Cloud Shell 아이콘(
>_) 클릭 - 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> - 출력
✓ admin claim 부여 완료확인 - 본인 계정 로그아웃 → 재로그인 (token 새로고침 시 claim 반영)
대안: 로컬 Node.js 실행
- https://console.firebase.google.com/project/spemer-blog-dfc3d/settings/serviceaccounts/adminsdk 에서 키 다운로드
export GOOGLE_APPLICATION_CREDENTIALS=<다운로드한 JSON 경로>cd <repo>npm install firebase-adminnode scripts/set-firebase-admin.js <YOUR_UID>- (보안) JSON 파일 즉시 삭제
검증
- 본인 Google 계정 재로그인 후 댓글 작성
- Firebase Console > Firestore > comments 컬렉션 → 본인 댓글 document 클릭
- status 필드를
approved로 직접 수정 → 성공하면 admin claim 적용 완료
3. App Check + reCAPTCHA v3 활성화 (강력 권장 — spam 차단)
Anonymous Auth는 bot도 쉽게 사용 가능. App Check로 클라이언트 검증 추가 필요.
절차
- https://www.google.com/recaptcha/admin/create 접속
- 라벨:
blog-spemer-com-comments - reCAPTCHA 유형: v3 선택
- 도메인 추가:
blog.spemer.comlocalhost(로컬 테스트용)
- 제출 → 표시되는 사이트 키 복사
- Firebase Console → 좌측 메뉴 빌드 → App Check
- 앱 등록 → blog-spemer-com 웹 앱 선택
- reCAPTCHA v3 공급자 선택 → 위에서 복사한 사이트 키 붙여넣기
- 저장
- 제품별 적용 탭에서:
- 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.yml에 appCheckSiteKey 필드 추가해서 관리 가능.
4. 운영 모더레이션 흐름 (즉시 노출 + 사후 모니터링)
정책
모든 댓글이 status: 'approved'로 즉시 저장 → 페이지에 실시간 노출. 운영자는 사후에 부적절 댓글을 발견 시 처리.
새 댓글이 들어오면
- 독자 댓글 작성 → Firestore
comments컬렉션에status: 'approved'로 저장 - 페이지에 실시간 노출 (다른 독자도 즉시 볼 수 있음)
- 운영자는 별도 작업 없음
부적절 댓글 발견 시 운영자 처리
- Firebase Console → Firestore > comments → 해당 document 클릭
- 다음 중 하나:
status: 'rejected'로 수정 — 작성자만 볼 수 있음 (조용한 거부, 작성자는 자기 댓글 그대로 보임)- document 삭제 — 영구 제거 (가장 단호)
- 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을 제공:
- 사용자가 댓글 페이지 방문 → 브라우저 콘솔에 다음과 유사한 에러 표시:
[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=... - URL 클릭 → Firebase Console로 이동 → 인덱스 만들기 자동 양식 채워짐
- 만들기 클릭 → 1-2분 대기 → 인덱스 활성화
- 페이지 새로고침 → 댓글 정상 로드
이 단계는 한 번만 하면 됨. 이후 모든 댓글 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.py의 POLICY_LAST_CHECKED 상수 갱신.