2026-05-07
장애 회고 — jsdom prod 호환 + 재발방지 가드 도입
- 장애: forum/topic mutation + culture/olen detail 페이지가 prod 에서 server component error. 진단 ~90분, 추측 fix 5번 무효. 사용자가 Vercel Function logs 의 정확한 throw message (ERR_REQUIRE_ESM ... @exodus/bytes/encoding-lite.js) 공유 후 1분 만에 해결
- 원인: lib/sanitize-html.ts 가 isomorphic-dompurify import → jsdom transitive dep ESM 모듈을 Vercel CommonJS Lambda 가 require() 시도 → throw. dev (Turbopack) 에선 module resolution 차이로 통과. server action 모듈 evaluate 단계부터 깨져서 forum mutation 전부 fail
- fix 1 (긴급): lib/sanitize-url.ts 분리 — sanitizeUrl 만 별도. server action 의 jsdom import chain 끊음
- fix 2 (완전): lib/sanitize-html.ts 자체를 jsdom-free 정규식 구현으로 재작성. <script>/<style>/on*/javascript:/iframe trusted host 모두 처리. trusted source 라 정규식 충분
- 재발방지 [A3]: scripts/check-jsdom-deps.sh + package.json prebuild hook. jsdom-가족 패키지 (isomorphic-dompurify, jsdom, happy-dom) import 시 빌드 차단
- 재발방지 [B1]: package.json 에서 isomorphic-dompurify dependency 제거. dead dep + 공격 표면 ↓
- 재발방지 [A2]: .github/workflows/prod-smoke.yml — main push 후 120초 대기 → 핵심 endpoint 52개 (public 200 + admin 307 + API 401) 자동 verify. 매일 0:00 UTC 정기 health check 도
- 재발방지 [B3]: app/error.tsx + global-error.tsx 가 error.digest + URL + timestamp 표시 + 클립보드 복사 button. 사용자가 관리자에게 logs 추적 정보 빠르게 전달
- 교훈: prod issue 시 첫 단계는 항상 Vercel Function logs 확보. 코드 추측 push 보다 우선. dev 통과 ≠ prod 통과 (module resolution / runtime 차이)