From 909d3e11b8eb6b78ee8f13cbe47171b679fba2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Wed, 11 Mar 2026 09:39:41 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20[standards]=20PDF=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=EC=8B=9C=20=ED=8F=B0=ED=8A=B8=20=EC=A0=95=EC=B1=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 구글 폰트 외부 로드 금지, isRemoteEnabled 금지 - 운영서버 권한 오류 사례 및 긴급 복구 절차 - 시스템 기본 폰트 사용 가이드, 로컬 폰트 설치 방법 --- INDEX.md | 1 + dev/standards/pdf-font-policy.md | 194 +++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 dev/standards/pdf-font-policy.md diff --git a/INDEX.md b/INDEX.md index f9141fc..2808cf3 100644 --- a/INDEX.md +++ b/INDEX.md @@ -104,6 +104,7 @@ DB 도메인별: | [quality-checklist.md](dev/standards/quality-checklist.md) | 품질 체크리스트 | | [pagination-policy.md](dev/standards/pagination-policy.md) | 페이지네이션 표준 | | [options-column-policy.md](dev/standards/options-column-policy.md) | JSON options 컬럼 정책 | +| [pdf-font-policy.md](dev/standards/pdf-font-policy.md) | PDF 생성 시 폰트 정책 (DomPDF) | --- diff --git a/dev/standards/pdf-font-policy.md b/dev/standards/pdf-font-policy.md new file mode 100644 index 0000000..4c705f4 --- /dev/null +++ b/dev/standards/pdf-font-policy.md @@ -0,0 +1,194 @@ +# PDF 생성 시 폰트 정책 + +> **작성일**: 2026-03-11 +> **상태**: 설계 확정 + +--- + +## 1. 개요 + +### 1.1 목적 + +DomPDF로 PDF를 생성할 때 폰트 관련 문제(권한 오류, 외부 의존성, 배포 시 재발)를 방지하기 위한 정책이다. + +### 1.2 배경 — 운영서버 장애 사례 + +급여명세서 PDF 생성 시 500 에러 발생. 원인은 DomPDF가 구글 폰트(Noto Sans KR)를 외부에서 다운로드한 후 캐시 파일(`.ufm`)을 `vendor/dompdf/dompdf/lib/fonts/`에 저장하려는데, `www-data` 유저에 쓰기 권한이 없어서 Permission denied 발생. + +``` +fopen(.../vendor/dompdf/dompdf/lib/fonts/noto_sans_kr_normal_...ufm): +Failed to open stream: Permission denied +``` + +### 1.3 핵심 원칙 + +``` +❌ PDF 뷰에서 구글 폰트(@import, ) 사용 금지 +❌ DomPDF의 isRemoteEnabled 옵션 사용 금지 +✅ 시스템 기본 폰트만 사용 +✅ 폰트가 필요하면 로컬 설치 후 DomPDF에 등록 +``` + +--- + +## 2. 금지 사항 + +### 2.1 구글 폰트 외부 로드 금지 + +``` +❌ @import url('https://fonts.googleapis.com/...'); +❌ +❌ font-face src: url('https://...'); +``` + +### 2.2 isRemoteEnabled 옵션 금지 + +```php +// ❌ 금지 — 외부 리소스 다운로드를 활성화하면 안 됨 +$pdf = Pdf::loadView('view', $data) + ->setOptions(['isRemoteEnabled' => true]); + +// ✅ 올바른 사용 +$pdf = Pdf::loadView('view', $data) + ->setPaper('a4'); +``` + +--- + +## 3. 금지 이유 + +### 3.1 배포 시 권한 문제 재발 + +`composer install`이 `vendor/`를 새로 생성하면 폰트 캐시 디렉토리 권한이 초기화된다. Jenkinsfile에 매번 권한 설정을 추가해야 하는데, `vendor/` 내부 특정 경로에 권한을 거는 것은 안티패턴이다. + +``` +배포 → composer install → vendor/ 재생성 → 폰트 캐시 권한 초기화 → PDF 생성 실패 +``` + +### 3.2 외부 네트워크 의존성 + +PDF를 생성할 때마다 `fonts.googleapis.com`에 요청한다. 외부 서버 장애, 네트워크 지연, 방화벽 차단 시 PDF 생성이 실패한다. 내부 ERP에서 외부 서비스에 의존할 이유가 없다. + +### 3.3 PDF에서 웹폰트 불필요 + +DomPDF는 웹 브라우저가 아니다. 구글 폰트를 다운로드 → 파싱 → 캐싱하는 과정이 불필요한 오버헤드다. 시스템 기본 폰트로 충분하다. + +--- + +## 4. 올바른 폰트 사용법 + +### 4.1 시스템 기본 폰트 사용 (권장) + +```css +/* PDF 뷰(Blade)에서 사용할 font-family */ +body { + font-family: 'Malgun Gothic', 'Apple SD Gothic Neo', sans-serif; +} +``` + +### 4.2 PDF 생성 코드 패턴 + +```php +// ✅ 올바른 PDF 생성 패턴 +$pdf = Pdf::loadView('emails.payslip', ['data' => $data]) + ->setPaper('a4'); + +$pdfContent = $pdf->output(); +``` + +### 4.3 한글 폰트가 필요한 경우 — 로컬 설치 + +시스템 기본 폰트로 부족하면 서버에 폰트를 직접 설치하고 DomPDF에 등록한다. + +```bash +# 1. 서버에 폰트 설치 (Level 2 — 사용자 확인 후 실행) +sudo apt install fonts-noto-cjk + +# 2. DomPDF 폰트 등록 (php artisan 명령) +php artisan dompdf:font "Noto Sans KR" \ + /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc +``` + +> 로컬 설치된 폰트는 `vendor/` 재생성과 무관하게 유지된다. + +--- + +## 5. 기존 코드 수정 가이드 + +구글 폰트를 사용하는 기존 PDF 뷰를 발견하면 다음 절차로 수정한다. + +### 5.1 Blade 뷰에서 제거 + +```html + + + + + +``` + +### 5.2 서비스/컨트롤러에서 제거 + +```php +// ❌ 수정 전 +$pdf = Pdf::loadView('emails.payslip', ['payslipData' => $payslipData]) + ->setOptions(['isRemoteEnabled' => true]) + ->setPaper('a4'); + +// ✅ 수정 후 +$pdf = Pdf::loadView('emails.payslip', ['payslipData' => $payslipData]) + ->setPaper('a4'); +``` + +--- + +## 6. 긴급 복구 — 운영서버 권한 오류 발생 시 + +이미 구글 폰트를 사용하는 코드가 배포되어 권한 오류가 발생한 경우의 즉시 조치이다. 근본 수정(구글 폰트 제거)을 반드시 병행한다. + +```bash +# Level 2 작업 — 사용자 확인 후 실행 +# 운영서버에서 폰트 캐시 디렉토리 권한 수정 +sudo chown -R www-data:webservice /home/webservice/mng/current/vendor/dompdf/dompdf/lib/fonts/ +sudo chmod -R 775 /home/webservice/mng/current/vendor/dompdf/dompdf/lib/fonts/ +``` + +> 이 조치는 임시이다. 재배포 시 `vendor/`가 새로 생성되면 다시 발생한다. + +--- + +## 7. 체크리스트 + +### PDF 뷰 작성 시 + +- [ ] `@import url('https://fonts.googleapis.com/...')` 미포함 +- [ ] `` 미포함 +- [ ] `font-family`에 구글 폰트명 미포함 +- [ ] 시스템 기본 폰트 사용 (`Malgun Gothic`, `sans-serif`) + +### PDF 생성 코드 작성 시 + +- [ ] `isRemoteEnabled` 옵션 미사용 +- [ ] `Pdf::loadView()->setPaper()` 패턴 사용 + +### 코드 리뷰 시 + +- [ ] PDF 관련 Blade 뷰에 외부 폰트 URL 없음 +- [ ] DomPDF 옵션에 `isRemoteEnabled` 없음 + +--- + +## 관련 문서 + +- 서버 운영 매뉴얼: `dev/deploys/ops-manual/README.md` +- DomPDF 패키지: `barryvdh/laravel-dompdf` + +--- + +**최종 업데이트**: 2026-03-11