fix(pipeline): XGT 프로토콜/이벤트 리포터/라우트 순서 수정

XGT FEnet 클라이언트
- 응답 data_length offset [12] → [16] (요청 시에만 [12,16] 둘 다 씀; 응답은 PLC가 [12:14]를 CPU 정보로 덮음)
- socket.setTimeout idle 타임아웃 제거 → connect 전용 수동 타이머 + setKeepAlive(10s). 폴링 간격(5s)마다 재연결되던 문제 해결

Edge 이벤트 리포터
- edgeStatusReporter.ts 추가: 60초 간격 edge_status_1 하트비트 + edge_events_1 이벤트 기록
- 기동/종료 이벤트 + PLC 상태 전이(connected/disconnected/error) 자동 기록
- PIPELINE_EDGE_* env 로 edge_id/company_id/UUID/table/interval 주입

edge_telemetry metadata 포맷 교정
- migrated_at → forwarded_at, _pipeline 추가 블록 제거
- 프로덕션 원본 스키마와 완전 호환: {priority, device_id(UUID), forwarded_at}

라우트 순서 버그 수정
- pipelineDeviceConnectionRoutes.ts: /target-databases* 가 /:id 뒤에 있어 /:id 가 먼저 매칭됨 → UI 저장 DB 드롭다운 비어있던 문제
- 정적 경로를 /:id 위로 이동

프론트 API URL 해석 일반화
- NEXT_PUBLIC_API_URL 가 localhost인데 브라우저는 원격이면 env 무시하고 현재 origin의 :8080 사용 → 엣지 원격 접속 시 API 연결 보장

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
chpark
2026-04-22 17:38:53 +09:00
parent 37cac72085
commit 156dd1ddb1
6 changed files with 998 additions and 79 deletions
+18 -10
View File
@@ -10,26 +10,34 @@ const authLog = (event: string, detail: string) => {
}
};
// API URL 동적 설정 - 환경변수 우선 사용
// API URL 동적 설정
// 우선순위: NEXT_PUBLIC_API_URL > 현재 브라우저 호스트 기반 > localhost
// 엣지 배포 시에도 프론트를 접속한 호스트를 그대로 재사용해야 CORS/접근성 문제 없음.
const getApiBaseUrl = (): string => {
if (process.env.NEXT_PUBLIC_API_URL) {
return process.env.NEXT_PUBLIC_API_URL;
// env 강제 지정이 있고 명시적으로 절대 URL인 경우 그대로 사용
// (단, 'http://localhost:' 로 시작하면서 실제로는 다른 호스트에서 접속된 케이스가 많아
// 배포용 컨테이너에선 origin fallback 을 우선시)
const envUrl = process.env.NEXT_PUBLIC_API_URL;
if (envUrl && typeof window !== "undefined") {
const currentHost = window.location.hostname;
const envIsLocalhost = /^https?:\/\/(localhost|127\.0\.0\.1)(:|\/|$)/.test(envUrl);
const browserIsLocalhost = currentHost === "localhost" || currentHost === "127.0.0.1";
// 브라우저가 원격에서 접속인데 env 는 localhost 면 env 무시 (원격에서 localhost:8080 못 감)
if (!(envIsLocalhost && !browserIsLocalhost)) return envUrl;
} else if (envUrl) {
return envUrl;
}
if (typeof window !== "undefined") {
const currentHost = window.location.hostname;
const currentPort = window.location.port;
if (currentHost === "v1.vexplor.com") {
return "https://api.vexplor.com/api";
}
if (
(currentHost === "localhost" || currentHost === "127.0.0.1") &&
(currentPort === "9771" || currentPort === "3000")
) {
return "http://localhost:8080/api";
}
// 접속 host 기준 포트 8080 백엔드로 — 엣지 배포 일반화 경로
const protocol = window.location.protocol;
return `${protocol}//${currentHost}:8080/api`;
}
return "http://localhost:8080/api";