- QMS: InspectionModal/InspectionModalV2 개선, mockData 정리 - 전자결재: DocumentCreate 기능 수정 - 생산대시보드: ProductionDashboard 개선 - 템플릿: IntegratedDetailTemplate/UniversalListPage 기능 수정 - 문서: i18n 가이드 업데이트, 문서뷰어 아키텍처 계획 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
11 KiB
11 KiB
문서 뷰어 아키텍처 설계
품질인정심사 1일차 기준/매뉴얼 문서 및 범용 문서 뷰어 구현 방안
1. 배경
품질인정심사 시스템의 1일차(기준/매뉴얼 심사)에서 작업표준서, 검사기준서 등 다양한 포맷의 문서를 웹에서 바로 열람해야 함. 문서 포맷은 HWP, HWPX, Excel, PDF 등 다양하며, 수정 없이 읽기 전용으로 표시하는 것이 목적.
적용 대상
- 품질인정심사 1일차: 스크린 작업표준서, 검사기준서 등
- 향후 확장: ERP 전반의 문서 열람 기능
2. 기술 검토 결과
2.1 HWP 웹 뷰어 현황
| 방식 | HWP | HWPX | Excel | 비용 | 비고 | |
|---|---|---|---|---|---|---|
| LibreOffice headless | ✅ | ✅ | - | ✅ | 무료 | H2Orestart 확장 필요 |
| 한컴 공식 API | ✅ | ✅ | ✅ | ✅ | 엔터프라이즈 | DocsConverter SDK |
| CloudConvert API | ✅ | ✅ | ✅ | ✅ | 월 250건 무료 | 클라우드 의존 |
| hwp.js (클라이언트) | △ | ❌ | ❌ | ❌ | 무료 | HWP 스펙 ~20% 구현, 사실상 폐기 |
| @ssabrojs/hwpxjs | ❌ | ✅ | ❌ | ❌ | 무료 | HWPX만 지원 |
- 웨일 브라우저: 네이티브 한글 뷰어 내장 (브라우저 바이너리에 포함). Chrome에서 재현 불가.
- Google Docs Viewer: HWP 미지원.
- 순수 클라이언트 HWP 렌더링: 신뢰할 수 있는 라이브러리 없음 (2026년 기준).
2.2 결론
순수 클라이언트에서 HWP를 직접 렌더링하는 것은 현실적으로 불가능. 서버사이드 PDF 변환 후 프론트에서 PDF 표시가 유일한 프로덕션 옵션.
3. 채택 아키텍처: 서버사이드 변환 + react-pdf
3.1 전체 흐름
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ 프론트엔드 │ │ Laravel 백엔드 │ │ 파일 스토리지 │
│ (Next.js) │ │ (PHP) │ │ (S3/로컬) │
└──────┬───────┘ └────────┬──────────┘ └────────┬────────┘
│ │ │
│ 1. 문서 열람 요청 │ │
│─────────────────────>│ │
│ │ 2. 원본 파일 조회 │
│ │────────────────────────>│
│ │<────────────────────────│
│ │ │
│ │ 3. PDF 변환 (캐싱) │
│ │ ┌───────────────────┐ │
│ │ │ LibreOffice │ │
│ │ │ --headless │ │
│ │ │ --convert-to pdf │ │
│ │ └───────────────────┘ │
│ │ │
│ │ 4. 변환된 PDF 저장 │
│ │────────────────────────>│
│ │ │
│ 5. PDF URL 반환 │ │
│<─────────────────────│ │
│ │ │
│ 6. react-pdf로 표시 │ │
│ (DocumentViewer 모달)│ │
3.2 백엔드 (Laravel)
변환 방식 A: LibreOffice headless (무료, 자체 호스팅)
# 서버 설치
sudo apt install libreoffice
# H2Orestart 확장 설치 (HWP 필터 지원)
# https://extensions.libreoffice.org/en/extensions/show/27504
# 변환 커맨드
libreoffice --headless --infilter="Hwp2002_File" --convert-to pdf:writer_pdf_Export input.hwp
libreoffice --headless --convert-to pdf:writer_pdf_Export input.hwpx
libreoffice --headless --convert-to pdf:writer_pdf_Export input.xlsx
// Laravel Controller 예시
class DocumentConvertController extends Controller
{
public function convert(Request $request, string $documentId)
{
$document = Document::findOrFail($documentId);
$originalPath = $document->file_path;
$pdfPath = $this->getCachedPdfPath($document);
// 캐시된 PDF가 있으면 바로 반환
if (Storage::exists($pdfPath)) {
return response()->json(['pdf_url' => Storage::url($pdfPath)]);
}
// LibreOffice로 변환
$outputDir = storage_path('app/converted');
$command = sprintf(
'libreoffice --headless --convert-to pdf --outdir %s %s',
escapeshellarg($outputDir),
escapeshellarg(Storage::path($originalPath))
);
exec($command, $output, $returnCode);
if ($returnCode !== 0) {
return response()->json(['error' => '변환 실패'], 500);
}
// 변환된 PDF 저장 및 URL 반환
return response()->json(['pdf_url' => Storage::url($pdfPath)]);
}
}
변환 방식 B: 한컴 API (유료, 높은 정확도)
// 한컴 DocsConverter API 활용
class HancomConvertController extends Controller
{
public function convert(Request $request, string $documentId)
{
$document = Document::findOrFail($documentId);
// 한컴 DocsConverter SDK 호출
// https://developer.hancom.com/docsconverter
$result = HancomSDK::convert($document->file_path, 'pdf');
return response()->json(['pdf_url' => $result->getPdfUrl()]);
}
}
API 엔드포인트 설계
GET /api/documents/{id}/preview → PDF URL 반환 (변환 필요시 자동 변환)
POST /api/documents/upload → 원본 파일 업로드
GET /api/documents/{id}/download → 원본 파일 다운로드
PDF 캐싱 전략
원본 파일 업로드 시점 또는 최초 열람 시점에 PDF 변환
→ converted/{document_id}.pdf로 캐싱
→ 원본 파일 변경 시 캐시 무효화 (파일 해시 비교)
→ 이미 PDF인 파일은 변환 없이 바로 반환
3.3 프론트엔드 (Next.js)
라이브러리
npm install react-pdf
# 또는
npm install @react-pdf-viewer/core @react-pdf-viewer/default-layout
구현 구조
품질인정심사 1일차
├── 점검표 항목 (좌측 패널)
├── 기준 문서화 (우측 패널)
│ └── 문서 클릭 시 → DocumentViewer 모달로 PDF 표시
│ ├── 기존 DocumentViewer 모달 재사용 (zoom/drag/print/PDF)
│ └── 내부에 react-pdf PDF 렌더러 삽입
// 개념 코드 (실제 구현은 기획서 확정 후)
import { Document, Page } from 'react-pdf';
function PdfDocumentViewer({ pdfUrl }: { pdfUrl: string }) {
const [numPages, setNumPages] = useState(0);
return (
<Document
file={pdfUrl}
onLoadSuccess={({ numPages }) => setNumPages(numPages)}
>
{Array.from({ length: numPages }, (_, i) => (
<Page key={i} pageNumber={i + 1} />
))}
</Document>
);
}
모달 통합
기존 DocumentViewer 모달 (2일차에서 사용 중)
├── 헤더: 문서명 + 날짜
├── 툴바: 축소/확대/맞춤/PDF/인쇄/다운로드
├── 본문:
│ ├── 기존: React 컴포넌트 렌더링 (수주서, 성적서 등)
│ └── 추가: PDF 렌더링 (업로드된 HWP/Excel/기타 문서)
4. 지원 포맷별 처리
| 파일 포맷 | 처리 방식 | 변환 필요 |
|---|---|---|
| 바로 표시 | ❌ | |
| HWP | LibreOffice + H2Orestart → PDF | ✅ |
| HWPX | LibreOffice → PDF | ✅ |
| Excel (.xlsx/.xls) | LibreOffice → PDF | ✅ |
| Word (.docx/.doc) | LibreOffice → PDF | ✅ |
| PowerPoint (.pptx) | LibreOffice → PDF | ✅ |
| 이미지 (.png/.jpg) | 바로 표시 (img 태그) | ❌ |
5. 서버 환경 요구사항
LibreOffice 방식
# Docker 예시
FROM php:8.2-fpm
RUN apt-get update && apt-get install -y libreoffice default-jre
# H2Orestart 확장 설치
COPY h2orestart.oxt /tmp/
RUN libreoffice --headless --norestore --nofirststartwizard \
"macro:///Tools.Install.installOxt(/tmp/h2orestart.oxt)"
| 항목 | 요구사항 |
|---|---|
| LibreOffice | 7.x 이상 |
| JRE | 8 이상 (H2Orestart용) |
| 디스크 | LibreOffice ~500MB + 변환 캐시 |
| 메모리 | 변환당 ~200-500MB |
| 주의사항 | LibreOffice는 thread-safe하지 않음 → 동시 변환 시 큐 처리 필요 |
한컴 API 방식
| 항목 | 요구사항 |
|---|---|
| 라이선스 | 엔터프라이즈 B2B (한컴 영업팀 문의) |
| SDK | DocsConverter SDK (서버 설치) |
| 장점 | HWP 변환 정확도 최고 |
| 단점 | 비용, 라이선스 관리 |
6. 1일차 UI 변경 사항 (요약)
현재 구조 (3컬럼)
[ 점검표 항목 ] [ 기준 문서화 ] [ 스크린 작업표준서 뷰어 ]
변경 후 구조 (2컬럼 + 모달)
[ 점검표 항목 ] [ 기준 문서화 ]
│
└── 문서 클릭 → DocumentViewer 모달 (PDF 표시)
- 우측
Day1DocumentViewer패널 제거 - 기준 문서화에서 문서 클릭 시 2일차와 동일한
DocumentViewer모달로 표시 - 모달 내부에서 서버 변환된 PDF를
react-pdf로 렌더링
7. 구현 우선순위
- 백엔드 API: 문서 업로드 + LibreOffice PDF 변환 + 캐싱
- 프론트엔드: react-pdf 통합 + DocumentViewer 모달 연동
- 1일차 UI: 3컬럼 → 2컬럼 레이아웃 변경 + 모달 연동
- 선택사항: 한컴 API 도입 (LibreOffice 변환 품질 불만족 시)
8. 참고 자료
- LibreOffice H2Orestart 확장 - HWP 필터 지원
- react-pdf - PDF 렌더링
- @react-pdf-viewer - PDF 뷰어 (줌/검색/썸네일)
- 한컴 DocsConverter - 한컴 공식 변환 SDK
- CloudConvert HWP to PDF - 클라우드 변환 API (월 250건 무료)
- hwp.js GitHub - 클라이언트 HWP 파서 (참고용, 프로덕션 부적합)
- @ssabrojs/hwpxjs - HWPX 파서 (참고용)