From cedb5e3ec37e7458c03bcac31fb198d28e49a36e Mon Sep 17 00:00:00 2001 From: kjs Date: Mon, 29 Sep 2025 10:23:21 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/controllers/adminController.ts | 4 +- backend-node/src/services/authService.ts | 2 +- 제어관리_시스템_개선_계획서.md | 469 ++++++++++++++++++ 3 files changed, 472 insertions(+), 3 deletions(-) create mode 100644 제어관리_시스템_개선_계획서.md diff --git a/backend-node/src/controllers/adminController.ts b/backend-node/src/controllers/adminController.ts index cc6b751e..e2e03e92 100644 --- a/backend-node/src/controllers/adminController.ts +++ b/backend-node/src/controllers/adminController.ts @@ -1523,7 +1523,7 @@ export const getUserInfo = async (req: AuthenticatedRequest, res: Response) => { partnerObjid: user.partner_objid, rank: user.rank, photo: user.photo - ? `data:image/jpeg;base64,${user.photo.toString("base64")}` + ? `data:image/jpeg;base64,${Buffer.from(user.photo).toString("base64")}` : null, locale: user.locale, companyCode: user.company_code, @@ -2415,7 +2415,7 @@ export const updateProfile = async ( const responseData = { ...updatedUser, photo: updatedUser?.photo - ? `data:image/jpeg;base64,${updatedUser.photo.toString("base64")}` + ? `data:image/jpeg;base64,${Buffer.from(updatedUser.photo).toString("base64")}` : null, }; diff --git a/backend-node/src/services/authService.ts b/backend-node/src/services/authService.ts index e02cd5b5..1502b97f 100644 --- a/backend-node/src/services/authService.ts +++ b/backend-node/src/services/authService.ts @@ -217,7 +217,7 @@ export class AuthService { authName: authNames || undefined, companyCode: userInfo.company_code || "ILSHIN", photo: userInfo.photo - ? `data:image/jpeg;base64,${userInfo.photo.toString("base64")}` + ? `data:image/jpeg;base64,${Buffer.from(userInfo.photo).toString("base64")}` : undefined, locale: userInfo.locale || "KR", }; diff --git a/제어관리_시스템_개선_계획서.md b/제어관리_시스템_개선_계획서.md new file mode 100644 index 00000000..1502af8a --- /dev/null +++ b/제어관리_시스템_개선_계획서.md @@ -0,0 +1,469 @@ +# 🔄 제어관리 시스템 개선 계획서 + +## 📋 개요 + +데이터 매핑 시스템이 추가되면서 기존 제어관리 로직과 버튼 연동 방식의 개선이 필요합니다. + +## 🎯 주요 개선사항 + +### 1. 명칭 변경: "관계도" → "관계" + +#### 1.1 변경 이유 + +- **기존**: "관계도"는 다이어그램 전체를 의미하는 용어 +- **현재**: 실제로는 개별 "관계"를 설정하고 관리 +- **개선**: 사용자 이해도 향상 및 용어 일관성 확보 + +#### 1.2 변경 대상 파일들 + +```typescript +// UI 컴포넌트들 +frontend / components / screen / config - + panels / ButtonDataflowConfigPanel.tsx; +frontend / components / dataflow / DataFlowDesigner.tsx; +frontend / components / dataflow / SaveDiagramModal.tsx; +frontend / components / dataflow / RelationshipListModal.tsx; +frontend / + components / + dataflow / + connection / + redesigned / + RightPanel / + ConnectionStep.tsx; + +// API 및 서비스 +frontend / lib / api / dataflow.ts; +frontend / hooks / useDataFlowDesigner.ts; + +// 타입 정의 +frontend / types / control - management.ts; +``` + +### 2. 버튼 제어관리 로직 개선 + +#### 2.1 현재 문제점 + +```typescript +// 🔴 기존: 복잡한 관계도 선택 방식 +interface ButtonDataflowConfig { + controlMode: "simple" | "advanced"; + selectedDiagramId?: number; // 관계도 전체 선택 + selectedRelationshipId?: string; // 개별 관계 선택 + // ... +} +``` + +#### 2.2 개선 방향 + +```typescript +// 🟢 개선: 단순화된 관계 직접 선택 +interface ButtonDataflowConfig { + controlMode: "relationship" | "external_call" | "custom"; + + // 관계 기반 제어 + relationshipConfig?: { + relationshipId: string; // 관계 직접 선택 + relationshipName: string; // 관계명 표시 + executionTiming: "before" | "after" | "replace"; + contextData?: Record; // 실행 시 전달할 컨텍스트 + }; + + // 외부호출 제어 + externalCallConfig?: { + configId: string; // external_call_configs ID + configName: string; // 설정명 표시 + executionTiming: "before" | "after" | "replace"; + dataMappingEnabled: boolean; // 데이터 매핑 사용 여부 + }; + + // 커스텀 제어 + customConfig?: { + actionType: string; + parameters: Record; + }; +} +``` + +### 3. 외부호출 연동 개선 + +#### 3.1 현재 외부호출 설정 방식 + +```typescript +// 🔴 현재: 복잡한 설정 구조 +interface ExternalCallConfig { + callType: "rest-api"; + restApiSettings: { + apiUrl: string; + httpMethod: string; + // ... 많은 설정들 + }; +} +``` + +#### 3.2 개선된 연동 방식 + +```typescript +// 🟢 개선: 단순화된 참조 구조 +interface ButtonExternalCallConfig { + // 1단계: 저장된 외부호출 설정 선택 + externalCallConfigId: string; // external_call_configs 테이블 ID + configName: string; // 설정명 (UI 표시용) + + // 2단계: 실행 시점 설정 + executionTiming: "before" | "after" | "replace"; + + // 3단계: 데이터 전달 방식 + dataMapping: { + enabled: boolean; // 데이터 매핑 사용 여부 + sourceMode: "form" | "table" | "custom"; // 데이터 소스 + sourceConfig?: { + tableName?: string; // table 모드용 + customData?: Record; // custom 모드용 + }; + }; + + // 4단계: 실행 옵션 + executionOptions: { + rollbackOnError: boolean; // 실패 시 롤백 + showLoadingIndicator: boolean; // 로딩 표시 + successMessage?: string; // 성공 메시지 + errorMessage?: string; // 실패 메시지 + }; +} +``` + +### 4. 버튼 액션 실행 로직 개선 + +#### 4.1 현재 실행 플로우 + +```mermaid +graph TD + A[버튼 클릭] --> B[기존 액션 실행] + B --> C[제어관리 확인] + C --> D[관계도 조회] + D --> E[관계 찾기] + E --> F[조건 검증] + F --> G[액션 실행] +``` + +#### 4.2 개선된 실행 플로우 + +```mermaid +graph TD + A[버튼 클릭] --> B[제어 설정 확인] + B --> C{제어 타입} + C -->|관계| D[관계 직접 실행] + C -->|외부호출| E[외부호출 실행] + C -->|없음| F[기존 액션만 실행] + + D --> G[조건 검증] + G --> H[관계 액션 실행] + + E --> I[데이터 매핑] + I --> J[외부 API 호출] + J --> K[응답 처리] + + H --> L[완료] + K --> L + F --> L +``` + +#### 4.3 개선된 ButtonActionExecutor + +```typescript +export class ButtonActionExecutor { + /** + * 🔥 개선된 버튼 액션 실행 + */ + static async executeButtonAction( + buttonConfig: ExtendedButtonTypeConfig, + formData: Record, + context: ButtonExecutionContext + ): Promise { + const executionPlan = this.createExecutionPlan(buttonConfig); + const results: ExecutionResult[] = []; + + try { + // 1. Before 타이밍 제어 실행 + if (executionPlan.beforeControls.length > 0) { + const beforeResults = await this.executeControls( + executionPlan.beforeControls, + formData, + context + ); + results.push(...beforeResults); + } + + // 2. 메인 액션 실행 (replace가 아닌 경우에만) + if (!executionPlan.hasReplaceControl) { + const mainResult = await this.executeMainAction( + buttonConfig, + formData, + context + ); + results.push(mainResult); + } + + // 3. After 타이밍 제어 실행 + if (executionPlan.afterControls.length > 0) { + const afterResults = await this.executeControls( + executionPlan.afterControls, + formData, + context + ); + results.push(...afterResults); + } + + return { + success: true, + results, + executionTime: Date.now() - context.startTime, + }; + } catch (error) { + // 롤백 처리 + await this.handleExecutionError(error, results, buttonConfig); + throw error; + } + } + + /** + * 🔥 제어 실행 (관계 또는 외부호출) + */ + private static async executeControls( + controls: ControlConfig[], + formData: Record, + context: ButtonExecutionContext + ): Promise { + const results: ExecutionResult[] = []; + + for (const control of controls) { + switch (control.type) { + case "relationship": + const relationshipResult = await this.executeRelationship( + control.relationshipConfig!, + formData, + context + ); + results.push(relationshipResult); + break; + + case "external_call": + const externalCallResult = await this.executeExternalCall( + control.externalCallConfig!, + formData, + context + ); + results.push(externalCallResult); + break; + } + } + + return results; + } + + /** + * 🔥 관계 실행 + */ + private static async executeRelationship( + config: RelationshipConfig, + formData: Record, + context: ButtonExecutionContext + ): Promise { + // 1. 관계 정보 조회 + const relationship = await RelationshipAPI.getRelationshipById( + config.relationshipId + ); + + // 2. 컨텍스트 데이터 준비 + const contextData = { + ...formData, + ...config.contextData, + buttonId: context.buttonId, + screenId: context.screenId, + userId: context.userId, + companyCode: context.companyCode, + }; + + // 3. 관계 실행 + return await EventTriggerService.executeSpecificRelationship( + relationship, + contextData, + context.companyCode + ); + } + + /** + * 🔥 외부호출 실행 + */ + private static async executeExternalCall( + config: ExternalCallConfig, + formData: Record, + context: ButtonExecutionContext + ): Promise { + // 1. 외부호출 설정 조회 + const externalCallConfig = await ExternalCallConfigAPI.getConfigById( + config.configId + ); + + // 2. 데이터 매핑 처리 + let mappedData = formData; + if (config.dataMappingEnabled && externalCallConfig.dataMappingConfig) { + mappedData = await DataMappingService.processOutboundData( + externalCallConfig.dataMappingConfig.outboundMapping, + formData + ); + } + + // 3. 외부 API 호출 + const callResult = await ExternalCallService.executeWithDataMapping( + externalCallConfig.configData, + externalCallConfig.dataMappingConfig, + mappedData + ); + + // 4. 응답 데이터 처리 (Inbound 매핑) + if ( + callResult.success && + config.dataMappingEnabled && + externalCallConfig.dataMappingConfig?.direction === "inbound" + ) { + await DataMappingService.processInboundData( + callResult.response, + externalCallConfig.dataMappingConfig.inboundMapping! + ); + } + + return { + success: callResult.success, + message: callResult.success ? "외부호출 성공" : callResult.error, + executionTime: callResult.executionTime, + data: callResult, + }; + } +} +``` + +### 5. UI/UX 개선 사항 + +#### 5.1 버튼 설정 패널 개선 + +```typescript +// 🟢 단순화된 제어 설정 UI +const ButtonControlConfigPanel = () => { + return ( + + + 버튼 제어 설정 + + + + + 제어 없음 + 관계 실행 + 외부 호출 + + + + + + + + + + + + + ); +}; +``` + +#### 5.2 관계 선택 컴포넌트 + +```typescript +const RelationshipSelector = ({ onSelect }) => { + const [relationships, setRelationships] = useState([]); + + useEffect(() => { + // 전체 관계 목록 로드 (관계도별 구분 없이) + loadAllRelationships(); + }, []); + + return ( +
+ + +
+ ); +}; +``` + +### 6. 구현 우선순위 + +#### Phase 1: 명칭 변경 (1일) + +1. **UI 텍스트 변경**: "관계도" → "관계" +2. **변수명 정리**: `diagram` → `relationship` 관련 +3. **API 엔드포인트 정리**: 일관성 있는 명명 + +#### Phase 2: 버튼 제어 로직 개선 (2-3일) + +1. **ButtonDataflowConfig 타입 개선** +2. **RelationshipSelector 컴포넌트 개발** +3. **ExternalCallSelector 컴포넌트 개발** +4. **ButtonActionExecutor 로직 개선** + +#### Phase 3: 외부호출 통합 (1-2일) + +1. **외부호출 설정 참조 방식 개선** +2. **데이터 매핑 통합** +3. **실행 플로우 최적화** + +#### Phase 4: 테스트 및 최적화 (1일) + +1. **전체 플로우 테스트** +2. **성능 최적화** +3. **사용자 가이드 업데이트** + +### 7. 기대 효과 + +#### 7.1 사용자 경험 개선 + +- **직관적인 용어**: "관계도" → "관계"로 이해도 향상 +- **단순화된 설정**: 복잡한 관계도 탐색 → 직접 관계 선택 +- **통합된 제어**: 관계 실행과 외부호출을 동일한 방식으로 관리 + +#### 7.2 개발 효율성 향상 + +- **명확한 책임 분리**: 관계 관리와 외부호출 관리 분리 +- **재사용성 증대**: 외부호출 설정의 재사용성 향상 +- **유지보수성 개선**: 단순화된 로직으로 디버깅 용이 + +#### 7.3 시스템 확장성 + +- **새로운 제어 타입 추가 용이**: 플러그인 방식으로 확장 가능 +- **데이터 매핑 시스템 완전 활용**: 외부 시스템과의 유연한 연동 +- **모니터링 및 로깅 강화**: 각 단계별 상세한 실행 로그 + +이 개선 계획을 통해 제어관리 시스템이 더욱 직관적이고 강력한 기능을 제공할 수 있을 것입니다.