Files
sam-docs/dev/dev_plans/dummy-data-seeding-plan.md
권혁성 db63fcff85 refactor: [docs] 팀별 폴더 구조 재편 (공유/개발/프론트/기획)
- 개발팀 전용 폴더 dev/ 생성 (standards, guides, quickstart, changes, deploys, data, history, dev_plans 이동)
- 프론트엔드 전용 폴더 frontend/ 생성 (api/ → frontend/api-specs/)
- 기획팀 폴더 requests/ 생성
- plans/ → dev/dev_plans/ 이름 변경
- README.md 신규 (사람용 안내), INDEX.md 재작성 (Claude Code용)
- resources.md 신규 (노션 링크용, assets/brochure 이관 예정)
- CURRENT_WORKS.md 삭제, TODO.md → dev/ 이동
- 전체 참조 경로 업데이트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:46:03 +09:00

76 KiB
Raw Blame History

더미 데이터 시딩 계획

작성일: 2025-12-23 목적: React API 연동 테스트를 위한 더미 데이터 생성 참고 문서: react-mock-to-api-migration-plan.md


1. 현황 분석

1.1 기존 데이터 현황

테이블 현재 개수 추가 목표 최종 목표
tenants 5 - 기존 활용
users 13 - 기존 활용
clients 4 (tenant 287) +20 24개
client_groups 0 +5 5개
bank_accounts 0 +5 5개
sales 0 (tenant 287) +80 80개
purchases 0 +70 70개
deposits 0 +60 60개
withdrawals 0 +60 60개
bills 0 +30 30개
bill_installments 0 +15 15개
총계 - ~345개 -

1.2 대상 테넌트

Target: ID 287 (프론트_테스트회사)

  • Code: JTKKPNNG6D
  • 기존 거래처 4개 보유 (ID: 9, 10, 11, 12)
  • 테스트 목적으로 적합

1.3 데이터 기간

2025년 1월 ~ 12월 (1년간)

  • 월별 균등 분포
  • 최근월(11~12월)은 draft 상태 포함

2. 테이블 의존성 분석

2.1 의존성 다이어그램

┌─────────────────────────────────────────────────────────────────┐
│  Level 0: 기반 데이터 (이미 존재)                                 │
├─────────────────────────────────────────────────────────────────┤
│  tenants (ID: 287) ──┬── users (ID: 1)                          │
│                      │                                          │
└──────────────────────┼──────────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────────┐
│  Level 1: 마스터 데이터 (5 + 5 = 10개)                           │
├─────────────────────────────────────────────────────────────────┤
│  ├── client_groups (5개) - 거래처 그룹                           │
│  └── bank_accounts (5개) - 은행 계좌                             │
└─────────────────────────────────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────────┐
│  Level 2: 거래처 데이터 (20개)                                   │
├─────────────────────────────────────────────────────────────────┤
│  clients (20개) ← client_group_id (optional)                    │
└─────────────────────────────────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────────┐
│  Level 3: 입출금/어음 데이터 (60 + 60 + 30 = 150개)              │
├─────────────────────────────────────────────────────────────────┤
│  ├── deposits (60개) ← client_id, bank_account_id               │
│  ├── withdrawals (60개) ← client_id, bank_account_id            │
│  └── bills (30개) ← client_id, bank_account_id                  │
│      └── bill_installments (15개) ← bill_id                     │
└─────────────────────────────────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────────┐
│  Level 4: 매출/매입 데이터 (80 + 70 = 150개)                     │
├─────────────────────────────────────────────────────────────────┤
│  ├── sales (80개) ← client_id, deposit_id (optional)            │
│  └── purchases (70개) ← client_id, withdrawal_id (optional)     │
└─────────────────────────────────────────────────────────────────┘

2.2 삽입 순서 및 수량

1. client_groups     (5개)   - 거래처 그룹
2. bank_accounts     (5개)   - 은행 계좌
3. clients           (20개)  - 거래처 (매출처/매입처)
4. deposits          (60개)  - 입금 (월 5건)
5. withdrawals       (60개)  - 출금 (월 5건)
6. bills             (30개)  - 어음 (수취 15건 + 발행 15건)
7. sales             (80개)  - 매출 (월 6~7건)
8. purchases         (70개)  - 매입 (월 5~6건)
────────────────────────────
총계                 ~345개

3. 더미 데이터 스키마

3.1 client_groups (거래처 그룹) - 5개

[
    ['group_code' => 'VIP',    'group_name' => 'VIP 고객',      'price_rate' => 0.95],
    ['group_code' => 'GOLD',   'group_name' => '골드 고객',     'price_rate' => 0.97],
    ['group_code' => 'SILVER', 'group_name' => '실버 고객',     'price_rate' => 0.98],
    ['group_code' => 'NORMAL', 'group_name' => '일반 고객',     'price_rate' => 1.00],
    ['group_code' => 'NEW',    'group_name' => '신규 고객',     'price_rate' => 1.00],
]

3.2 bank_accounts (은행 계좌) - 5개

[
    ['bank_code' => '004', 'bank_name' => 'KB국민은행',  'account_number' => '123-45-6789012',  'account_holder' => '프론트테스트', 'account_name' => '운영계좌', 'is_primary' => true],
    ['bank_code' => '088', 'bank_name' => '신한은행',    'account_number' => '110-123-456789',  'account_holder' => '프론트테스트', 'account_name' => '급여계좌', 'is_primary' => false],
    ['bank_code' => '020', 'bank_name' => '우리은행',    'account_number' => '1002-123-456789', 'account_holder' => '프론트테스트', 'account_name' => '예비계좌', 'is_primary' => false],
    ['bank_code' => '081', 'bank_name' => '하나은행',    'account_number' => '123-456789-12345','account_holder' => '프론트테스트', 'account_name' => '법인카드', 'is_primary' => false],
    ['bank_code' => '011', 'bank_name' => 'NH농협은행',  'account_number' => '351-1234-5678-12','account_holder' => '프론트테스트', 'account_name' => '비상금',   'is_primary' => false],
]

3.3 clients (거래처) - 20개

매출처 (SALES) - 10개

Code 회사명 사업자번호 그룹 담당자
S001 삼성전자 124-81-00998 VIP 김철수
S002 LG전자 107-86-14075 VIP 이영희
S003 SK하이닉스 204-81-17169 GOLD 박민수
S004 현대자동차 101-81-05765 GOLD 정은지
S005 네이버 220-81-62517 GOLD 최준호
S006 카카오 120-87-65763 SILVER 강미래
S007 쿠팡 120-88-00767 SILVER 임도현
S008 토스 120-87-83139 NORMAL 윤서연
S009 배달의민족 220-87-93847 NORMAL 한지민
S010 당근마켓 815-87-01234 NEW 오태양

매입처 (PURCHASE) - 7개

Code 회사명 사업자번호 그룹 담당자
P001 한화솔루션 138-81-00610 - 김재원
P002 포스코 506-81-08754 - 이현석
P003 롯데케미칼 301-81-07123 - 박서준
P004 GS칼텍스 104-81-23858 - 정해인
P005 대한항공 110-81-14794 - 송민호
P006 현대제철 130-81-12345 - 강동원
P007 SK이노베이션 110-81-67890 - 유재석

매출매입처 (BOTH) - 3개

Code 회사명 사업자번호 그룹 담당자
B001 두산에너빌리티 124-81-08628 GOLD 조인성
B002 CJ대한통운 104-81-39849 SILVER 공유
B003 삼성SDS 124-81-34567 VIP 이정재

3.4 월별 데이터 분포

입금 출금 매출 매입 상태
1월 5건 5건 6건 5건 confirmed/invoiced
2월 5건 5건 6건 5건 confirmed/invoiced
3월 5건 5건 7건 6건 confirmed/invoiced
4월 5건 5건 6건 5건 confirmed/invoiced
5월 5건 5건 7건 6건 confirmed/invoiced
6월 5건 5건 6건 6건 confirmed/invoiced
7월 5건 5건 7건 6건 confirmed/invoiced
8월 5건 5건 6건 6건 confirmed/invoiced
9월 5건 5건 7건 6건 confirmed/invoiced
10월 5건 5건 7건 6건 confirmed/invoiced
11월 5건 5건 8건 7건 confirmed + draft
12월 5건 5건 7건 6건 draft 위주
합계 60건 60건 80건 70건

3.5 금액 범위 및 분포

┌─────────────────────────────────────────────────────────────────┐
│  금액 분포 (공급가액 기준)                                        │
├─────────────────────────────────────────────────────────────────┤
│  소액 (30%):    1,000,000 ~ 5,000,000원                         │
│  중액 (50%):    5,000,000 ~ 30,000,000원                        │
│  대액 (20%):   30,000,000 ~ 100,000,000원                       │
├─────────────────────────────────────────────────────────────────┤
│  세액: 공급가액 × 10%                                            │
│  합계: 공급가액 × 110%                                           │
└─────────────────────────────────────────────────────────────────┘

3.6 deposits (입금) - 60개 예시

// 월별 5건씩, 총 60건
// 결제수단: transfer(70%), card(15%), cash(10%), check(5%)

$deposits = [
    // 1월
    ['date' => '2025-01-05', 'client' => '삼성전자',     'amount' => 55000000, 'method' => 'transfer'],
    ['date' => '2025-01-10', 'client' => 'LG전자',       'amount' => 28000000, 'method' => 'transfer'],
    ['date' => '2025-01-15', 'client' => '현대자동차',   'amount' => 42000000, 'method' => 'transfer'],
    ['date' => '2025-01-20', 'client' => '네이버',       'amount' => 15000000, 'method' => 'card'],
    ['date' => '2025-01-25', 'client' => '카카오',       'amount' => 8500000,  'method' => 'transfer'],

    // 2월
    ['date' => '2025-02-05', 'client' => 'SK하이닉스',   'amount' => 68000000, 'method' => 'transfer'],
    ['date' => '2025-02-10', 'client' => '쿠팡',         'amount' => 22000000, 'method' => 'transfer'],
    ['date' => '2025-02-15', 'client' => '토스',         'amount' => 9800000,  'method' => 'card'],
    ['date' => '2025-02-20', 'client' => '삼성SDS',      'amount' => 35000000, 'method' => 'transfer'],
    ['date' => '2025-02-25', 'client' => '두산에너빌리티','amount' => 48000000, 'method' => 'check'],

    // ... 3월 ~ 12월 (패턴 반복, Seeder에서 자동 생성)
];

3.7 withdrawals (출금) - 60개 예시

// 월별 5건씩, 총 60건
$withdrawals = [
    // 1월
    ['date' => '2025-01-03', 'client' => '한화솔루션',   'amount' => 32000000, 'method' => 'transfer'],
    ['date' => '2025-01-08', 'client' => '포스코',       'amount' => 45000000, 'method' => 'transfer'],
    ['date' => '2025-01-15', 'client' => '롯데케미칼',   'amount' => 18000000, 'method' => 'transfer'],
    ['date' => '2025-01-22', 'client' => 'GS칼텍스',     'amount' => 12500000, 'method' => 'card'],
    ['date' => '2025-01-28', 'client' => '대한항공',     'amount' => 5800000,  'method' => 'transfer'],

    // 2월
    ['date' => '2025-02-05', 'client' => '현대제철',     'amount' => 52000000, 'method' => 'transfer'],
    ['date' => '2025-02-12', 'client' => 'SK이노베이션', 'amount' => 28000000, 'method' => 'transfer'],
    ['date' => '2025-02-18', 'client' => 'CJ대한통운',   'amount' => 8500000,  'method' => 'transfer'],
    ['date' => '2025-02-22', 'client' => '한화솔루션',   'amount' => 25000000, 'method' => 'check'],
    ['date' => '2025-02-28', 'client' => '포스코',       'amount' => 38000000, 'method' => 'transfer'],

    // ... 3월 ~ 12월 (패턴 반복)
];

3.8 sales (매출) - 80개 예시

// 월별 6~7건, 총 80건
// 상태: 1~10월 invoiced/confirmed, 11~12월 draft 포함
$sales = [
    // 1월 (6건)
    ['number' => 'SAL-202501-0001', 'date' => '2025-01-05', 'client' => '삼성전자',     'supply' => 50000000, 'status' => 'invoiced'],
    ['number' => 'SAL-202501-0002', 'date' => '2025-01-08', 'client' => 'LG전자',       'supply' => 25454545, 'status' => 'invoiced'],
    ['number' => 'SAL-202501-0003', 'date' => '2025-01-12', 'client' => '현대자동차',   'supply' => 38181818, 'status' => 'invoiced'],
    ['number' => 'SAL-202501-0004', 'date' => '2025-01-18', 'client' => '네이버',       'supply' => 13636364, 'status' => 'confirmed'],
    ['number' => 'SAL-202501-0005', 'date' => '2025-01-22', 'client' => '카카오',       'supply' => 7727273,  'status' => 'confirmed'],
    ['number' => 'SAL-202501-0006', 'date' => '2025-01-28', 'client' => '삼성SDS',      'supply' => 31818182, 'status' => 'invoiced'],

    // ... 2월 ~ 10월 (invoiced/confirmed)

    // 11월 (8건 - draft 포함)
    ['number' => 'SAL-202511-0001', 'date' => '2025-11-03', 'client' => '삼성전자',     'supply' => 45000000, 'status' => 'invoiced'],
    ['number' => 'SAL-202511-0002', 'date' => '2025-11-06', 'client' => 'SK하이닉스',   'supply' => 62000000, 'status' => 'invoiced'],
    ['number' => 'SAL-202511-0003', 'date' => '2025-11-10', 'client' => '쿠팡',         'supply' => 18181818, 'status' => 'confirmed'],
    ['number' => 'SAL-202511-0004', 'date' => '2025-11-14', 'client' => '두산에너빌리티','supply' => 55000000, 'status' => 'confirmed'],
    ['number' => 'SAL-202511-0005', 'date' => '2025-11-18', 'client' => '당근마켓',     'supply' => 8909091,  'status' => 'confirmed'],
    ['number' => 'SAL-202511-0006', 'date' => '2025-11-22', 'client' => '토스',         'supply' => 12727273, 'status' => 'draft'],
    ['number' => 'SAL-202511-0007', 'date' => '2025-11-26', 'client' => '배달의민족',   'supply' => 15454545, 'status' => 'draft'],
    ['number' => 'SAL-202511-0008', 'date' => '2025-11-29', 'client' => 'LG전자',       'supply' => 28000000, 'status' => 'draft'],

    // 12월 (7건 - draft 위주)
    ['number' => 'SAL-202512-0001', 'date' => '2025-12-02', 'client' => '삼성전자',     'supply' => 48000000, 'status' => 'confirmed'],
    ['number' => 'SAL-202512-0002', 'date' => '2025-12-05', 'client' => '현대자동차',   'supply' => 35000000, 'status' => 'draft'],
    ['number' => 'SAL-202512-0003', 'date' => '2025-12-10', 'client' => '네이버',       'supply' => 22727273, 'status' => 'draft'],
    ['number' => 'SAL-202512-0004', 'date' => '2025-12-13', 'client' => '카카오',       'supply' => 16363636, 'status' => 'draft'],
    ['number' => 'SAL-202512-0005', 'date' => '2025-12-17', 'client' => '삼성SDS',      'supply' => 42000000, 'status' => 'draft'],
    ['number' => 'SAL-202512-0006', 'date' => '2025-12-20', 'client' => 'SK하이닉스',   'supply' => 58000000, 'status' => 'draft'],
    ['number' => 'SAL-202512-0007', 'date' => '2025-12-23', 'client' => '쿠팡',         'supply' => 20000000, 'status' => 'draft'],
];

3.9 purchases (매입) - 70개 예시

// 월별 5~6건, 총 70건
$purchases = [
    // 1월 (5건)
    ['number' => 'PUR-202501-0001', 'date' => '2025-01-03', 'client' => '한화솔루션',   'supply' => 29090909, 'status' => 'confirmed'],
    ['number' => 'PUR-202501-0002', 'date' => '2025-01-10', 'client' => '포스코',       'supply' => 40909091, 'status' => 'confirmed'],
    ['number' => 'PUR-202501-0003', 'date' => '2025-01-15', 'client' => '롯데케미칼',   'supply' => 16363636, 'status' => 'confirmed'],
    ['number' => 'PUR-202501-0004', 'date' => '2025-01-22', 'client' => 'GS칼텍스',     'supply' => 11363636, 'status' => 'confirmed'],
    ['number' => 'PUR-202501-0005', 'date' => '2025-01-28', 'client' => '대한항공',     'supply' => 5272727,  'status' => 'confirmed'],

    // ... 2월 ~ 10월 (confirmed)

    // 11월 (7건 - draft 포함)
    ['number' => 'PUR-202511-0001', 'date' => '2025-11-03', 'client' => '현대제철',     'supply' => 48000000, 'status' => 'confirmed'],
    ['number' => 'PUR-202511-0002', 'date' => '2025-11-08', 'client' => 'SK이노베이션', 'supply' => 32000000, 'status' => 'confirmed'],
    ['number' => 'PUR-202511-0003', 'date' => '2025-11-12', 'client' => 'CJ대한통운',   'supply' => 9090909,  'status' => 'confirmed'],
    ['number' => 'PUR-202511-0004', 'date' => '2025-11-18', 'client' => '한화솔루션',   'supply' => 35000000, 'status' => 'confirmed'],
    ['number' => 'PUR-202511-0005', 'date' => '2025-11-22', 'client' => '포스코',       'supply' => 42000000, 'status' => 'draft'],
    ['number' => 'PUR-202511-0006', 'date' => '2025-11-26', 'client' => '롯데케미칼',   'supply' => 18181818, 'status' => 'draft'],
    ['number' => 'PUR-202511-0007', 'date' => '2025-11-29', 'client' => '두산에너빌리티','supply' => 55000000, 'status' => 'draft'],

    // 12월 (6건 - draft 위주)
    ['number' => 'PUR-202512-0001', 'date' => '2025-12-02', 'client' => 'GS칼텍스',     'supply' => 15454545, 'status' => 'confirmed'],
    ['number' => 'PUR-202512-0002', 'date' => '2025-12-06', 'client' => '대한항공',     'supply' => 7272727,  'status' => 'draft'],
    ['number' => 'PUR-202512-0003', 'date' => '2025-12-11', 'client' => '현대제철',     'supply' => 52000000, 'status' => 'draft'],
    ['number' => 'PUR-202512-0004', 'date' => '2025-12-15', 'client' => 'SK이노베이션', 'supply' => 28000000, 'status' => 'draft'],
    ['number' => 'PUR-202512-0005', 'date' => '2025-12-19', 'client' => '한화솔루션',   'supply' => 38000000, 'status' => 'draft'],
    ['number' => 'PUR-202512-0006', 'date' => '2025-12-23', 'client' => '포스코',       'supply' => 45000000, 'status' => 'draft'],
];

3.10 bills (어음) - 30개 예시

// 수취 어음 15건 + 발행 어음 15건, 총 30건
// bill_type: received(수취), issued(발행)
// status (수취): stored, maturityAlert, maturityResult, paymentComplete, dishonored
// status (발행): stored, maturityAlert, collectionRequest, collectionComplete, suing, dishonored

$bills = [
    // 수취 어음 (received) - 15건
    ['bill_number' => '202501000001', 'type' => 'received', 'client' => '삼성전자',     'amount' => 50000000, 'issue_date' => '2025-01-15', 'maturity_date' => '2025-04-15', 'status' => 'paymentComplete'],
    ['bill_number' => '202501000002', 'type' => 'received', 'client' => 'LG전자',       'amount' => 35000000, 'issue_date' => '2025-02-10', 'maturity_date' => '2025-05-10', 'status' => 'paymentComplete'],
    ['bill_number' => '202502000001', 'type' => 'received', 'client' => 'SK하이닉스',   'amount' => 80000000, 'issue_date' => '2025-02-20', 'maturity_date' => '2025-05-20', 'status' => 'paymentComplete'],
    ['bill_number' => '202503000001', 'type' => 'received', 'client' => '현대자동차',   'amount' => 45000000, 'issue_date' => '2025-03-05', 'maturity_date' => '2025-06-05', 'status' => 'maturityResult'],
    ['bill_number' => '202504000001', 'type' => 'received', 'client' => '네이버',       'amount' => 25000000, 'issue_date' => '2025-04-12', 'maturity_date' => '2025-07-12', 'status' => 'maturityResult'],
    ['bill_number' => '202505000001', 'type' => 'received', 'client' => '카카오',       'amount' => 18000000, 'issue_date' => '2025-05-08', 'maturity_date' => '2025-08-08', 'status' => 'stored'],
    ['bill_number' => '202506000001', 'type' => 'received', 'client' => '쿠팡',         'amount' => 32000000, 'issue_date' => '2025-06-15', 'maturity_date' => '2025-09-15', 'status' => 'stored'],
    ['bill_number' => '202507000001', 'type' => 'received', 'client' => '삼성SDS',      'amount' => 65000000, 'issue_date' => '2025-07-20', 'maturity_date' => '2025-10-20', 'status' => 'stored'],
    ['bill_number' => '202508000001', 'type' => 'received', 'client' => '토스',         'amount' => 15000000, 'issue_date' => '2025-08-10', 'maturity_date' => '2025-11-10', 'status' => 'stored'],
    ['bill_number' => '202509000001', 'type' => 'received', 'client' => '두산에너빌리티','amount' => 55000000, 'issue_date' => '2025-09-05', 'maturity_date' => '2025-12-05', 'status' => 'maturityAlert'],
    ['bill_number' => '202510000001', 'type' => 'received', 'client' => '삼성전자',     'amount' => 42000000, 'issue_date' => '2025-10-15', 'maturity_date' => '2026-01-15', 'status' => 'stored'],
    ['bill_number' => '202511000001', 'type' => 'received', 'client' => 'LG전자',       'amount' => 28000000, 'issue_date' => '2025-11-08', 'maturity_date' => '2026-02-08', 'status' => 'stored'],
    ['bill_number' => '202511000002', 'type' => 'received', 'client' => '네이버',       'amount' => 38000000, 'issue_date' => '2025-11-20', 'maturity_date' => '2026-02-20', 'status' => 'stored'],
    ['bill_number' => '202512000001', 'type' => 'received', 'client' => '현대자동차',   'amount' => 52000000, 'issue_date' => '2025-12-10', 'maturity_date' => '2026-03-10', 'status' => 'stored'],
    ['bill_number' => '202512000002', 'type' => 'received', 'client' => 'SK하이닉스',   'amount' => 70000000, 'issue_date' => '2025-12-18', 'maturity_date' => '2026-03-18', 'status' => 'stored'],

    // 발행 어음 (issued) - 15건
    ['bill_number' => '202501100001', 'type' => 'issued', 'client' => '한화솔루션',   'amount' => 40000000, 'issue_date' => '2025-01-20', 'maturity_date' => '2025-04-20', 'status' => 'collectionComplete'],
    ['bill_number' => '202502100001', 'type' => 'issued', 'client' => '포스코',       'amount' => 55000000, 'issue_date' => '2025-02-15', 'maturity_date' => '2025-05-15', 'status' => 'collectionComplete'],
    ['bill_number' => '202503100001', 'type' => 'issued', 'client' => '롯데케미칼',   'amount' => 30000000, 'issue_date' => '2025-03-10', 'maturity_date' => '2025-06-10', 'status' => 'collectionComplete'],
    ['bill_number' => '202504100001', 'type' => 'issued', 'client' => 'GS칼텍스',     'amount' => 22000000, 'issue_date' => '2025-04-18', 'maturity_date' => '2025-07-18', 'status' => 'collectionComplete'],
    ['bill_number' => '202505100001', 'type' => 'issued', 'client' => '대한항공',     'amount' => 18000000, 'issue_date' => '2025-05-12', 'maturity_date' => '2025-08-12', 'status' => 'collectionRequest'],
    ['bill_number' => '202506100001', 'type' => 'issued', 'client' => '현대제철',     'amount' => 48000000, 'issue_date' => '2025-06-20', 'maturity_date' => '2025-09-20', 'status' => 'collectionRequest'],
    ['bill_number' => '202507100001', 'type' => 'issued', 'client' => 'SK이노베이션', 'amount' => 35000000, 'issue_date' => '2025-07-15', 'maturity_date' => '2025-10-15', 'status' => 'stored'],
    ['bill_number' => '202508100001', 'type' => 'issued', 'client' => 'CJ대한통운',   'amount' => 25000000, 'issue_date' => '2025-08-22', 'maturity_date' => '2025-11-22', 'status' => 'stored'],
    ['bill_number' => '202509100001', 'type' => 'issued', 'client' => '두산에너빌리티','amount' => 60000000, 'issue_date' => '2025-09-10', 'maturity_date' => '2025-12-10', 'status' => 'maturityAlert'],
    ['bill_number' => '202510100001', 'type' => 'issued', 'client' => '한화솔루션',   'amount' => 45000000, 'issue_date' => '2025-10-08', 'maturity_date' => '2026-01-08', 'status' => 'stored'],
    ['bill_number' => '202511100001', 'type' => 'issued', 'client' => '포스코',       'amount' => 58000000, 'issue_date' => '2025-11-05', 'maturity_date' => '2026-02-05', 'status' => 'stored'],
    ['bill_number' => '202511100002', 'type' => 'issued', 'client' => '롯데케미칼',   'amount' => 32000000, 'issue_date' => '2025-11-18', 'maturity_date' => '2026-02-18', 'status' => 'stored'],
    ['bill_number' => '202512100001', 'type' => 'issued', 'client' => 'GS칼텍스',     'amount' => 28000000, 'issue_date' => '2025-12-05', 'maturity_date' => '2026-03-05', 'status' => 'stored'],
    ['bill_number' => '202512100002', 'type' => 'issued', 'client' => '현대제철',     'amount' => 42000000, 'issue_date' => '2025-12-15', 'maturity_date' => '2026-03-15', 'status' => 'stored'],
    ['bill_number' => '202512100003', 'type' => 'issued', 'client' => 'SK이노베이션', 'amount' => 38000000, 'issue_date' => '2025-12-22', 'maturity_date' => '2026-03-22', 'status' => 'stored'],
];

// 일부 어음에 차수 관리 내역 추가 (15건)
$billInstallments = [
    // 수취 어음 차수
    ['bill_number' => '202501000001', 'installments' => [
        ['date' => '2025-02-15', 'amount' => 25000000, 'note' => '1차 분할 입금'],
        ['date' => '2025-03-15', 'amount' => 25000000, 'note' => '2차 분할 입금'],
    ]],
    ['bill_number' => '202502000001', 'installments' => [
        ['date' => '2025-03-20', 'amount' => 40000000, 'note' => '1차 분할 입금'],
        ['date' => '2025-04-20', 'amount' => 40000000, 'note' => '2차 분할 입금'],
    ]],
    ['bill_number' => '202507000001', 'installments' => [
        ['date' => '2025-08-20', 'amount' => 30000000, 'note' => '1차 분할 입금'],
        ['date' => '2025-09-20', 'amount' => 35000000, 'note' => '2차 분할 입금'],
    ]],

    // 발행 어음 차수
    ['bill_number' => '202501100001', 'installments' => [
        ['date' => '2025-02-20', 'amount' => 20000000, 'note' => '1차 분할 지급'],
        ['date' => '2025-03-20', 'amount' => 20000000, 'note' => '2차 분할 지급'],
    ]],
    ['bill_number' => '202502100001', 'installments' => [
        ['date' => '2025-03-15', 'amount' => 27500000, 'note' => '1차 분할 지급'],
        ['date' => '2025-04-15', 'amount' => 27500000, 'note' => '2차 분할 지급'],
    ]],
    ['bill_number' => '202506100001', 'installments' => [
        ['date' => '2025-07-20', 'amount' => 24000000, 'note' => '1차 분할 지급'],
        ['date' => '2025-08-20', 'amount' => 24000000, 'note' => '2차 분할 지급'],
    ]],
];

4. Laravel Seeder 구현 전략

4.1 Seeder 파일 구조

database/seeders/
├── DummyDataSeeder.php          ← 메인 Seeder (순서 제어)
└── Dummy/
    ├── DummyClientGroupSeeder.php    ← 거래처 그룹 (5개)
    ├── DummyBankAccountSeeder.php    ← 은행 계좌 (5개)
    ├── DummyClientSeeder.php         ← 거래처 (20개)
    ├── DummyDepositSeeder.php        ← 입금 (60개)
    ├── DummyWithdrawalSeeder.php     ← 출금 (60개)
    ├── DummyBillSeeder.php           ← 어음 (30개) + 차수 (15개)
    ├── DummySaleSeeder.php           ← 매출 (80개)
    └── DummyPurchaseSeeder.php       ← 매입 (70개)

4.2 메인 Seeder

<?php
// database/seeders/DummyDataSeeder.php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DummyDataSeeder extends Seeder
{
    // 대상 테넌트 ID
    public const TENANT_ID = 287;

    // 생성자 사용자 ID
    public const USER_ID = 1;

    public function run(): void
    {
        $this->command->info('🌱 더미 데이터 시딩 시작...');
        $this->command->info('   대상 테넌트: ID ' . self::TENANT_ID);

        $this->call([
            Dummy\DummyClientGroupSeeder::class,
            Dummy\DummyBankAccountSeeder::class,
            Dummy\DummyClientSeeder::class,
            Dummy\DummyDepositSeeder::class,
            Dummy\DummyWithdrawalSeeder::class,
            Dummy\DummyBillSeeder::class,
            Dummy\DummySaleSeeder::class,
            Dummy\DummyPurchaseSeeder::class,
        ]);

        $this->command->info('');
        $this->command->info('✅ 더미 데이터 시딩 완료!');
        $this->command->table(
            ['테이블', '생성 수량'],
            [
                ['client_groups', '5'],
                ['bank_accounts', '5'],
                ['clients', '20'],
                ['deposits', '60'],
                ['withdrawals', '60'],
                ['bills', '30'],
                ['bill_installments', '15'],
                ['sales', '80'],
                ['purchases', '70'],
                ['총계', '~345'],
            ]
        );
    }
}

4.3 실행 방법

# 더미 데이터 시딩
php artisan db:seed --class=DummyDataSeeder

# 특정 Seeder만 실행
php artisan db:seed --class=Database\\Seeders\\Dummy\\DummyClientSeeder

4.4 DB 스키마 상세 정의

4.4.1 client_groups 테이블

CREATE TABLE client_groups (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id       BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
    group_code      VARCHAR(30) NOT NULL COMMENT '그룹 코드',
    group_name      VARCHAR(100) NOT NULL COMMENT '그룹명',
    price_rate      DECIMAL(5,4) DEFAULT 1.0000 COMMENT '가격 배율',
    is_active       TINYINT DEFAULT 1 COMMENT '활성 여부',
    created_by      BIGINT UNSIGNED NULL COMMENT '생성자 ID',
    updated_by      BIGINT UNSIGNED NULL COMMENT '수정자 ID',
    deleted_by      BIGINT UNSIGNED NULL COMMENT '삭제자 ID',
    created_at      TIMESTAMP NULL,
    updated_at      TIMESTAMP NULL,
    deleted_at      TIMESTAMP NULL,

    UNIQUE INDEX uq_client_groups_tenant_code (tenant_id, group_code),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);

4.4.2 bank_accounts 테이블

CREATE TABLE bank_accounts (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id       BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
    bank_code       VARCHAR(10) NOT NULL COMMENT '은행 코드',
    bank_name       VARCHAR(50) NOT NULL COMMENT '은행명',
    account_number  VARCHAR(30) NOT NULL COMMENT '계좌번호',
    account_holder  VARCHAR(50) NOT NULL COMMENT '예금주',
    account_name    VARCHAR(100) NOT NULL COMMENT '계좌 별칭',
    status          VARCHAR(20) DEFAULT 'active' COMMENT '상태: active/inactive',
    assigned_user_id BIGINT UNSIGNED NULL COMMENT '담당자 ID',
    is_primary      BOOLEAN DEFAULT FALSE COMMENT '대표계좌 여부',
    created_by      BIGINT UNSIGNED NULL COMMENT '생성자 ID',
    updated_by      BIGINT UNSIGNED NULL COMMENT '수정자 ID',
    deleted_by      BIGINT UNSIGNED NULL COMMENT '삭제자 ID',
    created_at      TIMESTAMP NULL,
    updated_at      TIMESTAMP NULL,
    deleted_at      TIMESTAMP NULL
);

4.4.3 clients 테이블 (주요 컬럼)

-- 핵심 필드만 기재 (전체 스키마는 마이그레이션 참조)
CREATE TABLE clients (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id       BIGINT UNSIGNED NOT NULL,
    client_group_id BIGINT UNSIGNED NULL COMMENT '그룹 ID (FK)',
    client_code     VARCHAR(20) NOT NULL COMMENT '거래처 코드',
    name            VARCHAR(100) NOT NULL COMMENT '거래처명',
    client_type     VARCHAR(20) NULL COMMENT 'SALES/PURCHASE/BOTH',
    contact_person  VARCHAR(50) NULL COMMENT '담당자명',
    phone           VARCHAR(20) NULL,
    mobile          VARCHAR(20) NULL,
    email           VARCHAR(100) NULL,
    address         TEXT NULL,
    business_no     VARCHAR(20) NULL COMMENT '사업자번호',
    business_type   VARCHAR(50) NULL COMMENT '업종',
    business_item   VARCHAR(100) NULL COMMENT '업태',
    is_active       BOOLEAN DEFAULT TRUE,
    created_at      TIMESTAMP NULL,
    updated_at      TIMESTAMP NULL,
    deleted_at      TIMESTAMP NULL
);

4.4.4 deposits 테이블

CREATE TABLE deposits (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id       BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
    deposit_date    DATE NOT NULL COMMENT '입금일',
    client_id       BIGINT UNSIGNED NULL COMMENT '거래처 ID',
    client_name     VARCHAR(100) NULL COMMENT '비회원 거래처명',
    bank_account_id BIGINT UNSIGNED NULL COMMENT '입금 계좌 ID',
    amount          DECIMAL(15,2) NOT NULL COMMENT '금액',
    payment_method  VARCHAR(20) NOT NULL COMMENT 'cash/transfer/card/check',
    account_code    VARCHAR(20) NULL COMMENT '계정과목',
    description     TEXT NULL COMMENT '적요',
    reference_type  VARCHAR(50) NULL COMMENT '참조 유형',
    reference_id    BIGINT UNSIGNED NULL COMMENT '참조 ID',
    created_by      BIGINT UNSIGNED NULL,
    updated_by      BIGINT UNSIGNED NULL,
    deleted_by      BIGINT UNSIGNED NULL,
    created_at      TIMESTAMP NULL,
    updated_at      TIMESTAMP NULL,
    deleted_at      TIMESTAMP NULL
);

4.4.5 withdrawals 테이블

CREATE TABLE withdrawals (
    id                BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id         BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
    withdrawal_date   DATE NOT NULL COMMENT '출금일',
    client_id         BIGINT UNSIGNED NULL COMMENT '거래처 ID',
    client_name       VARCHAR(100) NULL COMMENT '비회원 거래처명',
    bank_account_id   BIGINT UNSIGNED NULL COMMENT '출금 계좌 ID',
    amount            DECIMAL(15,2) NOT NULL COMMENT '금액',
    payment_method    VARCHAR(20) NOT NULL COMMENT 'cash/transfer/card/check',
    account_code      VARCHAR(20) NULL COMMENT '계정과목',
    description       TEXT NULL COMMENT '적요',
    reference_type    VARCHAR(50) NULL COMMENT '참조 유형',
    reference_id      BIGINT UNSIGNED NULL COMMENT '참조 ID',
    created_by        BIGINT UNSIGNED NULL,
    updated_by        BIGINT UNSIGNED NULL,
    deleted_by        BIGINT UNSIGNED NULL,
    created_at        TIMESTAMP NULL,
    updated_at        TIMESTAMP NULL,
    deleted_at        TIMESTAMP NULL
);

4.4.6 sales 테이블

CREATE TABLE sales (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id       BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
    sale_number     VARCHAR(30) NOT NULL COMMENT '매출번호',
    sale_date       DATE NOT NULL COMMENT '매출일자',
    client_id       BIGINT UNSIGNED NOT NULL COMMENT '거래처 ID',
    supply_amount   DECIMAL(15,2) NOT NULL COMMENT '공급가액',
    tax_amount      DECIMAL(15,2) NOT NULL COMMENT '세액',
    total_amount    DECIMAL(15,2) NOT NULL COMMENT '합계',
    description     TEXT NULL COMMENT '적요',
    status          VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/confirmed/invoiced',
    tax_invoice_id  BIGINT UNSIGNED NULL COMMENT '세금계산서 ID',
    deposit_id      BIGINT UNSIGNED NULL COMMENT '입금 연결 ID',
    created_by      BIGINT UNSIGNED NULL,
    updated_by      BIGINT UNSIGNED NULL,
    deleted_by      BIGINT UNSIGNED NULL,
    created_at      TIMESTAMP NULL,
    updated_at      TIMESTAMP NULL,
    deleted_at      TIMESTAMP NULL,

    UNIQUE INDEX uk_tenant_sale_number (tenant_id, sale_number)
);

4.4.7 purchases 테이블

CREATE TABLE purchases (
    id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id       BIGINT UNSIGNED NOT NULL COMMENT '테넌트 ID',
    purchase_number VARCHAR(30) NOT NULL COMMENT '매입번호',
    purchase_date   DATE NOT NULL COMMENT '매입일자',
    client_id       BIGINT UNSIGNED NOT NULL COMMENT '거래처 ID',
    supply_amount   DECIMAL(15,2) NOT NULL COMMENT '공급가액',
    tax_amount      DECIMAL(15,2) NOT NULL COMMENT '세액',
    total_amount    DECIMAL(15,2) NOT NULL COMMENT '합계',
    description     TEXT NULL COMMENT '적요',
    status          VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/confirmed',
    withdrawal_id   BIGINT UNSIGNED NULL COMMENT '출금 연결 ID',
    created_by      BIGINT UNSIGNED NULL,
    updated_by      BIGINT UNSIGNED NULL,
    deleted_by      BIGINT UNSIGNED NULL,
    created_at      TIMESTAMP NULL,
    updated_at      TIMESTAMP NULL,
    deleted_at      TIMESTAMP NULL,

    UNIQUE INDEX uk_tenant_purchase_number (tenant_id, purchase_number)
);

4.5 모델 경로 및 네임스페이스

테이블 모델 클래스 네임스페이스
client_groups ClientGroup App\Models\Orders\ClientGroup
bank_accounts BankAccount App\Models\Tenants\BankAccount
clients Client App\Models\Orders\Client
deposits Deposit App\Models\Tenants\Deposit
withdrawals Withdrawal App\Models\Tenants\Withdrawal
sales Sale App\Models\Tenants\Sale
purchases Purchase App\Models\Tenants\Purchase

4.6 필수 상수값

결제수단 (payment_method)

// Deposit::PAYMENT_METHODS, Withdrawal::PAYMENT_METHODS
[
    'cash'     => '현금',
    'transfer' => '계좌이체',
    'card'     => '카드',
    'check'    => '수표',
]

매출 상태 (Sale::STATUSES)

[
    'draft'     => '임시저장',
    'confirmed' => '확정',
    'invoiced'  => '세금계산서발행',
]

매입 상태 (Purchase::STATUSES)

[
    'draft'     => '임시저장',
    'confirmed' => '확정',
]

거래처 유형 (client_type)

// common_codes 테이블에서 관리
// group: 'client_type'
[
    'SALES'    => '매출처',
    'PURCHASE' => '매입처',
    'BOTH'     => '매출매입처',
]

4.7 완전한 Seeder 코드 구현

4.7.1 DummyClientGroupSeeder.php

<?php

namespace Database\Seeders\Dummy;

use App\Models\Orders\ClientGroup;
use Database\Seeders\DummyDataSeeder;
use Illuminate\Database\Seeder;

class DummyClientGroupSeeder extends Seeder
{
    public function run(): void
    {
        $tenantId = DummyDataSeeder::TENANT_ID;
        $userId = DummyDataSeeder::USER_ID;

        $groups = [
            ['group_code' => 'VIP',    'group_name' => 'VIP 고객',   'price_rate' => 0.95],
            ['group_code' => 'GOLD',   'group_name' => '골드 고객',  'price_rate' => 0.97],
            ['group_code' => 'SILVER', 'group_name' => '실버 고객',  'price_rate' => 0.98],
            ['group_code' => 'NORMAL', 'group_name' => '일반 고객',  'price_rate' => 1.00],
            ['group_code' => 'NEW',    'group_name' => '신규 고객',  'price_rate' => 1.00],
        ];

        foreach ($groups as $group) {
            ClientGroup::create([
                'tenant_id'  => $tenantId,
                'group_code' => $group['group_code'],
                'group_name' => $group['group_name'],
                'price_rate' => $group['price_rate'],
                'is_active'  => true,
                'created_by' => $userId,
            ]);
        }

        $this->command->info('   ✓ client_groups: ' . count($groups) . '건 생성');
    }
}

4.7.2 DummyBankAccountSeeder.php

<?php

namespace Database\Seeders\Dummy;

use App\Models\Tenants\BankAccount;
use Database\Seeders\DummyDataSeeder;
use Illuminate\Database\Seeder;

class DummyBankAccountSeeder extends Seeder
{
    public function run(): void
    {
        $tenantId = DummyDataSeeder::TENANT_ID;
        $userId = DummyDataSeeder::USER_ID;

        $accounts = [
            ['bank_code' => '004', 'bank_name' => 'KB국민은행', 'account_number' => '123-45-6789012',   'account_holder' => '프론트테스트', 'account_name' => '운영계좌', 'is_primary' => true],
            ['bank_code' => '088', 'bank_name' => '신한은행',   'account_number' => '110-123-456789',  'account_holder' => '프론트테스트', 'account_name' => '급여계좌', 'is_primary' => false],
            ['bank_code' => '020', 'bank_name' => '우리은행',   'account_number' => '1002-123-456789', 'account_holder' => '프론트테스트', 'account_name' => '예비계좌', 'is_primary' => false],
            ['bank_code' => '081', 'bank_name' => '하나은행',   'account_number' => '123-456789-12345','account_holder' => '프론트테스트', 'account_name' => '법인카드', 'is_primary' => false],
            ['bank_code' => '011', 'bank_name' => 'NH농협은행', 'account_number' => '351-1234-5678-12','account_holder' => '프론트테스트', 'account_name' => '비상금',   'is_primary' => false],
        ];

        foreach ($accounts as $account) {
            BankAccount::create([
                'tenant_id'      => $tenantId,
                'bank_code'      => $account['bank_code'],
                'bank_name'      => $account['bank_name'],
                'account_number' => $account['account_number'],
                'account_holder' => $account['account_holder'],
                'account_name'   => $account['account_name'],
                'status'         => 'active',
                'is_primary'     => $account['is_primary'],
                'created_by'     => $userId,
            ]);
        }

        $this->command->info('   ✓ bank_accounts: ' . count($accounts) . '건 생성');
    }
}

4.7.3 DummyClientSeeder.php

<?php

namespace Database\Seeders\Dummy;

use App\Models\Orders\Client;
use App\Models\Orders\ClientGroup;
use Database\Seeders\DummyDataSeeder;
use Illuminate\Database\Seeder;

class DummyClientSeeder extends Seeder
{
    public function run(): void
    {
        $tenantId = DummyDataSeeder::TENANT_ID;
        $userId = DummyDataSeeder::USER_ID;

        // 그룹 ID 조회
        $groups = ClientGroup::where('tenant_id', $tenantId)
            ->pluck('id', 'group_code')
            ->toArray();

        // 매출처 (SALES) - 10개
        $salesClients = [
            ['code' => 'S001', 'name' => '삼성전자',     'business_no' => '124-81-00998', 'group' => 'VIP',    'contact' => '김철수', 'phone' => '02-1234-5678', 'email' => 'kim@samsung.com'],
            ['code' => 'S002', 'name' => 'LG전자',       'business_no' => '107-86-14075', 'group' => 'VIP',    'contact' => '이영희', 'phone' => '02-2345-6789', 'email' => 'lee@lg.com'],
            ['code' => 'S003', 'name' => 'SK하이닉스',   'business_no' => '204-81-17169', 'group' => 'GOLD',   'contact' => '박민수', 'phone' => '031-123-4567', 'email' => 'park@skhynix.com'],
            ['code' => 'S004', 'name' => '현대자동차',   'business_no' => '101-81-05765', 'group' => 'GOLD',   'contact' => '정은지', 'phone' => '02-3456-7890', 'email' => 'jung@hyundai.com'],
            ['code' => 'S005', 'name' => '네이버',       'business_no' => '220-81-62517', 'group' => 'GOLD',   'contact' => '최준호', 'phone' => '031-234-5678', 'email' => 'choi@naver.com'],
            ['code' => 'S006', 'name' => '카카오',       'business_no' => '120-87-65763', 'group' => 'SILVER', 'contact' => '강미래', 'phone' => '02-4567-8901', 'email' => 'kang@kakao.com'],
            ['code' => 'S007', 'name' => '쿠팡',         'business_no' => '120-88-00767', 'group' => 'SILVER', 'contact' => '임도현', 'phone' => '02-5678-9012', 'email' => 'lim@coupang.com'],
            ['code' => 'S008', 'name' => '토스',         'business_no' => '120-87-83139', 'group' => 'NORMAL', 'contact' => '윤서연', 'phone' => '02-6789-0123', 'email' => 'yoon@toss.im'],
            ['code' => 'S009', 'name' => '배달의민족',   'business_no' => '220-87-93847', 'group' => 'NORMAL', 'contact' => '한지민', 'phone' => '02-7890-1234', 'email' => 'han@woowahan.com'],
            ['code' => 'S010', 'name' => '당근마켓',     'business_no' => '815-87-01234', 'group' => 'NEW',    'contact' => '오태양', 'phone' => '02-8901-2345', 'email' => 'oh@daangn.com'],
        ];

        // 매입처 (PURCHASE) - 7개
        $purchaseClients = [
            ['code' => 'P001', 'name' => '한화솔루션',   'business_no' => '138-81-00610', 'group' => null, 'contact' => '김재원', 'phone' => '02-1111-2222', 'email' => 'kim@hanwha.com'],
            ['code' => 'P002', 'name' => '포스코',       'business_no' => '506-81-08754', 'group' => null, 'contact' => '이현석', 'phone' => '054-111-2222', 'email' => 'lee@posco.com'],
            ['code' => 'P003', 'name' => '롯데케미칼',   'business_no' => '301-81-07123', 'group' => null, 'contact' => '박서준', 'phone' => '02-2222-3333', 'email' => 'park@lottechem.com'],
            ['code' => 'P004', 'name' => 'GS칼텍스',     'business_no' => '104-81-23858', 'group' => null, 'contact' => '정해인', 'phone' => '02-3333-4444', 'email' => 'jung@gscaltex.com'],
            ['code' => 'P005', 'name' => '대한항공',     'business_no' => '110-81-14794', 'group' => null, 'contact' => '송민호', 'phone' => '02-4444-5555', 'email' => 'song@koreanair.com'],
            ['code' => 'P006', 'name' => '현대제철',     'business_no' => '130-81-12345', 'group' => null, 'contact' => '강동원', 'phone' => '032-555-6666', 'email' => 'kang@hyundaisteel.com'],
            ['code' => 'P007', 'name' => 'SK이노베이션', 'business_no' => '110-81-67890', 'group' => null, 'contact' => '유재석', 'phone' => '02-6666-7777', 'email' => 'yoo@skinnovation.com'],
        ];

        // 매출매입처 (BOTH) - 3개
        $bothClients = [
            ['code' => 'B001', 'name' => '두산에너빌리티', 'business_no' => '124-81-08628', 'group' => 'GOLD',   'contact' => '조인성', 'phone' => '02-7777-8888', 'email' => 'cho@doosan.com'],
            ['code' => 'B002', 'name' => 'CJ대한통운',    'business_no' => '104-81-39849', 'group' => 'SILVER', 'contact' => '공유',   'phone' => '02-8888-9999', 'email' => 'gong@cjlogistics.com'],
            ['code' => 'B003', 'name' => '삼성SDS',       'business_no' => '124-81-34567', 'group' => 'VIP',    'contact' => '이정재', 'phone' => '02-9999-0000', 'email' => 'lee@samsungsds.com'],
        ];

        $count = 0;

        // 매출처 생성
        foreach ($salesClients as $client) {
            $this->createClient($client, 'SALES', $tenantId, $userId, $groups);
            $count++;
        }

        // 매입처 생성
        foreach ($purchaseClients as $client) {
            $this->createClient($client, 'PURCHASE', $tenantId, $userId, $groups);
            $count++;
        }

        // 매출매입처 생성
        foreach ($bothClients as $client) {
            $this->createClient($client, 'BOTH', $tenantId, $userId, $groups);
            $count++;
        }

        $this->command->info('   ✓ clients: ' . $count . '건 생성');
    }

    private function createClient(array $data, string $type, int $tenantId, int $userId, array $groups): void
    {
        Client::create([
            'tenant_id'       => $tenantId,
            'client_group_id' => $data['group'] ? ($groups[$data['group']] ?? null) : null,
            'client_code'     => $data['code'],
            'name'            => $data['name'],
            'client_type'     => $type,
            'contact_person'  => $data['contact'],
            'phone'           => $data['phone'],
            'email'           => $data['email'],
            'business_no'     => $data['business_no'],
            'business_type'   => '제조업',
            'business_item'   => '전자제품',
            'is_active'       => true,
        ]);
    }
}

4.7.4 DummyDepositSeeder.php

<?php

namespace Database\Seeders\Dummy;

use App\Models\Orders\Client;
use App\Models\Tenants\BankAccount;
use App\Models\Tenants\Deposit;
use Database\Seeders\DummyDataSeeder;
use Illuminate\Database\Seeder;

class DummyDepositSeeder extends Seeder
{
    public function run(): void
    {
        $tenantId = DummyDataSeeder::TENANT_ID;
        $userId = DummyDataSeeder::USER_ID;

        // 거래처 매핑 (SALES, BOTH만)
        $clients = Client::where('tenant_id', $tenantId)
            ->whereIn('client_type', ['SALES', 'BOTH'])
            ->get()
            ->keyBy('name');

        // 은행계좌 (대표계좌 우선)
        $bankAccounts = BankAccount::where('tenant_id', $tenantId)
            ->where('status', 'active')
            ->orderByDesc('is_primary')
            ->get();

        $primaryBankId = $bankAccounts->first()?->id;

        // 결제수단 분포: transfer(70%), card(15%), cash(10%), check(5%)
        $methods = array_merge(
            array_fill(0, 14, 'transfer'),
            array_fill(0, 3, 'card'),
            array_fill(0, 2, 'cash'),
            array_fill(0, 1, 'check')
        );

        // 거래처 순환 목록
        $clientNames = [
            '삼성전자', 'LG전자', 'SK하이닉스', '현대자동차', '네이버',
            '카카오', '쿠팡', '토스', '배달의민족', '당근마켓',
            '두산에너빌리티', 'CJ대한통운', '삼성SDS',
        ];

        // 금액 범위
        $amounts = [
            'small'  => [1000000, 5000000],     // 30%
            'medium' => [5000000, 30000000],    // 50%
            'large'  => [30000000, 100000000],  // 20%
        ];

        $count = 0;
        $year = 2025;

        // 월별 5건씩, 총 60건
        for ($month = 1; $month <= 12; $month++) {
            $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);

            for ($i = 0; $i < 5; $i++) {
                $day = rand(1, $daysInMonth);
                $clientName = $clientNames[($month * 5 + $i) % count($clientNames)];
                $client = $clients->get($clientName);

                // 금액 결정 (분포에 따라)
                $rand = rand(1, 100);
                if ($rand <= 30) {
                    $amount = rand($amounts['small'][0], $amounts['small'][1]);
                } elseif ($rand <= 80) {
                    $amount = rand($amounts['medium'][0], $amounts['medium'][1]);
                } else {
                    $amount = rand($amounts['large'][0], $amounts['large'][1]);
                }

                Deposit::create([
                    'tenant_id'       => $tenantId,
                    'deposit_date'    => sprintf('%04d-%02d-%02d', $year, $month, $day),
                    'client_id'       => $client?->id,
                    'client_name'     => $client ? null : $clientName,
                    'bank_account_id' => $primaryBankId,
                    'amount'          => $amount,
                    'payment_method'  => $methods[array_rand($methods)],
                    'description'     => $clientName . ' 입금',
                    'created_by'      => $userId,
                ]);

                $count++;
            }
        }

        $this->command->info('   ✓ deposits: ' . $count . '건 생성');
    }
}

4.7.5 DummyWithdrawalSeeder.php

<?php

namespace Database\Seeders\Dummy;

use App\Models\Orders\Client;
use App\Models\Tenants\BankAccount;
use App\Models\Tenants\Withdrawal;
use Database\Seeders\DummyDataSeeder;
use Illuminate\Database\Seeder;

class DummyWithdrawalSeeder extends Seeder
{
    public function run(): void
    {
        $tenantId = DummyDataSeeder::TENANT_ID;
        $userId = DummyDataSeeder::USER_ID;

        // 거래처 매핑 (PURCHASE, BOTH만)
        $clients = Client::where('tenant_id', $tenantId)
            ->whereIn('client_type', ['PURCHASE', 'BOTH'])
            ->get()
            ->keyBy('name');

        // 은행계좌
        $primaryBankId = BankAccount::where('tenant_id', $tenantId)
            ->where('is_primary', true)
            ->value('id');

        // 결제수단 분포
        $methods = array_merge(
            array_fill(0, 14, 'transfer'),
            array_fill(0, 3, 'card'),
            array_fill(0, 2, 'cash'),
            array_fill(0, 1, 'check')
        );

        // 매입처 순환 목록
        $clientNames = [
            '한화솔루션', '포스코', '롯데케미칼', 'GS칼텍스', '대한항공',
            '현대제철', 'SK이노베이션', 'CJ대한통운', '두산에너빌리티',
        ];

        $amounts = [
            'small'  => [1000000, 5000000],
            'medium' => [5000000, 30000000],
            'large'  => [30000000, 80000000],
        ];

        $count = 0;
        $year = 2025;

        for ($month = 1; $month <= 12; $month++) {
            $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);

            for ($i = 0; $i < 5; $i++) {
                $day = rand(1, $daysInMonth);
                $clientName = $clientNames[($month * 5 + $i) % count($clientNames)];
                $client = $clients->get($clientName);

                $rand = rand(1, 100);
                if ($rand <= 30) {
                    $amount = rand($amounts['small'][0], $amounts['small'][1]);
                } elseif ($rand <= 80) {
                    $amount = rand($amounts['medium'][0], $amounts['medium'][1]);
                } else {
                    $amount = rand($amounts['large'][0], $amounts['large'][1]);
                }

                Withdrawal::create([
                    'tenant_id'       => $tenantId,
                    'withdrawal_date' => sprintf('%04d-%02d-%02d', $year, $month, $day),
                    'client_id'       => $client?->id,
                    'client_name'     => $client ? null : $clientName,
                    'bank_account_id' => $primaryBankId,
                    'amount'          => $amount,
                    'payment_method'  => $methods[array_rand($methods)],
                    'description'     => $clientName . ' 지급',
                    'created_by'      => $userId,
                ]);

                $count++;
            }
        }

        $this->command->info('   ✓ withdrawals: ' . $count . '건 생성');
    }
}

4.7.6 DummySaleSeeder.php

<?php

namespace Database\Seeders\Dummy;

use App\Models\Orders\Client;
use App\Models\Tenants\Sale;
use Database\Seeders\DummyDataSeeder;
use Illuminate\Database\Seeder;

class DummySaleSeeder extends Seeder
{
    public function run(): void
    {
        $tenantId = DummyDataSeeder::TENANT_ID;
        $userId = DummyDataSeeder::USER_ID;

        // 거래처 매핑 (SALES, BOTH만)
        $clients = Client::where('tenant_id', $tenantId)
            ->whereIn('client_type', ['SALES', 'BOTH'])
            ->get()
            ->keyBy('name');

        $clientNames = [
            '삼성전자', 'LG전자', 'SK하이닉스', '현대자동차', '네이버',
            '카카오', '쿠팡', '토스', '배달의민족', '당근마켓',
            '두산에너빌리티', 'CJ대한통운', '삼성SDS',
        ];

        $amounts = [
            'small'  => [1000000, 5000000],
            'medium' => [5000000, 30000000],
            'large'  => [30000000, 100000000],
        ];

        // 월별 건수: 1~10월 6~7건, 11월 8건, 12월 7건 = 80건
        $monthlyCount = [6, 6, 7, 6, 7, 6, 7, 6, 7, 7, 8, 7];

        $count = 0;
        $year = 2025;

        for ($month = 1; $month <= 12; $month++) {
            $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
            $salesCount = $monthlyCount[$month - 1];

            for ($i = 0; $i < $salesCount; $i++) {
                $day = (int) (($i + 1) * $daysInMonth / ($salesCount + 1));
                $day = max(1, min($day, $daysInMonth));

                $clientName = $clientNames[($count) % count($clientNames)];
                $client = $clients->get($clientName);

                // 금액 결정
                $rand = rand(1, 100);
                if ($rand <= 30) {
                    $supply = rand($amounts['small'][0], $amounts['small'][1]);
                } elseif ($rand <= 80) {
                    $supply = rand($amounts['medium'][0], $amounts['medium'][1]);
                } else {
                    $supply = rand($amounts['large'][0], $amounts['large'][1]);
                }

                // 상태 결정: 1~10월 invoiced/confirmed, 11~12월 draft 포함
                if ($month <= 10) {
                    $status = rand(0, 1) ? 'invoiced' : 'confirmed';
                } elseif ($month == 11) {
                    $status = $i < 5 ? (rand(0, 1) ? 'invoiced' : 'confirmed') : 'draft';
                } else {
                    $status = $i < 1 ? 'confirmed' : 'draft';
                }

                $tax = round($supply * 0.1);
                $total = $supply + $tax;

                Sale::create([
                    'tenant_id'     => $tenantId,
                    'sale_number'   => sprintf('SAL-%04d%02d-%04d', $year, $month, $i + 1),
                    'sale_date'     => sprintf('%04d-%02d-%02d', $year, $month, $day),
                    'client_id'     => $client->id,
                    'supply_amount' => $supply,
                    'tax_amount'    => $tax,
                    'total_amount'  => $total,
                    'description'   => $clientName . ' 매출',
                    'status'        => $status,
                    'created_by'    => $userId,
                ]);

                $count++;
            }
        }

        $this->command->info('   ✓ sales: ' . $count . '건 생성');
    }
}

4.7.7 DummyPurchaseSeeder.php

<?php

namespace Database\Seeders\Dummy;

use App\Models\Orders\Client;
use App\Models\Tenants\Purchase;
use Database\Seeders\DummyDataSeeder;
use Illuminate\Database\Seeder;

class DummyPurchaseSeeder extends Seeder
{
    public function run(): void
    {
        $tenantId = DummyDataSeeder::TENANT_ID;
        $userId = DummyDataSeeder::USER_ID;

        // 거래처 매핑 (PURCHASE, BOTH만)
        $clients = Client::where('tenant_id', $tenantId)
            ->whereIn('client_type', ['PURCHASE', 'BOTH'])
            ->get()
            ->keyBy('name');

        $clientNames = [
            '한화솔루션', '포스코', '롯데케미칼', 'GS칼텍스', '대한항공',
            '현대제철', 'SK이노베이션', 'CJ대한통운', '두산에너빌리티',
        ];

        $amounts = [
            'small'  => [1000000, 5000000],
            'medium' => [5000000, 30000000],
            'large'  => [30000000, 80000000],
        ];

        // 월별 건수: 1~10월 5~6건, 11월 7건, 12월 6건 = 70건
        $monthlyCount = [5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 7, 6];

        $count = 0;
        $year = 2025;

        for ($month = 1; $month <= 12; $month++) {
            $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
            $purchaseCount = $monthlyCount[$month - 1];

            for ($i = 0; $i < $purchaseCount; $i++) {
                $day = (int) (($i + 1) * $daysInMonth / ($purchaseCount + 1));
                $day = max(1, min($day, $daysInMonth));

                $clientName = $clientNames[($count) % count($clientNames)];
                $client = $clients->get($clientName);

                $rand = rand(1, 100);
                if ($rand <= 30) {
                    $supply = rand($amounts['small'][0], $amounts['small'][1]);
                } elseif ($rand <= 80) {
                    $supply = rand($amounts['medium'][0], $amounts['medium'][1]);
                } else {
                    $supply = rand($amounts['large'][0], $amounts['large'][1]);
                }

                // 상태 결정
                if ($month <= 10) {
                    $status = 'confirmed';
                } elseif ($month == 11) {
                    $status = $i < 4 ? 'confirmed' : 'draft';
                } else {
                    $status = $i < 1 ? 'confirmed' : 'draft';
                }

                $tax = round($supply * 0.1);
                $total = $supply + $tax;

                Purchase::create([
                    'tenant_id'       => $tenantId,
                    'purchase_number' => sprintf('PUR-%04d%02d-%04d', $year, $month, $i + 1),
                    'purchase_date'   => sprintf('%04d-%02d-%02d', $year, $month, $day),
                    'client_id'       => $client->id,
                    'supply_amount'   => $supply,
                    'tax_amount'      => $tax,
                    'total_amount'    => $total,
                    'description'     => $clientName . ' 매입',
                    'status'          => $status,
                    'created_by'      => $userId,
                ]);

                $count++;
            }
        }

        $this->command->info('   ✓ purchases: ' . $count . '건 생성');
    }
}

4.7.8 DummyBillSeeder.php

<?php

namespace Database\Seeders\Dummy;

use App\Models\Orders\Client;
use App\Models\Tenants\BankAccount;
use App\Models\Tenants\Bill;
use App\Models\Tenants\BillInstallment;
use Database\Seeders\DummyDataSeeder;
use Illuminate\Database\Seeder;

class DummyBillSeeder extends Seeder
{
    public function run(): void
    {
        $tenantId = DummyDataSeeder::TENANT_ID;
        $userId = DummyDataSeeder::USER_ID;

        // 거래처 매핑
        $clients = Client::where('tenant_id', $tenantId)->get()->keyBy('name');

        // 은행계좌 (대표계좌)
        $primaryBankId = BankAccount::where('tenant_id', $tenantId)
            ->where('is_primary', true)
            ->value('id');

        // 수취 어음 데이터 (received) - 15건
        $receivedBills = [
            ['bill_number' => '202501000001', 'client' => '삼성전자',      'amount' => 50000000, 'issue_date' => '2025-01-15', 'maturity_date' => '2025-04-15', 'status' => 'paymentComplete'],
            ['bill_number' => '202501000002', 'client' => 'LG전자',        'amount' => 35000000, 'issue_date' => '2025-02-10', 'maturity_date' => '2025-05-10', 'status' => 'paymentComplete'],
            ['bill_number' => '202502000001', 'client' => 'SK하이닉스',    'amount' => 80000000, 'issue_date' => '2025-02-20', 'maturity_date' => '2025-05-20', 'status' => 'paymentComplete'],
            ['bill_number' => '202503000001', 'client' => '현대자동차',    'amount' => 45000000, 'issue_date' => '2025-03-05', 'maturity_date' => '2025-06-05', 'status' => 'maturityResult'],
            ['bill_number' => '202504000001', 'client' => '네이버',        'amount' => 25000000, 'issue_date' => '2025-04-12', 'maturity_date' => '2025-07-12', 'status' => 'maturityResult'],
            ['bill_number' => '202505000001', 'client' => '카카오',        'amount' => 18000000, 'issue_date' => '2025-05-08', 'maturity_date' => '2025-08-08', 'status' => 'stored'],
            ['bill_number' => '202506000001', 'client' => '쿠팡',          'amount' => 32000000, 'issue_date' => '2025-06-15', 'maturity_date' => '2025-09-15', 'status' => 'stored'],
            ['bill_number' => '202507000001', 'client' => '삼성SDS',       'amount' => 65000000, 'issue_date' => '2025-07-20', 'maturity_date' => '2025-10-20', 'status' => 'stored'],
            ['bill_number' => '202508000001', 'client' => '토스',          'amount' => 15000000, 'issue_date' => '2025-08-10', 'maturity_date' => '2025-11-10', 'status' => 'stored'],
            ['bill_number' => '202509000001', 'client' => '두산에너빌리티', 'amount' => 55000000, 'issue_date' => '2025-09-05', 'maturity_date' => '2025-12-05', 'status' => 'maturityAlert'],
            ['bill_number' => '202510000001', 'client' => '삼성전자',      'amount' => 42000000, 'issue_date' => '2025-10-15', 'maturity_date' => '2026-01-15', 'status' => 'stored'],
            ['bill_number' => '202511000001', 'client' => 'LG전자',        'amount' => 28000000, 'issue_date' => '2025-11-08', 'maturity_date' => '2026-02-08', 'status' => 'stored'],
            ['bill_number' => '202511000002', 'client' => '네이버',        'amount' => 38000000, 'issue_date' => '2025-11-20', 'maturity_date' => '2026-02-20', 'status' => 'stored'],
            ['bill_number' => '202512000001', 'client' => '현대자동차',    'amount' => 52000000, 'issue_date' => '2025-12-10', 'maturity_date' => '2026-03-10', 'status' => 'stored'],
            ['bill_number' => '202512000002', 'client' => 'SK하이닉스',    'amount' => 70000000, 'issue_date' => '2025-12-18', 'maturity_date' => '2026-03-18', 'status' => 'stored'],
        ];

        // 발행 어음 데이터 (issued) - 15건
        $issuedBills = [
            ['bill_number' => '202501100001', 'client' => '한화솔루션',    'amount' => 40000000, 'issue_date' => '2025-01-20', 'maturity_date' => '2025-04-20', 'status' => 'collectionComplete'],
            ['bill_number' => '202502100001', 'client' => '포스코',        'amount' => 55000000, 'issue_date' => '2025-02-15', 'maturity_date' => '2025-05-15', 'status' => 'collectionComplete'],
            ['bill_number' => '202503100001', 'client' => '롯데케미칼',    'amount' => 30000000, 'issue_date' => '2025-03-10', 'maturity_date' => '2025-06-10', 'status' => 'collectionComplete'],
            ['bill_number' => '202504100001', 'client' => 'GS칼텍스',      'amount' => 22000000, 'issue_date' => '2025-04-18', 'maturity_date' => '2025-07-18', 'status' => 'collectionComplete'],
            ['bill_number' => '202505100001', 'client' => '대한항공',      'amount' => 18000000, 'issue_date' => '2025-05-12', 'maturity_date' => '2025-08-12', 'status' => 'collectionRequest'],
            ['bill_number' => '202506100001', 'client' => '현대제철',      'amount' => 48000000, 'issue_date' => '2025-06-20', 'maturity_date' => '2025-09-20', 'status' => 'collectionRequest'],
            ['bill_number' => '202507100001', 'client' => 'SK이노베이션',  'amount' => 35000000, 'issue_date' => '2025-07-15', 'maturity_date' => '2025-10-15', 'status' => 'stored'],
            ['bill_number' => '202508100001', 'client' => 'CJ대한통운',    'amount' => 25000000, 'issue_date' => '2025-08-22', 'maturity_date' => '2025-11-22', 'status' => 'stored'],
            ['bill_number' => '202509100001', 'client' => '두산에너빌리티', 'amount' => 60000000, 'issue_date' => '2025-09-10', 'maturity_date' => '2025-12-10', 'status' => 'maturityAlert'],
            ['bill_number' => '202510100001', 'client' => '한화솔루션',    'amount' => 45000000, 'issue_date' => '2025-10-08', 'maturity_date' => '2026-01-08', 'status' => 'stored'],
            ['bill_number' => '202511100001', 'client' => '포스코',        'amount' => 58000000, 'issue_date' => '2025-11-05', 'maturity_date' => '2026-02-05', 'status' => 'stored'],
            ['bill_number' => '202511100002', 'client' => '롯데케미칼',    'amount' => 32000000, 'issue_date' => '2025-11-18', 'maturity_date' => '2026-02-18', 'status' => 'stored'],
            ['bill_number' => '202512100001', 'client' => 'GS칼텍스',      'amount' => 28000000, 'issue_date' => '2025-12-05', 'maturity_date' => '2026-03-05', 'status' => 'stored'],
            ['bill_number' => '202512100002', 'client' => '현대제철',      'amount' => 42000000, 'issue_date' => '2025-12-15', 'maturity_date' => '2026-03-15', 'status' => 'stored'],
            ['bill_number' => '202512100003', 'client' => 'SK이노베이션',  'amount' => 38000000, 'issue_date' => '2025-12-22', 'maturity_date' => '2026-03-22', 'status' => 'stored'],
        ];

        // 차수 관리 데이터
        $installmentsData = [
            '202501000001' => [
                ['date' => '2025-02-15', 'amount' => 25000000, 'note' => '1차 분할 입금'],
                ['date' => '2025-03-15', 'amount' => 25000000, 'note' => '2차 분할 입금'],
            ],
            '202502000001' => [
                ['date' => '2025-03-20', 'amount' => 40000000, 'note' => '1차 분할 입금'],
                ['date' => '2025-04-20', 'amount' => 40000000, 'note' => '2차 분할 입금'],
            ],
            '202507000001' => [
                ['date' => '2025-08-20', 'amount' => 30000000, 'note' => '1차 분할 입금'],
                ['date' => '2025-09-20', 'amount' => 35000000, 'note' => '2차 분할 입금'],
            ],
            '202501100001' => [
                ['date' => '2025-02-20', 'amount' => 20000000, 'note' => '1차 분할 지급'],
                ['date' => '2025-03-20', 'amount' => 20000000, 'note' => '2차 분할 지급'],
            ],
            '202502100001' => [
                ['date' => '2025-03-15', 'amount' => 27500000, 'note' => '1차 분할 지급'],
                ['date' => '2025-04-15', 'amount' => 27500000, 'note' => '2차 분할 지급'],
            ],
            '202506100001' => [
                ['date' => '2025-07-20', 'amount' => 24000000, 'note' => '1차 분할 지급'],
                ['date' => '2025-08-20', 'amount' => 24000000, 'note' => '2차 분할 지급'],
            ],
        ];

        $billCount = 0;
        $installmentCount = 0;

        // 수취 어음 생성
        foreach ($receivedBills as $data) {
            $client = $clients->get($data['client']);
            $bill = Bill::create([
                'tenant_id'         => $tenantId,
                'bill_number'       => $data['bill_number'],
                'bill_type'         => 'received',
                'client_id'         => $client?->id,
                'client_name'       => $client ? null : $data['client'],
                'amount'            => $data['amount'],
                'issue_date'        => $data['issue_date'],
                'maturity_date'     => $data['maturity_date'],
                'status'            => $data['status'],
                'is_electronic'     => rand(0, 1) === 1,
                'bank_account_id'   => $primaryBankId,
                'installment_count' => isset($installmentsData[$data['bill_number']]) ? count($installmentsData[$data['bill_number']]) : 0,
                'created_by'        => $userId,
            ]);
            $billCount++;

            // 차수 관리 데이터 추가
            if (isset($installmentsData[$data['bill_number']])) {
                foreach ($installmentsData[$data['bill_number']] as $instData) {
                    BillInstallment::create([
                        'bill_id'          => $bill->id,
                        'installment_date' => $instData['date'],
                        'amount'           => $instData['amount'],
                        'note'             => $instData['note'],
                    ]);
                    $installmentCount++;
                }
            }
        }

        // 발행 어음 생성
        foreach ($issuedBills as $data) {
            $client = $clients->get($data['client']);
            $bill = Bill::create([
                'tenant_id'         => $tenantId,
                'bill_number'       => $data['bill_number'],
                'bill_type'         => 'issued',
                'client_id'         => $client?->id,
                'client_name'       => $client ? null : $data['client'],
                'amount'            => $data['amount'],
                'issue_date'        => $data['issue_date'],
                'maturity_date'     => $data['maturity_date'],
                'status'            => $data['status'],
                'is_electronic'     => rand(0, 1) === 1,
                'bank_account_id'   => $primaryBankId,
                'installment_count' => isset($installmentsData[$data['bill_number']]) ? count($installmentsData[$data['bill_number']]) : 0,
                'created_by'        => $userId,
            ]);
            $billCount++;

            // 차수 관리 데이터 추가
            if (isset($installmentsData[$data['bill_number']])) {
                foreach ($installmentsData[$data['bill_number']] as $instData) {
                    BillInstallment::create([
                        'bill_id'          => $bill->id,
                        'installment_date' => $instData['date'],
                        'amount'           => $instData['amount'],
                        'note'             => $instData['note'],
                    ]);
                    $installmentCount++;
                }
            }
        }

        $this->command->info('   ✓ bills: ' . $billCount . '건 생성');
        $this->command->info('   ✓ bill_installments: ' . $installmentCount . '건 생성');
    }
}

5. 데이터 검증

5.1 시딩 후 검증 쿼리

-- 테이블별 데이터 수 확인
SELECT 'client_groups' as tbl, COUNT(*) as cnt FROM client_groups WHERE tenant_id = 287
UNION ALL
SELECT 'bank_accounts', COUNT(*) FROM bank_accounts WHERE tenant_id = 287
UNION ALL
SELECT 'clients', COUNT(*) FROM clients WHERE tenant_id = 287
UNION ALL
SELECT 'deposits', COUNT(*) FROM deposits WHERE tenant_id = 287
UNION ALL
SELECT 'withdrawals', COUNT(*) FROM withdrawals WHERE tenant_id = 287
UNION ALL
SELECT 'bills', COUNT(*) FROM bills WHERE tenant_id = 287
UNION ALL
SELECT 'bill_installments', COUNT(*) FROM bill_installments WHERE bill_id IN (SELECT id FROM bills WHERE tenant_id = 287)
UNION ALL
SELECT 'sales', COUNT(*) FROM sales WHERE tenant_id = 287
UNION ALL
SELECT 'purchases', COUNT(*) FROM purchases WHERE tenant_id = 287;

-- 어음 현황 (수취/발행별)
SELECT bill_type, status, COUNT(*) as count, SUM(amount) as total_amount
FROM bills
WHERE tenant_id = 287
GROUP BY bill_type, status
ORDER BY bill_type, status;

-- 월별 매출 현황
SELECT DATE_FORMAT(sale_date, '%Y-%m') as month,
       COUNT(*) as count,
       SUM(total_amount) as total
FROM sales
WHERE tenant_id = 287
GROUP BY month
ORDER BY month;

-- 거래처별 매출/매입 합계
SELECT c.name,
       COALESCE(SUM(s.total_amount), 0) as total_sales,
       COALESCE(SUM(p.total_amount), 0) as total_purchases
FROM clients c
LEFT JOIN sales s ON c.id = s.client_id AND s.deleted_at IS NULL
LEFT JOIN purchases p ON c.id = p.client_id AND p.deleted_at IS NULL
WHERE c.tenant_id = 287
GROUP BY c.id, c.name
ORDER BY total_sales DESC;

5.2 예상 결과 요약

항목 예상 값
총 거래처 24개 (기존 4 + 신규 20)
총 매출건수 80건
총 매입건수 70건
총 입금건수 60건
총 출금건수 60건
총 어음건수 30건 (수취 15건 + 발행 15건)
총 차수건수 12건 (6개 어음 × 2차)
연간 매출액 약 25~30억원
연간 매입액 약 18~22억원
수취어음 총액 약 6.5억원
발행어음 총액 약 5.8억원

6. 변경 이력

날짜 내용 작성자
2025-12-23 문서 초안 작성 Claude
2025-12-23 1년치 300개 데이터로 확장 Claude
2025-12-23 DB 스키마 상세 정의 추가 (4.4) Claude
2025-12-23 모델 경로 및 네임스페이스 추가 (4.5) Claude
2025-12-23 필수 상수값 정의 추가 (4.6) Claude
2025-12-23 완전한 Seeder 코드 구현 추가 (4.7) Claude
2025-12-23 어음(bills) 더미 데이터 추가 (30건 + 차수 12건) Claude

7. 다음 단계

  1. Seeder 파일 구현 → 4.7 섹션에 완전한 코드 포함
  2. Seeder 파일 생성 (코드 복사 후 파일 생성)
  3. 시딩 실행 (php artisan db:seed --class=DummyDataSeeder)
  4. 데이터 검증 (5.1 검증 쿼리 실행)
  5. React 연동 테스트
  6. 추가 데이터 필요시 확장

8. 빠른 시작 가이드

8.1 Seeder 파일 생성 순서

# 1. Dummy 디렉토리 생성
mkdir -p api/database/seeders/Dummy

# 2. 파일 생성 (4.2 ~ 4.7 코드 복사)
# - api/database/seeders/DummyDataSeeder.php
# - api/database/seeders/Dummy/DummyClientGroupSeeder.php
# - api/database/seeders/Dummy/DummyBankAccountSeeder.php
# - api/database/seeders/Dummy/DummyClientSeeder.php
# - api/database/seeders/Dummy/DummyDepositSeeder.php
# - api/database/seeders/Dummy/DummyWithdrawalSeeder.php
# - api/database/seeders/Dummy/DummySaleSeeder.php
# - api/database/seeders/Dummy/DummyPurchaseSeeder.php

# 3. 시딩 실행
cd api
php artisan db:seed --class=DummyDataSeeder

# 4. 검증
php artisan tinker
>>> \App\Models\Tenants\Sale::where('tenant_id', 287)->count()
# 결과: 80

8.2 주요 참조 정보

항목
대상 테넌트 ID 287
생성자 사용자 ID 1
데이터 기간 2025년 1월 ~ 12월
총 레코드 수 ~300개

8.3 관련 문서