ERP-node/backend-node/src/routes/dataflow/node-flows.ts

280 lines
6.8 KiB
TypeScript

/**
* 노드 기반 데이터 플로우 API
*/
import { Router, Request, Response } from "express";
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();
/**
* 플로우 목록 조회
*/
router.get("/", async (req: AuthenticatedRequest, res: Response) => {
try {
const userCompanyCode = req.user?.companyCode;
let sqlQuery = `
SELECT
flow_id as "flowId",
flow_name as "flowName",
flow_description as "flowDescription",
company_code as "companyCode",
created_at as "createdAt",
updated_at as "updatedAt"
FROM node_flows
`;
const params: any[] = [];
// 슈퍼 관리자가 아니면 회사별 필터링
if (userCompanyCode && userCompanyCode !== "*") {
sqlQuery += ` WHERE company_code = $1`;
params.push(userCompanyCode);
}
sqlQuery += ` ORDER BY updated_at DESC`;
const flows = await query(sqlQuery, params);
return res.json({
success: true,
data: flows,
});
} catch (error) {
logger.error("플로우 목록 조회 실패:", error);
return res.status(500).json({
success: false,
message: "플로우 목록을 조회하지 못했습니다.",
});
}
});
/**
* 플로우 상세 조회
*/
router.get("/:flowId", async (req: Request, res: Response) => {
try {
const { flowId } = req.params;
const flow = await queryOne(
`
SELECT
flow_id as "flowId",
flow_name as "flowName",
flow_description as "flowDescription",
flow_data as "flowData",
created_at as "createdAt",
updated_at as "updatedAt"
FROM node_flows
WHERE flow_id = $1
`,
[flowId]
);
if (!flow) {
return res.status(404).json({
success: false,
message: "플로우를 찾을 수 없습니다.",
});
}
return res.json({
success: true,
data: flow,
});
} catch (error) {
logger.error("플로우 조회 실패:", error);
return res.status(500).json({
success: false,
message: "플로우를 조회하지 못했습니다.",
});
}
});
/**
* 플로우 저장 (신규)
*/
router.post("/", async (req: AuthenticatedRequest, res: Response) => {
try {
const { flowName, flowDescription, flowData } = req.body;
const userCompanyCode = req.user?.companyCode || "*";
if (!flowName || !flowData) {
return res.status(400).json({
success: false,
message: "플로우 이름과 데이터는 필수입니다.",
});
}
const result = await queryOne(
`
INSERT INTO node_flows (flow_name, flow_description, flow_data, company_code)
VALUES ($1, $2, $3, $4)
RETURNING flow_id as "flowId"
`,
[flowName, flowDescription || "", flowData, userCompanyCode]
);
logger.info(
`플로우 저장 성공: ${result.flowId} (회사: ${userCompanyCode})`
);
return res.json({
success: true,
message: "플로우가 저장되었습니다.",
data: {
flowId: result.flowId,
},
});
} catch (error) {
logger.error("플로우 저장 실패:", error);
return res.status(500).json({
success: false,
message: "플로우를 저장하지 못했습니다.",
});
}
});
/**
* 플로우 수정
*/
router.put("/", async (req: Request, res: Response) => {
try {
const { flowId, flowName, flowDescription, flowData } = req.body;
if (!flowId || !flowName || !flowData) {
return res.status(400).json({
success: false,
message: "플로우 ID, 이름, 데이터는 필수입니다.",
});
}
await query(
`
UPDATE node_flows
SET flow_name = $1,
flow_description = $2,
flow_data = $3,
updated_at = NOW()
WHERE flow_id = $4
`,
[flowName, flowDescription || "", flowData, flowId]
);
logger.info(`플로우 수정 성공: ${flowId}`);
return res.json({
success: true,
message: "플로우가 수정되었습니다.",
data: {
flowId,
},
});
} catch (error) {
logger.error("플로우 수정 실패:", error);
return res.status(500).json({
success: false,
message: "플로우를 수정하지 못했습니다.",
});
}
});
/**
* 플로우 삭제
*/
router.delete("/:flowId", async (req: Request, res: Response) => {
try {
const { flowId } = req.params;
await query(
`
DELETE FROM node_flows
WHERE flow_id = $1
`,
[flowId]
);
logger.info(`플로우 삭제 성공: ${flowId}`);
return res.json({
success: true,
message: "플로우가 삭제되었습니다.",
});
} catch (error) {
logger.error("플로우 삭제 실패:", error);
return res.status(500).json({
success: false,
message: "플로우를 삭제하지 못했습니다.",
});
}
});
/**
* 플로우 실행
* POST /api/dataflow/node-flows/:flowId/execute
*/
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,
});
// 🔍 디버깅: req.user 전체 확인
logger.info(`🔍 req.user 전체 정보:`, {
user: req.user,
hasUser: !!req.user,
});
// 사용자 정보를 contextData에 추가
const enrichedContextData = {
...contextData,
userId: req.user?.userId,
userName: req.user?.userName,
companyCode: req.user?.companyCode,
};
// 🔍 디버깅: enrichedContextData 확인
logger.info(`🔍 enrichedContextData:`, {
userId: enrichedContextData.userId,
companyCode: enrichedContextData.companyCode,
});
// 플로우 실행
const result = await NodeFlowExecutionService.executeFlow(
parseInt(flowId, 10),
enrichedContextData
);
return res.json({
success: result.success,
message: result.message,
data: result,
});
} catch (error) {
logger.error("플로우 실행 실패:", error);
return res.status(500).json({
success: false,
message:
error instanceof Error
? error.message
: "플로우 실행 중 오류가 발생했습니다.",
});
}
}
);
export default router;