# 한의원 약재 관리 시스템 ER 다이어그램

## 핵심 엔티티 관계도

```mermaid
erDiagram
    HERB_MASTERS ||--o{ HERB_ITEMS : "has"
    HERB_MASTERS ||--o{ FORMULA_INGREDIENTS : "used_in"
    HERB_ITEMS ||--o{ INVENTORY_LOTS : "has"
    HERB_ITEMS ||--o{ COMPOUND_INGREDIENTS : "used_in"
    HERB_ITEMS ||--o{ HERB_ITEM_TAGS : "has"
    HERB_EFFICACY_TAGS ||--o{ HERB_ITEM_TAGS : "assigned_to"

    FORMULAS ||--o{ FORMULA_INGREDIENTS : "contains"
    FORMULAS ||--o{ COMPOUNDS : "used_for"

    PATIENTS ||--o{ COMPOUNDS : "receives"
    PATIENTS ||--o{ PATIENT_SURVEYS : "completes"

    COMPOUNDS ||--o{ COMPOUND_INGREDIENTS : "contains"
    COMPOUND_INGREDIENTS ||--o{ COMPOUND_CONSUMPTIONS : "consumes"

    INVENTORY_LOTS ||--o{ COMPOUND_CONSUMPTIONS : "consumed_by"
    INVENTORY_LOTS }o--|| SUPPLIERS : "supplied_by"
    INVENTORY_LOTS }o--|| PURCHASE_RECEIPT_LINES : "received_from"

    SUPPLIERS ||--o{ PURCHASE_RECEIPTS : "provides"
    PURCHASE_RECEIPTS ||--o{ PURCHASE_RECEIPT_LINES : "contains"

    STOCK_ADJUSTMENTS ||--o{ STOCK_ADJUSTMENT_DETAILS : "contains"
    STOCK_LEDGER }o--|| HERB_ITEMS : "tracks"
    STOCK_LEDGER }o--|| INVENTORY_LOTS : "tracks"

    HERB_MASTERS {
        string ingredient_code PK
        string herb_name
        string herb_name_hanja
        string herb_name_latin
        text description
        boolean is_active
    }

    HERB_ITEMS {
        int herb_item_id PK
        string ingredient_code FK
        string insurance_code
        string herb_name
        string specification
        boolean is_active
    }

    INVENTORY_LOTS {
        int lot_id PK
        int herb_item_id FK
        int supplier_id FK
        date received_date
        string origin_country
        decimal unit_price_per_g
        decimal quantity_onhand
        date expiry_date
        boolean is_depleted
    }

    FORMULAS {
        int formula_id PK
        string formula_code
        string formula_name
        string formula_type
        int base_cheop
        int base_pouches
        boolean is_active
    }

    FORMULA_INGREDIENTS {
        int ingredient_id PK
        int formula_id FK
        string ingredient_code FK
        decimal grams_per_cheop
        int sort_order
    }

    COMPOUNDS {
        int compound_id PK
        int patient_id FK
        int formula_id FK
        date compound_date
        decimal cheop_total
        decimal pouch_total
        decimal cost_total
        string status
    }

    PATIENTS {
        int patient_id PK
        string name
        string phone
        string gender
        date birth_date
        boolean is_active
    }
```

## 재고 흐름도

```mermaid
flowchart TB
    subgraph 입고
        S[공급처/Suppliers]
        PR[구매영수증/Purchase Receipts]
        PRL[구매영수증라인/Purchase Receipt Lines]
        S --> PR
        PR --> PRL
    end

    subgraph 재고
        HM[약재마스터/Herb Masters]
        HI[약재제품/Herb Items]
        IL[재고로트/Inventory Lots]
        SL[재고원장/Stock Ledger]

        HM --> HI
        HI --> IL
        PRL --> IL
        IL -.-> SL
    end

    subgraph 조제/출고
        F[처방/Formulas]
        FI[처방구성/Formula Ingredients]
        C[조제/Compounds]
        CI[조제구성/Compound Ingredients]
        CC[조제소비/Compound Consumptions]

        F --> FI
        FI -.->|ingredient_code| HM
        F --> C
        C --> CI
        CI --> CC
        CC --> IL
    end

    subgraph 재고조정
        SA[재고조정/Stock Adjustments]
        SAD[조정상세/Adjustment Details]

        SA --> SAD
        SAD --> IL
    end

    IL --> SL
    CC --> SL
    SAD --> SL

    classDef master fill:#e1f5fe
    classDef transaction fill:#fff3e0
    classDef inventory fill:#f3e5f5
    classDef ledger fill:#e8f5e9

    class HM,HI,F master
    class PR,PRL,C,CI,CC transaction
    class IL inventory
    class SL,SA,SAD ledger
```

## 데이터 플로우

### 1. 약재 마스터 데이터 흐름
```
herb_masters (성분코드)
    ↓
herb_items (제품별 재고 단위)
    ↓
inventory_lots (로트별 실재고)
```

### 2. 처방 → 조제 흐름
```
formulas (처방 마스터)
    ↓
formula_ingredients (ingredient_code 기반)
    ↓
compounds (실제 조제)
    ↓
compound_ingredients (제품 선택)
    ↓
compound_consumptions (로트별 소비)
```

### 3. 구매 → 재고 흐름
```
suppliers (공급처)
    ↓
purchase_receipts (영수증)
    ↓
purchase_receipt_lines (라인)
    ↓
inventory_lots (재고 생성)
    ↓
stock_ledger (원장 기록)
```

## 주요 비즈니스 규칙

### 재고 관리
1. **FIFO (선입선출)**: 오래된 로트부터 자동 소비
2. **로트 추적**: 모든 재고는 lot_id로 추적
3. **원산지 관리**: 로트별 origin_country 관리
4. **가격 추적**: 로트별 unit_price_per_g 관리

### 처방 관리
1. **성분코드 기반**: formula_ingredients는 ingredient_code 사용
2. **유연한 제품 선택**: 동일 성분의 다른 제품 선택 가능
3. **2단계 선택**: 약재(마스터) → 제품 → 로트

### 조제 관리
1. **처방 조제**: 등록된 처방 사용
2. **직접 조제**: 처방 없이 직접 구성
3. **가감 가능**: 처방 기본 구성에서 추가/제거 가능

### 원가 계산
```
조제 원가 = Σ(사용량 × 로트별 단가)
```

## 인덱스 전략

### 주요 인덱스
- `herb_items.ingredient_code`: 성분코드 조회
- `inventory_lots.herb_item_id, is_depleted`: 가용 재고 조회
- `inventory_lots.origin_country`: 원산지별 재고 조회
- `formula_ingredients.formula_id`: 처방 구성 조회
- `compounds.patient_id, compound_date`: 환자 조제 이력
- `stock_ledger.herb_item_id, event_time`: 재고 변동 이력

## 데이터 무결성

### 외래키 제약
- `herb_items.ingredient_code` → `herb_masters.ingredient_code`
- `formula_ingredients.ingredient_code` → `herb_masters.ingredient_code`
- `inventory_lots.herb_item_id` → `herb_items.herb_item_id`
- `compound_ingredients.herb_item_id` → `herb_items.herb_item_id`
- `compound_consumptions.lot_id` → `inventory_lots.lot_id`

### 체크 제약
- `inventory_lots.quantity_onhand >= 0`
- `compound_consumptions.quantity_used > 0`
- `purchase_receipt_lines.quantity_g > 0`
- `formula_ingredients.grams_per_cheop > 0`

### 트리거
- 재고 변동 시 `stock_ledger` 자동 기록
- `inventory_lots.quantity_onhand = 0` 시 `is_depleted = 1` 자동 설정