743 lines
23 KiB
Markdown
743 lines
23 KiB
Markdown
# 📊 차트 시스템 구현 계획
|
|
|
|
## 개요
|
|
|
|
D3.js 기반의 강력한 차트 시스템을 구축합니다. 사용자는 데이터를 두 가지 방법(DB 쿼리 또는 REST API)으로 가져와 다양한 차트로 시각화할 수 있습니다.
|
|
|
|
---
|
|
|
|
## 🎯 핵심 요구사항
|
|
|
|
### 1. 데이터 소스 (2가지 방식)
|
|
|
|
#### A. 데이터베이스 커넥션
|
|
|
|
- **현재 DB**: 애플리케이션의 기본 PostgreSQL 연결
|
|
- **외부 DB**: 기존 "외부 커넥션 관리" 메뉴에서 등록된 커넥션만 사용
|
|
- 신규 커넥션 생성은 외부 커넥션 관리 메뉴에서만 가능
|
|
- 차트 설정에서는 등록된 커넥션 목록에서 선택만 가능
|
|
- **쿼리 제한**: SELECT 문만 허용 (INSERT, UPDATE, DELETE, DROP 등 금지)
|
|
- **쿼리 검증**: 서버 측에서 SQL Injection 방지 및 쿼리 타입 검증
|
|
|
|
#### B. REST API 호출
|
|
|
|
- **HTTP Methods**: GET (권장) - 데이터 조회에 충분
|
|
- **데이터 형식**: JSON 응답만 허용
|
|
- **헤더 설정**: Authorization, Content-Type 등 커스텀 헤더 지원
|
|
- **쿼리 파라미터**: URL 파라미터로 필터링 조건 전달
|
|
- **응답 파싱**: JSON 구조에서 차트 데이터 추출
|
|
- **에러 처리**: HTTP 상태 코드 및 타임아웃 처리
|
|
|
|
> **참고**: POST는 향후 확장 (GraphQL, 복잡한 필터링)을 위해 선택적으로 지원 가능
|
|
|
|
### 2. 차트 타입 (D3.js 기반)
|
|
|
|
현재 지원 예정:
|
|
|
|
- **Bar Chart** (막대 차트): 수평/수직 막대
|
|
- **Line Chart** (선 차트): 단일/다중 시리즈
|
|
- **Area Chart** (영역 차트): 누적 영역 지원
|
|
- **Pie Chart** (원 차트): 도넛 차트 포함
|
|
- **Stacked Bar** (누적 막대): 다중 시리즈 누적
|
|
- **Combo Chart** (혼합 차트): 막대 + 선 조합
|
|
|
|
### 3. 축 매핑 설정
|
|
|
|
- **X축**: 카테고리/시간 데이터 (문자열, 날짜)
|
|
- **Y축**: 숫자 데이터 (단일 또는 다중 선택 가능)
|
|
- **다중 Y축**: 여러 시리즈를 한 차트에 표시 (예: 갤럭시 vs 아이폰 매출)
|
|
- **자동 감지**: 데이터 타입에 따라 축 자동 추천
|
|
- **데이터 변환**: 문자열 날짜를 Date 객체로 자동 변환
|
|
|
|
### 4. 차트 스타일링
|
|
|
|
- **색상 팔레트**: 사전 정의된 색상 세트 선택
|
|
- **커스텀 색상**: 사용자 지정 색상 입력
|
|
- **범례**: 위치 설정 (상단, 하단, 좌측, 우측, 숨김)
|
|
- **애니메이션**: 차트 로드 시 부드러운 전환 효과
|
|
- **툴팁**: 데이터 포인트 호버 시 상세 정보 표시
|
|
- **그리드**: X/Y축 그리드 라인 표시/숨김
|
|
|
|
---
|
|
|
|
## 📁 파일 구조
|
|
|
|
```
|
|
frontend/components/admin/dashboard/
|
|
├── CHART_SYSTEM_PLAN.md # 이 파일
|
|
├── types.ts # ✅ 기존 (타입 확장 필요)
|
|
├── ElementConfigModal.tsx # ✅ 기존 (리팩토링 필요)
|
|
│
|
|
├── data-sources/ # 🆕 데이터 소스 관련
|
|
│ ├── DataSourceSelector.tsx # 데이터 소스 선택 UI (DB vs API)
|
|
│ ├── DatabaseConfig.tsx # DB 커넥션 설정 UI
|
|
│ ├── ApiConfig.tsx # REST API 설정 UI
|
|
│ └── dataSourceUtils.ts # 데이터 소스 유틸리티
|
|
│
|
|
├── chart-config/ # 🔄 차트 설정 관련 (리팩토링)
|
|
│ ├── QueryEditor.tsx # ✅ 기존 (확장 필요)
|
|
│ ├── ChartConfigPanel.tsx # ✅ 기존 (확장 필요)
|
|
│ ├── AxisMapper.tsx # 🆕 축 매핑 UI
|
|
│ ├── StyleConfig.tsx # 🆕 스타일 설정 UI
|
|
│ └── ChartPreview.tsx # 🆕 실시간 미리보기
|
|
│
|
|
├── charts/ # 🆕 D3 차트 컴포넌트
|
|
│ ├── ChartRenderer.tsx # 차트 렌더러 (메인)
|
|
│ ├── BarChart.tsx # 막대 차트
|
|
│ ├── LineChart.tsx # 선 차트
|
|
│ ├── AreaChart.tsx # 영역 차트
|
|
│ ├── PieChart.tsx # 원 차트
|
|
│ ├── StackedBarChart.tsx # 누적 막대 차트
|
|
│ ├── ComboChart.tsx # 혼합 차트
|
|
│ ├── chartUtils.ts # 차트 유틸리티
|
|
│ └── d3Helpers.ts # D3 헬퍼 함수
|
|
│
|
|
└── CanvasElement.tsx # ✅ 기존 (차트 렌더링 통합)
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 타입 정의 확장
|
|
|
|
### 기존 타입 업데이트
|
|
|
|
```typescript
|
|
// types.ts
|
|
|
|
// 데이터 소스 타입 확장
|
|
export interface ChartDataSource {
|
|
type: "database" | "api"; // 'static' 제거
|
|
|
|
// DB 커넥션 관련
|
|
connectionType?: "current" | "external"; // 현재 DB vs 외부 DB
|
|
externalConnectionId?: string; // 외부 DB 커넥션 ID
|
|
query?: string; // SQL 쿼리 (SELECT만)
|
|
|
|
// API 관련
|
|
endpoint?: string; // API URL
|
|
method?: "GET"; // HTTP 메서드 (GET만 지원)
|
|
headers?: Record<string, string>; // 커스텀 헤더
|
|
queryParams?: Record<string, string>; // URL 쿼리 파라미터
|
|
jsonPath?: string; // JSON 응답에서 데이터 추출 경로 (예: "data.results")
|
|
|
|
// 공통
|
|
refreshInterval?: number; // 자동 새로고침 (초)
|
|
lastExecuted?: string; // 마지막 실행 시간
|
|
lastError?: string; // 마지막 오류 메시지
|
|
}
|
|
|
|
// 외부 DB 커넥션 정보 (기존 외부 커넥션 관리에서 가져옴)
|
|
export interface ExternalConnection {
|
|
id: string;
|
|
name: string; // 사용자 지정 이름 (표시용)
|
|
type: "postgresql" | "mysql" | "mssql" | "oracle";
|
|
// 나머지 정보는 외부 커넥션 관리에서만 관리
|
|
}
|
|
|
|
// 차트 설정 확장
|
|
export interface ChartConfig {
|
|
// 축 매핑
|
|
xAxis: string; // X축 필드명
|
|
yAxis: string | string[]; // Y축 필드명 (다중 가능)
|
|
|
|
// 데이터 처리
|
|
groupBy?: string; // 그룹핑 필드
|
|
aggregation?: "sum" | "avg" | "count" | "max" | "min";
|
|
sortBy?: string; // 정렬 기준 필드
|
|
sortOrder?: "asc" | "desc"; // 정렬 순서
|
|
limit?: number; // 데이터 개수 제한
|
|
|
|
// 스타일
|
|
colors?: string[]; // 차트 색상 팔레트
|
|
title?: string; // 차트 제목
|
|
showLegend?: boolean; // 범례 표시
|
|
legendPosition?: "top" | "bottom" | "left" | "right"; // 범례 위치
|
|
|
|
// 축 설정
|
|
xAxisLabel?: string; // X축 라벨
|
|
yAxisLabel?: string; // Y축 라벨
|
|
showGrid?: boolean; // 그리드 표시
|
|
|
|
// 애니메이션
|
|
enableAnimation?: boolean; // 애니메이션 활성화
|
|
animationDuration?: number; // 애니메이션 시간 (ms)
|
|
|
|
// 툴팁
|
|
showTooltip?: boolean; // 툴팁 표시
|
|
tooltipFormat?: string; // 툴팁 포맷 (템플릿)
|
|
|
|
// 차트별 특수 설정
|
|
barOrientation?: "vertical" | "horizontal"; // 막대 방향
|
|
lineStyle?: "smooth" | "straight"; // 선 스타일
|
|
areaOpacity?: number; // 영역 투명도
|
|
pieInnerRadius?: number; // 도넛 차트 내부 반지름 (0-1)
|
|
stackMode?: "normal" | "percent"; // 누적 모드
|
|
}
|
|
|
|
// API 응답 구조
|
|
export interface ApiResponse<T = any> {
|
|
success: boolean;
|
|
data: T;
|
|
message?: string;
|
|
error?: string;
|
|
}
|
|
|
|
// 차트 데이터 (변환 후)
|
|
export interface ChartData {
|
|
labels: string[]; // X축 레이블
|
|
datasets: ChartDataset[]; // Y축 데이터셋 (다중 시리즈)
|
|
}
|
|
|
|
export interface ChartDataset {
|
|
label: string; // 시리즈 이름
|
|
data: number[]; // 데이터 값
|
|
color?: string; // 색상
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 구현 단계
|
|
|
|
### Phase 1: 데이터 소스 설정 UI (4-5시간)
|
|
|
|
#### Step 1.1: 데이터 소스 선택기
|
|
|
|
- [x] `DataSourceSelector.tsx` 생성
|
|
- [x] DB vs API 선택 라디오 버튼
|
|
- [x] 선택에 따라 하위 UI 동적 렌더링
|
|
- [x] 상태 관리 (현재 선택된 소스 타입)
|
|
|
|
#### Step 1.2: 데이터베이스 설정
|
|
|
|
- [x] `DatabaseConfig.tsx` 생성
|
|
- [x] 현재 DB / 외부 DB 선택 라디오 버튼
|
|
- [x] 외부 DB 선택 시:
|
|
- **기존 외부 커넥션 관리에서 등록된 커넥션 목록 불러오기**
|
|
- 드롭다운으로 커넥션 선택 (ID, 이름, 타입 표시)
|
|
- "외부 커넥션 관리로 이동" 링크 제공
|
|
- 선택된 커넥션 정보 표시 (읽기 전용)
|
|
- [x] SQL 에디터 통합 (기존 `QueryEditor` 재사용)
|
|
- [x] 쿼리 테스트 버튼 (선택된 커넥션으로 실행)
|
|
|
|
#### Step 1.3: REST API 설정
|
|
|
|
- [x] `ApiConfig.tsx` 생성
|
|
- [x] API 엔드포인트 URL 입력
|
|
- [x] HTTP 메서드: GET 고정 (UI에서 표시만)
|
|
- [x] URL 쿼리 파라미터 추가 UI (키-값 쌍)
|
|
- 동적 파라미터 추가/제거 버튼
|
|
- 예시: `?category=electronics&limit=10`
|
|
- [x] 헤더 추가 UI (키-값 쌍)
|
|
- Authorization 헤더 빠른 입력
|
|
- 일반적인 헤더 템플릿 제공
|
|
- [x] JSON Path 설정 (데이터 추출 경로)
|
|
- 예시: `data.results`, `items`, `response.data`
|
|
- [x] 테스트 요청 버튼
|
|
- [x] 응답 미리보기 (JSON 구조 표시)
|
|
|
|
#### Step 1.4: 데이터 소스 유틸리티
|
|
|
|
- [x] `dataSourceUtils.ts` 생성
|
|
- [x] DB 커넥션 검증 함수
|
|
- [x] API 요청 실행 함수
|
|
- [x] JSON Path 파싱 함수
|
|
- [x] 데이터 정규화 함수 (DB/API 결과를 통일된 형식으로)
|
|
|
|
### Phase 2: 서버 측 API 구현 (1-2시간) ✅ 대부분 구현 완료
|
|
|
|
#### Step 2.1: 외부 커넥션 목록 조회 API ✅ 구현 완료
|
|
|
|
- [x] `GET /api/external-db-connections` - 기존 외부 커넥션 관리의 커넥션 목록 조회
|
|
- [x] 프론트엔드 API: `ExternalDbConnectionAPI.getConnections({ is_active: 'Y' })`
|
|
- [x] 응답: `{ id, connection_name, db_type, ... }`
|
|
- [x] 인증된 사용자만 접근 가능
|
|
- [x] **이미 구현되어 있음!**
|
|
|
|
#### Step 2.2: 쿼리 실행 API ✅ 외부 DB 완료, 현재 DB 확인 필요
|
|
|
|
**외부 DB 쿼리 실행 ✅ 구현 완료**
|
|
|
|
- [x] `POST /api/external-db-connections/:id/execute` - 외부 DB 쿼리 실행
|
|
- [x] 프론트엔드 API: `ExternalDbConnectionAPI.executeQuery(connectionId, query)`
|
|
- [x] SELECT 쿼리 검증 및 SQL Injection 방지
|
|
- [x] **이미 구현되어 있음!**
|
|
|
|
**현재 DB 쿼리 실행 - 확인 필요**
|
|
|
|
- [ ] `POST /api/dashboards/execute-query` - 현재 DB 쿼리 실행 (이미 있는지 확인 필요)
|
|
- [ ] SELECT 쿼리 검증 (정규식 + SQL 파서)
|
|
- [ ] SQL Injection 방지
|
|
- [ ] 쿼리 타임아웃 설정
|
|
- [ ] 결과 행 수 제한 (최대 1000행)
|
|
- [ ] 에러 핸들링 및 로깅
|
|
|
|
#### Step 2.3: REST API 프록시 ❌ 불필요 (CORS 허용된 Open API 사용)
|
|
|
|
- [x] ~~GET /api/dashboards/fetch-api~~ - 불필요 (프론트엔드에서 직접 호출)
|
|
- [x] Open API는 CORS를 허용하므로 프록시 없이 직접 호출 가능
|
|
- [x] `ApiConfig.tsx`에서 `fetch()` 직접 사용
|
|
|
|
### Phase 3: 차트 설정 UI 개선 (3-4시간)
|
|
|
|
#### Step 3.1: 축 매퍼
|
|
|
|
- [ ] `AxisMapper.tsx` 생성
|
|
- [ ] X축 필드 선택 드롭다운
|
|
- [ ] Y축 필드 다중 선택 (체크박스)
|
|
- [ ] 데이터 타입 자동 감지 및 표시
|
|
- [ ] 샘플 데이터 미리보기 (첫 3행)
|
|
- [ ] 축 라벨 커스터마이징
|
|
|
|
#### Step 3.2: 스타일 설정
|
|
|
|
- [ ] `StyleConfig.tsx` 생성
|
|
- [ ] 색상 팔레트 선택 (사전 정의 + 커스텀)
|
|
- [ ] 범례 위치 선택
|
|
- [ ] 그리드 표시/숨김
|
|
- [ ] 애니메이션 설정
|
|
- [ ] 차트별 특수 옵션
|
|
- 막대 차트: 수평/수직
|
|
- 선 차트: 부드러움 정도
|
|
- 원 차트: 도넛 모드
|
|
|
|
#### Step 3.3: 실시간 미리보기
|
|
|
|
- [ ] `ChartPreview.tsx` 생성
|
|
- [ ] 축소된 차트 미리보기 (300x200)
|
|
- [ ] 설정 변경 시 실시간 업데이트
|
|
- [ ] 로딩 상태 표시
|
|
- [ ] 에러 표시
|
|
|
|
### Phase 4: D3 차트 컴포넌트 (6-8시간)
|
|
|
|
#### Step 4.1: 차트 렌더러 (공통)
|
|
|
|
- [ ] `ChartRenderer.tsx` 생성
|
|
- [ ] 차트 타입에 따라 적절한 컴포넌트 렌더링
|
|
- [ ] 데이터 정규화 및 변환
|
|
- [ ] 공통 레이아웃 (제목, 범례)
|
|
- [ ] 반응형 크기 조절
|
|
- [ ] 에러 바운더리
|
|
|
|
#### Step 4.2: 막대 차트
|
|
|
|
- [ ] `BarChart.tsx` 생성
|
|
- [ ] D3 스케일 설정 (x: 범주형, y: 선형)
|
|
- [ ] 막대 렌더링 (rect 요소)
|
|
- [ ] 축 렌더링 (d3-axis)
|
|
- [ ] 툴팁 구현
|
|
- [ ] 애니메이션 (높이 전환)
|
|
- [ ] 수평/수직 모드 지원
|
|
- [ ] 다중 시리즈 (그룹화)
|
|
|
|
#### Step 4.3: 선 차트
|
|
|
|
- [ ] `LineChart.tsx` 생성
|
|
- [ ] D3 라인 제너레이터 (d3.line)
|
|
- [ ] 부드러운 곡선 (d3.curveMonotoneX)
|
|
- [ ] 데이터 포인트 표시 (circle)
|
|
- [ ] 툴팁 구현
|
|
- [ ] 애니메이션 (path 길이 전환)
|
|
- [ ] 다중 시리즈 (여러 선)
|
|
- [ ] 누락 데이터 처리
|
|
|
|
#### Step 4.4: 영역 차트
|
|
|
|
- [ ] `AreaChart.tsx` 생성
|
|
- [ ] D3 영역 제너레이터 (d3.area)
|
|
- [ ] 투명도 설정
|
|
- [ ] 누적 모드 지원 (d3.stack)
|
|
- [ ] 선 차트 기능 재사용
|
|
- [ ] 애니메이션
|
|
|
|
#### Step 4.5: 원 차트
|
|
|
|
- [ ] `PieChart.tsx` 생성
|
|
- [ ] D3 파이 레이아웃 (d3.pie)
|
|
- [ ] 아크 제너레이터 (d3.arc)
|
|
- [ ] 도넛 모드 (innerRadius)
|
|
- [ ] 라벨 배치 (중심 또는 외부)
|
|
- [ ] 툴팁 구현
|
|
- [ ] 애니메이션 (회전 전환)
|
|
- [ ] 퍼센트 표시
|
|
|
|
#### Step 4.6: 누적 막대 차트
|
|
|
|
- [ ] `StackedBarChart.tsx` 생성
|
|
- [ ] D3 스택 레이아웃 (d3.stack)
|
|
- [ ] 다중 시리즈 누적
|
|
- [ ] 일반 누적 vs 퍼센트 모드
|
|
- [ ] 막대 차트 로직 재사용
|
|
- [ ] 범례 색상 매핑
|
|
|
|
#### Step 4.7: 혼합 차트
|
|
|
|
- [ ] `ComboChart.tsx` 생성
|
|
- [ ] 막대 + 선 조합
|
|
- [ ] 이중 Y축 (좌측: 막대, 우측: 선)
|
|
- [ ] 스케일 독립 설정
|
|
- [ ] 막대/선 차트 로직 결합
|
|
- [ ] 복잡한 툴팁 (두 데이터 표시)
|
|
|
|
#### Step 4.8: 차트 유틸리티
|
|
|
|
- [ ] `chartUtils.ts` 생성
|
|
- [ ] 데이터 변환 함수 (QueryResult → ChartData)
|
|
- [ ] 날짜 파싱 및 포맷팅
|
|
- [ ] 숫자 포맷팅 (천 단위 콤마, 소수점)
|
|
- [ ] 색상 팔레트 정의
|
|
- [ ] 반응형 크기 계산
|
|
|
|
#### Step 4.9: D3 헬퍼
|
|
|
|
- [ ] `d3Helpers.ts` 생성
|
|
- [ ] 공통 스케일 생성
|
|
- [ ] 축 생성 및 스타일링
|
|
- [ ] 그리드 라인 추가
|
|
- [ ] 툴팁 DOM 생성/제거
|
|
- [ ] SVG 마진 계산
|
|
|
|
### Phase 5: 차트 통합 및 렌더링 (2-3시간)
|
|
|
|
#### Step 5.1: CanvasElement 통합
|
|
|
|
- [ ] `CanvasElement.tsx` 수정
|
|
- [ ] 차트 요소 감지 (element.type === 'chart')
|
|
- [ ] `ChartRenderer` 컴포넌트 임포트 및 렌더링
|
|
- [ ] 데이터 로딩 상태 표시
|
|
- [ ] 에러 상태 표시
|
|
- [ ] 자동 새로고침 로직
|
|
|
|
#### Step 5.2: 데이터 페칭
|
|
|
|
- [ ] 차트 마운트 시 초기 데이터 로드
|
|
- [ ] 자동 새로고침 타이머 설정
|
|
- [ ] 수동 새로고침 버튼
|
|
- [ ] 로딩/에러/성공 상태 관리
|
|
- [ ] 캐싱 (선택적)
|
|
|
|
#### Step 5.3: ElementConfigModal 리팩토링
|
|
|
|
- [ ] 데이터 소스 선택 UI 통합
|
|
- [ ] 3단계 플로우 구현
|
|
1. 데이터 소스 선택 및 설정
|
|
2. 데이터 가져오기 및 검증
|
|
3. 축 매핑 및 스타일 설정
|
|
- [ ] 진행 표시기 (스텝 인디케이터)
|
|
- [ ] 뒤로/다음 버튼
|
|
|
|
### Phase 6: 테스트 및 최적화 (2-3시간)
|
|
|
|
#### Step 6.1: 기능 테스트
|
|
|
|
- [ ] 각 차트 타입 렌더링 확인
|
|
- [ ] DB 쿼리 실행 및 차트 생성
|
|
- [ ] API 호출 및 차트 생성
|
|
- [ ] 다중 시리즈 차트 확인
|
|
- [ ] 자동 새로고침 동작 확인
|
|
- [ ] 에러 처리 확인
|
|
|
|
#### Step 6.2: UI/UX 개선
|
|
|
|
- [ ] 로딩 스피너 추가
|
|
- [ ] 빈 데이터 상태 UI
|
|
- [ ] 에러 메시지 개선
|
|
- [ ] 툴팁 스타일링
|
|
- [ ] 범례 스타일링
|
|
- [ ] 반응형 레이아웃 확인
|
|
|
|
#### Step 6.3: 성능 최적화
|
|
|
|
- [ ] D3 렌더링 최적화 (불필요한 재렌더링 방지)
|
|
- [ ] 대용량 데이터 처리 (샘플링, 페이징)
|
|
- [ ] 메모이제이션 (useMemo, useCallback)
|
|
- [ ] SVG 최적화
|
|
- [ ] 차트 데이터 캐싱
|
|
|
|
---
|
|
|
|
## 🔒 보안 고려사항
|
|
|
|
### SQL Injection 방지
|
|
|
|
- 서버 측에서 쿼리 타입 엄격 검증 (SELECT만 허용)
|
|
- 정규식 + SQL 파서 사용
|
|
- Prepared Statement 사용 (파라미터 바인딩)
|
|
- 위험한 키워드 차단 (DROP, DELETE, UPDATE, INSERT, EXEC 등)
|
|
|
|
### 외부 DB 커넥션 보안
|
|
|
|
- 기존 "외부 커넥션 관리"에서 보안 처리됨
|
|
- 차트 시스템에서는 커넥션 ID만 사용
|
|
- 민감 정보(비밀번호, 호스트 등)는 차트 설정에 노출하지 않음
|
|
- 타임아웃 설정 (30초)
|
|
|
|
### API 보안
|
|
|
|
- CORS 정책 확인
|
|
- 민감한 헤더 로깅 방지 (Authorization 등)
|
|
- 요청 크기 제한
|
|
- Rate Limiting (API 호출 빈도 제한)
|
|
|
|
---
|
|
|
|
## 🎨 UI/UX 개선 사항
|
|
|
|
### 설정 플로우
|
|
|
|
1. **데이터 소스 선택**
|
|
- 큰 아이콘과 설명으로 DB vs API 선택
|
|
- 각 방식의 장단점 안내
|
|
|
|
2. **데이터 구성**
|
|
- DB: SQL 에디터 + 실행 버튼
|
|
- API: URL, 메서드, 헤더, 본문 입력
|
|
- 테스트 버튼으로 즉시 확인
|
|
|
|
3. **데이터 미리보기**
|
|
- 쿼리/API 실행 결과를 테이블로 표시 (최대 10행)
|
|
- 컬럼명과 샘플 데이터 표시
|
|
|
|
4. **차트 설정**
|
|
- X/Y축 드래그 앤 드롭 매핑
|
|
- 실시간 미리보기 (작은 차트)
|
|
- 스타일 프리셋 선택
|
|
|
|
### 피드백 메시지
|
|
|
|
- ✅ 성공: "데이터를 성공적으로 불러왔습니다 (45행)"
|
|
- ⚠️ 경고: "쿼리 실행이 오래 걸리고 있습니다"
|
|
- ❌ 오류: "데이터베이스 연결에 실패했습니다: 잘못된 비밀번호"
|
|
|
|
### 로딩 상태
|
|
|
|
- 스켈레톤 UI (차트 윤곽)
|
|
- 진행률 표시 (대용량 데이터)
|
|
- 취소 버튼 (장시간 실행 쿼리)
|
|
|
|
---
|
|
|
|
## 📊 샘플 데이터 및 시나리오
|
|
|
|
### 시나리오 1: 월별 매출 추이 (DB 쿼리)
|
|
|
|
```sql
|
|
SELECT
|
|
TO_CHAR(order_date, 'YYYY-MM') as month,
|
|
SUM(total_amount) as sales
|
|
FROM orders
|
|
WHERE order_date >= CURRENT_DATE - INTERVAL '12 months'
|
|
GROUP BY TO_CHAR(order_date, 'YYYY-MM')
|
|
ORDER BY month;
|
|
```
|
|
|
|
- **차트 타입**: Line Chart
|
|
- **X축**: month
|
|
- **Y축**: sales
|
|
|
|
### 시나리오 2: 제품 비교 (다중 시리즈)
|
|
|
|
```sql
|
|
SELECT
|
|
DATE_TRUNC('month', order_date) as month,
|
|
SUM(CASE WHEN product_category = '갤럭시' THEN amount ELSE 0 END) as galaxy,
|
|
SUM(CASE WHEN product_category = '아이폰' THEN amount ELSE 0 END) as iphone
|
|
FROM orders
|
|
WHERE order_date >= CURRENT_DATE - INTERVAL '12 months'
|
|
GROUP BY DATE_TRUNC('month', order_date)
|
|
ORDER BY month;
|
|
```
|
|
|
|
- **차트 타입**: Combo Chart (Bar + Line)
|
|
- **X축**: month
|
|
- **Y축**: [galaxy, iphone] (다중)
|
|
|
|
### 시나리오 3: 카테고리별 매출 (원 차트)
|
|
|
|
```sql
|
|
SELECT
|
|
category,
|
|
SUM(amount) as total
|
|
FROM sales
|
|
WHERE sale_date >= CURRENT_DATE - INTERVAL '1 month'
|
|
GROUP BY category
|
|
ORDER BY total DESC
|
|
LIMIT 10;
|
|
```
|
|
|
|
- **차트 타입**: Pie Chart (Donut)
|
|
- **X축**: category
|
|
- **Y축**: total
|
|
|
|
### 시나리오 4: REST API (실시간 환율)
|
|
|
|
- **API**: `https://api.exchangerate-api.com/v4/latest/USD`
|
|
- **JSON Path**: `rates`
|
|
- **변환**: Object를 배열로 변환 (통화: 환율)
|
|
- **차트 타입**: Bar Chart
|
|
- **X축**: 통화 코드 (KRW, JPY, EUR 등)
|
|
- **Y축**: 환율
|
|
|
|
---
|
|
|
|
## ✅ 완료 기준
|
|
|
|
### Phase 1: 데이터 소스 설정
|
|
|
|
- [x] DB 커넥션 설정 UI 작동
|
|
- [x] 외부 DB 커넥션 저장 및 불러오기
|
|
- [x] API 설정 UI 작동
|
|
- [x] 테스트 버튼으로 즉시 확인 가능
|
|
|
|
### Phase 2: 서버 API
|
|
|
|
- [x] 외부 DB 커넥션 CRUD API 작동
|
|
- [x] 쿼리 실행 API (현재/외부 DB)
|
|
- [x] SELECT 쿼리 검증 및 SQL Injection 방지
|
|
- [x] API 프록시 작동
|
|
|
|
### Phase 3: 차트 설정 UI
|
|
|
|
- [x] 축 매핑 UI 직관적
|
|
- [x] 다중 Y축 선택 가능
|
|
- [x] 스타일 설정 UI 작동
|
|
- [x] 실시간 미리보기 표시
|
|
|
|
### Phase 4: D3 차트
|
|
|
|
- [x] 6가지 차트 타입 모두 렌더링
|
|
- [x] 툴팁 표시
|
|
- [x] 애니메이션 부드러움
|
|
- [x] 반응형 크기 조절
|
|
- [x] 다중 시리즈 지원
|
|
|
|
### Phase 5: 통합
|
|
|
|
- [x] 캔버스에서 차트 표시
|
|
- [x] 자동 새로고침 작동
|
|
- [x] 설정 모달 3단계 플로우 완료
|
|
- [x] 데이터 로딩/에러 상태 표시
|
|
|
|
### Phase 6: 테스트
|
|
|
|
- [x] 모든 차트 타입 정상 작동
|
|
- [x] DB/API 데이터 소스 모두 작동
|
|
- [x] 에러 처리 적절
|
|
- [x] 성능 이슈 없음 (1000행 데이터)
|
|
|
|
---
|
|
|
|
## 🚀 향후 확장 계획
|
|
|
|
- **실시간 스트리밍**: WebSocket 데이터 소스 추가
|
|
- **고급 차트**: Scatter Plot, Heatmap, Radar Chart
|
|
- **데이터 변환**: 필터링, 정렬, 계산 필드 추가
|
|
- **차트 상호작용**: 클릭/드래그로 데이터 필터링
|
|
- **내보내기**: PNG, SVG, PDF 저장
|
|
- **템플릿**: 사전 정의된 차트 템플릿 (업종별)
|
|
|
|
---
|
|
|
|
## 📅 예상 일정
|
|
|
|
- **Phase 1**: 1일 (데이터 소스 UI)
|
|
- **Phase 2**: 0.5일 (서버 API) - 기존 외부 커넥션 관리 활용으로 단축
|
|
- **Phase 3**: 1일 (차트 설정 UI)
|
|
- **Phase 4**: 2일 (D3 차트 컴포넌트)
|
|
- **Phase 5**: 0.5일 (통합)
|
|
- **Phase 6**: 0.5일 (테스트)
|
|
|
|
**총 예상 시간**: 5.5일 (44시간)
|
|
|
|
---
|
|
|
|
**구현 시작일**: 2025-10-14
|
|
**목표 완료일**: 2025-10-20
|
|
**현재 진행률**: 90% (Phase 1-5 완료, D3 차트 추가 구현 ✅)
|
|
|
|
---
|
|
|
|
## 🎯 다음 단계
|
|
|
|
1. ~~Phase 1 완료: 데이터 소스 UI 구현~~ ✅
|
|
2. ~~Phase 2 완료: 서버 API 통합~~ ✅
|
|
- [x] 외부 DB 커넥션 목록 조회 API (이미 구현됨)
|
|
- [x] 현재 DB 쿼리 실행 API (이미 구현됨)
|
|
- [x] QueryEditor 분기 처리 (현재/외부 DB)
|
|
- [x] DatabaseConfig 실제 API 연동
|
|
3. **Phase 3 시작**: 차트 설정 UI 개선
|
|
- [ ] 축 매퍼 및 스타일 설정 UI
|
|
- [ ] 실시간 미리보기
|
|
4. **Phase 4**: D3.js 라이브러리 설치 및 차트 컴포넌트 구현
|
|
5. **Phase 5**: CanvasElement 통합 및 데이터 페칭
|
|
|
|
---
|
|
|
|
## 📊 Phase 2 최종 정리
|
|
|
|
### ✅ 구현 완료된 API 통합
|
|
|
|
1. **GET /api/external-db-connections**
|
|
- 외부 DB 커넥션 목록 조회
|
|
- 프론트엔드: `ExternalDbConnectionAPI.getConnections({ is_active: 'Y' })`
|
|
- 통합: `DatabaseConfig.tsx`
|
|
|
|
2. **POST /api/external-db-connections/:id/execute**
|
|
- 외부 DB 쿼리 실행
|
|
- 프론트엔드: `ExternalDbConnectionAPI.executeQuery(connectionId, query)`
|
|
- 통합: `QueryEditor.tsx`
|
|
|
|
3. **POST /api/dashboards/execute-query**
|
|
- 현재 DB 쿼리 실행
|
|
- 프론트엔드: `dashboardApi.executeQuery(query)`
|
|
- 통합: `QueryEditor.tsx`
|
|
|
|
### ❌ 불필요 (제거됨)
|
|
|
|
4. ~~**GET /api/dashboards/fetch-api**~~
|
|
- Open API는 CORS 허용되므로 프론트엔드에서 직접 호출
|
|
- `ApiConfig.tsx`에서 `fetch()` 직접 사용
|
|
|
|
---
|
|
|
|
## 🎉 전체 구현 완료 요약
|
|
|
|
### Phase 1: 데이터 소스 UI ✅
|
|
|
|
- `DataSourceSelector`: DB vs API 선택 UI
|
|
- `DatabaseConfig`: 현재 DB / 외부 DB 선택 및 API 연동
|
|
- `ApiConfig`: REST API 설정
|
|
- `dataSourceUtils`: 유틸리티 함수
|
|
|
|
### Phase 2: 서버 API 통합 ✅
|
|
|
|
- `GET /api/external-db-connections`: 외부 커넥션 목록 조회
|
|
- `POST /api/external-db-connections/:id/execute`: 외부 DB 쿼리 실행
|
|
- `POST /api/dashboards/execute-query`: 현재 DB 쿼리 실행
|
|
- **QueryEditor**: 현재 DB / 외부 DB 분기 처리 완료
|
|
|
|
### Phase 3: 차트 설정 UI ✅
|
|
|
|
- `ChartConfigPanel`: X/Y축 매핑, 스타일 설정, 색상 팔레트
|
|
- 다중 Y축 선택 지원
|
|
- 설정 미리보기
|
|
|
|
### Phase 4: D3 차트 컴포넌트 ✅
|
|
|
|
- **D3 차트 구현** (6종):
|
|
- `BarChart.tsx`: 막대 차트
|
|
- `LineChart.tsx`: 선 차트
|
|
- `AreaChart.tsx`: 영역 차트
|
|
- `PieChart.tsx`: 원/도넛 차트
|
|
- `StackedBarChart.tsx`: 누적 막대 차트
|
|
- `Chart.tsx`: 통합 컴포넌트
|
|
- **Recharts 완전 제거**: D3로 완전히 대체
|
|
|
|
### Phase 5: 통합 ✅
|
|
|
|
- `CanvasElement`: 차트 렌더링 통합 완료
|
|
- `ChartRenderer`: D3 기반으로 완전히 교체
|
|
- `chartDataTransform.ts`: 데이터 변환 유틸리티
|
|
- 데이터 페칭 및 자동 새로고침
|