# 100처방 마스터 데이터 등록 가이드

> AI Agent가 `official_formulas` / `official_formula_ingredients` 테이블을 채울 때 따라야 할 절차와 규칙.

---

## 1. DB 구조

### 1-1. `official_formulas` (처방 기본 정보)

| 컬럼 | 타입 | 설명 | 채워야 하는 값 |
|------|------|------|---------------|
| `official_formula_id` | INTEGER PK | 자동생성 | (이미 존재) |
| `formula_number` | INTEGER | 연번 1~100 | (이미 존재) |
| `formula_name` | TEXT | 처방명 (한글) | (이미 존재) |
| `formula_name_hanja` | TEXT | **한자명** | ✅ 채워야 함 |
| `source_text` | TEXT | 출전 | (이미 존재) |
| `description` | TEXT | **효능 요약** | ✅ 채워야 함 |
| `reference_notes` | TEXT | **상담 참고자료** | ✅ 채워야 함 |

### 1-2. `official_formula_ingredients` (구성 약재)

| 컬럼 | 타입 | 설명 |
|------|------|------|
| `ingredient_id` | INTEGER PK | 자동생성 |
| `official_formula_id` | INTEGER FK | 처방 ID |
| `ingredient_code` | TEXT | **herb_masters.ingredient_code** (예: `3400H1AHM`) |
| `grams_per_cheop` | REAL | **1첩당 그램수** |
| `notes` | TEXT | **역할** (군약/신약/좌약/사약 등) |
| `sort_order` | INTEGER | 정렬 순서 (1부터) |

---

## 2. 등록 절차 (Step-by-Step)

### Step 1: 대상 처방 확인

```sql
-- 미등록 처방 확인 (formula_name_hanja가 NULL이면 미등록)
SELECT official_formula_id, formula_number, formula_name, source_text
FROM official_formulas
WHERE formula_name_hanja IS NULL
ORDER BY formula_number;
```

### Step 2: 원방 조사

출전 서적 기반으로 아래 정보를 조사한다:

1. **한자명** — 예: 四君子湯
2. **효능 요약** — 한의학 용어 + 한자 병기. 예: `보기건비 (補氣健脾)`
3. **구성 약재** — 약재명, 1첩당 그램수, 군신좌사 역할
4. **상담 참고자료** — 출전, 주치, OTC 대비 장점 (1~2문장)

#### 용량 기준 원칙

- **출전(원방)의 현대 환산 용량**을 우선 적용
- 1전(錢) = 3.75g, 1냥(兩) = 37.5g 기준 환산
- 감초는 대부분 사약으로 2~3g (다른 약재보다 적은 것이 일반적)
- 동량(等分) 처방이라도 현대 임상 표준이 차등이면 표준을 따름

#### description 작성 규칙

```
한글효능 (한자효능)
```

예시:
- `발한해기, 생진서근 (發汗解肌, 生津舒筋)`
- `온보기혈 (溫補氣血)`
- `익기해표, 이기화담 (益氣解表, 理氣化痰)`

#### reference_notes 작성 규칙

1문장: 출전 + 주치 증상
나머지: OTC 대비 차별점 또는 첩제만의 장점

```
예: "상한론 원방. 외감풍한으로 인한 두통, 발열, 오한, 항강 증상에 사용. OTC 갈근탕 대비 생약량 2.16배, 생강→건강 대체 없이 원물 사용으로 발한 효과 우수."
```

#### notes(역할) 작성 규칙

| 값 | 의미 |
|----|------|
| `군약` | 주약 (主藥) — 처방의 핵심 |
| `신약` | 보조약 (臣藥) — 군약을 도움 |
| `좌약` | 보좌약 (佐藥) — 부작용 완화 또는 보조 |
| `사약` | 조화약 (使藥) — 제약 조화 (대부분 감초) |

복합 역할인 경우 괄호로 추가 설명:
- `군약(보기)` — 보기 역할의 군약
- `신약(보혈)` — 보혈 역할의 신약

### Step 3: ingredient_code 조회

```sql
-- 약재명으로 성분코드 조회 (정확 매칭 우선)
SELECT ingredient_code, herb_name
FROM herb_masters
WHERE herb_name = '인삼';

-- 정확 매칭 없으면 LIKE 검색
SELECT ingredient_code, herb_name
FROM herb_masters
WHERE herb_name LIKE '%복령%';
```

#### 주의: 동명이약 구분

| 약재 | 올바른 코드 | 주의 |
|------|------------|------|
| 진피(陳皮) | `3466H1AHM` | 진피(秦皮) `3467H1AHM`과 구분 |
| 백출 | `3204H1AHM` | 백출초 `3611H1AHM`, 백출미감침 `3610H1AHM`과 구분 |
| 감초 | `3007H1AHM` | 감초초 `3010H1AHM`, 감초밀자 `3009H1AHM`과 구분 |
| 반하 | `3182H1AHM` | 반하생강백반제 등 포제품과 구분 |
| 마황 | `3147H1AHM` | 마황탕포 `3606H1AHM`과 구분 |

### Step 4: SQL 실행

```sql
-- (1) 기본 정보 업데이트
UPDATE official_formulas SET
    formula_name_hanja = '四君子湯',
    description = '보기건비 (補氣健脾)',
    reference_notes = '화제국방 원방. 비기허로 인한 ...',
    updated_at = CURRENT_TIMESTAMP
WHERE official_formula_id = 38;

-- (2) 구성 약재 INSERT (sort_order는 1부터 순서대로)
INSERT INTO official_formula_ingredients
    (official_formula_id, ingredient_code, grams_per_cheop, notes, sort_order)
VALUES
    (38, '3400H1AHM', 4.0, '군약', 1),   -- 인삼
    (38, '3204H1AHM', 4.0, '신약', 2),   -- 백출
    (38, '3215H1AHM', 4.0, '좌약', 3),   -- 복령
    (38, '3007H1AHM', 2.0, '사약', 4);   -- 감초
```

### Step 5: 검증

```sql
-- 등록 결과 확인
SELECT hm.herb_name, ofi.ingredient_code, ofi.grams_per_cheop, ofi.notes
FROM official_formula_ingredients ofi
JOIN herb_masters hm ON ofi.ingredient_code = hm.ingredient_code
WHERE ofi.official_formula_id = ?
ORDER BY ofi.sort_order;
```

검증 체크리스트:
- [ ] herb_masters에 없는 ingredient_code가 없는지
- [ ] grams_per_cheop이 0 이하인 것이 없는지
- [ ] 중복 ingredient_code가 없는지
- [ ] 1첩 총량이 상식적 범위(10~50g)인지
- [ ] 군약이 최소 1개 이상인지

---

## 3. 등록 완료 예시

### 사군자탕 (四君子湯) — ID:38

| 순서 | 약재 | 성분코드 | 1첩량 | 역할 |
|------|------|----------|-------|------|
| 1 | 인삼 | 3400H1AHM | 4.0g | 군약 |
| 2 | 백출 | 3204H1AHM | 4.0g | 신약 |
| 3 | 복령 | 3215H1AHM | 4.0g | 좌약 |
| 4 | 감초 | 3007H1AHM | 2.0g | 사약 |

- 한자명: 四君子湯
- 설명: `보기건비 (補氣健脾)`
- 1첩 총량: 14.0g

### 갈근탕 (葛根湯) — ID:3

| 순서 | 약재 | 성분코드 | 1첩량 | 역할 |
|------|------|----------|-------|------|
| 1 | 갈근 | 3002H1AHM | 8.0g | 군약 |
| 2 | 마황 | 3147H1AHM | 4.0g | 신약 |
| 3 | 계지 | 3033H1AHM | 3.0g | 좌약 |
| 4 | 작약 | 3419H1AHM | 3.0g | 좌약 |
| 5 | 생강 | 3260H1AHM | 3.0g | 좌약 |
| 6 | 대추 | 3115H1AHM | 4.0g | 좌약 |
| 7 | 감초 | 3007H1AHM | 2.0g | 사약 |

- 한자명: 葛根湯
- 설명: `발한해기, 생진서근 (發汗解肌, 生津舒筋)`
- 1첩 총량: 27.0g

---

## 4. 자주 사용되는 성분코드 (Quick Reference)

| 약재 | ingredient_code | 비고 |
|------|----------------|------|
| 감초 | 3007H1AHM | 사약 역할 빈출 |
| 갈근 | 3002H1AHM | |
| 건강 | 3017H1AHM | 생강 포제품 |
| 계지 | 3033H1AHM | |
| 길경 | 3077H1AHM | |
| 당귀 | 3105H1AHM | |
| 대추 | 3115H1AHM | |
| 마황 | 3147H1AHM | |
| 반하 | 3182H1AHM | |
| 백출 | 3204H1AHM | |
| 복령 | 3215H1AHM | |
| 생강 | 3260H1AHM | |
| 석고 | 3265H1AHM | |
| 세신 | 3285H1AHM | |
| 숙지황 | 3299H1AHM | |
| 오미자 | 3342H1AHM | |
| 인삼 | 3400H1AHM | |
| 자소엽 | 3411H1AHM | |
| 작약 | 3419H1AHM | |
| 전호 | 3433H1AHM | |
| 지각 | 3454H1AHM | |
| 진피(陳皮) | 3466H1AHM | ⚠️ 秦皮와 구분 |
| 천궁 | 3475H1AHM | |
| 황기 | 3583H1AHM | |
| 육계 | 3384H1AHM | |

---

## 5. 미등록 처방 목록 (93개)

| # | 처방명 | 출전 |
|---|--------|------|
| 1 | 가미온담탕 | 의종금감 |
| 4 | 강활유풍탕 | 의학발명 |
| 5 | 계지가용골모려탕 | 금궤요략 |
| 6 | 계지작약지모탕 | 금궤요략 |
| 7 | 곽향정기산 | 화제국방 |
| 8 | 구미강활탕 | 차사난지 |
| 9 | 궁귀교애탕 | 금궤요략 |
| 10 | 귀비탕 | 제생방 |
| 11 | 귀출파징탕 | 동의보감 |
| 12 | 금수육군전 | 경악전서 |
| 13 | 녹용대보탕 | 갑병원류서촉 |
| 14 | 당귀사역가오수유생강탕 | 상한론 |
| 15 | 당귀수산 | 의학입문 |
| 16 | 당귀육황탕 | 난실비장 |
| 17 | 당귀작약산 | 금궤요략 |
| 18 | 대강활탕 | 위생보감 |
| 19 | 대건중탕 | 금궤요략 |
| 20 | 대금음자 | 화제국방 |
| 21 | 대방풍탕 | 화제국방 |
| 22 | 대청룡탕 | 상한론 |
| 23 | 대황목단피탕 | 금궤요략 |
| 24 | 독활기생탕 | 천금방 |
| 25 | 마행의감탕 | 금궤요략 |
| 26 | 마황부자세신탕 | 상한론 |
| 27 | 반하백출천마탕 | 의학심오 |
| 28 | 반하사심탕 | 상한론 |
| 29 | 반하후박탕 | 금궤요략 |
| 30 | 방기황기탕 | 금궤요략 |
| 31 | 방풍통성산 | 선명논방 |
| 32 | 배농산급탕 | 춘림헌방함 |
| 33 | 백출산 | 외대비요 |
| 34 | 보생탕 | 부인양방 |
| 35 | 보중익기탕 | 비위론 |
| 36 | 복령음 | 외대비요 |
| 37 | 분심기음 | 직지방 |
| 39 | 사물탕 | 화제국방 |
| 40 | 삼령백출산 | 화제국방 |
| 42 | 삼출건비탕 | 동의보감 |
| 43 | 삼환사심탕 | 금궤요략 |
| 44 | 생혈윤부탕 | 의학정전 |
| 45 | 세간명목탕 | 중보만병회춘 |
| 46 | 소건중탕 | 상한론 |
| 47 | 소시호탕 | 상한론 |
| 48 | 소요산 | 화제국방 |
| 49 | 소자강기탕 | 화제국방 |
| 50 | 소적정원산 | 의학입문 |
| 52 | 소풍산 | 외과정종 |
| 53 | 소풍활혈탕 | 심씨존생서 |
| 54 | 속명탕 | 금궤요략 |
| 55 | 승마갈근탕 | 염씨소아방론 |
| 56 | 시함탕 | 중정통속상한론 |
| 57 | 시호계강탕 | 상한론 |
| 58 | 시호억간탕 | 의학입문 |
| 59 | 시호청간탕 | 구치유요 |
| 62 | 안중산 | 화제국방 |
| 63 | 양격산 | 화제국방 |
| 64 | 연령고본단 | 만병회춘 |
| 65 | 영감강미신하인탕 | 금궤요략 |
| 66 | 영계출감탕 | 상한론 |
| 67 | 오약순기산 | 화제국방 |
| 68 | 오적산 | 화제국방 |
| 69 | 온경탕 | 금궤요략 |
| 70 | 온백원 | 화제금궤 |
| 71 | 용담사간탕 | 의종금감 |
| 73 | 위령탕 | 만병회춘 |
| 74 | 육군자탕 | 부인양방 |
| 75 | 육미지황환 | 소아약증직결 |
| 76 | 육울탕 | 단계심법 |
| 77 | 이기거풍산 | 고금의감 |
| 78 | 이중환 | 상한론 |
| 79 | 이진탕 | 화제국방 |
| 80 | 인삼양영탕 | 화제국방 |
| 81 | 인삼양위탕 | 화제국방 |
| 82 | 인삼패독산 | 소아약증질결 |
| 83 | 인진오령산 | 금궤요략 |
| 84 | 자감초탕 | 상한론 |
| 85 | 자음강화탕 | 만병회춘 |
| 86 | 자음건비탕 | 만병회푼 |
| 87 | 저령탕 | 상한론 |
| 88 | 조경종옥탕 | 고금의감 |
| 89 | 지황음자 | 선명논방 |
| 90 | 진무탕 | 상한론 |
| 91 | 청간해올탕 | 증치준승 |
| 92 | 청금강화탕 | 고금의감 |
| 93 | 청상방풍탕 | 만병회춘 |
| 94 | 청서익기탕 | 비위론 |
| 95 | 청심연자음 | 화제국방 |
| 96 | 평위산 | 화제국방 |
| 97 | 형계연교탕 | 일관당 |
| 98 | 형방패독산 | 섭생중묘방 |
| 99 | 황련아교탕 | 상한론 |
| 100 | 황련해독탕 | 외대비요 |

---

## 6. Agent 실행 시 Python 코드 템플릿

```python
import sqlite3

DB_PATH = '/root/kdrug/database/kdrug.db'
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()

# === 대상 처방 ===
FORMULA_ID = 38          # official_formula_id
HANJA = '四君子湯'
DESCRIPTION = '보기건비 (補氣健脾)'
REFERENCE = '화제국방 원방. 비기허로 인한 ...'

# === Step 1: 기본 정보 업데이트 ===
c.execute('''UPDATE official_formulas SET
    formula_name_hanja = ?,
    description = ?,
    reference_notes = ?,
    updated_at = CURRENT_TIMESTAMP
WHERE official_formula_id = ?''', (HANJA, DESCRIPTION, REFERENCE, FORMULA_ID))

# === Step 2: 구성 약재 등록 ===
# (official_formula_id, ingredient_code, grams_per_cheop, notes, sort_order)
ingredients = [
    (FORMULA_ID, '3400H1AHM', 4.0, '군약', 1),   # 인삼
    (FORMULA_ID, '3204H1AHM', 4.0, '신약', 2),   # 백출
    (FORMULA_ID, '3215H1AHM', 4.0, '좌약', 3),   # 복령
    (FORMULA_ID, '3007H1AHM', 2.0, '사약', 4),   # 감초
]

for ing in ingredients:
    c.execute('''INSERT INTO official_formula_ingredients
                 (official_formula_id, ingredient_code, grams_per_cheop, notes, sort_order)
                 VALUES (?, ?, ?, ?, ?)''', ing)

conn.commit()

# === Step 3: 검증 ===
c.execute('''SELECT hm.herb_name, ofi.ingredient_code, ofi.grams_per_cheop, ofi.notes
             FROM official_formula_ingredients ofi
             JOIN herb_masters hm ON ofi.ingredient_code = hm.ingredient_code
             WHERE ofi.official_formula_id = ?
             ORDER BY ofi.sort_order''', (FORMULA_ID,))

total = 0
for r in c.fetchall():
    total += r[2]
    print(f'  {r[0]} ({r[1]}): {r[2]}g ({r[3]})')
print(f'  1첩 총량: {total}g')

conn.close()
```

---

## 7. 주의사항

1. **ingredient_code는 반드시 herb_masters 테이블에 존재해야 한다** — JOIN이 실패하면 UI에 표시 안 됨
2. **한 처방에 같은 ingredient_code 중복 불가** — UNIQUE 제약
3. **기존 데이터 확인 후 INSERT** — 이미 등록된 처방에 중복 INSERT하면 에러
4. **출전(source_text)은 이미 seed 데이터로 들어가 있음** — UPDATE 불필요
5. **grams_per_cheop은 소수점 1자리까지** — 예: 4.0, 3.5, 2.0
6. **DB 경로**: `/root/kdrug/database/kdrug.db`

---

*이 문서는 kdrug 시스템의 100처방 마스터 데이터 일괄 등록을 위해 작성되었습니다.*
*최종 수정: 2026-02-18*
