chore: 저장소 구조 정리 및 문서화, 첫 커밋

- src/dist 산출물 분리 원칙 정리(.gitignore, .gitattributes)
- 루트 및 주요 폴더(config/scripts/prompts/tests/src, 런타임 폴더 5종)에
  안내용 README.md 추가
- CHANGELOG.md, LICENSE, docs/ops/05-release-and-versioning.md 추가
- docs/README.md 문서 지도 갱신
This commit is contained in:
Yun Chan 2026-09-04 09:25:44 +09:00
commit 56a6e2da93
159 changed files with 145825 additions and 0 deletions

238
README.md Normal file
View file

@ -0,0 +1,238 @@
# DMF Crawler
식약처 **원료의약품등록(DMF) 현황**을 매일 아침 자동으로 받아와, 어제와 달라진 것(신규·변경·취하)을 찾아
엑셀 리포트로 만들어 주는 프로그램입니다. PC 를 켜 두기만 하면 사람이 할 일은 없습니다.
- **자료 출처**: 식품의약품안전처 「원료의약품등록(DMF)현황」. 공공데이터포털 인증키가 있으면 공식 Open API 를 우선 사용하고, 키가 없거나 브라우저 모드를 고르면 AGY가 보이는 Chrome으로 의약품안전나라 엑셀을 내려받습니다.
- **동작 환경**: Windows 11, Python 3.11 이상
- **결과물**: `reports\DMF_리포트_최신.xlsx` (매일 갱신)
---
## 1. 5분 설치
### 1-1. 준비물
| 준비물 | 확인 방법 | 없으면 |
|---|---|---|
| Python 3.11 이상 | PowerShell 에서 `python --version` | https://www.python.org/downloads/ 에서 설치. 설치 화면에서 **Add python.exe to PATH** 를 반드시 체크 |
공공데이터포털 인증키는 **선택**입니다. 키가 없어도 설치·스케줄 등록은 막지 않습니다. 키가 없으면 AGY가 보이는 Chrome으로 의약품안전나라 DMF 엑셀을 내려받습니다. 공식 API 수집을 쓰고 싶을 때만 아래 2절에서 등록하면 됩니다.
### 1-2. 설치 실행
탐색기에서 설치 폴더를 열고 **`bootstrap.cmd` 를 더블클릭**합니다. 다음 일이 순서대로 일어납니다.
1. `.venv` 가상환경 생성
2. 의존성 3개 설치 (`httpx`, `XlsxWriter`, `jsonschema`)
3. 바탕화면에 바로가기 2개 생성 — **DMF 설정**, **지금 실행**
4. 설정 창(온보딩 마법사) 자동 실행
명령줄로 하고 싶다면 PowerShell 에서:
```powershell
cd D:\workspace\DMF_Crawler
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -e .
.\.venv\Scripts\python.exe -m dmf_crawler doctor
```
`doctor` 가 항목별로 통과/실패를 표로 보여 줍니다. 실패 항목은 무엇을 하면 되는지 함께 알려 줍니다.
---
## 2. 공식 API 인증키 등록 (선택)
공공데이터포털 인증키는 선택입니다. 없어도 기존 자료 리포트 생성은 계속되고, 등록하면 공식 Open API 최신 수집이 켜집니다.
### 2-1. 발급받기
1. https://www.data.go.kr 회원가입·로그인
2. https://www.data.go.kr/data/15057075/openapi.do 접속
3. **활용신청** 클릭 → 활용 목적을 적고 신청
4. 승인되면 **마이페이지 → 데이터활용 → 오픈API → 개발계정** 에서 인증키 확인
5. **Decoding 키**(디코딩된 일반 인증키)를 복사합니다. Encoding 키가 아닙니다.
> 개발계정은 하루 10,000건까지 호출할 수 있습니다. 이 프로그램은 하루 100건 남짓 쓰므로 넉넉합니다.
### 2-2. 등록하기
바탕화면의 **DMF 설정** 바로가기를 더블클릭 → `공공데이터포털 인증키` 항목의 **[인증키 입력]** 버튼 →
복사한 키를 붙여넣고 저장.
저장하면 곧바로 실제 호출 1건으로 키가 유효한지 확인합니다. 키는 **Windows DPAPI 로 암호화**되어
`%LOCALAPPDATA%\DMF_Crawler\service_key.bin` 에 저장되며, 이 PC 의 이 계정에서만 풀립니다.
설정 파일이나 로그에는 절대 남지 않습니다.
### 2-3. AGY headful 브라우저 수집 / AI 요약 (선택)
공식 API 키가 없거나 `config\config.toml``source.mode``browser`이면 `agy`가 보이는 Chrome을 조작해 의약품안전나라 DMF 엑셀을 내려받습니다. 이 경우 AGY 설치와 Google 로그인이 필요할 수 있습니다.
AI 한 줄 요약도 `agy`를 씁니다. 설정 창의 `AGY 수집/AI 요약` 항목에서 **[설치]** → **[로그인]** 을 차례로 누르면 됩니다.
**AGY가 없어도 막히지는 않습니다.** 공식 API 키가 있으면 API로 수집하고, 수집이 실패하면 마지막 성공 자료로 리포트를 만듭니다.
---
## 3. 수동 실행
바탕화면의 **지금 실행** 바로가기를 눌러도 되고, PowerShell 에서 직접 실행해도 됩니다.
```powershell
cd D:\workspace\DMF_Crawler
# 전체 파이프라인 1회 실행 (수집 → 비교 → 저장 → 리포트)
.\.venv\Scripts\python.exe -m dmf_crawler run
# 오늘 이미 성공했더라도 다시 실행
.\.venv\Scripts\python.exe -m dmf_crawler run --force
# 수집 없이 리포트만 다시 만들기 (엑셀 파일이 깨졌을 때)
.\.venv\Scripts\python.exe -m dmf_crawler report-only
# 진단 (설치·인증키·DB·작업 등록 상태를 한 번에 확인)
.\.venv\Scripts\python.exe -m dmf_crawler doctor
# 자동 실행 등록 / 해제
.\.venv\Scripts\python.exe -m dmf_crawler install-task
.\.venv\Scripts\python.exe -m dmf_crawler uninstall-task
```
`pip install -e .` 로 설치했다면 `dmf run`, `dmf doctor` 처럼 짧게 쓸 수도 있습니다.
### 종료 코드
| 코드 | 뜻 |
|---|---|
| `0` | 정상. **리포트 파일이 만들어졌습니다** (부분 성공·건너뜀 포함) |
| `1` | 실패. 리포트가 만들어지지 않았습니다. 다시 시도할 가치가 있습니다 |
| `2` | 전제조건 미충족(설정 오류, DB 손상 등). 다시 시도해도 같은 결과입니다. 인증키 없음만으로는 `2`가 되지 않습니다 |
| `130` | 사용자가 중단(Ctrl+C) |
### 첫 며칠은 변경분이 비어 있습니다
첫 실행은 **기준선을 세우는 날**입니다. 비교할 어제가 없으므로 전체 건수를 그대로 담고
신규 0건으로 기록합니다. 다음 날부터 변경분이 채워집니다. 정상 동작입니다.
---
## 4. 결과물 보는 법
| 경로 | 내용 |
|---|---|
| `reports\DMF_리포트_최신.xlsx` | **평소에는 이 파일만 보면 됩니다.** 항상 최신본입니다 |
| `reports\DMF_리포트_2026-09-02.xlsx` | 날짜별 보관본 |
| `logs\run_20260902_060013\pipeline.log` | 그날 무슨 일이 있었는지 사람이 읽는 기록 |
| `logs\run_20260902_060013\events.jsonl` | 같은 내용의 기계 판독용 기록 |
| `data\raw\2026-09-02\` | 그날 API 가 준 원문. 나중에 다시 해석할 수 있게 그대로 보관합니다 |
| `backup\dmf_2026-09-02.sqlite3` | 자동 백업본 |
리포트 첫 장은 **대시보드**입니다. 오늘 몇 건이 신규·변경·취하됐는지, 무엇을 먼저 봐야 하는지가
맨 위에 옵니다. 나머지 시트로 가는 링크도 여기 있습니다.
---
## 5. 장애 대응 — 증상별 5분 가이드
문제가 생기면 프로그램이 먼저 알려 줍니다. 알림은 항상 네 가지를 말합니다:
**무엇이 / 왜 / 어떻게 고치는지 / 지금 무엇을 누르면 되는지.**
그래도 막히면 아래 표를 보세요.
| 증상 | 원인 | 대응 |
|---|---|---|
| **리포트가 어제 날짜 그대로다** | 06:00 배치가 돌지 않았다 | `doctor` 실행 → `최근 실행 상태` 항목 확인. 바탕화면 **지금 실행** 을 눌러 즉시 수집 |
| **"인증키를 사용할 수 없습니다"** | 키 만료·오타·활용신청 만료 | 설정 창 → [인증키 입력] 으로 재입력. 포털 마이페이지에서 키 상태 확인 |
| **"하루 호출 한도를 넘겼습니다"** | 개발계정 10,000건 초과 | 오늘은 그대로 두면 됩니다. 내일 06:00 에 자동 재시도. 반복되면 포털에서 운영계정 신청 |
| **"오늘 받은 자료가 평소와 크게 다릅니다"** | 안전장치가 비교를 막았다 | **정상 동작입니다.** `data\raw\<날짜>\` 의 원문을 확인하고, 진짜 대량 변동이면 `config.local.toml``integrity.max_churn_ratio` 를 올린 뒤 `run --force` |
| **"리포트 파일이 열려 있어 덮어쓰지 못했습니다"** | 엑셀로 파일을 열어 둔 상태 | 엑셀을 닫고 `report-only` 실행. 그동안의 결과는 다른 이름으로 이미 저장돼 있습니다 |
| **"AGY 로그인이 필요합니다" 또는 "AI 로그인이 만료됐습니다"** | headful 브라우저 수집 또는 AI 요약에 필요한 Google 인증 만료 | 설정 창 → [로그인] → 재로그인(1분). 공식 API 키가 있거나 마지막 성공 자료가 있으면 리포트는 계속 생성됩니다 |
| **"자료 보관소 파일이 손상됐습니다"** | DB 손상 | 설정 창 → [백업으로 복원] → 최근 백업 선택. 복원 후 `run --force` |
| **"자동 실행이 등록돼 있지 않습니다"** | 작업 스케줄러 항목 삭제됨 | 설정 창 → [작업 다시 등록], 또는 `install-task` |
| **아무 창도 안 뜨고 조용하다** | 알림 에이전트가 죽었다 | `doctor` 로 확인. 로그오프 상태였다면 다음 로그온 때 밀린 알림이 한 번에 표시됩니다 |
| **파이썬 자체가 안 돌아간다** | venv 손상 | `bootstrap.cmd` 를 다시 실행. 기존 데이터는 지워지지 않습니다 |
### 도움을 요청할 때
아래 세 가지를 함께 보내면 원인 파악이 훨씬 빠릅니다.
1. `doctor` 실행 결과 (`python -m dmf_crawler doctor > 진단.txt`)
2. 문제가 난 날의 `logs\run_*\pipeline.log`
3. `state\alerts.json`
세 파일 모두 **비밀 값은 자동으로 가려진 상태**로 기록됩니다(인증키는 `***` 로 표시).
---
## 6. 설정 바꾸기
| 무엇을 | 어디를 |
|---|---|
| 이 PC 만의 값(백업 드라이브, 리포트 폴더, 실행 시각) | `config\config.local.toml``config.local.toml.example` 을 복사해 쓰세요 |
| 모든 PC 공통 기본값 | `config\config.toml` |
| 인증키·메신저 주소 같은 비밀 값 | **설정 파일이 아니라 설정 창에서** 입력합니다(암호화 저장) |
값을 바꾼 뒤에는 `python -m dmf_crawler doctor` 로 확인하세요. 오타가 있으면 어떤 키가 잘못됐는지
줄 단위로 알려 줍니다.
---
## 7. 폴더 구조
```
DMF_Crawler\
├─ bootstrap.cmd 최초 설치 진입점
├─ CHANGELOG.md 버전별 변경 이력
├─ LICENSE 라이선스 고지
├─ config\ 설정 (config.toml + PC별 config.local.toml) → config\README.md
├─ prompts\ AI 요약 프롬프트 템플릿 → prompts\README.md
├─ scripts\ 작업 스케줄러 등록·바로가기 생성 스크립트 → scripts\README.md
├─ src\dmf_crawler\ 프로그램 본체 (git 추적 대상은 여기뿐이다) → src\dmf_crawler\README.md
├─ tests\ 테스트 → tests\README.md
├─ data\ DB 와 API 원문 보관 (자동 생성, git 미추적) → data\README.md
├─ state\ 상태 파일 — 마지막 성공 시각, 미해소 알림 (자동 생성) → state\README.md
├─ logs\ 실행 로그 (자동 생성, git 미추적) → logs\README.md
├─ reports\ 엑셀 리포트 (자동 생성, git 미추적) → reports\README.md
├─ backup\ DB 백업 (자동 생성, git 미추적) → backup\README.md
├─ dist\ / build\ `python -m build` 산출물 (git 미추적, §9 참고)
└─ docs\ 설계 문서. 코드와 어긋나면 문서가 정본입니다 → docs\README.md
```
각 폴더의 `README.md`는 그 폴더 안에서만 통하는 세부 사항(추적 여부, 파일별 역할)을
안내한다. 전체 아키텍처와 모듈 계약의 정본은 `docs\design\01-architecture.md`다.
---
## 8. 빌드와 릴리스
이 저장소는 **소스(`src\`)와 빌드 산출물(`dist\`, `build\`)을 분리**한다. `dist\`는 언제나
`src\`에서 다시 만들 수 있어야 하므로 git에 올리지 않는다.
```powershell
.\.venv\Scripts\python.exe -m pip install --upgrade build
.\.venv\Scripts\python.exe -m build # dist\dmf_crawler-X.Y.Z-py3-none-any.whl 생성
```
버전 번호 규칙, git 태그, 릴리스 절차, 최종 사용자 zip 배포 방법은
`docs\ops\05-release-and-versioning.md`가 정본이다. 버전별 변경 이력은
루트 `CHANGELOG.md`에 있다.
이 저장소의 정본 원격은 `git.chanpaca.net`(공개)이다.
---
## 9. 자세한 내용
| 알고 싶은 것 | 문서 |
|---|---|
| 무엇을 만들려는 것인가 | `docs\00-REQUIREMENTS.md` |
| 왜 크롤링이 아니라 공식 API 인가 | `docs\design\00-DATA-SOURCE-DECISION.md` |
| 전체 구조와 모듈 계약 | `docs\design\01-architecture.md` |
| 데이터 모델과 변경 탐지 규칙 | `docs\design\02-data-model.md` |
| 리포트 시트 명세 | `docs\design\03-xlsx-report-spec.md` |
| 설정 창 화면 명세 | `docs\design\04-onboarding-wizard.md` |
| 자동 실행과 장애 복구 운영 | `docs\ops\01-scheduling-and-resilience.md`, `docs\ops\02-failure-alerting.md` |
| API 이용 정책 준수 기록 | `docs\ops\03-api-usage-policy.md` |
| 버전·태그·릴리스 절차 | `docs\ops\05-release-and-versioning.md` |
| 버전별 변경 이력 | `CHANGELOG.md` |
| AI agent 작업 지침(TDD/RED) | `AGENTS.md` |