fix(flow): 제어 실행 시 writer와 company_code 자동 입력 기능 추가
🐛 문제: - 제어(플로우) 실행으로 데이터 INSERT 시 writer, company_code 컬럼이 비어있는 문제 - 플로우 실행 API에 인증이 없어 사용자 정보를 사용할 수 없었음 ✅ 해결: 1. 플로우 실행 API에 authenticateToken 미들웨어 추가 2. 사용자 정보(userId, userName, companyCode)를 contextData에 포함 3. INSERT 노드 실행 시 writer와 company_code 자동 추가 - 필드 매핑에 없는 경우에만 자동 추가 - writer: 현재 로그인한 사용자 ID - company_code: 현재 사용자의 회사 코드 - 최고 관리자(companyCode = '*')는 제외 4. 플로우 제어 자동 감지 개선 - flowConfig가 있으면 controlMode 없이도 플로우 모드로 인식 - 데이터 미선택 시 명확한 오류 메시지 표시 🎯 영향: - 입고처리, 출고처리 등 제어 기반 데이터 생성 시 멀티테넌시 보장 - 데이터 추적성 향상 (누가 생성했는지 자동 기록) 📝 수정 파일: - frontend/lib/utils/buttonActions.ts - backend-node/src/routes/dataflow/node-flows.ts - backend-node/src/services/nodeFlowExecutionService.ts
This commit is contained in:
@@ -7,6 +7,7 @@ import { query, queryOne } from "../../database/db";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { NodeFlowExecutionService } from "../../services/nodeFlowExecutionService";
|
||||
import { AuthenticatedRequest } from "../../types/auth";
|
||||
import { authenticateToken } from "../../middleware/authMiddleware";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -217,19 +218,29 @@ router.delete("/:flowId", async (req: Request, res: Response) => {
|
||||
* 플로우 실행
|
||||
* POST /api/dataflow/node-flows/:flowId/execute
|
||||
*/
|
||||
router.post("/:flowId/execute", async (req: Request, res: Response) => {
|
||||
router.post("/:flowId/execute", authenticateToken, async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const { flowId } = req.params;
|
||||
const contextData = req.body;
|
||||
|
||||
logger.info(`🚀 플로우 실행 요청: flowId=${flowId}`, {
|
||||
contextDataKeys: Object.keys(contextData),
|
||||
userId: req.user?.userId,
|
||||
companyCode: req.user?.companyCode,
|
||||
});
|
||||
|
||||
// 사용자 정보를 contextData에 추가
|
||||
const enrichedContextData = {
|
||||
...contextData,
|
||||
userId: req.user?.userId,
|
||||
userName: req.user?.userName,
|
||||
companyCode: req.user?.companyCode,
|
||||
};
|
||||
|
||||
// 플로우 실행
|
||||
const result = await NodeFlowExecutionService.executeFlow(
|
||||
parseInt(flowId, 10),
|
||||
contextData
|
||||
enrichedContextData
|
||||
);
|
||||
|
||||
return res.json({
|
||||
|
||||
@@ -938,6 +938,30 @@ export class NodeFlowExecutionService {
|
||||
insertedData[mapping.targetField] = value;
|
||||
});
|
||||
|
||||
// 🆕 writer와 company_code 자동 추가 (필드 매핑에 없는 경우)
|
||||
const hasWriterMapping = fieldMappings.some((m: any) => m.targetField === "writer");
|
||||
const hasCompanyCodeMapping = fieldMappings.some((m: any) => m.targetField === "company_code");
|
||||
|
||||
// 컨텍스트에서 사용자 정보 추출
|
||||
const userId = context.buttonContext?.userId;
|
||||
const companyCode = context.buttonContext?.companyCode;
|
||||
|
||||
// writer 자동 추가 (매핑에 없고, 컨텍스트에 userId가 있는 경우)
|
||||
if (!hasWriterMapping && userId) {
|
||||
fields.push("writer");
|
||||
values.push(userId);
|
||||
insertedData.writer = userId;
|
||||
console.log(` 🔧 자동 추가: writer = ${userId}`);
|
||||
}
|
||||
|
||||
// company_code 자동 추가 (매핑에 없고, 컨텍스트에 companyCode가 있는 경우)
|
||||
if (!hasCompanyCodeMapping && companyCode && companyCode !== "*") {
|
||||
fields.push("company_code");
|
||||
values.push(companyCode);
|
||||
insertedData.company_code = companyCode;
|
||||
console.log(` 🔧 자동 추가: company_code = ${companyCode}`);
|
||||
}
|
||||
|
||||
const sql = `
|
||||
INSERT INTO ${targetTable} (${fields.join(", ")})
|
||||
VALUES (${fields.map((_, i) => `$${i + 1}`).join(", ")})
|
||||
|
||||
@@ -1673,7 +1673,11 @@ export class ButtonActionExecutor {
|
||||
});
|
||||
|
||||
// 🔥 새로운 버튼 액션 실행 시스템 사용
|
||||
if (config.dataflowConfig?.controlMode === "flow" && config.dataflowConfig?.flowConfig) {
|
||||
// flowConfig가 있으면 controlMode가 명시되지 않아도 플로우 모드로 간주
|
||||
const hasFlowConfig = config.dataflowConfig?.flowConfig && config.dataflowConfig.flowConfig.flowId;
|
||||
const isFlowMode = config.dataflowConfig?.controlMode === "flow" || hasFlowConfig;
|
||||
|
||||
if (isFlowMode && config.dataflowConfig?.flowConfig) {
|
||||
console.log("🎯 노드 플로우 실행:", config.dataflowConfig.flowConfig);
|
||||
|
||||
const { flowId, executionTiming } = config.dataflowConfig.flowConfig;
|
||||
@@ -1711,6 +1715,8 @@ export class ButtonActionExecutor {
|
||||
});
|
||||
} else {
|
||||
console.warn("⚠️ flow-selection 모드이지만 선택된 플로우 데이터가 없습니다.");
|
||||
toast.error("플로우에서 데이터를 먼저 선택해주세요.");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1723,6 +1729,8 @@ export class ButtonActionExecutor {
|
||||
});
|
||||
} else {
|
||||
console.warn("⚠️ table-selection 모드이지만 선택된 행이 없습니다.");
|
||||
toast.error("테이블에서 처리할 항목을 먼저 선택해주세요.");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user