diff --git a/backend-node/prisma/schema.prisma b/backend-node/prisma/schema.prisma index 5d0aa77b..bb214604 100644 --- a/backend-node/prisma/schema.prisma +++ b/backend-node/prisma/schema.prisma @@ -5328,6 +5328,12 @@ model dataflow_diagrams { diagram_name String @db.VarChar(255) relationships Json // 모든 관계 정보를 JSON으로 저장 node_positions Json? // 테이블 노드의 캔버스 위치 정보 (JSON 형태) + + // 조건부 연결 관련 컬럼들 + control Json? // 조건 설정 (트리거 타입, 조건 트리) + category Json? // 연결 종류 (타입, 기본 옵션) + plan Json? // 실행 계획 (대상 액션들) + company_code String @db.VarChar(50) created_at DateTime? @default(now()) @db.Timestamp(6) updated_at DateTime? @default(now()) @updatedAt @db.Timestamp(6) diff --git a/backend-node/src/services/dataflowDiagramService.ts b/backend-node/src/services/dataflowDiagramService.ts index 16524e4a..c477df93 100644 --- a/backend-node/src/services/dataflowDiagramService.ts +++ b/backend-node/src/services/dataflowDiagramService.ts @@ -8,6 +8,12 @@ interface CreateDataflowDiagramData { diagram_name: string; relationships: any; // JSON 데이터 node_positions?: any; // JSON 데이터 (노드 위치 정보) + + // 조건부 연결 관련 필드 + control?: any; // JSON 데이터 (조건 설정) + category?: any; // JSON 데이터 (연결 종류) + plan?: any; // JSON 데이터 (실행 계획) + company_code: string; created_by: string; updated_by: string; @@ -17,6 +23,12 @@ interface UpdateDataflowDiagramData { diagram_name?: string; relationships?: any; // JSON 데이터 node_positions?: any; // JSON 데이터 (노드 위치 정보) + + // 조건부 연결 관련 필드 + control?: any; // JSON 데이터 (조건 설정) + category?: any; // JSON 데이터 (연결 종류) + plan?: any; // JSON 데이터 (실행 계획) + updated_by: string; } diff --git a/docs/조건부_연결_구현_계획.md b/docs/조건부_연결_구현_계획.md new file mode 100644 index 00000000..a16b7cd7 --- /dev/null +++ b/docs/조건부_연결_구현_계획.md @@ -0,0 +1,297 @@ +# 🔗 조건부 연결 기능 구현 계획 + +## 📋 프로젝트 개요 + +현재 DataFlow 시스템에서 3가지 연결 종류를 지원하고 있으며, 이 중 **데이터 저장**과 **외부 호출** 기능에 조건부 실행 로직을 추가해야 합니다. + +### 현재 연결 종류 + +1. **단순 키값 연결** - 조건 설정 불필요 (기존 방식 유지) +2. **데이터 저장** - 조건부 실행 필요 ✨ +3. **외부 호출** - 조건부 실행 필요 ✨ + +## 🎯 기능 요구사항 + +### 데이터 저장 기능 + +``` +"from 테이블의 컬럼이 특정 조건을 만족하면 to 테이블에 특정 액션을 취할 것" +``` + +**예시 시나리오:** + +- `work_order` 테이블의 `status = 'APPROVED'` 이고 `quantity > 0` 일 때 +- `material_requirement` 테이블에 자재 소요량 데이터 INSERT + +### 외부 호출 기능 + +``` +"from테이블의 컬럼이 특정 조건을 만족하면 외부 api호출이나 이메일 발송 등의 동작을 취해야 함" +``` + +**예시 시나리오:** + +- `employee_master` 테이블의 `employment_status = 'APPROVED'` 일 때 +- 외부 이메일 API 호출하여 환영 메일 발송 + +## 🗄️ 데이터베이스 스키마 변경 + +### 1. 컬럼 추가 + +```sql +-- 기존 데이터 삭제 후 dataflow_diagrams 테이블에 3개 컬럼 추가 +DELETE FROM dataflow_diagrams; -- 기존 데이터 전체 삭제 + +ALTER TABLE dataflow_diagrams +ADD COLUMN control JSONB, -- 조건 설정 +ADD COLUMN category JSONB, -- 연결 종류 설정 +ADD COLUMN plan JSONB; -- 실행 계획 설정 + +-- 인덱스 추가 +CREATE INDEX idx_dataflow_control_trigger ON dataflow_diagrams USING GIN ((control->'triggerType')); +CREATE INDEX idx_dataflow_category_type ON dataflow_diagrams USING GIN ((category->'type')); +``` + +### 2. 데이터 구조 설계 + +#### `control` 컬럼 - 조건 설정 + +```json +{ + "triggerType": "insert", + "conditionTree": { + "type": "group", + "operator": "AND", + "children": [ + { + "type": "condition", + "field": "status", + "operator": "=", + "value": "APPROVED" + } + ] + } +} +``` + +#### `category` 컬럼 - 연결 종류 + +```json +{ + "type": "data-save", // "simple-key" | "data-save" | "external-call" + "rollbackOnError": true, + "enableLogging": true +} +``` + +#### `plan` 컬럼 - 실행 계획 + +```json +{ + "sourceTable": "work_order", + "targetActions": [ + { + "id": "action_1", + "actionType": "insert", + "targetTable": "material_requirement", + "enabled": true, + "fieldMappings": [ + { + "sourceField": "work_order_id", + "targetField": "order_id" + } + ] + } + ] +} +``` + +## 🎨 프론트엔드 UI 개선 + +### ConnectionSetupModal.tsx 재설계 + +#### 현재 구조 문제점 + +- 모든 연결 종류에 동일한 UI 적용 +- 조건 설정 기능 없음 +- 단순 키값 연결과 조건부 연결의 구분 없음 + +#### 개선 방안 + +##### 1. 연결 종류별 UI 분기 + +```tsx +// 연결 종류 선택 후 조건부 렌더링 +{ + config.connectionType === "simple-key" && ; +} + +{ + (config.connectionType === "data-save" || + config.connectionType === "external-call") && ( + + ); +} +``` + +##### 2. 조건 설정 섹션 추가 + +```tsx +// control.html의 제어 조건 설정 섹션을 참조하여 구현 +
+

📋 실행 조건 설정

+ +
+``` + +##### 3. 액션 설정 섹션 + +```tsx +
+

⚡ 실행 액션

+ {config.connectionType === "data-save" && } + {config.connectionType === "external-call" && } +
+``` + +### 새로운 컴포넌트 구조 + +``` +ConnectionSetupModal.tsx +├── BasicConnectionInfo (공통) +├── ConnectionTypeSelector (공통) +├── SimpleKeyConnectionSettings (단순 키값 전용) +└── ConditionalConnectionSettings (조건부 연결 전용) + ├── ConditionBuilder (조건 설정) + ├── DataSaveActionSettings (데이터 저장 액션) + └── ExternalCallActionSettings (외부 호출 액션) +``` + +## ⚙️ 백엔드 서비스 구현 + +### 1. EventTriggerService 생성 + +```typescript +// backend-node/src/services/eventTriggerService.ts +export class EventTriggerService { + static async executeEventTriggers( + triggerType: "insert" | "update" | "delete", + tableName: string, + data: Record, + companyCode: string + ): Promise; + + static async executeDataSaveAction( + action: TargetAction, + sourceData: Record + ): Promise; + + static async executeExternalCallAction( + action: ExternalCallAction, + sourceData: Record + ): Promise; +} +``` + +### 2. DynamicFormService 연동 + +```typescript +// 기존 saveFormData 메서드에 트리거 실행 추가 +async saveFormData(screenId: number, tableName: string, data: Record) { + // 기존 저장 로직 + const result = await this.saveToDatabase(data); + + // 🔥 조건부 연결 실행 + await EventTriggerService.executeEventTriggers("insert", tableName, data, companyCode); + + return result; +} +``` + +### 3. API 엔드포인트 추가 + +```typescript +// backend-node/src/routes/dataflowRoutes.ts +router.post("/diagrams/:id/test-conditions", async (req, res) => { + // 조건 테스트 실행 +}); + +router.post("/diagrams/:id/execute-actions", async (req, res) => { + // 액션 수동 실행 +}); +``` + +## 📝 구현 단계별 계획 + +### Phase 1: 데이터베이스 준비 + +- [ ] dataflow_diagrams 테이블 컬럼 추가 (기존 데이터 삭제 후 진행) +- [ ] Prisma 스키마 업데이트 + +### Phase 2: 프론트엔드 UI 개선 + +- [ ] ConnectionSetupModal.tsx 재구조화 +- [ ] ConditionBuilder 컴포넌트 개발 +- [ ] 연결 종류별 설정 컴포넌트 분리 +- [ ] control.html 참조하여 조건 설정 UI 구현 + +### Phase 3: 백엔드 서비스 개발 + +- [ ] EventTriggerService 기본 구조 생성 +- [ ] 조건 평가 엔진 구현 +- [ ] 데이터 저장 액션 실행 로직 +- [ ] DynamicFormService 연동 + +### Phase 4: 외부 호출 기능 + +- [ ] 외부 API 호출 서비스 +- [ ] 이메일 발송 기능 +- [ ] 웹훅 지원 +- [ ] 오류 처리 및 재시도 로직 + +## 🔧 기술적 고려사항 + +### 1. 성능 최적화 + +- 조건 평가 시 인덱스 활용 +- 대량 데이터 처리 시 배치 처리 +- 비동기 실행으로 메인 로직 블로킹 방지 + +### 2. 오류 처리 + +- 트랜잭션 롤백 지원 +- 부분 실패 시 복구 메커니즘 +- 상세한 실행 로그 저장 + +### 3. 보안 + +- SQL 인젝션 방지 +- 외부 API 호출 시 인증 처리 +- 민감 데이터 마스킹 + +### 4. 확장성 + +- 새로운 액션 타입 추가 용이성 +- 복잡한 조건문 지원 +- 다양한 외부 서비스 연동 + +## 📚 참고 자료 + +- [control.html](../control.html) - 제어 조건 설정 UI 참조 +- [ConnectionSetupModal.tsx](../frontend/components/dataflow/ConnectionSetupModal.tsx) - 현재 구현 +- [화면간*데이터*관계*설정*시스템\_설계.md](./화면간_데이터_관계_설정_시스템_설계.md) - 전체 시스템 설계 + +## 🚀 다음 단계 + +1. **데이터베이스 스키마 업데이트** 부터 시작 +2. **UI 재설계** - control.html 참조하여 조건 설정 UI 구현 +3. **백엔드 서비스** 단계별 구현 +4. **외부 호출 기능** 구현 + +--- + +_이 문서는 조건부 연결 기능 구현을 위한 전체적인 로드맵을 제시합니다. 각 단계별로 상세한 구현 계획을 수립하여 진행할 예정입니다._ diff --git a/frontend/lib/api/dataflow.ts b/frontend/lib/api/dataflow.ts index da3cb7f6..04c95785 100644 --- a/frontend/lib/api/dataflow.ts +++ b/frontend/lib/api/dataflow.ts @@ -2,6 +2,68 @@ import { apiClient, ApiResponse } from "./client"; // 테이블 간 데이터 관계 설정 관련 타입 정의 +// 조건부 연결 관련 타입들 +export interface ConditionControl { + triggerType: "insert" | "update" | "delete" | "insert_update"; + conditionTree: ConditionNode; +} + +export interface ConditionNode { + type: "group" | "condition"; + operator?: "AND" | "OR"; + children?: ConditionNode[]; + field?: string; + operator_type?: + | "=" + | "!=" + | ">" + | "<" + | ">=" + | "<=" + | "LIKE" + | "NOT_LIKE" + | "CONTAINS" + | "STARTS_WITH" + | "ENDS_WITH" + | "IN" + | "NOT_IN" + | "IS_NULL" + | "IS_NOT_NULL" + | "BETWEEN" + | "NOT_BETWEEN"; + value?: any; + dataType?: string; +} + +export interface ConnectionCategory { + type: "simple-key" | "data-save" | "external-call" | "conditional-link"; + rollbackOnError?: boolean; + enableLogging?: boolean; + maxRetryCount?: number; +} + +export interface ExecutionPlan { + sourceTable: string; + targetActions: TargetAction[]; +} + +export interface TargetAction { + id: string; + actionType: "insert" | "update" | "delete" | "upsert"; + targetTable: string; + enabled: boolean; + fieldMappings: FieldMapping[]; + conditions?: ConditionNode; + description?: string; +} + +export interface FieldMapping { + sourceField: string; + targetField: string; + transformFunction?: string; + defaultValue?: string; +} + export interface ColumnInfo { columnName: string; columnLabel?: string; @@ -46,7 +108,7 @@ export interface TableRelationship { to_table_name: string; to_column_name: string; relationship_type: "one-to-one" | "one-to-many" | "many-to-one" | "many-to-many"; - connection_type: "simple-key" | "data-save" | "external-call"; + connection_type: "simple-key" | "data-save" | "external-call" | "conditional-link"; settings?: Record; company_code: string; is_active?: string; @@ -98,6 +160,11 @@ export interface DataFlowDiagram { relationshipCount: number; tables: string[]; companyCode: string; // 회사 코드 추가 + + // 조건부 연결 관련 필드 + control?: ConditionControl; // 조건 설정 + category?: ConnectionCategory; // 연결 종류 + plan?: ExecutionPlan; // 실행 계획 createdAt: Date; createdBy: string; updatedAt: Date;