# 08. CEO 대시보드 시스템

> **대상**: 프론트엔드/백엔드 개발자
> **버전**: 1.0.0
> **최종 수정**: 2026-03-09

---

## 1. 아키텍처 개요

CEO 대시보드는 20개 섹션으로 구성된 실시간 경영 현황 화면.

```
CEODashboard.tsx
├── useCEODashboard()           # 12개 섹션 API 통합 Hook
├── useEntertainment()          # 접대비 독립 Hook
├── useWelfare()                # 복리후생비 독립 Hook
├── useTodayIssue()             # 금일 이슈 Hook
├── useCalendar()               # 캘린더 Hook
├── useVat()                    # 부가세 Hook
├── SummaryNavBar               # 섹션 바로가기 네비게이션
├── DashboardSettingsDialog     # 섹션 표시/순서 설정
├── DetailModal                 # 상세 모달 (공통)
└── sections/                   # 20개 섹션 컴포넌트
    ├── DailyReportSection
    ├── MonthlyExpenseSection
    ├── EntertainmentSection
    ├── WelfareSection
    └── ... (17개 더)
```

---

## 2. 섹션 목록

| 섹션 | API Hook | 데이터 소스 |
|------|----------|------------|
| 일일일보 | useCEODashboard.dailyReport | sam_stat 캐시 |
| 현황보드 | useCEODashboard.statusBoard | 실시간 집계 |
| 당월예상지출 | useCEODashboard.monthlyExpense | 예상경비 테이블 |
| 카드/가지급금 | useCEODashboard.cardManagement | 가지급금 테이블 |
| 매출채권 | useCEODashboard.receivable | 매출/입금 |
| 채권회수 | useCEODashboard.debtCollection | 부실채권 |
| 매출현황 | useCEODashboard.salesStatus | 매출 통계 |
| 매입현황 | useCEODashboard.purchaseStatus | 매입 통계 |
| 일일생산 | useCEODashboard.dailyProduction | 생산실적 |
| 미출하 | useCEODashboard.unshipped | 출하 대기 |
| 공사현황 | useCEODashboard.construction | 공사 진행 |
| 근태현황 | useCEODashboard.dailyAttendance | 근태 데이터 |
| **접대비** | **useEntertainment()** | **expense_accounts** |
| **복리후생비** | **useWelfare()** | **expense_accounts** |
| 금일이슈 | useTodayIssue() | 이슈 목록 |
| 부가세 | useVat() | 부가세 신고 |
| 캘린더 | useCalendar() | 일정 |
| 출하현황 | useCEODashboard.dailyProduction | 출하 실적 |

---

## 3. Invalidation 시스템

다른 화면에서 CUD 발생 시 대시보드 데이터 자동 갱신.

### 흐름

```
[입금관리에서 입금 등록]
    ↓
invalidateDashboard('deposit')
    ↓
DOMAIN_SECTION_MAP에서 영향 섹션 조회
  deposit → ['dailyReport', 'receivable']
    ↓
1. sessionStorage에 stale 섹션 저장
2. CustomEvent 발행
    ↓
[대시보드가 마운트 중이면]
  → 즉시 해당 섹션만 refetch
[대시보드 비마운트 상태면]
  → 다음 방문 시 stale 섹션 refetch
```

### 도메인 → 섹션 매핑

| 도메인 | 영향 섹션 |
|--------|----------|
| `deposit` | dailyReport, receivable |
| `withdrawal` | dailyReport, monthlyExpense |
| `sales` | dailyReport, salesStatus, receivable |
| `purchase` | dailyReport, purchaseStatus, monthlyExpense |
| `badDebt` | debtCollection, receivable |
| `expectedExpense` | monthlyExpense |
| `bill` | dailyReport, receivable |
| `giftCertificate` | entertainment, cardManagement |
| `journalEntry` | entertainment, welfare, monthlyExpense |

### 사용법 (CUD 완료 후)

```typescript
import { invalidateDashboard } from '@/lib/dashboard-invalidation';

// 입금 등록 성공 후
const handleSuccess = () => {
  loadData();
  invalidateDashboard('deposit');
};

// 전표 등록 성공 후
const handleJournalSuccess = () => {
  loadData();
  invalidateDashboard('journalEntry');
};
```

### 새 도메인 추가 시

`src/lib/dashboard-invalidation.ts`에서:
1. `DomainKey`에 새 도메인 추가
2. `DOMAIN_SECTION_MAP`에 영향 섹션 매핑 추가
3. 해당 도메인의 CUD 콜백에서 `invalidateDashboard('newDomain')` 호출

---

## 4. 사용자 설정

### 섹션 표시/숨김 + 순서

```typescript
// localStorage에 저장
const settings: DashboardSettings = {
  dailyReport: true,
  monthlyExpense: true,
  entertainment: { enabled: true, companyType: 'medium' },
  welfare: { enabled: true, calculationType: 'monthly' },
  sectionOrder: ['dailyReport', 'statusBoard', 'monthlyExpense', ...],
};
localStorage.setItem('ceo-dashboard-settings', JSON.stringify(settings));
```

### 순서 변경
- DashboardSettingsDialog에서 드래그 앤 드롭 또는 순서 변경
- `sectionOrder` 배열로 관리

---

## 5. expense_accounts 동기화

접대비/복리후생비 대시보드 카드의 데이터 소스는 `expense_accounts` 테이블.

### 현재 동기화 경로

| 입력 경로 | expense_accounts 반영 |
|----------|----------------------|
| 일반전표 (수기전표) | **반영됨** — syncExpenseAccounts() |
| 가지급금 상품권 | **반영됨** — LoanService |
| 출금관리/카드사용내역 | **확인 중** |
| 세금계산서 | **확인 중** |
| 예상경비 | **확인 중** |

### 동기화 원리
- 전표/거래에서 계정과목명에 "복리후생비" 또는 "접대비"가 포함되면
- `expense_accounts` 테이블에 자동 INSERT
- CUD 시 delete-then-insert 전략 (정확한 추적)
- `journal_entry_id`, `journal_entry_line_id`로 원본 추적 가능

---

## 6. 백엔드 참고

### 대시보드 관련 API

| 엔드포인트 | 용도 |
|-----------|------|
| GET /api/v1/daily-report/summary | 일일일보 요약 |
| GET /api/v1/monthly-expense/summary | 당월 예상 지출 |
| GET /api/v1/entertainments/summary | 접대비 리스크 카드 |
| GET /api/v1/welfares/summary | 복리후생비 리스크 카드 |
| GET /api/v1/card-management/summary | 카드/가지급금 |
| GET /api/v1/receivable/summary | 매출채권 |

### sam_stat 캐시
- 일부 대시보드 API는 5분 캐시 (sam_stat 테이블)
- 실시간이 아닌 근사치 데이터
- invalidation은 프론트 refetch → 백엔드가 캐시 갱신 여부 판단
