Files
sam-docs/frontend/v1/08-dashboard-system.md
유병철 8f939d3609 docs: [frontend] 프론트엔드 아키텍처/가이드 문서 v1 작성
- _index.md: 문서 목록 및 버전 관리
- 01~09: 아키텍처, API패턴, 컴포넌트, 폼, 스타일, 인증, 대시보드, 컨벤션
- 10: 문서 API 연동 스펙 (api-specs에서 이관)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:24:25 +09:00

184 lines
5.9 KiB
Markdown

# 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 → 백엔드가 캐시 갱신 여부 판단