docs: HWP 지원 구현 문서 작성 및 매트릭스 업데이트

- ideas/250916 전략 분석 문서 삭제
- troubleshooting/20251010 실행 문서 작성
  - skill-rag-file 현재 구조 (파일명:줄번호)
  - LibreOffice CLI 구현 계획
  - 테스트 방법 명시
- 매트릭스에서 HWP 처리 전략 항목 제거

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
happybell80 2025-10-10 00:26:23 +09:00
parent 0bd16d80bb
commit e3011106e0
3 changed files with 77 additions and 279 deletions

View File

@ -1,277 +0,0 @@
# 파이썬 기반 HWP-PDF 변환 방법론에 대한 전략적 분석
## 1. Executive Summary
본 보고서는 파이썬(Python) 환경에서 한글(HWP) 문서를 PDF로 변환하는 다양한 기술적 접근법을 심층적으로 분석하고, 각 방법론의 장단점과 비용 구조를 비교하여 최적의 솔루션 선택을 위한 전략적 가이드라인을 제공한다. 분석 결과, 높은 완성도를 보장하는 순수 파이썬 오픈소스 라이브러리는 현재 존재하지 않는다는 결론에 도달했다.
**[현재 프로젝트 상태]** skill-rag-file은 HWP 파일을 지원하지 않음 (app/core/config.py의 ALLOWED_EXTENSIONS에 .hwp 누락, TextExtractor에 HWP 처리 로직 없음, Dockerfile에 LibreOffice 미설치).
HWP 파일 변환의 핵심 과제는 한글과컴퓨터(Hancom Inc.)가 개발한 HWP 포맷의 독점적(proprietary) 특성에서 비롯된다. 공개된 명세가 없는 이 기술적 장벽은 외부 애플리케이션이나 서비스를 활용하는 간접적인 해결책을 강제한다. 따라서 개발자는 단순히 '라이브러리'를 찾는 것이 아니라, 주어진 요구사항에 가장 적합한 '기술적 가교'를 선택하는 문제에 직면하게 된다.
본 보고서는 실질적으로 구현 가능한 세 가지 핵심 전략을 제시하고 분석한다.
* **COM 자동화 (COM Automation):** `pywin32` 라이브러리를 사용하여 윈도우(Windows)에 설치된 한컴오피스를 프로그래밍 방식으로 제어한다. 원본과 동일한, 완벽한 품질의 변환을 보장한다.
* **클라우드 기반 REST API:** 외부 전문 변환 서비스(예: CloudConvert)에 HWP 파일을 전송하여 PDF 결과물을 받는 방식이다. 플랫폼에 독립적이며 확장성이 뛰어나다.
* **명령줄 인터페이스(CLI) 래퍼:** 파이썬 스크립트 내에서 리브레오피스(LibreOffice)와 같은 외부 커맨드라인 도구를 호출하여 변환을 수행한다. 무료이며 여러 운영체제에서 사용 가능하지만, 변환 품질의 일관성은 보장되지 않는다.
최종적으로, 각 전략은 특정 사용 사례에 맞춰 권장된다. 높은 보안이 요구되는 기업 환경에서는 COM 자동화가, 다양한 플랫폼을 지원해야 하는 웹 애플리케이션에는 클라우드 API가, 그리고 비용 제약이 있는 내부 프로젝트에는 CLI 래퍼 방식이 가장 적합한 솔루션으로 평가된다.
## 2. HWP 변환의 기술적 과제: 근본 원인 분석
파이썬 생태계에서 HWP를 PDF로 직접 변환하는 라이브러리를 찾기 어려운 이유는 파이썬 언어의 한계가 아닌, HWP 포맷 자체의 본질적인 특성에 기인한다.
### 2.1. 독점적 파일 포맷의 장벽
HWP는 한글과컴퓨터가 개발하고 소유한 독점적 파일 포맷이다. DOCX나 ODT와 같이 공개된 표준과 달리, HWP 파일의 내부 구조와 데이터 명세는 외부에 공개되어 있지 않다.¹ 이로 인해 제3자 개발자들이 HWP 파일의 내용을 정확하게 해석하고 시각적으로 재현(rendering)하는 파서(parser)를 만드는 것은 기술적으로 매우 어렵다.
### 2.2. 파이썬 생태계에 미치는 영향
이러한 독점적 특성은 파이썬 오픈소스 커뮤니티에서 HWP 지원 라이브러리가 발전하지 못하는 직접적인 원인이 되었다. 파이썬은 `pypdf`³, `PyMuPDF`⁴, `pikepdf`⁵ 등 PDF 문서를 생성하고 조작하는 강력한 라이브러리들을 다수 보유하고 있다. 하지만 이 라이브러리들은 이미 구조화된 PDF를 다루는 데 특화되어 있을 뿐, HWP 파일의 원시 데이터를 읽어 들여 해석하는 기능은 전무하다.
결과적으로, HWP를 PDF로 변환하려는 개발자는 HWP 포맷을 공식적으로 지원하는 외부 소프트웨어에 의존하는 우회적인 방법을 선택할 수밖에 없다.
* `pywin32`는 한컴오피스로의 '가교' 역할을 하고,⁶
* HTTP 요청은 클라우드 API 서버로의 '가교' 역할을 하며,¹
* `subprocess` 모듈은 리브레오피스라는 외부 프로그램으로의 '가교' 역할을 하는 것이 바로 그 증거이다.
> 즉, 문제는 PDF 생성이 아니라 HWP 해석에 있다.
### 2.3. 텍스트 추출과 완전한 변환의 차이
일부 라이브러리는 HWP 파일에서 텍스트를 '추출'하는 기능을 제공하지만, 이는 완전한 '변환'과는 명백히 다르다. 예를 들어, `olefile` 라이브러리는 HWP 파일이 사용하는 OLE(Object Linking and Embedding) 컨테이너 구조를 분석하여 `PrvText`(미리보기 텍스트)나 `BodyText`(본문 텍스트)와 같은 원시 텍스트 스트림을 읽어올 수 있다.⁷
그러나 이 방식은 글꼴, 서식, 이미지, 표, 차트 등 문서의 시각적 레이아웃 정보를 전혀 해석하지 못한다. 따라서 단순한 텍스트 마이닝이나 데이터 분석 목적을 넘어, 원본 문서의 시각적 형태를 그대로 보존해야 하는 PDF 변환 요구사항은 충족시킬 수 없다.
## 3. COM 자동화를 통한 고품질 변환 (Windows 환경)
Windows 환경에서 가장 안정적이고 높은 품질의 변환 결과를 얻을 수 있는 방법은 COM(Component Object Model) 자동화를 통해 로컬에 설치된 한컴오피스를 직접 제어하는 것이다.
### 3.1. 메커니즘 및 아키텍처
COM은 마이크로소프트 윈도우의 핵심 기술로, 서로 다른 애플리케이션 간의 상호 운용성을 지원하는 표준 인터페이스이다. 한컴오피스는 외부 프로그램이 자신을 제어할 수 있도록 COM 인터페이스를 제공한다. 파이썬의 `pywin32` 라이브러리(win32com으로도 알려짐)는 이 COM 인터페이스에 접근할 수 있는 다리 역할을 수행한다.⁶
변환 프로세스는 다음과 같은 순서로 진행된다.
1. 파이썬 스크립트가 `win32.gencache.EnsureDispatch("HWPFrame.HwpObject")` 코드를 통해 한컴오피스 애플리케이션 객체를 생성한다.⁶
2. 생성된 객체의 `Open` 메서드를 호출하여 대상 HWP 파일을 연다.
3. `SaveAs` 메서드를 호출하면서 두 번째 인자로 `"PDF"`를 지정하여 문서를 PDF 포맷으로 저장한다.⁶
4. 변환이 완료되면 `Quit` 메서드를 호출하여 한컴오피스 애플리케이션을 종료한다.
### 3.2. 구현 가이드
**사전 요구사항:**
* Windows 운영체제
* 한컴오피스 소프트웨어 설치 및 정품 라이선스
* `pywin32` 라이브러리 설치 (`pip install pywin32`)⁸
**코드 예제:**
```python
import os
import win32com.client as win32
def convert_hwp_to_pdf_com(hwp_path, pdf_path):
"""
COM 자동화를 사용하여 HWP 파일을 PDF로 변환합니다.
:param hwp_path: 원본 HWP 파일의 전체 경로
:param pdf_path: 저장할 PDF 파일의 전체 경로
"""
hwp = None
try:
hwp = win32.gencache.EnsureDispatch("HWPFrame.HwpObject")
hwp.RegisterModule("FilePathCheckDLL", "SecurityModule") # 보안 모듈 등록
hwp.Open(hwp_path)
# PDF 저장 설정 (필요시 사용)
# 예: hwp.HAction.GetDefault("FileSaveAsPdf", hwp.HParameterSet.HFileOpenSave.HSet)
# hwp.HParameterSet.HFileOpenSave.filename = pdf_path
# hwp.HParameterSet.HFileOpenSave.Format = "PDF"
# hwp.HAction.Execute("FileSaveAsPdf", hwp.HParameterSet.HFileOpenSave.HSet)
hwp.SaveAs(pdf_path, "PDF")
print(f"'{hwp_path}' -> '{pdf_path}' 변환 성공")
except Exception as e:
print(f"변환 중 오류 발생: {e}")
finally:
if hwp:
hwp.Quit()
# 사용 예시
# hwp_file = "C:\path\to\document.hwp"
# pdf_file = "C:\path\to\document.pdf"
# convert_hwp_to_pdf_com(hwp_file, pdf_file)
```
> **중요 고려사항: 보안 승인 모듈**
> 자동화 스크립트로 한컴오피스를 제어할 때, "한글을 이용하여 위 파일에 접근하려는 시도가 있습니다"와 같은 보안 경고 팝업이 발생할 수 있다.⁶ 완전한 자동화를 위해서는 이 팝업을 비활성화해야 한다. 이를 위해 한컴에서 제공하는 보안 승인 모듈을 다운로드하고 레지스트리에 등록하는 과정이 필요하다.⁹ 이는 무인 환경에서 스크립트가 중단 없이 실행되기 위한 필수적인 절차이다.
### 3.3. 장점 및 단점 분석
* **장점:**
* **최상의 변환 품질:** HWP 문서를 만든 네이티브 애플리케이션이 직접 변환을 수행하므로, 모든 요소가 원본과 동일하게 보존된다.
* **세부적인 제어 기능:** PDF의 세부 속성을 프로그래밍 방식으로 제어할 수 있다.¹⁰
* **높은 보안성:** 모든 변환 과정이 로컬에서 이루어져 데이터 유출 위험이 없다.
* **단점:**
* **플랫폼 종속성:** 오직 윈도우 운영체제에서만 작동한다.
* **소프트웨어 의존성:** 한컴오피스 전체 버전이 설치되어 있어야 한다.
* **자원 소모 및 프로세스 관리:** 상당한 시스템 자원을 소모하며, 견고한 예외 처리가 필요하다.
### 3.4. 비용 구조 분석
이 솔루션은 한컴오피스 소프트웨어 라이선스 구매 비용이 발생한다.
* **구독형 모델:** '한컴독스' 기업용 플랜은 1인당 월 8,250원¹⁷ 또는 월 7.00 달러¹⁹ 수준이다.
* **영구 라이선스:** '한컴오피스 2024 기업용'은 약 46만 원 ~ 51만 원.²⁰
* **볼륨 라이선스 (ALA):** 다수 사용자 대상 연간 계약.²⁰
총 소유 비용(TCO)에는 윈도우 서버 라이선스 및 유지보수 비용도 포함되어야 한다.
## 4. 클라우드 기반 REST API를 이용한 플랫폼 독립적 변환
운영체제에 구애받지 않고 유연하게 HWP 변환 기능을 구현해야 할 경우, 외부 전문 서비스를 활용하는 클라우드 기반 REST API가 효과적인 대안이 될 수 있다.
### 4.1. 메커니즘 및 아키텍처
클라이언트(파이썬 스크립트)가 HTTP 요청으로 HWP 파일을 API 서버에 전송하면, 서버가 PDF로 변환하여 결과를 응답으로 돌려주는 방식이다.
### 4.2. 주요 서비스 제공업체 및 구현
* **CloudConvert:** HWP to PDF 변환을 지원하는 대표적인 서비스.¹ `requests` 라이브러리로 연동 가능하다.
* **CoolUtils:** 온라인 변환 서비스 및 데스크톱/서버용 소프트웨어 판매.²⁴
* **기타 서비스:** Allinpdf,²⁶ FreeConvert²⁸ 등.
### 4.3. 장점 및 단점 분석
* **장점:**
* **크로스 플랫폼 호환성:** 모든 OS에서 작동한다.
* **로컬 의존성 없음:** 별도 소프트웨어 설치가 불필요하다.
* **높은 확장성:** 인프라 관리가 필요 없다.
* **단점:**
* **데이터 프라이버시 및 보안:** 민감 정보를 외부 서버에 업로드해야 한다.
* **지속적인 운영 비용:** 사용량 기반 또는 구독 모델로 비용이 계속 발생한다.
* **네트워크 의존성 및 지연 시간:** 인터넷 연결이 필수이며, 속도 저하가 발생할 수 있다.
* **제한적인 제어:** API가 제공하는 범위 내로 기능이 한정된다.
### 4.4. 비용 구조 분석
* **CloudConvert:** '변환 크레딧'이라는 과금 체계를 사용한다.¹
* **CoolUtils:** 주로 소프트웨어 라이선스 형태로 판매 (서버 라이선 $750).²⁵
> 클라우드 API 선택은 리스크 관리 및 규정 준수(compliance)에 대한 결정이기도 하다. 서비스 제공업체의 보안 정책, ISO 27001 인증¹, 데이터 처리 계약(DPA) 등을 검토하는 '신뢰 비용(Trust Tax)'이 발생할 수 있다.
## 5. 오픈소스 대안: CLI 도구 활용
비용을 최소화하면서 크로스 플랫폼을 지원해야 하는 경우, 파이썬에서 외부 명령줄 인터페이스(CLI) 도구를 호출하는 방식이 대안이 될 수 있다.
### 5.1. 메커니즘 및 아키텍처
파이썬의 `subprocess` 모듈을 사용하여 리브레오피스(LibreOffice)와 같은 외부 프로그램을 실행하고 파일 변환을 오케스트레이션한다.
### 5.2. 주요 도구: 리브레오피스 (LibreOffice)
리브레오피스는 HWP 파일 가져오기 기능을 일부 지원한다. 아래 명령어로 변환을 수행할 수 있다.
```bash
soffice --headless --convert-to pdf <입력파일.hwp> --outdir <출력경로>
```
`--headless` 플래그는 GUI 없이 백그라운드에서 작업을 수행하게 한다.³⁰
**파이썬 코드 예제:**
```python
import subprocess
import os
def convert_hwp_to_pdf_libreoffice(hwp_path, output_dir):
"""
LibreOffice CLI를 사용하여 HWP 파일을 PDF로 변환합니다.
:param hwp_path: 원본 HWP 파일의 경로
:param output_dir: PDF 파일을 저장할 디렉토리
"""
if not os.path.exists(hwp_path):
print(f"오류: 파일이 존재하지 않습니다 - {hwp_path}")
return
try:
# OS별 soffice 경로
# Windows: "C:\Program Files\LibreOffice\program\soffice.exe"
# Linux: "libreoffice" or "soffice"
# macOS: "/Applications/LibreOffice.app/Contents/MacOS/soffice"
soffice_path = "soffice" # 시스템 PATH에 등록되어 있다고 가정
command = [
soffice_path,
"--headless",
"--convert-to", "pdf",
hwp_path,
"--outdir", output_dir
]
result = subprocess.run(command, check=True, capture_output=True, text=True)
print(f"LibreOffice 변환 성공. 출력:
{result.stdout}")
except FileNotFoundError:
print("오류: 'soffice' 명령을 찾을 수 없습니다. LibreOffice가 설치되어 있고 PATH에 등록되었는지 확인하세요.")
except subprocess.CalledProcessError as e:
print(f"LibreOffice 변환 실패. 오류:
{e.stderr}")
# 사용 예시
# hwp_file_path = "/path/to/document.hwp"
# pdf_output_dir = "/path/to/output"
# convert_hwp_to_pdf_libreoffice(hwp_file_path, pdf_output_dir)
```
### 5.3. 장점 및 단점 분석
* **장점:**
* **무료:** 소프트웨어 라이선스 비용이 없다.
* **크로스 플랫폼:** Windows, Linux, macOS를 모두 지원한다.
* **일괄 처리 지원:** 스크립트를 통한 대량 변환에 용이하다.³²
* **단점:**
* **가변적인 변환 품질:** 가장 결정적인 약점. 리버스 엔지니어링 기반이므로 레이아웃이 깨질 수 있다.
* **무거운 의존성:** 리브레오피스 스위트 전체를 서버에 설치해야 한다.
* **성능:** 프로세스를 새로 시작해야 하므로 속도가 느릴 수 있다.
> 이 접근법은 '품질 대 자유(Fidelity vs. Freedom)'의 트레이드오프를 보여준다. 공식 문서보다는 내용 확인이나 미리보기 생성 등 비핵심 업무에 적합하다.
## 6. 고려하지 않아야 할 접근법 및 흔한 함정
* **`olefile`은 텍스트 추출 전용:** 시각적 구조 렌더링 기능이 없다.⁷
* **유지보수가 중단된 라이브러리 (`hwp2pdf`):** GitHub 저장소에 'unmaintained'로 명시되어 있으며,³³ 프로덕션 사용은 심각한 리스크를 초래한다.
* **범용 PDF 처리 라이브러리 (`PyMuPDF`, `pypdf` 등):** HWP 소스 파일을 해석하는 기능이 없다.³
## 7. 솔루션 선택을 위한 비교 프레임워크
최적의 솔루션은 프로젝트의 운영 환경, 예산, 보안 요구사항, 품질 허용 범위에 따라 달라진다.
**HWP-PDF 변환 방법론 비교 매트릭스**
| 기능 | COM 자동화 (pywin32) | 클라우드 API (예: CloudConvert) | CLI 래퍼 (LibreOffice) |
| :--- | :--- | :--- | :--- |
| **OS 호환성** | Windows 전용 | Windows, macOS, Linux | Windows, macOS, Linux |
| **주요 의존성** | 한컴오피스 라이선스 | 인터넷 연결, API 구독 | 리브레오피스 스위트 설치 |
| **변환 품질** | 매우 높음 (네이티브) | 높음 ~ 매우 높음 (독자적 엔진) | 중간 ~ 높음 (리버스 엔지니어링) |
| **비용 모델** | 자본/운영 비용 | 운영 비용 (사용량 기반) | 무료 (숨겨진 유지보수 비용) |
| **성능** | 높음 (로컬 처리) | 네트워크에 의존 | 중간 (프로세스 오버헤드) |
| **보안/프라이버시**| 매우 높음 (On-Premise) | 낮음 ~ 중간 (외부 업로드) | 매우 높음 (On-Premise) |
| **설정 난이도** | 중간 | 쉬움 | 중간 |
| **이상적인 사용 사례**| 보안이 중요한 기업 백오피스 | 대국민 웹/모바일 서비스 | 예산 제한적인 내부 도구 |
## 8. 전략적 권장사항 및 최종 결론
### 8.1. 시나리오 1: Windows 기반의 기업 환경
* **권장 솔루션:** **COM 자동화 (pywin32)**
* **근거:** 최고의 변환 품질과 완벽한 데이터 보안을 보장한다.
### 8.2. 시나리오 2: 크로스 플랫폼 웹 또는 모바일 애플리케이션
* **권장 솔루션:** **신뢰할 수 있는 클라우드 API (예: CloudConvert)**
* **근거:** 플랫폼 독립성과 확장성을 제공하는 가장 현실적인 해결책이다. 단, 제공업체에 대한 보안 검토가 필수적이다.
### 8.3. 시나리오 3: 예산이 제한적이거나 Linux 중심의 개발 환경
* **권장 솔루션:** **리브레오피스 CLI 래퍼 (주의하여 사용)**
* **근거:** 무료로 사용할 수 있는 유일한 크로스 플랫폼 방법이다. 단, 도입 전 충분한 품질 테스트가 반드시 필요하다.
### 8.4. 최종 결론
> HWP를 PDF로 변환하는 '최고의' 단일 방법은 존재하지 않는다. 최적의 선택은 전적으로 주어진 프로젝트의 기술적 아키텍처, 비즈니스 요구사항, 그리고 리스크 허용 범위에 달려있다. 본 보고서는 각 접근법의 전략적 트레이드오프를 명확히 제시함으로써, 개발자와 의사결정권자가 자신의 상황에 가장 부합하는 현명한 결정을 내릴 수 있도록 필요한 분석적 토대를 제공한다.

View File

@ -10,8 +10,7 @@
4. **rb8001 리팩토링** - 계획 단계, 미구현 (3주) [→250914](../ideas/250914_rb8001_리팩토링_계획.md)
5. **네이버웍스 캘린더 연동** - 가이드만 존재, 미구현 (2주) [→250917](../troubleshooting/250917_네이버웍스_캘린더_API_연동_가이드.md)
6. **Slack 캔버스 통합** - 아이디어 단계, 미구현 (2주) [→250916](../ideas/250916_슬랙_캔버스_API_활용_방안.md)
7. **HWP 처리 전략** - 전략 분석만 완료, 미구현 (1주) [→250916](../ideas/250916_HWP-PDF_변환_전략_분석.md)
8. **news 엔드포인트 리팩토링** - DB 영속화 완료(250920), 서비스 레이어 리팩토링 미완 (1주) [→250920_db](../troubleshooting/250920_news_db_persistence_implementation.md)
7. **news 엔드포인트 리팩토링** - DB 영속화 완료(250920), 서비스 레이어 리팩토링 미완 (1주) [→250920_db](../troubleshooting/250920_news_db_persistence_implementation.md)
## 🟡 Fill-ins (낮은 중요도 + 쉬운 구현) → 시간 날 때
1. **scheduled_tasks 테이블** - 미구현 (스키마만 존재) (3시간) [→250827](../troubleshooting/250827_frontend_backend_preferences_API_연동_완료.md)

View File

@ -0,0 +1,76 @@
# skill-rag-file HWP 지원 구현
**작성일**: 2025-10-10
**작성자**: Claude (로컬 개발자)
**상태**: 실행 예정
## 목표
skill-rag-file에 HWP 파일 처리 기능 추가 (LibreOffice CLI 방식)
## 현재 상태
### 미지원 확인
- **config.py:33-36** - ALLOWED_EXTENSIONS에 .hwp 누락
- **text_extractor.py:15-57** - extract()에 .hwp 처리 로직 없음
- **Dockerfile:6-9** - LibreOffice 미설치
### 선택한 방식
**LibreOffice CLI 래퍼** (무료, 크로스 플랫폼)
- HWP → PDF 변환 후 텍스트 추출
- 명령어: `soffice --headless --convert-to pdf <hwp파일> --outdir <경로>`
- 출처: `/DOCS/ideas/250916_HWP-PDF_변환_전략_분석.md`
## 구현 계획
### 1. Dockerfile 수정
- **위치**: skill-rag-file/Dockerfile:6-9
- **추가**: `libreoffice --headless` 설치
### 2. config.py 수정
- **위치**: skill-rag-file/app/core/config.py:33-36
- **추가**: `".hwp"` to ALLOWED_EXTENSIONS
### 3. text_extractor.py 수정
- **위치**: skill-rag-file/app/services/text_extractor.py
- **extract() 메서드:15-57** - `.hwp` 분기 추가
- **신규 메서드** - `_extract_hwp(file_path)` 추가
- subprocess로 soffice 호출
- HWP → PDF 변환
- PyPDF2로 텍스트 추출
### 4. 배포
- docker-compose down && up --build
- Gitea Actions 자동 배포
## 테스트 방법
### 로컬 테스트
```bash
# LibreOffice 설치 (Ubuntu)
apt-get install -y libreoffice --no-install-recommends
# 변환 테스트
soffice --headless --convert-to pdf test.hwp --outdir /tmp
```
### API 테스트
```bash
# 파일 업로드
curl -X POST http://localhost:8508/api/v1/upload \
-H "Authorization: Bearer {TOKEN}" \
-F "file=@test.hwp" \
-F "user_uuid={UUID}"
```
## 주의사항
1. **변환 품질**: 리버스 엔지니어링 기반, 레이아웃 깨질 수 있음
2. **성능**: soffice 프로세스 시작 오버헤드 있음
3. **Dockerfile 크기**: LibreOffice 추가 시 ~300MB 증가
4. **에러 처리**: subprocess 실패 시 적절한 로그 필요
## 참고 문서
- `/DOCS/ideas/250916_HWP-PDF_변환_전략_분석.md` - 전략 분석
- `/DOCS/300_architecture/311_FastAPI_구조_원칙.md` - 계층 분리 원칙