diff --git a/plans/sam-stat-database-design-plan.md b/plans/sam-stat-database-design-plan.md index 7e689cf..f63455e 100644 --- a/plans/sam-stat-database-design-plan.md +++ b/plans/sam-stat-database-design-plan.md @@ -3,7 +3,7 @@ > **작성일**: 2026-01-29 > **목적**: SAM ERP의 확장 가능한 통계 전용 데이터베이스(sam_stat) 설계 > **기준 문서**: `docs/specs/database-schema.md`, `docs/architecture/system-overview.md` -> **상태**: 📋 설계 제안 (검토 대기) +> **상태**: ✅ 구현 완료 --- @@ -11,10 +11,10 @@ | 항목 | 내용 | |------|------| -| **마지막 완료 작업** | Phase 5: 최적화 및 안정화 완료 (백필/검증 커맨드, 파티셔닝 준비, Redis 캐싱, 모니터링 알림) | -| **다음 작업** | Phase 6: 문서화 및 마무리 | -| **진행률** | 5/6 Phase (83%) | -| **마지막 업데이트** | 2026-01-29 | +| **마지막 완료 작업** | Phase 6: 문서화 및 마무리 완료 (Swagger, DB 스키마 문서, 계획 문서 완료 처리) | +| **다음 작업** | ✅ 전체 완료 | +| **진행률** | 6/6 Phase (100%) | +| **마지막 업데이트** | 2026-01-30 | --- @@ -1118,6 +1118,13 @@ docker compose exec mysql mysql -u root -proot sam_stat \ | 5.4 | Redis 캐싱 | ✅ | `StatQueryService` - Cache::remember TTL 5분. 키 패턴: `stat:{daily\|monthly\|dashboard}:{tenantId}:...`. `invalidateCache()` 정적 메서드: Redis keys 패턴 매칭 삭제. 집계 완료 시 StatAggregatorService에서 자동 호출 | | 5.5 | 모니터링 알림 | ✅ | `StatMonitorService` - recordAggregationFailure(critical), recordMissingData(warning), recordMismatch(critical), resolveAlerts(). StatAggregatorService catch 블록에서 자동 호출. stat_alerts 테이블 연동 검증 완료 | +### Phase 6: 문서화 및 마무리 +| # | 작업 항목 | 상태 | 구체적 작업 내용 | +|---|----------|:----:|-----------------| +| 6.1 | Swagger API 문서 | ✅ | `app/Swagger/v1/StatApi.php` - Stats 태그, 4개 엔드포인트 (summary/daily/monthly/alerts), StatSalesDaily/StatFinanceDaily/StatDashboardSummary/StatAlert 스키마 정의. `l5-swagger:generate` 성공 | +| 6.2 | DB 스키마 문서 | ✅ | `docs/specs/database-schema.md`에 sam_stat 섹션 추가 - 20개 테이블 (메타 2, 차원 3, 일간 7, 월간 4, KPI/알림/이벤트 4) + Artisan 커맨드 5개 + API 엔드포인트 4개 | +| 6.3 | 계획 문서 완료 | ✅ | Phase 6 섹션 추가, 진행률 100%, 상태 완료 | + --- ## 7. 기술 설계 요약 @@ -1280,6 +1287,7 @@ StatSalesDaily::updateOrCreate( | 2026-01-29 | Phase 3 완료 | P1 도메인: dim_client/dim_product 차원 + 재고/견적/인사 일간 3개 + KPI/알림 2개 = 테이블 7개, 모델 7개, 서비스 4개(Dimension/Inventory/Quote/Hr/KpiAlert), 커맨드 1개, 스케줄러 1개. 실데이터 검증 완료. products→items, client_groups.name→group_name 수정 | | 2026-01-29 | Phase 4 완료 | P2 도메인 + API + 대시보드: stat_project_monthly/stat_system_daily/stat_events/stat_snapshots 테이블 4개, 모델 4개, 서비스 4개(Project/System/StatEvent/StatQuery), StatController + FormRequest 3개 + routes/stats.php, StatEventObserver(6모델), DashboardService sam_stat 전환(폴백 패턴). 버그: whereHas→DB Builder 제거, User모델경로 수정. sam_stat 총 20테이블 | | 2026-01-29 | Phase 5 완료 | 최적화 및 안정화: StatBackfillCommand(백필), StatVerifyCommand(정합성 검증+자동 재집계), 파티셔닝 준비 마이그레이션(7테이블 RANGE), StatQueryService Redis 캐싱(TTL 5분+invalidateCache), StatMonitorService(집계 실패/누락/불일치 알림→stat_alerts), StatAggregatorService에 모니터링+캐시 무효화 연동. severity enum 수정(high→critical). 전체 테스트 통과 | +| 2026-01-30 | Phase 6 완료 | 문서화 및 마무리: StatApi.php Swagger 문서(4 엔드포인트, 4 스키마), database-schema.md sam_stat 섹션 추가(20테이블+5커맨드+4API). 전체 6 Phase 100% 완료 | --- diff --git a/specs/database-schema.md b/specs/database-schema.md index b8a1c31..21b676c 100644 --- a/specs/database-schema.md +++ b/specs/database-schema.md @@ -1,8 +1,8 @@ # SAM 데이터베이스 스키마 -**업데이트**: 2025-12-26 +**업데이트**: 2026-01-29 **데이터베이스**: samdb (MySQL 8.0.44) -**전체 테이블**: 171개 +**전체 테이블**: 219개 --- @@ -470,5 +470,76 @@ $role->syncPermissions(['users.view', 'users.create']); --- -**최종 업데이트**: 2025-11-24 -**Phase 4**: 완료 (8개 테이블 상세화) \ No newline at end of file +**최종 업데이트**: 2026-01-30 +**Phase 4**: 완료 (8개 테이블 상세화) +**테이블 수 갱신**: samdb 219개 + sam_stat 20개 = 239개 + +--- + +## sam_stat 데이터베이스 (통계 전용) + +> 별도 MySQL 데이터베이스. Laravel `sam_stat` 커넥션 사용. 마이그레이션 경로: `database/migrations/stats/` + +### 메타/관리 테이블 + +| 테이블 | 설명 | 주요 컬럼 | +|--------|------|----------| +| `stat_definitions` | 통계 정의 마스터 | domain, stat_type, table_name, is_active | +| `stat_job_logs` | 집계 작업 로그 | tenant_id, job_type, target_date, status, records_processed, duration_ms | + +### 차원 테이블 + +| 테이블 | 설명 | 주요 컬럼 | +|--------|------|----------| +| `dim_date` | 날짜 차원 (2020~2030) | date, year, quarter, month, day, day_of_week, is_weekend, is_holiday | +| `dim_client` | 고객 차원 (samdb 동기화) | tenant_id, source_client_id, client_name, group_name | +| `dim_product` | 제품 차원 (samdb 동기화) | tenant_id, source_product_id, product_name, product_type | + +### 일간 팩트 테이블 (7개) + +| 테이블 | 도메인 | UK | 주요 지표 | +|--------|--------|------|----------| +| `stat_sales_daily` | 매출/수주 | (tenant_id, stat_date) | order_count/amount, sales_count/amount, new/active_client_count, shipment_count/amount | +| `stat_finance_daily` | 재무/회계 | (tenant_id, stat_date) | deposit/withdrawal count/amount, net_cashflow, purchase_count/amount, bank_balance_total | +| `stat_production_daily` | 생산/작업 | (tenant_id, stat_date) | work_order_count, completed/in_progress_count, defect_count/rate, total_quantity | +| `stat_inventory_daily` | 재고 | (tenant_id, stat_date) | receipt_count/quantity, shipment_count/quantity, total_stock_value, low_stock_count | +| `stat_quote_pipeline_daily` | 견적/영업 | (tenant_id, stat_date) | new/sent/won/lost_quote_count, pipeline_value, conversion_rate, avg_quote_amount | +| `stat_hr_attendance_daily` | 인사/근태 | (tenant_id, stat_date) | total/present/absent/late/leave_count, overtime_hours, attendance_rate | +| `stat_system_daily` | 시스템/감사 | (tenant_id, stat_date) | api_request/error_count, active_user_count, audit_create/update/delete_count, fcm_sent/failed_count | + +### 월간 요약 테이블 (4개) + +| 테이블 | 도메인 | UK | 주요 지표 | +|--------|--------|------|----------| +| `stat_sales_monthly` | 매출/수주 | (tenant_id, stat_year, stat_month) | order/sales/shipment count/amount, unique_client_count, avg_order_amount, mom/yoy_growth_rate | +| `stat_finance_monthly` | 재무/회계 | (tenant_id, stat_year, stat_month) | deposit/withdrawal/purchase_total, net_cashflow, bank_balance_end, mom_cashflow_change | +| `stat_production_monthly` | 생산/작업 | (tenant_id, stat_year, stat_month) | total_work_orders, completed/in_progress_count, avg_defect_rate, total_production_quantity | +| `stat_project_monthly` | 건설/프로젝트 | (tenant_id, stat_year, stat_month) | active/completed_site_count, new_contract_count/amount, gross_profit/rate | + +### KPI/알림/이벤트 테이블 + +| 테이블 | 설명 | 주요 컬럼 | +|--------|------|----------| +| `stat_kpi_targets` | KPI 목표값 | tenant_id, domain, metric_code, target_year/month, target_value, actual_value | +| `stat_alerts` | 통계 알림 | tenant_id, domain, alert_type, severity(enum: info/warning/critical), title, message, is_read, is_resolved | +| `stat_events` | 실시간 이벤트 로그 | tenant_id, domain, event_type, entity_type, entity_id, payload(JSON), occurred_at | +| `stat_snapshots` | 상태 스냅샷 | tenant_id, snapshot_date, domain, snapshot_type, data(JSON) | + +### Artisan 커맨드 + +| 커맨드 | 설명 | +|--------|------| +| `stat:aggregate-daily` | 일간 통계 집계 (스케줄러: 매일 01:00) | +| `stat:aggregate-monthly` | 월간 통계 집계 (스케줄러: 매월 1일 02:00) | +| `stat:sync-dimensions` | 차원 테이블 동기화 (스케줄러: 매일 00:30) | +| `stat:backfill --from= --to=` | 과거 데이터 일괄 백필 | +| `stat:verify --date=` | 원본 DB vs sam_stat 정합성 검증 | + +### API 엔드포인트 + +| Method | Path | 설명 | +|--------|------|------| +| GET | `/api/v1/stats/summary` | 대시보드 통계 요약 | +| GET | `/api/v1/stats/daily` | 도메인별 일간 통계 (domain, start_date, end_date) | +| GET | `/api/v1/stats/monthly` | 도메인별 월간 통계 (domain, year, month?) | +| GET | `/api/v1/stats/alerts` | 통계 알림 목록 (limit?, unread_only?) | \ No newline at end of file