Firebase 에뮬레이터 개발 가이드
로컬에서 production Firestore 를 건드리지 않고 안전하게 개발·검증하는 표준 흐름.
TL;DR
일상 개발 (가벼움 — 권장):
터미널 1: pnpm emulator # auth · firestore · storage · functions
터미널 2: pnpm seed:emulator # 첫 실행 1회
터미널 3: pnpm dev # next dev: web=3000 / ops=3001
브라우저: http://localhost:3000 (web), http://localhost:3001 (ops). Emulator UI: http://localhost:4000.
E2E 테스트 (apphosting 포함 — 무거움):
터미널 1: pnpm emulator:e2e # 위 + apphosting (web=5002 / ops=5003)
터미널 2: pnpm seed:emulator
터미널 3: pnpm e2e # Playwright 가 localhost:5002 향함
E2E 모드의 web/ops 는 firebase 가 spawn 한 next dev 인스턴스 (5002·5003). playwright.config.ts 의 baseURL: http://localhost:5002 와 정합.
셋업 체크리스트
1. .env.local 에 NEXT_PUBLIC_USE_EMULATOR=true
apps/web/.env.local 와 apps/ops/.env.local 모두 필요:
NEXT_PUBLIC_USE_EMULATOR=true
이 한 줄만 있으면:
- 클라이언트 SDK —
connectFirestoreEmulator등으로 자동 연결 (apps/web/lib/firebase/client.ts) - Admin SDK —
lib/firebase/admin-emulator.ts가FIRESTORE_EMULATOR_HOST·FIREBASE_AUTH_EMULATOR_HOST·FIREBASE_STORAGE_EMULATOR_HOST자동 셋 (initializeApp 직전)
NEXT_PUBLIC_USE_EMULATOR 가 true 가 아니면 Server Action 의 모든 mutation 이 production Firestore 직행. 클라만 emulator 보고 서버는 production 쓰는 split-brain 사고 차단을 위해 본 가드가 존재.
서버 콘솔에 다음 로그 떠야 정상:
[Firebase Admin] Emulator 라우팅 활성: Firestore 127.0.0.1:8080 · Auth 127.0.0.1:9099 · Storage 127.0.0.1:9199
2. firebase emulators:start
루트에서 pnpm emulator 실행 — Auth (9099) · Firestore (8080) · Storage (9199) · Functions (5001) 동시 기동. UI 4000.
firebase.json 의 emulators 섹션이 SSoT — 포트 변경은 거기서.
3. 시드 — pnpm seed:emulator
emulator 가 떠 있는 동안 1회 실행하면:
tenants/t-test-001(테스트 사무소) — owner 멤버 1명 + super_admin masterAdmintenants/t-test-001/cases/case-test-001— 대여금 사건, 회수율 9.4%- 변제 1건 + 미래 변론기일 1건
config/appMetadata.testing.testTenantIds에t-test-001추가 (ops 시나리오 화이트리스트 자동 통과)
스크립트는 멱등 — 재실행해도 안전.
4. dev 서버 — pnpm dev (또는 individual)
pnpm dev --filter=@neohollo/web # 3000 (or 5002)
pnpm dev --filter=@neohollo/ops # 3001 (or 5003)
ops 시나리오 검증
/scenarios 페이지에서 입력:
tenantId:t-test-001caseId:case-test-001
14 개 시나리오 카드 모두 emulator 안전 (운영 데이터 무영향). destructive purgeCase 도 ops 콘솔의 confirm() + isTestTenantId 화이트리스트로 이중 가드.
데이터 보존 (옵션)
pnpm emulator:import 로 띄우면:
.firebase/emulator-data디렉토리에서 자동 복원- 종료 시 자동 export — 다음 실행에 시드 + 추가 데이터 유지
pnpm emulator:export 로 수동 스냅샷.
트러블슈팅
포트 점유 매트릭스
두 모드는 상호 배타적. 절대 동시 실행 금지.
| 포트 | 일상 dev (pnpm emulator + pnpm dev) | E2E (pnpm emulator:e2e) |
|---|---|---|
| 3000 | web (next dev) | — |
| 3001 | ops (next dev) | — |
| 4000 | emulator UI | emulator UI |
| 5001 | functions emulator | functions emulator |
| 5002 | — | web (firebase apphosting → next dev with PORT=5002) |
| 5003 | — | ops (firebase apphosting → next dev with PORT=5003) |
| 8080 | firestore emulator | firestore emulator |
| 9099 | auth emulator | auth emulator |
| 9199 | storage emulator | storage emulator |
흔한 증상
| 증상 | 원인 | 해결 |
|---|---|---|
EADDRINUSE: 3001 (ops 충돌) | 일상 dev (pnpm dev) 와 E2E (pnpm emulator:e2e) 동시 실행 | 모드 한 번에 하나만. 다른 모드 종료 후 재시작 |
| apphosting emulator 5003 응답 없음 | ops dev 스크립트의 -p 3001 하드코딩이 PORT 환경변수 무시 (#1123 fix 이전 회귀) | apps/ops/package.json 의 dev 가 next dev -p ${PORT:-3001} 형식인지 확인 |
[Firebase Admin] Emulator 라우팅 활성 로그 안 뜸 | .env.local 에 NEXT_PUBLIC_USE_EMULATOR=true 누락 | .env.local 확인 후 dev 서버 재시작 |
seed:emulator 가 FIRESTORE_EMULATOR_HOST 가 설정되지 않았습니다 | emulator 가 안 떠 있음 | 다른 터미널에서 pnpm emulator 먼저 |
| ops 시나리오 "테스트 tenant 화이트리스트 외" 거부 | config/appMetadata.testing.testTenantIds 비어있음 | pnpm seed:emulator 재실행 |
좀비 프로세스 (8080 already in use 등) | 이전 emulator 비정상 종료 | lsof -ti :8080,:9099,:5001,:5002,:5003 | xargs kill |
| Google 로그인 'No matching frame' | CSP frame-src 에 localhost:9099 누락 (#1122 이전 회귀) | dev 서버 재시작 (CSP 헤더 갱신) |
| Rules denied (Firestore 권한 오류) | masterAdmins 화이트리스트 누락 | seed 후 emulator UI 에서 masterAdmins 컬렉션 확인 |
한 줄 정리 — 좀비 정리 + 재시작
# 모든 emulator/dev 프로세스 강제 종료
lsof -ti :3000,:3001,:4000,:5001,:5002,:5003,:8080,:9099,:9199 | xargs kill -9 2>/dev/null
# 일상 dev 재시작
pnpm emulator & # 백그라운드
pnpm dev
운영 안전선
.env.production/ 배포 환경에는NEXT_PUBLIC_USE_EMULATOR=false또는 미설정.admin-emulator.ts가 no-op 으로 빠진다.- production 자격증명 (FB_ADMIN_*) + emulator 라우팅 동시 는 위험 — emulator 라우팅이 우선이지만 자격증명이 production 인 채로 남는 상태가 헷갈리므로 dev 환경은 dev project (
neohollo-dev등) 자격증명 사용 권장. - 시드 스크립트는 emulator 외 절대 실행 금지 —
FIRESTORE_EMULATOR_HOST가드로 자동 차단되지만, env var 를 수동으로 셋한 후 실수 실행은 가드 우회 가능. 실행 전 1초만 호스트 확인.