37cac72085
- 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>
148 lines
5.3 KiB
TypeScript
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;
|