Files
pipeline/backend-node/src/routes/pipelineDeviceConnectionRoutes.ts
T
chpark 37cac72085 refactor: Pipeline 네이밍 통일 및 AI 에이전트/장비 연결 기능 추가
- Docker/K8s 배포 설정을 pipeline-backend/pipeline-front로 통일
- 네임스페이스, 서비스, PVC 등 k8s 리소스명 pipeline-* 로 변경
- AI 에이전트 관리 기능 추가 (에이전트, 그룹, 프로바이더, 대화, API 키, 지식베이스)
- 장비 연결 관리 기능 추가 (PLC/Modbus/OPC-UA/MQTT)
- 배치 스케줄러에 AI agent/device collection/crawling 타입 추가
- 배치 편집 UI 개선 (6가지 실행 방식 지원)
- 회사별 페이지(COMPANY_*) 제거 및 AdminPageRenderer 최적화
- 메뉴 재구성: 장비 연결 관리 시스템관리로 이동, 에이전트 오케스트레이션으로 개명
- ai-assistant 디렉토리 제거 (backend-node로 통합)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 12:14:50 +09:00

148 lines
5.3 KiB
TypeScript

import { Router, Response } from "express";
import { PipelineDeviceConnectionService } from "../services/pipelineDeviceConnectionService";
import { PROTOCOL_OPTIONS, PROTOCOL_DEFAULTS, TAG_DATA_TYPE_OPTIONS, ADDRESS_TYPE_OPTIONS } from "../types/pipelineDeviceTypes";
import { authenticateToken } from "../middleware/authMiddleware";
import { AuthenticatedRequest } from "../types/auth";
const router = Router();
// 모든 라우트 인증 필요
router.use(authenticateToken);
// ===== 프로토콜 목록 (정적 경로 우선) =====
router.get("/protocols", async (req: AuthenticatedRequest, res: Response) => {
res.json({
success: true,
data: { protocols: PROTOCOL_OPTIONS, defaults: PROTOCOL_DEFAULTS, tagDataTypes: TAG_DATA_TYPE_OPTIONS, addressTypes: ADDRESS_TYPE_OPTIONS },
});
});
// ===== 태그 수정/삭제 (정적 경로 우선) =====
router.put("/tags/:tagId", async (req: AuthenticatedRequest, res: Response) => {
try {
const result = await PipelineDeviceConnectionService.updateTagMapping(parseInt(req.params.tagId), req.body);
res.status(result.success ? 200 : 400).json(result);
} catch (e: any) {
res.status(500).json({ success: false, message: e.message });
}
});
router.delete("/tags/:tagId", async (req: AuthenticatedRequest, res: Response) => {
try {
const result = await PipelineDeviceConnectionService.deleteTagMapping(parseInt(req.params.tagId));
res.json(result);
} catch (e: any) {
res.status(500).json({ success: false, message: e.message });
}
});
// ===== 연결 CRUD =====
router.get("/", async (req: AuthenticatedRequest, res: Response) => {
try {
const userCompanyCode = req.user?.companyCode;
let companyCodeFilter: string | undefined;
if (userCompanyCode === "*") {
companyCodeFilter = req.query.company_code as string;
} else {
companyCodeFilter = userCompanyCode;
}
const filter = {
protocol: req.query.protocol as string,
is_active: req.query.is_active as string,
company_code: companyCodeFilter,
search: req.query.search as string,
status: req.query.status as string,
};
Object.keys(filter).forEach((key) => {
if (!filter[key as keyof typeof filter]) delete filter[key as keyof typeof filter];
});
const result = await PipelineDeviceConnectionService.getConnections(filter, userCompanyCode);
res.json(result);
} catch (e: any) {
res.status(500).json({ success: false, message: e.message });
}
});
router.get("/:id", async (req: AuthenticatedRequest, res: Response) => {
try {
const result = await PipelineDeviceConnectionService.getConnectionById(parseInt(req.params.id));
res.status(result.success ? 200 : 404).json(result);
} catch (e: any) {
res.status(500).json({ success: false, message: e.message });
}
});
router.post("/", async (req: AuthenticatedRequest, res: Response) => {
try {
const data = {
...req.body,
company_code: req.body.company_code || req.user?.companyCode,
created_by: req.user?.userId,
};
const result = await PipelineDeviceConnectionService.createConnection(data);
res.status(result.success ? 201 : 400).json(result);
} catch (e: any) {
if (e.message?.includes("duplicate") || e.code === "23505") {
res.status(409).json({ success: false, message: "동일한 연결명이 이미 존재합니다." });
} else {
res.status(500).json({ success: false, message: e.message });
}
}
});
router.put("/:id", async (req: AuthenticatedRequest, res: Response) => {
try {
const result = await PipelineDeviceConnectionService.updateConnection(parseInt(req.params.id), req.body);
res.status(result.success ? 200 : 404).json(result);
} catch (e: any) {
res.status(500).json({ success: false, message: e.message });
}
});
router.delete("/:id", async (req: AuthenticatedRequest, res: Response) => {
try {
const result = await PipelineDeviceConnectionService.deleteConnection(parseInt(req.params.id));
res.json(result);
} catch (e: any) {
res.status(500).json({ success: false, message: e.message });
}
});
// ===== 연결 테스트 =====
router.post("/:id/test", async (req: AuthenticatedRequest, res: Response) => {
try {
const result = await PipelineDeviceConnectionService.testConnection(parseInt(req.params.id));
res.json({ success: result.success, data: result });
} catch (e: any) {
res.status(500).json({ success: false, message: e.message });
}
});
// ===== 태그 매핑 =====
router.get("/:id/tags", async (req: AuthenticatedRequest, res: Response) => {
try {
const result = await PipelineDeviceConnectionService.getTagMappings(parseInt(req.params.id));
res.json(result);
} catch (e: any) {
res.status(500).json({ success: false, message: e.message });
}
});
router.post("/:id/tags", async (req: AuthenticatedRequest, res: Response) => {
try {
const result = await PipelineDeviceConnectionService.createTagMapping(parseInt(req.params.id), req.body);
res.status(result.success ? 201 : 400).json(result);
} catch (e: any) {
if (e.message?.includes("duplicate") || e.code === "23505") {
res.status(409).json({ success: false, message: "동일한 태그명이 이미 존재합니다." });
} else {
res.status(500).json({ success: false, message: e.message });
}
}
});
export default router;