Compare commits
104 Commits
2b70cd95a4
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| db5623341a | |||
| d389266de6 | |||
| 8d0a8bdb5c | |||
| 88221b828e | |||
| c9f5915419 | |||
| 50c5039ec0 | |||
| cd6a081a55 | |||
| 78d549194c | |||
| 493b07ec30 | |||
| fb4179eaa5 | |||
| f15b666da9 | |||
| fab7a5ba49 | |||
| 687ae0445c | |||
| 861934dad1 | |||
| 430c6b1efb | |||
| 12bafdd148 | |||
| 27056073da | |||
| 42fa743d7a | |||
| 2f365aebac | |||
| 242df2a11f | |||
| a63987d168 | |||
| b29ea93f78 | |||
| 28dc55bc11 | |||
| 998f97f12f | |||
| 4301ebe1b8 | |||
| 0174f1bd27 | |||
| a8de6fd275 | |||
| 5f6288cc8b | |||
| 917441cdae | |||
| 123eb926bc | |||
| 01abedcdea | |||
| 5ff37ecf06 | |||
| 0a22052cca | |||
| 04f91bd307 | |||
| 37b24c1b76 | |||
| d6c50136b0 | |||
| 7883636fef | |||
| ee558309a6 | |||
| 70902bc319 | |||
| 02390996cb | |||
| 2f762f698b | |||
| dde35babdb | |||
| 6e27c7bd25 | |||
| ebeded783b | |||
| 74e85171b0 | |||
| 741155fe55 | |||
| 5ce4a1a6ce | |||
| f86fab8459 | |||
| 508ea1b00c | |||
| 3f3e578f98 | |||
| 2753b361d5 | |||
| 70446e444e | |||
| d0040bd2af | |||
| 7d6889b0ff | |||
| 0be91bb540 | |||
| 5400db9fb4 | |||
| b5ebe3f369 | |||
| d813e053ca | |||
| 1ff418fa73 | |||
| 86f9feba3b | |||
| 31e86baa63 | |||
| 216d76c8a0 | |||
| 0ad583f3a9 | |||
| 50eeb4ff76 | |||
| 62604fe1b7 | |||
| 39f41d90b0 | |||
| b071aff2d9 | |||
| 653d9ccb32 | |||
| 3a622ee3ee | |||
| bdeb5f64ce | |||
| a22baec49d | |||
| 34d95de479 | |||
| fcf99167db | |||
| 098fa0b3f1 | |||
| 2f4c7062c7 | |||
| 0d4f2737a0 | |||
| b1df37309b | |||
| 2b33c9f4be | |||
| 1ee28f3a4d | |||
| f85e4adc35 | |||
| db8f69743b | |||
| 06af24d1c7 | |||
| af6c64f052 | |||
| d3dc5d87d1 | |||
| 73bac743c2 | |||
| ff58d1ed39 | |||
| 5e0471988e | |||
| a37ac3d6a1 | |||
| d8c5e8f436 | |||
| 869308b82e | |||
| 264954cc32 | |||
| b461949266 | |||
| 2545dd263f | |||
| 9b965118db | |||
| cfd9ae6add | |||
| 2e0e2bde29 | |||
| 57f71b2503 | |||
| 6aa99f3d6d | |||
| 3df4398618 | |||
| 2df9191889 | |||
| 68ff71c1f7 | |||
| fa98eafa8f | |||
| 5f3e691d95 | |||
| 83210543a3 |
Regular → Executable
+1
@@ -15,3 +15,4 @@ local-dev/run/
|
|||||||
local-dev/logs/
|
local-dev/logs/
|
||||||
server-dev/run/
|
server-dev/run/
|
||||||
server-dev/logs/
|
server-dev/logs/
|
||||||
|
.venv-data/
|
||||||
|
|||||||
Regular → Executable
+4
@@ -14,3 +14,7 @@
|
|||||||
path = kakaoChatbotSkill-chatbot2.0-agent
|
path = kakaoChatbotSkill-chatbot2.0-agent
|
||||||
url = https://github.com/KoreaExpressWayCorp/kakaoChatbotSkill.git
|
url = https://github.com/KoreaExpressWayCorp/kakaoChatbotSkill.git
|
||||||
branch = chatbot2.0-agent
|
branch = chatbot2.0-agent
|
||||||
|
[submodule "chatbotApp-test"]
|
||||||
|
path = chatbotApp-test
|
||||||
|
url = https://github.com/KoreaExpressWayCorp/chatbotApp-test.git
|
||||||
|
branch = chatbot2.0-agent
|
||||||
|
|||||||
Submodule chatbotApi-chatbot2.0-agent updated: 647e047bf0...b4d90acdfb
Binary file not shown.
Submodule chatbotApp-chatbot2.0-agent updated: 8d68a16231...70c2d2855a
Binary file not shown.
Submodule
+1
Submodule chatbotApp-test added at 20835ab277
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
.venv-icons/
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
Executable
+48
@@ -0,0 +1,48 @@
|
|||||||
|
# EX AI Chatbot 데스크톱 앱
|
||||||
|
|
||||||
|
Electron 래퍼 — 브라우저 주소표시줄 없이 챗봇을 독립 창으로 실행합니다.
|
||||||
|
|
||||||
|
## 빌드 · 배포
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build-and-publish.sh
|
||||||
|
# 또는
|
||||||
|
npm run dist:mac # dmg(설치) + zip(포터블), intel + silicon
|
||||||
|
npm run dist:win # Setup.exe(설치) + portable.exe, win32 + win64
|
||||||
|
npm run publish-downloads
|
||||||
|
```
|
||||||
|
|
||||||
|
산출물은 `chatbotApp-chatbot2.0-agent/public-ai/downloads/` 로 복사됩니다.
|
||||||
|
|
||||||
|
| 구분 | 파일 |
|
||||||
|
|------|------|
|
||||||
|
| Mac 설치 (Intel) | `exAIChatbot 2.0-mac-intel.dmg` |
|
||||||
|
| Mac 포터블 (Intel) | `exAIChatbot 2.0-mac-intel.zip` |
|
||||||
|
| Mac 설치 (Apple Silicon) | `exAIChatbot 2.0-mac-silicon.dmg` |
|
||||||
|
| Mac 포터블 (Apple Silicon) | `exAIChatbot 2.0-mac-silicon.zip` |
|
||||||
|
| Windows 설치 64비트 | `exAIChatbot 2.0-win64-Setup.exe` |
|
||||||
|
| Windows 포터블 64비트 | `exAIChatbot 2.0-win64-portable.exe` |
|
||||||
|
| Windows 설치 32비트 | `exAIChatbot 2.0-win32-Setup.exe` |
|
||||||
|
| Windows 포터블 32비트 | `exAIChatbot 2.0-win32-portable.exe` |
|
||||||
|
|
||||||
|
다운로드 URL 예:
|
||||||
|
|
||||||
|
- `/chatbot/ai/downloads/exAIChatbot%202.0-mac-silicon.dmg`
|
||||||
|
- `/chatbot/ai/downloads/exAIChatbot%202.0-win64-Setup.exe`
|
||||||
|
|
||||||
|
## 앱 아이콘
|
||||||
|
|
||||||
|
공식 길통이·차로(`ai-mascot.png`)로 Dock/바로가기 아이콘을 생성합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build:icons # build/icon.png · icon.icns · icon.ico
|
||||||
|
```
|
||||||
|
|
||||||
|
`dist:mac` / `dist:win` 실행 시 자동으로 아이콘을 다시 만든 뒤 패키징합니다.
|
||||||
|
|
||||||
|
## 사용 안내
|
||||||
|
|
||||||
|
- **Mac dmg:** 앱을 Applications로 드래그. 차단 시 설정 화면「Mac 설치 명령 복사」.
|
||||||
|
- **Mac zip:** `실행하기.command` 또는 `.app` 실행.
|
||||||
|
- **Windows Setup:** 설치 마법사 실행.
|
||||||
|
- **Windows portable:** 압축 없이 exe 바로 실행. SmartScreen → 추가 정보 → 실행.
|
||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Electron 데스크톱 앱 재빌드 → chatbotApp public-ai/downloads/ 배포
|
||||||
|
#
|
||||||
|
# ./chatbotDesktopApp-chatbot2.0/build-and-publish.sh
|
||||||
|
# SKIP_WIN=1 ./chatbotDesktopApp-chatbot2.0/build-and-publish.sh # Mac만
|
||||||
|
# SKIP_MAC=1 ./chatbotDesktopApp-chatbot2.0/build-and-publish.sh # Win만
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DESKTOP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
ROOT_DIR="$(cd "${DESKTOP_DIR}/.." && pwd)"
|
||||||
|
DOWNLOADS_DIR="${ROOT_DIR}/chatbotApp-chatbot2.0-agent/public-ai/downloads"
|
||||||
|
|
||||||
|
export PATH="/opt/homebrew/bin:/usr/local/bin:${PATH}"
|
||||||
|
export CSC_IDENTITY_AUTO_DISCOVERY="${CSC_IDENTITY_AUTO_DISCOVERY:-false}"
|
||||||
|
|
||||||
|
log() { echo "[desktop-build $(date '+%H:%M:%S')] $*"; }
|
||||||
|
warn() { log "⚠️ $*"; }
|
||||||
|
fail() { log "ERROR: $*"; exit 1; }
|
||||||
|
|
||||||
|
[[ -f "${DESKTOP_DIR}/package.json" ]] || fail "package.json 없음: ${DESKTOP_DIR}"
|
||||||
|
|
||||||
|
cd "${DESKTOP_DIR}"
|
||||||
|
|
||||||
|
if [[ ! -d node_modules/electron ]]; then
|
||||||
|
log "npm 의존성 설치..."
|
||||||
|
npm ci --prefer-offline 2>/dev/null || npm install
|
||||||
|
else
|
||||||
|
log "npm 의존성 확인..."
|
||||||
|
npm ci --prefer-offline 2>/dev/null || npm install --prefer-offline
|
||||||
|
fi
|
||||||
|
|
||||||
|
SKIP_MAC="${SKIP_MAC:-0}"
|
||||||
|
SKIP_WIN="${SKIP_WIN:-0}"
|
||||||
|
built_any=false
|
||||||
|
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Darwin)
|
||||||
|
if [[ "${SKIP_MAC}" != "1" ]]; then
|
||||||
|
log "잔여 DMG 볼륨 정리..."
|
||||||
|
hdiutil detach "/Volumes/EX AI Chatbot" -force 2>/dev/null || true
|
||||||
|
hdiutil detach "/Volumes/EX AI Chatbot Intel" -force 2>/dev/null || true
|
||||||
|
hdiutil detach "/Volumes/EX AI Chatbot Silicon" -force 2>/dev/null || true
|
||||||
|
log "Mac Intel + Apple Silicon (dmg+zip) 빌드..."
|
||||||
|
# electron-builder는 arch별 dir(.app)만 순차 생성 → finalize-mac이 dmg/zip 생성
|
||||||
|
# (dmg를 동시 빌드하면 hdiutil detach 충돌로 실패함)
|
||||||
|
npm run dist:mac
|
||||||
|
built_any=true
|
||||||
|
fi
|
||||||
|
if [[ "${SKIP_WIN}" != "1" ]]; then
|
||||||
|
log "Windows 32/64비트 (Setup+portable) 빌드 (크로스)..."
|
||||||
|
if npm run dist:win; then
|
||||||
|
built_any=true
|
||||||
|
else
|
||||||
|
warn "Windows 빌드 실패 — Mac 산출물만 배포합니다"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
Linux)
|
||||||
|
if [[ "${SKIP_WIN}" != "1" ]]; then
|
||||||
|
log "Windows 32/64비트 (Setup+portable) 빌드..."
|
||||||
|
if npm run dist:win; then
|
||||||
|
built_any=true
|
||||||
|
else
|
||||||
|
warn "Windows 빌드 실패"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ "${SKIP_MAC}" != "1" ]]; then
|
||||||
|
warn "Linux에서는 Mac 빌드를 건너뜁니다 (SKIP_MAC 강제)"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
MINGW*|MSYS*|CYGWIN*|Windows_NT)
|
||||||
|
if [[ "${SKIP_WIN}" != "1" ]]; then
|
||||||
|
log "Windows 32/64비트 (Setup+portable) 빌드..."
|
||||||
|
npm run dist:win
|
||||||
|
built_any=true
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
fail "지원하지 않는 OS: $(uname -s)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
$built_any || fail "빌드된 산출물이 없습니다"
|
||||||
|
|
||||||
|
log "downloads/ 로 복사..."
|
||||||
|
npm run publish-downloads
|
||||||
|
|
||||||
|
[[ -d "${DOWNLOADS_DIR}" ]] || fail "downloads 디렉터리 없음: ${DOWNLOADS_DIR}"
|
||||||
|
log "✅ 데스크톱 앱 배포 완료 → ${DOWNLOADS_DIR}"
|
||||||
|
ls -lh "${DOWNLOADS_DIR}" | sed 's/^/ /'
|
||||||
Executable
+181
@@ -0,0 +1,181 @@
|
|||||||
|
const { app, BrowserWindow, shell, Menu, session } = require("electron");
|
||||||
|
const path = require("node:path");
|
||||||
|
const fs = require("node:fs");
|
||||||
|
|
||||||
|
// Gatekeeper / ad-hoc 서명 환경에서 GPU Helper SIGTRAP 완화
|
||||||
|
app.disableHardwareAcceleration();
|
||||||
|
app.commandLine.appendSwitch("disable-gpu");
|
||||||
|
app.commandLine.appendSwitch("disable-gpu-compositing");
|
||||||
|
app.commandLine.appendSwitch("disable-software-rasterizer");
|
||||||
|
app.commandLine.appendSwitch("no-sandbox");
|
||||||
|
app.commandLine.appendSwitch("disable-dev-shm-usage");
|
||||||
|
|
||||||
|
const WINDOW_WIDTH = 390;
|
||||||
|
const WINDOW_HEIGHT = 720;
|
||||||
|
|
||||||
|
const DEFAULT_URL =
|
||||||
|
process.env.CHATBOT_APP_URL ||
|
||||||
|
"https://chatbot.exdev.co.kr/chatbot/ai/?desktop=1";
|
||||||
|
|
||||||
|
const logFile = path.join(app.getPath("userData"), "ex-ai-chatbot.log");
|
||||||
|
|
||||||
|
function log(msg) {
|
||||||
|
const line = `[${new Date().toISOString()}] ${msg}\n`;
|
||||||
|
try {
|
||||||
|
fs.appendFileSync(logFile, line);
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 챗봇 주소의 마이크·위치 요청은 매번 묻지 않고 허용한다. */
|
||||||
|
function allowMicrophoneForChatbot() {
|
||||||
|
const allowed = new Set([
|
||||||
|
"media",
|
||||||
|
"audioCapture",
|
||||||
|
"mediaKeySystem",
|
||||||
|
"geolocation",
|
||||||
|
]);
|
||||||
|
const appOrigin = (() => {
|
||||||
|
try {
|
||||||
|
return new URL(DEFAULT_URL).origin;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
const isChatbotOrigin = (url) => {
|
||||||
|
if (!appOrigin || !url) return false;
|
||||||
|
try {
|
||||||
|
return new URL(url).origin === appOrigin;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ses = session.defaultSession;
|
||||||
|
|
||||||
|
ses.setPermissionRequestHandler((webContents, permission, callback, details) => {
|
||||||
|
const url = details?.requestingUrl || webContents?.getURL();
|
||||||
|
callback(allowed.has(permission) && isChatbotOrigin(url));
|
||||||
|
});
|
||||||
|
|
||||||
|
ses.setPermissionCheckHandler((_webContents, permission, requestingOrigin, details) => {
|
||||||
|
const url = requestingOrigin || details?.requestingUrl;
|
||||||
|
return allowed.has(permission) && isChatbotOrigin(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof ses.setDevicePermissionHandler === "function") {
|
||||||
|
ses.setDevicePermissionHandler((details) => isChatbotOrigin(details?.origin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
const iconPath = path.join(__dirname, "build", process.platform === "win32" ? "icon.ico" : "icon.png");
|
||||||
|
const winOpts = {
|
||||||
|
width: WINDOW_WIDTH,
|
||||||
|
height: WINDOW_HEIGHT,
|
||||||
|
minWidth: 360,
|
||||||
|
minHeight: 520,
|
||||||
|
title: "한국도로공사 AI 챗봇",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, "preload.js"),
|
||||||
|
contextIsolation: true,
|
||||||
|
nodeIntegration: false,
|
||||||
|
sandbox: false,
|
||||||
|
webSecurity: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (fs.existsSync(iconPath)) {
|
||||||
|
winOpts.icon = iconPath;
|
||||||
|
}
|
||||||
|
const win = new BrowserWindow(winOpts);
|
||||||
|
|
||||||
|
Menu.setApplicationMenu(null);
|
||||||
|
|
||||||
|
win.once("ready-to-show", () => {
|
||||||
|
win.show();
|
||||||
|
if (process.platform === "darwin" && app.dock) {
|
||||||
|
const dockIcon = path.join(__dirname, "build", "icon.png");
|
||||||
|
if (fs.existsSync(dockIcon)) {
|
||||||
|
try {
|
||||||
|
app.dock.setIcon(dockIcon);
|
||||||
|
} catch (e) {
|
||||||
|
log(`dock.setIcon failed: ${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.dock.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
win.webContents.on("did-fail-load", (_e, code, desc, url) => {
|
||||||
|
log(`did-fail-load code=${code} desc=${desc} url=${url}`);
|
||||||
|
// 네트워크 실패 시에도 빈 창으로 종료되지 않도록 안내 페이지
|
||||||
|
const html = `<!doctype html><meta charset="utf-8"/>
|
||||||
|
<body style="font:14px -apple-system,sans-serif;padding:40px;line-height:1.6">
|
||||||
|
<h2>연결 실패</h2>
|
||||||
|
<p>챗봇 서버에 연결하지 못했습니다.</p>
|
||||||
|
<p style="color:#666">${code}: ${desc}</p>
|
||||||
|
<p><a href="${DEFAULT_URL}">다시 시도</a></p>
|
||||||
|
</body>`;
|
||||||
|
win.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(html)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
win.webContents.on("render-process-gone", (_e, details) => {
|
||||||
|
log(`render-process-gone ${JSON.stringify(details)}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
win.on("unresponsive", () => log("window unresponsive"));
|
||||||
|
|
||||||
|
log(`loadURL ${DEFAULT_URL}`);
|
||||||
|
win.loadURL(DEFAULT_URL).catch((err) => log(`loadURL error: ${err}`));
|
||||||
|
|
||||||
|
win.webContents.setWindowOpenHandler(({ url }) => {
|
||||||
|
shell.openExternal(url);
|
||||||
|
return { action: "deny" };
|
||||||
|
});
|
||||||
|
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gotLock = app.requestSingleInstanceLock();
|
||||||
|
if (!gotLock) {
|
||||||
|
app.quit();
|
||||||
|
} else {
|
||||||
|
app.on("second-instance", () => {
|
||||||
|
const wins = BrowserWindow.getAllWindows();
|
||||||
|
if (wins.length > 0) {
|
||||||
|
if (wins[0].isMinimized()) wins[0].restore();
|
||||||
|
wins[0].focus();
|
||||||
|
} else {
|
||||||
|
createWindow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
app.setName("EX AI Chatbot");
|
||||||
|
log(`ready userData=${app.getPath("userData")}`);
|
||||||
|
allowMicrophoneForChatbot();
|
||||||
|
createWindow();
|
||||||
|
|
||||||
|
app.on("activate", () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on("window-all-closed", () => {
|
||||||
|
if (process.platform !== "darwin") {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("uncaughtException", (err) => {
|
||||||
|
log(`uncaughtException ${err?.stack || err}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
+5288
File diff suppressed because it is too large
Load Diff
Executable
+72
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"name": "ex-ai-chatbot-desktop",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "한국도로공사 AI 챗봇 데스크톱 앱 (Electron 래퍼)",
|
||||||
|
"main": "main.js",
|
||||||
|
"author": "EX",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "electron .",
|
||||||
|
"build:icons": "python3 scripts/build-icons.py",
|
||||||
|
"dist:mac:detach": "hdiutil detach '/Volumes/EX AI Chatbot' -force 2>/dev/null || hdiutil detach '/Volumes/EX AI Chatbot Intel' -force 2>/dev/null || hdiutil detach '/Volumes/EX AI Chatbot Silicon' -force 2>/dev/null || true",
|
||||||
|
"dist:mac:x64": "npm run dist:mac:detach && electron-builder --mac dir --x64",
|
||||||
|
"dist:mac:arm64": "npm run dist:mac:detach && electron-builder --mac dir --arm64",
|
||||||
|
"dist:mac": "npm run build:icons && npm run dist:mac:x64 && npm run dist:mac:arm64 && node scripts/finalize-mac.mjs",
|
||||||
|
"dist:win": "npm run build:icons && electron-builder --win --x64 --ia32 && node scripts/finalize-win.mjs",
|
||||||
|
"dist:all": "npm run dist:mac && npm run dist:win",
|
||||||
|
"publish-downloads": "node scripts/publish-downloads.mjs"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"appId": "kr.co.ex.aichatbot",
|
||||||
|
"productName": "EX AI Chatbot",
|
||||||
|
"copyright": "Copyright © Korea Expressway Corporation",
|
||||||
|
"directories": {
|
||||||
|
"output": "dist",
|
||||||
|
"buildResources": "build"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"main.js",
|
||||||
|
"preload.js",
|
||||||
|
"package.json",
|
||||||
|
"build/icon.png",
|
||||||
|
"build/icon.ico"
|
||||||
|
],
|
||||||
|
"mac": {
|
||||||
|
"category": "public.app-category.utilities",
|
||||||
|
"icon": "build/icon.icns",
|
||||||
|
"target": ["dir"],
|
||||||
|
"identity": null
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"icon": "build/icon.ico",
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"target": "nsis",
|
||||||
|
"arch": ["x64", "ia32"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target": "portable",
|
||||||
|
"arch": ["x64", "ia32"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nsis": {
|
||||||
|
"oneClick": false,
|
||||||
|
"allowToChangeInstallationDirectory": true,
|
||||||
|
"createDesktopShortcut": true,
|
||||||
|
"createStartMenuShortcut": true,
|
||||||
|
"shortcutName": "EX AI Chatbot",
|
||||||
|
"installerIcon": "build/icon.ico",
|
||||||
|
"uninstallerIcon": "build/icon.ico",
|
||||||
|
"artifactName": "raw-win-${arch}-Setup.${ext}"
|
||||||
|
},
|
||||||
|
"portable": {
|
||||||
|
"artifactName": "raw-win-${arch}-portable.${ext}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"electron": "^35.1.2",
|
||||||
|
"electron-builder": "^25.1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.allow-jit</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
EX AI Chatbot — Mac 설치 안내
|
||||||
|
================================
|
||||||
|
|
||||||
|
이 패키지는 Apple 공증(notarization)이 없는 사내/개발용 빌드입니다.
|
||||||
|
Chrome 등으로 받은 뒤 앱을 바로 열면
|
||||||
|
「손상되었기 때문에 열 수 없습니다」가 뜰 수 있습니다.
|
||||||
|
(포터블 zip의 「실행하기.command」는 이 문제를 자동으로 피합니다.)
|
||||||
|
|
||||||
|
────────────────────────────────
|
||||||
|
A. 설치 파일 (.dmg) — 반드시 아래 순서
|
||||||
|
────────────────────────────────
|
||||||
|
1. dmg를 연다
|
||||||
|
2. 「응용 프로그램에 설치하고 실행.command」를 더블클릭
|
||||||
|
→ Applications에 설치 + 검역 속성 제거 + 실행까지 한 번에 처리
|
||||||
|
3. (대안) 앱을 Applications로 드래그한 뒤, 아래 C. 터미널 명령을 실행
|
||||||
|
|
||||||
|
※ Applications의 앱을 더블클릭만 하면 macOS가 다시 차단할 수 있습니다.
|
||||||
|
처음 한 번은 반드시 「설치하고 실행.command」또는 터미널(xattr)을 사용하세요.
|
||||||
|
|
||||||
|
────────────────────────────────
|
||||||
|
B. 포터블 (.zip)
|
||||||
|
────────────────────────────────
|
||||||
|
1. zip 압축 해제
|
||||||
|
2. 「실행하기.command」를 더블클릭
|
||||||
|
3. 차단되면 아래 「터미널 설치」를 사용
|
||||||
|
|
||||||
|
────────────────────────────────
|
||||||
|
C. 터미널 설치 (손상됨 / 차단될 때)
|
||||||
|
────────────────────────────────
|
||||||
|
1. Spotlight(⌘+스페이스) → 「터미널」실행
|
||||||
|
2. 챗봇 설정 화면의 「Mac 설치 명령 복사」붙여넣기(⌘+V) 후 Enter
|
||||||
|
|
||||||
|
직접 입력 (Applications에 넣은 경우):
|
||||||
|
xattr -cr "/Applications/EX AI Chatbot.app" && open "/Applications/EX AI Chatbot.app"
|
||||||
|
|
||||||
|
Apple Silicon → mac-silicon / Intel → mac-intel 파일을 받으세요.
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 주의: 웹에서 받은 .command 는 macOS가 같이 차단할 수 있습니다.
|
||||||
|
# 차단되면 「설치안내.txt」의 터미널 방법을 사용하세요.
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
APP="EX AI Chatbot.app"
|
||||||
|
|
||||||
|
if [[ ! -d "${APP}" ]]; then
|
||||||
|
osascript -e 'display dialog "같은 폴더에 「EX AI Chatbot.app」이 없습니다.\n압축을 해제한 뒤, 차단되면 터미널 설치 방법을 사용하세요.\n(설치안내.txt 참고)" buttons {"확인"} default button 1 with title "EX AI Chatbot"' >/dev/null 2>&1 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 자기 자신·앱 검역 제거 시도 (권한이 되면 성공)
|
||||||
|
xattr -cr . 2>/dev/null || true
|
||||||
|
xattr -cr "${APP}" 2>/dev/null || true
|
||||||
|
|
||||||
|
open "${APP}"
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# DMG에서 실행: Applications로 복사 + Gatekeeper 검역 제거 후 실행
|
||||||
|
# (미서명 빌드에서 「손상되었기 때문에 열 수 없습니다」 방지)
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
APP_NAME="EX AI Chatbot.app"
|
||||||
|
SRC="$(pwd)/${APP_NAME}"
|
||||||
|
DEST="/Applications/${APP_NAME}"
|
||||||
|
|
||||||
|
if [[ ! -d "${SRC}" ]]; then
|
||||||
|
osascript -e 'display dialog "같은 디스크에 「EX AI Chatbot.app」이 없습니다.\ndmg 창에서 이 스크립트를 실행해 주세요." buttons {"확인"} default button 1 with title "EX AI Chatbot"' >/dev/null 2>&1 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 기존 설치 교체
|
||||||
|
rm -rf "${DEST}"
|
||||||
|
cp -R "${SRC}" "${DEST}"
|
||||||
|
|
||||||
|
# 다운로드/복사로 붙은 quarantine 제거 (손상됨 팝업 핵심 해결)
|
||||||
|
xattr -cr "${DEST}" 2>/dev/null || true
|
||||||
|
|
||||||
|
open "${DEST}"
|
||||||
|
|
||||||
|
osascript -e 'display dialog "응용 프로그램에 설치하고 실행했습니다.\n다음에 실행할 때는 Launchpad 또는 응용 프로그램 폴더의 「EX AI Chatbot」을 사용하세요." buttons {"확인"} default button 1 with title "EX AI Chatbot"' >/dev/null 2>&1 || true
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
const { contextBridge } = require("electron");
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld("exDesktop", {
|
||||||
|
isDesktop: true,
|
||||||
|
platform: process.platform,
|
||||||
|
});
|
||||||
+230
@@ -0,0 +1,230 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
공식 길통이+차로(ai-mascot.png)로 Electron 앱 아이콘 생성
|
||||||
|
- build/icon.png (1024)
|
||||||
|
- build/icon.icns (macOS)
|
||||||
|
- build/icon.ico (Windows)
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import plistlib
|
||||||
|
import shutil
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import zlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
BUILD = ROOT / "build"
|
||||||
|
SRC_CANDIDATES = [
|
||||||
|
ROOT.parent / "chatbotApp-chatbot2.0-agent" / "web" / "public" / "images" / "ai-mascot.png",
|
||||||
|
ROOT.parent / "chatbotApp-chatbot2.0-agent" / "public-ai" / "images" / "ai-mascot.png",
|
||||||
|
]
|
||||||
|
|
||||||
|
# EX 브랜드 블루
|
||||||
|
BG = (36, 107, 235, 255)
|
||||||
|
WHITE = (255, 255, 255, 255)
|
||||||
|
|
||||||
|
|
||||||
|
def _venv_python(venv: Path) -> Path:
|
||||||
|
if sys.platform == "win32":
|
||||||
|
return venv / "Scripts" / "python.exe"
|
||||||
|
py = venv / "bin" / "python3"
|
||||||
|
return py if py.exists() else venv / "bin" / "python"
|
||||||
|
|
||||||
|
|
||||||
|
def _in_venv(venv: Path) -> bool:
|
||||||
|
"""Homebrew venv의 bin/python은 시스템 바이너리 symlink라 executable.resolve() 비교는 불가."""
|
||||||
|
try:
|
||||||
|
return Path(sys.prefix).resolve() == venv.resolve()
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_pip(py: Path) -> None:
|
||||||
|
try:
|
||||||
|
subprocess.check_call([str(py), "-m", "pip", "--version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print("[build-icons] ensurepip으로 pip 부트스트랩…", flush=True)
|
||||||
|
subprocess.check_call([str(py), "-m", "ensurepip", "--upgrade"])
|
||||||
|
|
||||||
|
|
||||||
|
def _pip_install_pillow(py: Path) -> None:
|
||||||
|
_ensure_pip(py)
|
||||||
|
cmd = [str(py), "-m", "pip", "install", "Pillow", "-q"]
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print("[build-icons] pip 재시도 (ensurepip 후)…", flush=True)
|
||||||
|
subprocess.check_call([str(py), "-m", "ensurepip", "--upgrade"])
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def require_pillow():
|
||||||
|
try:
|
||||||
|
from PIL import Image, ImageDraw # noqa: F401
|
||||||
|
return
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
venv = ROOT / ".venv-icons"
|
||||||
|
py = _venv_python(venv)
|
||||||
|
if not py.exists():
|
||||||
|
print("[build-icons] venv 생성 중…", flush=True)
|
||||||
|
subprocess.check_call([sys.executable, "-m", "venv", str(venv)])
|
||||||
|
py = _venv_python(venv)
|
||||||
|
print("[build-icons] Pillow 설치 중…", flush=True)
|
||||||
|
_pip_install_pillow(py)
|
||||||
|
# 현재 프로세스에 Pillow가 없으면 venv로 재실행 (sys.prefix로 판별)
|
||||||
|
if not _in_venv(venv):
|
||||||
|
raise SystemExit(subprocess.call([str(py), str(Path(__file__).resolve()), *sys.argv[1:]]))
|
||||||
|
from PIL import Image, ImageDraw # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
|
def rounded_rect_mask(size: int, radius: int):
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
mask = Image.new("L", (size, size), 0)
|
||||||
|
draw = ImageDraw.Draw(mask)
|
||||||
|
draw.rounded_rectangle((0, 0, size - 1, size - 1), radius=radius, fill=255)
|
||||||
|
return mask
|
||||||
|
|
||||||
|
|
||||||
|
def make_icon_png(src: Path, out: Path, size: int = 1024) -> None:
|
||||||
|
from PIL import Image, ImageDraw, ImageFilter
|
||||||
|
|
||||||
|
mascot = Image.open(src).convert("RGBA")
|
||||||
|
# 흰 배경 제거에 가깝게: 거의 흰 픽셀을 투명 처리
|
||||||
|
pixels = mascot.load()
|
||||||
|
w, h = mascot.size
|
||||||
|
for y in range(h):
|
||||||
|
for x in range(w):
|
||||||
|
r, g, b, a = pixels[x, y]
|
||||||
|
if r > 245 and g > 245 and b > 245:
|
||||||
|
pixels[x, y] = (r, g, b, 0)
|
||||||
|
|
||||||
|
canvas = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||||
|
draw = ImageDraw.Draw(canvas)
|
||||||
|
# macOS 아이콘용 라운드 사각 (약 22% radius)
|
||||||
|
radius = int(size * 0.223)
|
||||||
|
draw.rounded_rectangle((0, 0, size - 1, size - 1), radius=radius, fill=BG)
|
||||||
|
|
||||||
|
# 안쪽 밝은 원형 배지
|
||||||
|
badge = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||||
|
bd = ImageDraw.Draw(badge)
|
||||||
|
pad = int(size * 0.08)
|
||||||
|
bd.ellipse((pad, pad, size - pad, size - pad), fill=(255, 255, 255, 235))
|
||||||
|
canvas = Image.alpha_composite(canvas, badge)
|
||||||
|
|
||||||
|
# 마스코트 배치 (여백 확보)
|
||||||
|
max_side = int(size * 0.78)
|
||||||
|
mw, mh = mascot.size
|
||||||
|
scale = min(max_side / mw, max_side / mh)
|
||||||
|
nw, nh = int(mw * scale), int(mh * scale)
|
||||||
|
mascot = mascot.resize((nw, nh), Image.Resampling.LANCZOS)
|
||||||
|
ox = (size - nw) // 2
|
||||||
|
oy = (size - nh) // 2 + int(size * 0.02)
|
||||||
|
canvas.alpha_composite(mascot, (ox, oy))
|
||||||
|
|
||||||
|
# 마스크로 모서리 정리
|
||||||
|
mask = rounded_rect_mask(size, radius)
|
||||||
|
out_img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||||
|
out_img.paste(canvas, (0, 0), mask=mask)
|
||||||
|
|
||||||
|
out.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
out_img.save(out, "PNG")
|
||||||
|
print(f"[build-icons] ✅ {out} ({size}x{size})")
|
||||||
|
|
||||||
|
|
||||||
|
def build_icns(png_1024: Path, icns_path: Path) -> None:
|
||||||
|
sizes = [
|
||||||
|
(16, "icon_16x16.png"),
|
||||||
|
(32, "diana.k@example.org"),
|
||||||
|
(32, "icon_32x32.png"),
|
||||||
|
(64, "ivan.p@example.net"),
|
||||||
|
(128, "icon_128x128.png"),
|
||||||
|
(256, "wendy.h@example.net"),
|
||||||
|
(256, "icon_256x256.png"),
|
||||||
|
(512, "wendy.h@example.net"),
|
||||||
|
(512, "icon_512x512.png"),
|
||||||
|
(1024, "walt.e@example.net"),
|
||||||
|
]
|
||||||
|
iconset = BUILD / "icon.iconset"
|
||||||
|
if iconset.exists():
|
||||||
|
shutil.rmtree(iconset)
|
||||||
|
iconset.mkdir(parents=True)
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
base = Image.open(png_1024).convert("RGBA")
|
||||||
|
for px, name in sizes:
|
||||||
|
img = base.resize((px, px), Image.Resampling.LANCZOS)
|
||||||
|
img.save(iconset / name, "PNG")
|
||||||
|
|
||||||
|
if icns_path.exists():
|
||||||
|
icns_path.unlink()
|
||||||
|
subprocess.check_call(["iconutil", "-c", "icns", str(iconset), "-o", str(icns_path)])
|
||||||
|
shutil.rmtree(iconset)
|
||||||
|
print(f"[build-icons] ✅ {icns_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def _png_chunk(tag: bytes, data: bytes) -> bytes:
|
||||||
|
return struct.pack(">I", len(data)) + tag + data + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)
|
||||||
|
|
||||||
|
|
||||||
|
def rgba_to_png_bytes(img) -> bytes:
|
||||||
|
"""Pillow 이미지 → PNG bytes (ICO용)."""
|
||||||
|
import io
|
||||||
|
|
||||||
|
buf = io.BytesIO()
|
||||||
|
img.save(buf, format="PNG")
|
||||||
|
return buf.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
def build_ico(png_1024: Path, ico_path: Path) -> None:
|
||||||
|
"""여러 해상도 PNG를 담은 .ico 생성 (electron-builder는 256 필수)."""
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
sizes = [(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)]
|
||||||
|
base = Image.open(png_1024).convert("RGBA")
|
||||||
|
# Pillow: 원본에서 sizes= 로 리사이즈한 멀티 엔트리 ICO 생성
|
||||||
|
# (append_images + 작은 첫 프레임은 16x16만 남는 버그 회피)
|
||||||
|
base.save(ico_path, format="ICO", sizes=sizes)
|
||||||
|
print(f"[build-icons] ✅ {ico_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
require_pillow()
|
||||||
|
src = next((p for p in SRC_CANDIDATES if p.exists()), None)
|
||||||
|
if not src:
|
||||||
|
print("[build-icons] ai-mascot.png 없음", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
BUILD.mkdir(parents=True, exist_ok=True)
|
||||||
|
png = BUILD / "icon.png"
|
||||||
|
make_icon_png(src, png, 1024)
|
||||||
|
# electron-builder 호환 별칭
|
||||||
|
shutil.copy2(png, BUILD / "icon-1024.png")
|
||||||
|
|
||||||
|
if sys.platform == "darwin":
|
||||||
|
try:
|
||||||
|
build_icns(png, BUILD / "icon.icns")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[build-icons] icns 실패 (png만 사용): {e}", file=sys.stderr)
|
||||||
|
else:
|
||||||
|
print("[build-icons] icns는 macOS에서만 생성합니다")
|
||||||
|
|
||||||
|
try:
|
||||||
|
build_ico(png, BUILD / "icon.ico")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[build-icons] ico 실패: {e}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print("[build-icons] 완료")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/** 다운로드 산출물 파일명 (공백 포함 — URL 인코딩 필요) */
|
||||||
|
export const DOWNLOAD_ARTIFACTS = {
|
||||||
|
macIntelInstaller: "exAIChatbot 2.0-mac-intel.dmg",
|
||||||
|
macIntelPortable: "exAIChatbot 2.0-mac-intel.zip",
|
||||||
|
macSiliconInstaller: "exAIChatbot 2.0-mac-silicon.dmg",
|
||||||
|
macSiliconPortable: "exAIChatbot 2.0-mac-silicon.zip",
|
||||||
|
win32Installer: "exAIChatbot 2.0-win32-Setup.exe",
|
||||||
|
win32Portable: "exAIChatbot 2.0-win32-portable.exe",
|
||||||
|
win64Installer: "exAIChatbot 2.0-win64-Setup.exe",
|
||||||
|
win64Portable: "exAIChatbot 2.0-win64-portable.exe",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DOWNLOAD_ARTIFACT_LIST = Object.values(DOWNLOAD_ARTIFACTS);
|
||||||
|
|
||||||
|
/** 이전 배포 파일명 (정리용) */
|
||||||
|
export const OBSOLETE_DOWNLOAD_ARTIFACTS = [
|
||||||
|
"exAIChatbot 2.0-win32.zip",
|
||||||
|
"exAIChatbot 2.0-win64.zip",
|
||||||
|
"EX-AI-Chatbot-mac-universal.zip",
|
||||||
|
"EX-AI-Chatbot-Setup.exe",
|
||||||
|
"EX-AI-Chatbot-Setup.exe.blockmap",
|
||||||
|
"EX-AI-Chatbot-mac-universal.zip.blockmap",
|
||||||
|
];
|
||||||
+226
@@ -0,0 +1,226 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Mac 산출물 정리
|
||||||
|
* - zip(포터블): .app + 실행하기.command
|
||||||
|
* - dmg(설치형): 동일 서명 .app + 「응용 프로그램에 설치하고 실행.command」
|
||||||
|
* (Gatekeeper 「손상됨」팝업 방지 — 설치 시 xattr -cr 수행)
|
||||||
|
*/
|
||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import os from "node:os";
|
||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { DOWNLOAD_ARTIFACTS } from "./download-artifacts.mjs";
|
||||||
|
|
||||||
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
|
const distDir = path.join(root, "dist");
|
||||||
|
const appName = "EX AI Chatbot.app";
|
||||||
|
const packagingMac = path.join(root, "packaging", "mac");
|
||||||
|
const installCmdName = "응용 프로그램에 설치하고 실행.command";
|
||||||
|
const runCmdName = "실행하기.command";
|
||||||
|
const guideName = "설치안내.txt";
|
||||||
|
|
||||||
|
const TARGETS = [
|
||||||
|
{
|
||||||
|
appDirs: [path.join(distDir, "mac-x64", appName), path.join(distDir, "mac", appName)],
|
||||||
|
zipName: DOWNLOAD_ARTIFACTS.macIntelPortable,
|
||||||
|
dmgName: DOWNLOAD_ARTIFACTS.macIntelInstaller,
|
||||||
|
label: "intel (x64)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
appDirs: [path.join(distDir, "mac-arm64", appName)],
|
||||||
|
zipName: DOWNLOAD_ARTIFACTS.macSiliconPortable,
|
||||||
|
dmgName: DOWNLOAD_ARTIFACTS.macSiliconInstaller,
|
||||||
|
label: "silicon (arm64)",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function codesignApp(appPath, label) {
|
||||||
|
try {
|
||||||
|
execFileSync(
|
||||||
|
"codesign",
|
||||||
|
[
|
||||||
|
"--force",
|
||||||
|
"--deep",
|
||||||
|
"--sign",
|
||||||
|
"-",
|
||||||
|
"--entitlements",
|
||||||
|
path.join(packagingMac, "entitlements.plist"),
|
||||||
|
appPath,
|
||||||
|
],
|
||||||
|
{ stdio: "inherit" },
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(`[finalize-mac] entitlements codesign 실패 (${label}), ad-hoc 재시도:`, e.message);
|
||||||
|
try {
|
||||||
|
execFileSync("codesign", ["--force", "--deep", "--sign", "-", appPath], {
|
||||||
|
stdio: "inherit",
|
||||||
|
});
|
||||||
|
} catch (e2) {
|
||||||
|
console.warn(`[finalize-mac] codesign 실패 (${label}):`, e2.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
execFileSync("xattr", ["-cr", appPath], { stdio: "ignore" });
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensurePackagingFiles() {
|
||||||
|
for (const name of [runCmdName, installCmdName, guideName]) {
|
||||||
|
const p = path.join(packagingMac, name);
|
||||||
|
if (!fs.existsSync(p)) throw new Error(`packaging/mac 파일 없음: ${name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function packZip(appPath, zipName, label) {
|
||||||
|
console.log(`[finalize-mac] zip ${label}: ${appPath}`);
|
||||||
|
const stage = fs.mkdtempSync(path.join(os.tmpdir(), "ex-ai-mac-zip-"));
|
||||||
|
try {
|
||||||
|
fs.cpSync(appPath, path.join(stage, appName), { recursive: true });
|
||||||
|
fs.copyFileSync(path.join(packagingMac, runCmdName), path.join(stage, runCmdName));
|
||||||
|
fs.copyFileSync(path.join(packagingMac, guideName), path.join(stage, guideName));
|
||||||
|
fs.chmodSync(path.join(stage, runCmdName), 0o755);
|
||||||
|
try {
|
||||||
|
execFileSync("xattr", ["-cr", stage], { stdio: "ignore" });
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
|
||||||
|
const zipPath = path.join(distDir, zipName);
|
||||||
|
if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath);
|
||||||
|
execFileSync("zip", ["-r", "-y", zipPath, appName, runCmdName, guideName], {
|
||||||
|
cwd: stage,
|
||||||
|
stdio: "inherit",
|
||||||
|
});
|
||||||
|
const size = fs.statSync(zipPath).size;
|
||||||
|
console.log(`[finalize-mac] ✅ zip ${zipName} (${Math.round(size / 1024 / 1024)} MB)`);
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(stage, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function detachStaleVolumes() {
|
||||||
|
for (const vol of ["EX AI Chatbot", "EX AI Chatbot Intel", "EX AI Chatbot Silicon"]) {
|
||||||
|
try {
|
||||||
|
execFileSync("hdiutil", ["detach", `/Volumes/${vol}`, "-force"], { stdio: "ignore" });
|
||||||
|
} catch {
|
||||||
|
/* not mounted */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function packDmg(appPath, dmgName, label) {
|
||||||
|
console.log(`[finalize-mac] dmg ${label}: ${appPath}`);
|
||||||
|
const stage = fs.mkdtempSync(path.join(os.tmpdir(), "ex-ai-mac-dmg-"));
|
||||||
|
const rwDmg = path.join(os.tmpdir(), `ex-ai-mac-${Date.now()}-${process.pid}.dmg`);
|
||||||
|
// arch별 볼륨명 — 동시/잔여 마운트 충돌 방지
|
||||||
|
const volName = label.includes("silicon") ? "EX AI Chatbot Silicon" : "EX AI Chatbot Intel";
|
||||||
|
try {
|
||||||
|
fs.cpSync(appPath, path.join(stage, appName), { recursive: true });
|
||||||
|
fs.copyFileSync(path.join(packagingMac, installCmdName), path.join(stage, installCmdName));
|
||||||
|
fs.copyFileSync(path.join(packagingMac, guideName), path.join(stage, guideName));
|
||||||
|
fs.chmodSync(path.join(stage, installCmdName), 0o755);
|
||||||
|
// Applications 폴더 바로가기 (일반 dmg UX)
|
||||||
|
try {
|
||||||
|
fs.symlinkSync("/Applications", path.join(stage, "Applications"));
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
execFileSync("xattr", ["-cr", stage], { stdio: "ignore" });
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
|
||||||
|
const outPath = path.join(distDir, dmgName);
|
||||||
|
if (fs.existsSync(outPath)) fs.unlinkSync(outPath);
|
||||||
|
if (fs.existsSync(rwDmg)) fs.unlinkSync(rwDmg);
|
||||||
|
|
||||||
|
detachStaleVolumes();
|
||||||
|
|
||||||
|
// 읽기 전용 압축 dmg 생성 (electron-builder DMG 미사용 — hdiutil 경합 회피)
|
||||||
|
// Finder/Spotlight가 잠깐 잡고 있으면 "리소스 사용 중"이 나므로 재시도한다.
|
||||||
|
const createArgs = [
|
||||||
|
"create",
|
||||||
|
"-volname",
|
||||||
|
volName,
|
||||||
|
"-srcfolder",
|
||||||
|
stage,
|
||||||
|
"-ov",
|
||||||
|
"-format",
|
||||||
|
"UDZO",
|
||||||
|
outPath,
|
||||||
|
];
|
||||||
|
let lastErr = null;
|
||||||
|
for (let attempt = 1; attempt <= 4; attempt += 1) {
|
||||||
|
try {
|
||||||
|
if (attempt > 1) {
|
||||||
|
console.warn(`[finalize-mac] hdiutil create 재시도 ${attempt}/4 (${label})`);
|
||||||
|
detachStaleVolumes();
|
||||||
|
try {
|
||||||
|
execFileSync("sleep", [String(1.5 * attempt)], { stdio: "ignore" });
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
execFileSync("hdiutil", createArgs, { stdio: "inherit" });
|
||||||
|
lastErr = null;
|
||||||
|
break;
|
||||||
|
} catch (e) {
|
||||||
|
lastErr = e;
|
||||||
|
const msg = String(e?.stderr || e?.message || e);
|
||||||
|
const busy = /리소스 사용 중|Resource busy|Device busy|hdiutil/i.test(msg) || e?.status === 1;
|
||||||
|
if (!busy || attempt === 4) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastErr) throw lastErr;
|
||||||
|
|
||||||
|
const size = fs.statSync(outPath).size;
|
||||||
|
console.log(`[finalize-mac] ✅ dmg ${dmgName} (${Math.round(size / 1024 / 1024)} MB)`);
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(stage, { recursive: true, force: true });
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(rwDmg)) fs.unlinkSync(rwDmg);
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(distDir)) {
|
||||||
|
console.error("[finalize-mac] dist 없음");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ensurePackagingFiles();
|
||||||
|
|
||||||
|
let done = 0;
|
||||||
|
for (const t of TARGETS) {
|
||||||
|
const appPath = t.appDirs.find((p) => fs.existsSync(p));
|
||||||
|
if (!appPath) {
|
||||||
|
console.warn(`[finalize-mac] skip ${t.label}: .app 없음`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
codesignApp(appPath, t.label);
|
||||||
|
|
||||||
|
if (packDmg(appPath, t.dmgName, t.label)) done += 1;
|
||||||
|
if (packZip(appPath, t.zipName, t.label)) done += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 빌더 raw zip/dmg 잔여 정리
|
||||||
|
for (const raw of fs.readdirSync(distDir)) {
|
||||||
|
if (/^raw-mac-/.test(raw) && (raw.endsWith(".zip") || raw.endsWith(".dmg"))) {
|
||||||
|
fs.unlinkSync(path.join(distDir, raw));
|
||||||
|
console.log(`[finalize-mac] removed ${raw}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done === 0) {
|
||||||
|
console.error("[finalize-mac] 패키징할 Mac 산출물이 없습니다.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Windows 산출물 정리
|
||||||
|
* - Setup.exe (NSIS 설치형)
|
||||||
|
* - portable.exe (포터블)
|
||||||
|
*/
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { DOWNLOAD_ARTIFACTS } from "./download-artifacts.mjs";
|
||||||
|
|
||||||
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
|
const distDir = path.join(root, "dist");
|
||||||
|
|
||||||
|
const MAP = [
|
||||||
|
{
|
||||||
|
patterns: [/^raw-win-x64-Setup\.exe$/i],
|
||||||
|
out: DOWNLOAD_ARTIFACTS.win64Installer,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: [/^raw-win-x64-portable\.exe$/i],
|
||||||
|
out: DOWNLOAD_ARTIFACTS.win64Portable,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: [/^raw-win-ia32-Setup\.exe$/i, /^raw-win-i386-Setup\.exe$/i],
|
||||||
|
out: DOWNLOAD_ARTIFACTS.win32Installer,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: [/^raw-win-ia32-portable\.exe$/i, /^raw-win-i386-portable\.exe$/i],
|
||||||
|
out: DOWNLOAD_ARTIFACTS.win32Portable,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!fs.existsSync(distDir)) {
|
||||||
|
console.error("[finalize-win] dist 없음");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = fs.readdirSync(distDir);
|
||||||
|
let done = 0;
|
||||||
|
|
||||||
|
for (const rule of MAP) {
|
||||||
|
const srcName = files.find((f) => rule.patterns.some((re) => re.test(f)));
|
||||||
|
if (!srcName) {
|
||||||
|
console.warn(`[finalize-win] skip (원본 없음): ${rule.out}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const src = path.join(distDir, srcName);
|
||||||
|
const dest = path.join(distDir, rule.out);
|
||||||
|
if (src !== dest) {
|
||||||
|
if (fs.existsSync(dest)) fs.unlinkSync(dest);
|
||||||
|
fs.renameSync(src, dest);
|
||||||
|
}
|
||||||
|
const size = fs.statSync(dest).size;
|
||||||
|
console.log(`[finalize-win] ✅ ${rule.out} (${Math.round(size / 1024 / 1024)} MB) ← ${srcName}`);
|
||||||
|
done += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const f of fs.readdirSync(distDir)) {
|
||||||
|
if (/^raw-win-/.test(f)) {
|
||||||
|
fs.unlinkSync(path.join(distDir, f));
|
||||||
|
console.log(`[finalize-win] removed ${f}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done === 0) {
|
||||||
|
console.error("[finalize-win] Windows 설치/포터블 산출물을 찾지 못했습니다.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* electron-builder 산출물 → chatbotApp public-ai/downloads/ 복사
|
||||||
|
*/
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import {
|
||||||
|
DOWNLOAD_ARTIFACTS,
|
||||||
|
DOWNLOAD_ARTIFACT_LIST,
|
||||||
|
OBSOLETE_DOWNLOAD_ARTIFACTS,
|
||||||
|
} from "./download-artifacts.mjs";
|
||||||
|
|
||||||
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
|
const distDir = path.join(root, "dist");
|
||||||
|
const downloadsDir = path.resolve(
|
||||||
|
root,
|
||||||
|
"../chatbotApp-chatbot2.0-agent/public-ai/downloads",
|
||||||
|
);
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
|
||||||
|
|
||||||
|
if (!fs.existsSync(distDir)) {
|
||||||
|
console.error(`[publish-downloads] dist 없음: ${distDir}`);
|
||||||
|
console.error("먼저 npm run dist:mac 또는 dist:win 을 실행하세요.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.mkdirSync(downloadsDir, { recursive: true });
|
||||||
|
|
||||||
|
for (const name of OBSOLETE_DOWNLOAD_ARTIFACTS) {
|
||||||
|
const p = path.join(downloadsDir, name);
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
fs.unlinkSync(p);
|
||||||
|
console.log(`[publish-downloads] removed obsolete ${name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const copied = [];
|
||||||
|
for (const name of DOWNLOAD_ARTIFACT_LIST) {
|
||||||
|
const src = path.join(distDir, name);
|
||||||
|
if (!fs.existsSync(src)) {
|
||||||
|
console.warn(`[publish-downloads] skip (없음): ${name}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const dest = path.join(downloadsDir, name);
|
||||||
|
fs.copyFileSync(src, dest);
|
||||||
|
const stat = fs.statSync(dest);
|
||||||
|
copied.push({
|
||||||
|
file: name,
|
||||||
|
size: stat.size,
|
||||||
|
mtime: stat.mtime.toISOString(),
|
||||||
|
});
|
||||||
|
console.log(`[publish-downloads] ${name} → ${dest}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const manifest = {
|
||||||
|
version: pkg.version,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
files: { ...DOWNLOAD_ARTIFACTS },
|
||||||
|
artifacts: copied,
|
||||||
|
note:
|
||||||
|
"미서명 빌드 — Mac: dmg(설치) / zip(포터블·실행하기.command). Windows: Setup.exe(설치) / portable.exe(포터블).",
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(downloadsDir, "manifest.json"),
|
||||||
|
`${JSON.stringify(manifest, null, 2)}\n`,
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (copied.length === 0) {
|
||||||
|
console.error("[publish-downloads] 복사된 파일이 없습니다.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[publish-downloads] ✅ ${copied.length}개 → ${downloadsDir}`);
|
||||||
Submodule exAiChatBot-chatbot2.0-agent updated: 19f7c338f7...c6d9a32187
Binary file not shown.
+342
-54
@@ -1,30 +1,57 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# GitHub upstream → monorepo submodule 최신 소스 반영 (pull only, push 없음)
|
# 5개 submodule: 로컬 변경 → 공식 GitHub chatbot2.0-agent commit + push
|
||||||
#
|
#
|
||||||
# ./git_fetch_all.sh # 4개 submodule fetch + fast-forward
|
# ★ 공식 GitHub(KoreaExpressWayCorp) 반영은 이 스크립트로만 수행한다.
|
||||||
|
# start-all-server.sh / push-to-gitea.sh 는 개발서버(Gitea/exdev)만 다룬다.
|
||||||
|
#
|
||||||
|
# ./git_fetch_all.sh # fetch/merge + commit + push (공식 GitHub)
|
||||||
# ./git_fetch_all.sh --init # submodule 미초기화 시 clone 포함
|
# ./git_fetch_all.sh --init # submodule 미초기화 시 clone 포함
|
||||||
# ./git_fetch_all.sh --dry-run # 실행 없이 변경 예상만 출력
|
# ./git_fetch_all.sh --dry-run # 실행 없이 상태만 출력
|
||||||
|
# ./git_fetch_all.sh --no-push # commit까지, push 생략
|
||||||
|
# ./git_fetch_all.sh --no-commit # fetch/merge만 (commit·push 생략)
|
||||||
#
|
#
|
||||||
# 대상 (.gitmodules):
|
# ★ 운영(GitHub) push 전용 — 개발서버(exdev) 주소를 커밋/push 하지 않는다.
|
||||||
# chatbotApp-chatbot2.0-agent → KoreaExpressWayCorp/chatbotApp (chatbot2.0-agent)
|
# start-all-server.sh 가 런타임 ENV 로만 exdev(127.0.0.1 Mongo / localhost Oracle TROAD /
|
||||||
# chatbotApi-chatbot2.0-agent → KoreaExpressWayCorp/chatbotApi (chatbot2.0-agent)
|
# host.docker.internal RAG)를 적용한다.
|
||||||
# exAiChatBot-chatbot2.0-agent → KoreaExpressWayCorp/exAiChatBot (chatbot2.0-agent)
|
# 이 스크립트는 commit 직전에 운영 기본값(172.16.*)을 파일에 복원한 뒤 push 한다.
|
||||||
# kakaoChatbotSkill-chatbot2.0-agent → KoreaExpressWayCorp/kakaoChatbotSkill (chatbot2.0-agent)
|
# (.env / EXDEV_LOCAL / server-dev 오버레이는 GitHub 대상이 아님)
|
||||||
|
#
|
||||||
|
# 대상 (.gitmodules) — 모두 branch=chatbot2.0-agent (main 사용 안 함):
|
||||||
|
# chatbotApi-chatbot2.0-agent
|
||||||
|
# chatbotApp-chatbot2.0-agent
|
||||||
|
# chatbotApp-test
|
||||||
|
# exAiChatBot-chatbot2.0-agent
|
||||||
|
# kakaoChatbotSkill-chatbot2.0-agent
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
# bare repo 배포 시 상위에서 GIT_DIR 이 export 되면 submodule git 이 깨짐
|
# bare repo 배포 시 상위에서 GIT_DIR 이 export 되면 submodule git 이 깨짐
|
||||||
MONOREPO_GIT_DIR="${MONOREPO_GIT_DIR:-${GIT_DIR:-}}"
|
MONOREPO_GIT_DIR="${MONOREPO_GIT_DIR:-${GIT_DIR:-}}"
|
||||||
unset GIT_DIR GIT_WORK_TREE
|
unset GIT_DIR GIT_WORK_TREE
|
||||||
|
|
||||||
INIT=false
|
INIT=false
|
||||||
DRY_RUN=false
|
DRY_RUN=false
|
||||||
|
DO_COMMIT=true
|
||||||
|
DO_PUSH=true
|
||||||
|
TARGET_BRANCH="chatbot2.0-agent"
|
||||||
|
|
||||||
|
# 명시 대상 (순서 고정). .gitmodules 와 일치해야 함.
|
||||||
|
TARGET_PATHS=(
|
||||||
|
"chatbotApi-chatbot2.0-agent"
|
||||||
|
"chatbotApp-chatbot2.0-agent"
|
||||||
|
"chatbotApp-test"
|
||||||
|
"exAiChatBot-chatbot2.0-agent"
|
||||||
|
"kakaoChatbotSkill-chatbot2.0-agent"
|
||||||
|
)
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--init) INIT=true ;;
|
--init) INIT=true ;;
|
||||||
--dry-run) DRY_RUN=true ;;
|
--dry-run) DRY_RUN=true ;;
|
||||||
|
--no-commit) DO_COMMIT=false; DO_PUSH=false ;;
|
||||||
|
--no-push) DO_PUSH=false ;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
sed -n '2,14p' "$0"
|
sed -n '2,22p' "$0"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -36,6 +63,7 @@ done
|
|||||||
|
|
||||||
log() { echo "[git_fetch_all] $*"; }
|
log() { echo "[git_fetch_all] $*"; }
|
||||||
warn() { echo "[git_fetch_all] ⚠️ $*" >&2; }
|
warn() { echo "[git_fetch_all] ⚠️ $*" >&2; }
|
||||||
|
ok() { echo "[git_fetch_all] ✅ $*"; }
|
||||||
|
|
||||||
cd "${ROOT_DIR}"
|
cd "${ROOT_DIR}"
|
||||||
|
|
||||||
@@ -44,20 +72,6 @@ if [[ ! -f .gitmodules ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SUBMODULE_PATHS=()
|
|
||||||
while IFS= read -r _path; do
|
|
||||||
[[ -n "${_path}" ]] && SUBMODULE_PATHS+=("${_path}")
|
|
||||||
done < <(git config -f .gitmodules --get-regexp '^submodule\..*\.path$' | awk '{print $2}')
|
|
||||||
|
|
||||||
if [[ ${#SUBMODULE_PATHS[@]} -eq 0 ]]; then
|
|
||||||
echo "ERROR: .gitmodules 에 submodule 경로 없음"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $INIT && ! $DRY_RUN; then
|
|
||||||
log "submodule init (direct clone)..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
resolve_monorepo_git_dir() {
|
resolve_monorepo_git_dir() {
|
||||||
if [[ -n "${MONOREPO_GIT_DIR}" && -d "${MONOREPO_GIT_DIR}" ]]; then
|
if [[ -n "${MONOREPO_GIT_DIR}" && -d "${MONOREPO_GIT_DIR}" ]]; then
|
||||||
echo "${MONOREPO_GIT_DIR}"
|
echo "${MONOREPO_GIT_DIR}"
|
||||||
@@ -104,18 +118,181 @@ restore_monorepo_overlays() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# GitHub push 전: exdev 런타임 주소를 커밋하지 않고 운영 기본값(172.16.180.130) 유지
|
||||||
|
# - 런타임(exdev): start-all-server.sh ENV / .env / EXDEV_LOCAL=true → 127.0.0.1·host.docker.internal
|
||||||
|
# - 커밋/push: application.yml·env.template·chatbot_tool_client.py 기본값을 운영 IP로 고정
|
||||||
|
PROD_WAS_HOST="172.16.180.130"
|
||||||
|
PROD_WAS_API="http://${PROD_WAS_HOST}:8086/api"
|
||||||
|
PROD_RAG_CHAT="http://${PROD_WAS_HOST}:28012/agent/chat"
|
||||||
|
PROD_MONGO_URI="mongodb://exDev:ehfhrhdtk!!@${PROD_WAS_HOST}:27017/chatbot?heartbeatFrequencyMS=30000&minPoolSize=8&maxIdleTimeMS=18000000"
|
||||||
|
# 운영 TROAD Oracle (start-all 은 SPRING_DATASOURCE_TROAD_* ENV 로 localhost 오버라이드)
|
||||||
|
PROD_TROAD_JDBC_URL="jdbc:oracle:thin:@172.16.163.76:1522/TROAD"
|
||||||
|
PROD_TROAD_USERNAME="TROAD_APP"
|
||||||
|
PROD_TROAD_PASSWORD='!ryxhdapp2025'
|
||||||
|
|
||||||
|
restore_production_endpoints_before_commit() {
|
||||||
|
local path="$1"
|
||||||
|
local dir="${ROOT_DIR}/${path}"
|
||||||
|
|
||||||
|
case "${path}" in
|
||||||
|
chatbotApi-chatbot2.0-agent)
|
||||||
|
local yml="${dir}/src/main/resources/application.yml"
|
||||||
|
if [[ -f "${yml}" ]]; then
|
||||||
|
# 수동/임시로 바꾼 로컬 Mongo URI 를 운영 기본값으로 복원 (start-all 은 ENV 로만 오버라이드)
|
||||||
|
# URI 의 @ 는 perl 치환부 배열 보간을 피하기 위해 ENV 로 전달
|
||||||
|
PROD_MONGO_URI="${PROD_MONGO_URI}" perl -i -pe \
|
||||||
|
's|uri:\s*mongodb://\S+|uri: $ENV{PROD_MONGO_URI}|g' "${yml}"
|
||||||
|
# troad datasource 를 로컬 Oracle 로 바꿔 둔 경우 운영값 복원
|
||||||
|
PROD_TROAD_JDBC_URL="${PROD_TROAD_JDBC_URL}" \
|
||||||
|
PROD_TROAD_USERNAME="${PROD_TROAD_USERNAME}" \
|
||||||
|
PROD_TROAD_PASSWORD="${PROD_TROAD_PASSWORD}" \
|
||||||
|
perl -i -0pe '
|
||||||
|
s|(troad:\s*\n(?:[ \t]+[^\n]*\n)*?[ \t]+url:\s*)\S+|$1$ENV{PROD_TROAD_JDBC_URL}|g;
|
||||||
|
s|(troad:\s*\n(?:[ \t]+[^\n]*\n)*?[ \t]+username:\s*)\S+|$1$ENV{PROD_TROAD_USERNAME}|g;
|
||||||
|
s|(troad:\s*\n(?:[ \t]+[^\n]*\n)*?[ \t]+password:\s*).*|$1"$ENV{PROD_TROAD_PASSWORD}"|g;
|
||||||
|
' "${yml}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
kakaoChatbotSkill-chatbot2.0-agent)
|
||||||
|
local yml="${dir}/src/main/resources/application.yml"
|
||||||
|
if [[ -f "${yml}" ]]; then
|
||||||
|
# ${ENV:default} 형태의 default 만 운영 IP로 고정 (실행 시 ENV 로컬 오버라이드는 유지)
|
||||||
|
PROD_WAS_API="${PROD_WAS_API}" PROD_RAG_CHAT="${PROD_RAG_CHAT}" PROD_WAS_HOST="${PROD_WAS_HOST}" \
|
||||||
|
perl -i -pe '
|
||||||
|
s|CHATBOT_API_BASE_URL:[^}]+}|CHATBOT_API_BASE_URL:$ENV{PROD_WAS_API}/}|g;
|
||||||
|
s|RAG_AGENT_CHAT_URL:[^}]+}|RAG_AGENT_CHAT_URL:$ENV{PROD_RAG_CHAT}}|g;
|
||||||
|
s|base-url:\s*http://127\.0\.0\.1:8086/api/?|base-url: \${CHATBOT_API_BASE_URL:$ENV{PROD_WAS_API}/}|g;
|
||||||
|
s|base-url:\s*http://host\.docker\.internal:8086/api/?|base-url: \${CHATBOT_API_BASE_URL:$ENV{PROD_WAS_API}/}|g;
|
||||||
|
s|url:\s*http://127\.0\.0\.1:28012/agent/chat|url: \${RAG_AGENT_CHAT_URL:$ENV{PROD_RAG_CHAT}}|g;
|
||||||
|
s|url:\s*http://host\.docker\.internal:28012/agent/chat|url: \${RAG_AGENT_CHAT_URL:$ENV{PROD_RAG_CHAT}}|g;
|
||||||
|
' "${yml}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
exAiChatBot-chatbot2.0-agent)
|
||||||
|
if [[ -f "${dir}/env.template" ]]; then
|
||||||
|
PROD_WAS_API="${PROD_WAS_API}" perl -i -pe \
|
||||||
|
's|^CHATBOT_API_BASE_URL=.*|CHATBOT_API_BASE_URL=$ENV{PROD_WAS_API}|' "${dir}/env.template"
|
||||||
|
# EXDEV_LOCAL 은 커밋 템플릿에 넣지 않음 (server-dev 전용)
|
||||||
|
perl -i -ne 'print unless /^EXDEV_LOCAL=/' "${dir}/env.template"
|
||||||
|
fi
|
||||||
|
if [[ -f "${dir}/env.example" ]]; then
|
||||||
|
PROD_WAS_API="${PROD_WAS_API}" perl -i -pe \
|
||||||
|
's|^CHATBOT_API_BASE_URL=.*|CHATBOT_API_BASE_URL=$ENV{PROD_WAS_API}|' "${dir}/env.example" 2>/dev/null || true
|
||||||
|
perl -i -ne 'print unless /^EXDEV_LOCAL=/' "${dir}/env.example" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
if [[ -f "${dir}/scripts/agent/chatbot_tool_client.py" ]]; then
|
||||||
|
# 운영 기본값(_PROD_WAS_API / legacy getenv default)만 복원.
|
||||||
|
PROD_WAS_API="${PROD_WAS_API}" perl -i -pe '
|
||||||
|
s|_PROD_WAS_API = "http://[^"]+"|_PROD_WAS_API = "$ENV{PROD_WAS_API}"|g;
|
||||||
|
s|os\.getenv\("TOOL_API_BASE_URL", "http://[^"]+"\)|os.getenv("TOOL_API_BASE_URL", "$ENV{PROD_WAS_API}")|g;
|
||||||
|
s|os\.getenv\("CHATBOT_API_BASE_URL", "http://[^"]+"\)|os.getenv("CHATBOT_API_BASE_URL", "$ENV{PROD_WAS_API}")|g;
|
||||||
|
' "${dir}/scripts/agent/chatbot_tool_client.py"
|
||||||
|
fi
|
||||||
|
# monorepo overlay compose 는 push 대상에서 제외 (로컬 exdev 전용)
|
||||||
|
git -C "${dir}" checkout HEAD -- docker-compose.server.yml docker-compose.local.yml 2>/dev/null || true
|
||||||
|
# .env 는 gitignore — 스테이징 실수 방지
|
||||||
|
git -C "${dir}" reset HEAD -- .env .env.local 2>/dev/null || true
|
||||||
|
rm -f "${dir}/.env.local" 2>/dev/null || true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# 복원 후에도 개발서버 전용 호스트가 커밋 대상 설정 파일에 남으면 push 중단
|
||||||
|
assert_no_exdev_endpoints_for_push() {
|
||||||
|
local path="$1"
|
||||||
|
local dir="${ROOT_DIR}/${path}"
|
||||||
|
local hits=""
|
||||||
|
|
||||||
|
case "${path}" in
|
||||||
|
chatbotApi-chatbot2.0-agent)
|
||||||
|
hits="$(grep -nE 'mongodb://(127\.0\.0\.1|localhost)|host\.docker\.internal|jdbc:oracle:thin:@(127\.0\.0\.1|localhost)' \
|
||||||
|
"${dir}/src/main/resources/application.yml" 2>/dev/null || true)"
|
||||||
|
# troad 블록이 로컬 계정(OPR_MAIN)으로 바뀌었는지도 차단
|
||||||
|
if awk '
|
||||||
|
/^[[:space:]]*troad:[[:space:]]*$/ { in_troad=1; next }
|
||||||
|
in_troad && /^[[:space:]]*[a-zA-Z0-9_-]+:[[:space:]]*$/ && $0 !~ /^[[:space:]]*troad:/ { in_troad=0 }
|
||||||
|
in_troad && /username:[[:space:]]*OPR_MAIN/ { found=1 }
|
||||||
|
END { exit found ? 0 : 1 }
|
||||||
|
' "${dir}/src/main/resources/application.yml" 2>/dev/null; then
|
||||||
|
hits+=$'\n'"troad.username=OPR_MAIN (exdev local Oracle — must not commit)"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
kakaoChatbotSkill-chatbot2.0-agent)
|
||||||
|
hits="$(grep -nE '127\.0\.0\.1:(8086|28012)|host\.docker\.internal:(8086|28012)' \
|
||||||
|
"${dir}/src/main/resources/application.yml" 2>/dev/null || true)"
|
||||||
|
;;
|
||||||
|
exAiChatBot-chatbot2.0-agent)
|
||||||
|
hits="$(grep -nE '^(CHATBOT_API_BASE_URL|TOOL_API_BASE_URL)=.*(127\.0\.0\.1|host\.docker\.internal)|EXDEV_LOCAL=' \
|
||||||
|
"${dir}/env.template" "${dir}/env.example" 2>/dev/null || true)"
|
||||||
|
hits+="$(grep -nE 'getenv\(\"TOOL_API_BASE_URL\", \"http://(127\.0\.0\.1|host\.docker\.internal)' \
|
||||||
|
"${dir}/scripts/agent/chatbot_tool_client.py" 2>/dev/null || true)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -n "${hits}" ]]; then
|
||||||
|
warn "${path}: 개발서버(exdev) 주소가 남아 push 중단"
|
||||||
|
echo "${hits}" | sed 's/^/ /'
|
||||||
|
warn "start-all-server.sh 런타임 ENV 로만 exdev 주소를 쓰고, 소스 기본값은 운영 IP 를 유지하세요"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
submodule_is_cloned() {
|
submodule_is_cloned() {
|
||||||
local path="$1"
|
local path="$1"
|
||||||
[[ -e "${ROOT_DIR}/${path}/.git" ]]
|
[[ -e "${ROOT_DIR}/${path}/.git" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch_one() {
|
repo_is_dirty() {
|
||||||
local path="$1"
|
! git diff --quiet || ! git diff --cached --quiet || [[ -n "$(git ls-files --others --exclude-standard)" ]]
|
||||||
local url branch old new dirty
|
}
|
||||||
|
|
||||||
url="$(git config -f .gitmodules "submodule.${path}.url")"
|
ensure_branch() {
|
||||||
branch="$(git config -f .gitmodules "submodule.${path}.branch" || echo main)"
|
local branch="$1"
|
||||||
branch="${branch:-main}"
|
local git_dir
|
||||||
|
# submodule 은 .git 이 파일일 수 있음 → rev-parse 사용
|
||||||
|
git_dir="$(git rev-parse --git-dir 2>/dev/null || echo .git)"
|
||||||
|
if [[ -d "${git_dir}/rebase-merge" || -d "${git_dir}/rebase-apply" ]]; then
|
||||||
|
warn "rebase 진행 중 — 수동 해결 후 재실행 (git rebase --continue / --abort)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ -f "${git_dir}/MERGE_HEAD" ]]; then
|
||||||
|
warn "merge 진행 중 — 수동 해결 후 재실행"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local cur
|
||||||
|
cur="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo DETACHED)"
|
||||||
|
if [[ "${cur}" == "${branch}" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if git show-ref --verify --quiet "refs/heads/${branch}"; then
|
||||||
|
git checkout "${branch}"
|
||||||
|
elif git show-ref --verify --quiet "refs/remotes/origin/${branch}"; then
|
||||||
|
git checkout -B "${branch}" "origin/${branch}"
|
||||||
|
else
|
||||||
|
git checkout -B "${branch}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_one() {
|
||||||
|
local path="$1"
|
||||||
|
local url branch old new stashed=0 ahead
|
||||||
|
|
||||||
|
url="$(git config -f .gitmodules "submodule.${path}.url" 2>/dev/null || true)"
|
||||||
|
if [[ -z "${url}" ]]; then
|
||||||
|
warn "${path} — .gitmodules 에 없음, 건너뜀"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 사용자 요구: main 금지, chatbot2.0-agent 고정
|
||||||
|
branch="$(git config -f .gitmodules "submodule.${path}.branch" || echo "${TARGET_BRANCH}")"
|
||||||
|
branch="${branch:-${TARGET_BRANCH}}"
|
||||||
|
if [[ "${branch}" != "${TARGET_BRANCH}" ]]; then
|
||||||
|
warn "${path} — .gitmodules branch=${branch} → ${TARGET_BRANCH} 로 강제"
|
||||||
|
branch="${TARGET_BRANCH}"
|
||||||
|
fi
|
||||||
|
|
||||||
log ">>> ${path}"
|
log ">>> ${path}"
|
||||||
log " url=${url} branch=${branch}"
|
log " url=${url} branch=${branch}"
|
||||||
@@ -135,52 +312,152 @@ fetch_one() {
|
|||||||
|
|
||||||
(
|
(
|
||||||
cd "${ROOT_DIR}/${path}"
|
cd "${ROOT_DIR}/${path}"
|
||||||
|
unset GIT_DIR GIT_WORK_TREE
|
||||||
if ! git diff --quiet || ! git diff --cached --quiet; then
|
|
||||||
dirty=yes
|
|
||||||
warn "${path} — 로컬 변경 있음 (fetch는 진행, fast-forward 실패 가능)"
|
|
||||||
else
|
|
||||||
dirty=no
|
|
||||||
fi
|
|
||||||
|
|
||||||
old="$(git rev-parse HEAD 2>/dev/null || echo none)"
|
old="$(git rev-parse HEAD 2>/dev/null || echo none)"
|
||||||
|
|
||||||
if $DRY_RUN; then
|
if $DRY_RUN; then
|
||||||
|
ensure_branch "${branch}" || true
|
||||||
git fetch origin "${branch}" 2>/dev/null || git fetch origin
|
git fetch origin "${branch}" 2>/dev/null || git fetch origin
|
||||||
new="$(git rev-parse "origin/${branch}" 2>/dev/null || echo unknown)"
|
new="$(git rev-parse "origin/${branch}" 2>/dev/null || echo unknown)"
|
||||||
if [[ "${old}" == "${new}" ]]; then
|
if [[ "${old}" == "${new}" ]]; then
|
||||||
log " [dry-run] 이미 최신: ${old:0:7}"
|
log " [dry-run] 원격 최신: ${old:0:7}"
|
||||||
else
|
else
|
||||||
log " [dry-run] ${old:0:7} → ${new:0:7}"
|
log " [dry-run] 원격 변경 ${old:0:7} → ${new:0:7}"
|
||||||
git log --oneline "${old}..origin/${branch}" 2>/dev/null | sed 's/^/ /' || true
|
git log --oneline "HEAD..origin/${branch}" 2>/dev/null | sed 's/^/ /' || true
|
||||||
|
fi
|
||||||
|
if repo_is_dirty; then
|
||||||
|
log " [dry-run] 로컬 미커밋 변경 있음 → commit/push 대상"
|
||||||
|
git status -sb | sed 's/^/ /'
|
||||||
|
else
|
||||||
|
log " [dry-run] 로컬 미커밋 변경 없음"
|
||||||
fi
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 1) 원격 fetch + 브랜치 고정
|
||||||
git fetch origin "${branch}"
|
git fetch origin "${branch}"
|
||||||
git checkout "${branch}" 2>/dev/null || git checkout -B "${branch}" "origin/${branch}"
|
ensure_branch "${branch}" || exit 1
|
||||||
|
git branch --set-upstream-to="origin/${branch}" "${branch}" 2>/dev/null || true
|
||||||
|
|
||||||
if git merge-base --is-ancestor HEAD "origin/${branch}" 2>/dev/null \
|
# 2) 로컬 미커밋 변경이 pull 을 막으면 stash
|
||||||
&& [[ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/${branch}")" ]]; then
|
if repo_is_dirty; then
|
||||||
|
log " 로컬 변경 stash 후 원격 반영..."
|
||||||
|
git stash push -u -m "git_fetch_all auto-stash $(date '+%Y-%m-%d %H:%M:%S')" || true
|
||||||
|
stashed=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3) GitHub 변경사항 merge (ff → rebase → merge)
|
||||||
|
if [[ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/${branch}")" ]]; then
|
||||||
|
log " 원격 변경 merge: origin/${branch}"
|
||||||
|
if git merge-base --is-ancestor HEAD "origin/${branch}" 2>/dev/null; then
|
||||||
git merge --ff-only "origin/${branch}"
|
git merge --ff-only "origin/${branch}"
|
||||||
elif [[ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/${branch}")" ]]; then
|
else
|
||||||
warn "${path} — fast-forward 불가 (로컬 커밋/변경 존재). 수동 merge 필요"
|
if ! git pull --rebase origin "${branch}"; then
|
||||||
|
warn "${path} — rebase 실패, merge 로 재시도"
|
||||||
|
git rebase --abort 2>/dev/null || true
|
||||||
|
if ! git pull --no-rebase origin "${branch}"; then
|
||||||
|
warn "${path} — merge 충돌. 수동 해결 필요"
|
||||||
|
git status -sb | sed 's/^/ /'
|
||||||
|
if [[ "${stashed}" -eq 1 ]]; then
|
||||||
|
git stash pop || true
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
ok "${path} 원격 반영 $(git log -1 --oneline)"
|
||||||
|
else
|
||||||
|
log " 원격과 동일 (fetch 완료)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4) stash 복원
|
||||||
|
if [[ "${stashed}" -eq 1 ]]; then
|
||||||
|
log " stash 복원..."
|
||||||
|
if ! git stash pop; then
|
||||||
|
warn "${path} — stash pop 충돌. 수동 해결 후 commit/push"
|
||||||
git status -sb | sed 's/^/ /'
|
git status -sb | sed 's/^/ /'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5) 로컬 수정사항 commit (exdev 주소는 복원 후·검증 통과 시에만)
|
||||||
|
if $DO_COMMIT && repo_is_dirty; then
|
||||||
|
log " 로컬 변경 commit..."
|
||||||
|
# push 전에 운영 WAS/RAG/Mongo 기본 주소 복원 (exdev 주소는 start-all-server.sh ENV 전용)
|
||||||
|
restore_production_endpoints_before_commit "${path}"
|
||||||
|
if ! assert_no_exdev_endpoints_for_push "${path}"; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
log " 운영 엔드포인트 기본값 유지: WAS ${PROD_WAS_API} / Mongo ${PROD_WAS_HOST}"
|
||||||
|
git add -A
|
||||||
|
# .env 등 ignore 대상이 스테이징되지 않도록 한 번 더 정리
|
||||||
|
git reset HEAD -- .env .env.local 2>/dev/null || true
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
log " staged 변경 없음 (ignore 된 파일만 있을 수 있음)"
|
||||||
|
else
|
||||||
|
# staged diff 에 exdev 호스트가 남아 있으면 push 금지
|
||||||
|
if git diff --cached -U0 | grep -E '^\+' | grep -qE '127\.0\.0\.1:(27017|8086|28012)|host\.docker\.internal|EXDEV_LOCAL=true'; then
|
||||||
|
warn "${path}: staged diff 에 개발서버 주소가 포함됨 — commit 중단"
|
||||||
|
git diff --cached --stat | sed 's/^/ /'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
git commit -m "$(cat <<EOF
|
||||||
|
sync: monorepo local updates ($(date '+%Y-%m-%d %H:%M'))
|
||||||
|
|
||||||
|
git_fetch_all.sh 로 chatbot2.0-agent 동기화 후 로컬 수정을 반영한다.
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
ok "${path} commit $(git log -1 --oneline)"
|
||||||
|
fi
|
||||||
|
elif ! $DO_COMMIT && repo_is_dirty; then
|
||||||
|
log " [--no-commit] 미커밋 변경 유지 (운영 주소 복원 미적용)"
|
||||||
|
git status -sb | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6) push (chatbot2.0-agent 만) — push 직전 운영 주소 재검증
|
||||||
|
if $DO_PUSH; then
|
||||||
|
restore_production_endpoints_before_commit "${path}"
|
||||||
|
if ! assert_no_exdev_endpoints_for_push "${path}"; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# 복원으로 생긴 미커밋이 있으면 반영
|
||||||
|
if $DO_COMMIT && repo_is_dirty; then
|
||||||
|
git add -A
|
||||||
|
git reset HEAD -- .env .env.local 2>/dev/null || true
|
||||||
|
if ! git diff --cached --quiet; then
|
||||||
|
git commit -m "$(cat <<EOF
|
||||||
|
chore: restore production endpoints before push
|
||||||
|
|
||||||
|
git_fetch_all.sh — exdev 런타임 주소를 커밋에서 제거한다.
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
ahead="$(git rev-list --count "origin/${branch}..HEAD" 2>/dev/null || echo 0)"
|
||||||
|
if [[ "${ahead}" != "0" ]]; then
|
||||||
|
log " push origin ${branch} (ahead ${ahead})..."
|
||||||
|
if git push origin "${branch}"; then
|
||||||
|
ok "${path} push 완료"
|
||||||
|
else
|
||||||
|
warn "${path} — push 실패 (대용량 파일/권한 등). 로그 확인"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log " push 생략 (원격과 동일)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log " [--no-push] push 생략"
|
||||||
|
fi
|
||||||
|
|
||||||
new="$(git rev-parse HEAD)"
|
new="$(git rev-parse HEAD)"
|
||||||
if [[ "${old}" == "${new}" ]]; then
|
log " HEAD ${old:0:7} → ${new:0:7} $(git log -1 --oneline)"
|
||||||
log " ✅ 최신 유지 $(git log -1 --oneline)"
|
|
||||||
else
|
|
||||||
log " ✅ 갱신 ${old:0:7} → ${new:0:7} $(git log -1 --oneline)"
|
|
||||||
fi
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
failures=0
|
failures=0
|
||||||
for path in "${SUBMODULE_PATHS[@]}"; do
|
for path in "${TARGET_PATHS[@]}"; do
|
||||||
if ! fetch_one "${path}"; then
|
if ! sync_one "${path}"; then
|
||||||
failures=$((failures + 1))
|
failures=$((failures + 1))
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
@@ -192,7 +469,12 @@ fi
|
|||||||
|
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
log "submodule 상태:"
|
log "submodule 상태:"
|
||||||
git submodule status || true
|
git submodule status 2>/dev/null || true
|
||||||
|
for path in "${TARGET_PATHS[@]}"; do
|
||||||
|
if submodule_is_cloned "${path}"; then
|
||||||
|
printf " %-36s %s\n" "${path}" "$(git -C "${ROOT_DIR}/${path}" log -1 --oneline 2>/dev/null || echo '?')"
|
||||||
|
fi
|
||||||
|
done
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
|
|
||||||
if [[ ${failures} -gt 0 ]]; then
|
if [[ ${failures} -gt 0 ]]; then
|
||||||
@@ -200,5 +482,11 @@ if [[ ${failures} -gt 0 ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "완료 — GitHub → 로컬 반영 (push 없음)"
|
if $DRY_RUN; then
|
||||||
log "monorepo 커밋 갱신: git add .gitmodules *-chatbot2.0-agent && git status"
|
log "완료 — dry-run (변경 없음)"
|
||||||
|
elif $DO_PUSH; then
|
||||||
|
log "완료 — ${TARGET_BRANCH}: fetch/merge → commit → push"
|
||||||
|
else
|
||||||
|
log "완료 — ${TARGET_BRANCH}: fetch/merge$($DO_COMMIT && echo ' → commit' || true) (push 생략)"
|
||||||
|
fi
|
||||||
|
log "monorepo 포인터 갱신: git add *-chatbot2.0-agent chatbotApp-test && git status"
|
||||||
|
|||||||
Submodule kakaoChatbotSkill-chatbot2.0-agent updated: 630501b221...9a489a68bd
Binary file not shown.
Regular → Executable
Regular → Executable
Executable
+132
@@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Minimal rsync stand-in for Windows Git Bash (tar-over-ssh).
|
||||||
|
# Supports the flags used by server-dev/sync-submodules-rsync.sh:
|
||||||
|
# rsync -az [--delete] [--exclude PATTERN ...] SRC/ HOST:DEST/
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DELETE=false
|
||||||
|
EXCLUDES=()
|
||||||
|
ARGS=()
|
||||||
|
|
||||||
|
while (($#)); do
|
||||||
|
case "$1" in
|
||||||
|
-az|-a|-z|-v|-q|-P|--progress) shift ;;
|
||||||
|
--delete) DELETE=true; shift ;;
|
||||||
|
--exclude)
|
||||||
|
EXCLUDES+=("$2"); shift 2 ;;
|
||||||
|
--exclude=*)
|
||||||
|
EXCLUDES+=("${1#--exclude=}"); shift ;;
|
||||||
|
-*)
|
||||||
|
# ignore unknown short/long flags used by callers
|
||||||
|
shift ;;
|
||||||
|
*)
|
||||||
|
ARGS+=("$1"); shift ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if ((${#ARGS[@]} < 2)); then
|
||||||
|
echo "rsync-shim: need SRC and DEST" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SRC="${ARGS[0]}"
|
||||||
|
DEST="${ARGS[1]}"
|
||||||
|
|
||||||
|
# Git Bash /d/foo → Windows D:/foo (OpenSSH scp 용)
|
||||||
|
to_win_path() {
|
||||||
|
local p="$1"
|
||||||
|
if [[ "${p}" =~ ^/([a-zA-Z])/(.*)$ ]]; then
|
||||||
|
local drive rest
|
||||||
|
drive="$(echo "${BASH_REMATCH[1]}" | tr 'a-z' 'A-Z')"
|
||||||
|
rest="${BASH_REMATCH[2]}"
|
||||||
|
echo "${drive}:/${rest}"
|
||||||
|
else
|
||||||
|
echo "${p}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_file_remote() {
|
||||||
|
local src_file="$1"
|
||||||
|
local dest="$2"
|
||||||
|
local win_src
|
||||||
|
win_src="$(to_win_path "${src_file}")"
|
||||||
|
if [[ -f "${win_src}" || -f "${src_file}" ]]; then
|
||||||
|
local local_src="${src_file}"
|
||||||
|
[[ -f "${win_src}" ]] && local_src="${win_src}"
|
||||||
|
scp -o BatchMode=yes -q "${local_src}" "${dest}" && return 0
|
||||||
|
fi
|
||||||
|
# fallback: tar stream single file
|
||||||
|
local base dir
|
||||||
|
base="$(basename "${src_file}")"
|
||||||
|
dir="$(cd "$(dirname "${src_file}")" && pwd)"
|
||||||
|
local host="${dest%%:*}"
|
||||||
|
local remote="${dest#*:}"
|
||||||
|
local remote_dir remote_base
|
||||||
|
if [[ "${remote}" == */ ]]; then
|
||||||
|
remote_dir="${remote%/}"
|
||||||
|
remote_base="${base}"
|
||||||
|
else
|
||||||
|
remote_dir="$(dirname "${remote}")"
|
||||||
|
remote_base="$(basename "${remote}")"
|
||||||
|
fi
|
||||||
|
ssh -o BatchMode=yes "${host}" "mkdir -p '${remote_dir}'"
|
||||||
|
tar -C "${dir}" -cf - "${base}" \
|
||||||
|
| ssh -o BatchMode=yes "${host}" "tar -C '${remote_dir}' -xf - && if [[ '${remote_base}' != '${base}' ]]; then mv '${remote_dir}/${base}' '${remote_dir}/${remote_base}'; fi"
|
||||||
|
}
|
||||||
|
|
||||||
|
# file → file copy (overlay yml etc.)
|
||||||
|
if [[ -f "${SRC}" && "${DEST}" == *:* ]]; then
|
||||||
|
copy_file_remote "${SRC}" "${DEST}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# normalize trailing slash semantics like rsync SRC/
|
||||||
|
SRC_DIR="${SRC%/}"
|
||||||
|
if [[ ! -d "${SRC_DIR}" ]]; then
|
||||||
|
# allow copying a single file into a remote dir
|
||||||
|
if [[ -f "${SRC_DIR}" ]]; then
|
||||||
|
copy_file_remote "${SRC_DIR}" "${DEST}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "rsync-shim: source not found: ${SRC}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${DEST}" != *:* ]]; then
|
||||||
|
echo "rsync-shim: only remote DEST (host:path) supported" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
HOST="${DEST%%:*}"
|
||||||
|
REMOTE_PATH="${DEST#*:}"
|
||||||
|
REMOTE_PATH="${REMOTE_PATH%/}"
|
||||||
|
|
||||||
|
TAR_EXCLUDES=()
|
||||||
|
for pat in "${EXCLUDES[@]}"; do
|
||||||
|
# tar 의 --exclude 는 'node_modules/' 처럼 슬래시로 끝나면 디렉터리에 매칭되지 않는다.
|
||||||
|
# (rsync 문법 그대로 넘기면 node_modules 가 통째로 전송돼 메모리 부족으로 죽는다)
|
||||||
|
pat="${pat%/}"
|
||||||
|
if [[ "${pat}" == /* ]]; then
|
||||||
|
# rsync 의 선행 슬래시 = 전송 루트 기준 고정. tar 멤버명은 './' 로 시작한다.
|
||||||
|
TAR_EXCLUDES+=(--anchored --exclude ".${pat}")
|
||||||
|
else
|
||||||
|
TAR_EXCLUDES+=(--no-anchored --exclude "${pat}")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
ssh -o BatchMode=yes "${HOST}" "mkdir -p '${REMOTE_PATH}'"
|
||||||
|
|
||||||
|
if $DELETE; then
|
||||||
|
# wipe remote dir contents then unpack (approx --delete)
|
||||||
|
# 서버 public-* 등이 root/docker 소유일 수 있어 실패해도 이어서 덮어쓴다
|
||||||
|
ssh -o BatchMode=yes "${HOST}" \
|
||||||
|
"chmod -R u+w '${REMOTE_PATH}' 2>/dev/null || true; \
|
||||||
|
find '${REMOTE_PATH}' -mindepth 1 -maxdepth 1 -exec rm -rf {} + 2>/dev/null || true" \
|
||||||
|
|| true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
tar -C "${SRC_DIR}" "${TAR_EXCLUDES[@]}" -cf - . \
|
||||||
|
| ssh -o BatchMode=yes "${HOST}" "tar -C '${REMOTE_PATH}' -xf -"
|
||||||
|
|
||||||
|
echo "rsync-shim: synced ${SRC_DIR}/ -> ${HOST}:${REMOTE_PATH}/"
|
||||||
Regular → Executable
Regular → Executable
+4
-1
@@ -35,12 +35,15 @@ MONGO_USER=
|
|||||||
MONGO_PASSWORD=
|
MONGO_PASSWORD=
|
||||||
MONGO_DATABASE=chat_history
|
MONGO_DATABASE=chat_history
|
||||||
MONGO_COLLECTION=rag_conversations
|
MONGO_COLLECTION=rag_conversations
|
||||||
|
MONGO_FEEDBACK_DATABASE=chatbot
|
||||||
|
MONGO_FEEDBACK_COLLECTION=answer_feedback
|
||||||
|
MONGO_IMPROVEMENT_COLLECTION=improvement_suggestions
|
||||||
|
|
||||||
VECTOR_STORE=qdrant
|
VECTOR_STORE=qdrant
|
||||||
QDRANT_HOST=stock.exdev.co.kr
|
QDRANT_HOST=stock.exdev.co.kr
|
||||||
QDRANT_PORT=6333
|
QDRANT_PORT=6333
|
||||||
# stock.exdev.co.kr 운영 컬렉션 (8488 vectors, 2026-07)
|
# stock.exdev.co.kr 운영 컬렉션 (8488 vectors, 2026-07)
|
||||||
QDRANT_COLLECTION=qa_vectors
|
QDRANT_COLLECTION=qa_vectors_v2
|
||||||
|
|
||||||
# chatbotApi (WAS) — stock MongoDB chatbot DB
|
# chatbotApi (WAS) — stock MongoDB chatbot DB
|
||||||
MONGODB_URI=mongodb://exDev:ehfhrhdtk!!@stock.exdev.co.kr:27017/chatbot?authSource=chatbot&heartbeatFrequencyMS=30000&minPoolSize=3&maxIdleTimeMS=1800000
|
MONGODB_URI=mongodb://exDev:ehfhrhdtk!!@stock.exdev.co.kr:27017/chatbot?authSource=chatbot&heartbeatFrequencyMS=30000&minPoolSize=3&maxIdleTimeMS=1800000
|
||||||
|
|||||||
Executable
+29
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Windows (Git Bash) helper for ./start-all-server.sh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
export PATH="${ROOT_DIR}/local-dev/bin:/c/Program Files/nodejs:/c/Program Files/Git/usr/bin:${PATH}"
|
||||||
|
export GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-ssh -o BatchMode=yes -o ConnectTimeout=20}"
|
||||||
|
# Git Bash/MSYS 가 /chatbot/app 같은 env 를 Windows 경로로 바꾸지 않게
|
||||||
|
export MSYS_NO_PATHCONV=1
|
||||||
|
export MSYS2_ARG_CONV_EXCL='*'
|
||||||
|
|
||||||
|
# Prefer Windows OpenSSH (has the exdev key)
|
||||||
|
if [[ -x /c/Windows/System32/OpenSSH/ssh.exe ]]; then
|
||||||
|
export GIT_SSH_COMMAND="/c/Windows/System32/OpenSSH/ssh.exe -o BatchMode=yes -o ConnectTimeout=20"
|
||||||
|
export PATH="/c/Windows/System32/OpenSSH:${PATH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "${ROOT_DIR}"
|
||||||
|
echo "[windows] node=$(command -v node) $(node -v 2>/dev/null || true)"
|
||||||
|
echo "[windows] npm=$(command -v npm)"
|
||||||
|
echo "[windows] rsync=$(command -v rsync)"
|
||||||
|
echo "[windows] ssh=$(command -v ssh)"
|
||||||
|
|
||||||
|
# smoke checks
|
||||||
|
ssh -o BatchMode=yes -o ConnectTimeout=15 aidev@chatbot.exdev.co.kr 'echo SSH_CHATBOT_OK'
|
||||||
|
git ls-remote origin HEAD >/dev/null
|
||||||
|
echo "[windows] Gitea git OK"
|
||||||
|
|
||||||
|
exec bash ./start-all-server.sh "$@"
|
||||||
+43
-8
@@ -1,11 +1,13 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# 로컬 전체 스택 기동 (exdev AI SSH 터널 + 원격 Mongo/Qdrant + RAG + WAS + Skill + chatbotApp)
|
# 로컬 전체 스택 기동 (exdev AI SSH 터널 + 원격 Mongo/Qdrant + RAG + WAS + Skill + chatbotApp + Desktop)
|
||||||
# Mongo/Qdrant 는 stock.exdev.co.kr 를 사용 (로컬 컨테이너 미기동)
|
# Mongo/Qdrant 는 stock.exdev.co.kr 를 사용 (로컬 컨테이너 미기동)
|
||||||
#
|
#
|
||||||
# ./local-dev/start-all.sh
|
# ./local-dev/start-all.sh
|
||||||
|
# ./start-all.sh # 루트 래퍼
|
||||||
# ./local-dev/start-all.sh --no-tunnel
|
# ./local-dev/start-all.sh --no-tunnel
|
||||||
# ./local-dev/start-all.sh --skip-java
|
# ./local-dev/start-all.sh --skip-java
|
||||||
# ./local-dev/start-all.sh --no-build
|
# ./local-dev/start-all.sh --no-build # RAG/웹/데스크톱 빌드 생략
|
||||||
|
# ./local-dev/start-all.sh --skip-desktop # Electron 재빌드만 생략
|
||||||
#
|
#
|
||||||
# 종료: ./local-dev/stop-all.sh
|
# 종료: ./local-dev/stop-all.sh
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -19,6 +21,7 @@ RAG_DIR="${ROOT_DIR}/exAiChatBot-chatbot2.0-agent"
|
|||||||
API_DIR="${ROOT_DIR}/chatbotApi-chatbot2.0-agent"
|
API_DIR="${ROOT_DIR}/chatbotApi-chatbot2.0-agent"
|
||||||
SKILL_DIR="${ROOT_DIR}/kakaoChatbotSkill-chatbot2.0-agent"
|
SKILL_DIR="${ROOT_DIR}/kakaoChatbotSkill-chatbot2.0-agent"
|
||||||
APP_DIR="${ROOT_DIR}/chatbotApp-chatbot2.0-agent"
|
APP_DIR="${ROOT_DIR}/chatbotApp-chatbot2.0-agent"
|
||||||
|
DESKTOP_DIR="${ROOT_DIR}/chatbotDesktopApp-chatbot2.0"
|
||||||
|
|
||||||
ENV_TEMPLATE="${LOCAL_DEV_DIR}/env.exdev-ai.template"
|
ENV_TEMPLATE="${LOCAL_DEV_DIR}/env.exdev-ai.template"
|
||||||
RAG_ENV="${RAG_DIR}/.env"
|
RAG_ENV="${RAG_DIR}/.env"
|
||||||
@@ -42,17 +45,19 @@ QDRANT_PORT="${QDRANT_PORT:-6333}"
|
|||||||
SKIP_TUNNEL=false
|
SKIP_TUNNEL=false
|
||||||
SKIP_JAVA=false
|
SKIP_JAVA=false
|
||||||
NO_BUILD=false
|
NO_BUILD=false
|
||||||
|
SKIP_DESKTOP=false
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--no-tunnel) SKIP_TUNNEL=true ;;
|
--no-tunnel) SKIP_TUNNEL=true ;;
|
||||||
--skip-java) SKIP_JAVA=true ;;
|
--skip-java) SKIP_JAVA=true ;;
|
||||||
--no-build) NO_BUILD=true ;;
|
--no-build) NO_BUILD=true ;;
|
||||||
|
--skip-desktop) SKIP_DESKTOP=true ;;
|
||||||
--sync-qdrant)
|
--sync-qdrant)
|
||||||
echo "경고: 원격 Qdrant 사용 중이라 --sync-qdrant 는 무시됩니다."
|
echo "경고: 원격 Qdrant 사용 중이라 --sync-qdrant 는 무시됩니다."
|
||||||
;;
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
sed -n '2,12p' "$0"
|
sed -n '2,14p' "$0"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -159,6 +164,7 @@ ensure_rag_env() {
|
|||||||
patch_env "TEI_RERANK_URL" "http://host.docker.internal:${RERANK_PORT}"
|
patch_env "TEI_RERANK_URL" "http://host.docker.internal:${RERANK_PORT}"
|
||||||
patch_env "EMBED_API_STYLE" "tei"
|
patch_env "EMBED_API_STYLE" "tei"
|
||||||
patch_env "RERANK_API_STYLE" "legacy"
|
patch_env "RERANK_API_STYLE" "legacy"
|
||||||
|
patch_env "EXDEV_LOCAL" "true"
|
||||||
patch_env "CHATBOT_API_BASE_URL" "http://host.docker.internal:${WAS_PORT}/api"
|
patch_env "CHATBOT_API_BASE_URL" "http://host.docker.internal:${WAS_PORT}/api"
|
||||||
patch_env "INTERNAL_TOOL_API_KEY" "${INTERNAL_TOOL_API_KEY}"
|
patch_env "INTERNAL_TOOL_API_KEY" "${INTERNAL_TOOL_API_KEY}"
|
||||||
|
|
||||||
@@ -171,7 +177,7 @@ ensure_rag_env() {
|
|||||||
patch_env "MONGO_DATABASE" "chat_history"
|
patch_env "MONGO_DATABASE" "chat_history"
|
||||||
patch_env "QDRANT_HOST" "${EXDEV_DATA_HOST}"
|
patch_env "QDRANT_HOST" "${EXDEV_DATA_HOST}"
|
||||||
patch_env "QDRANT_PORT" "${QDRANT_PORT}"
|
patch_env "QDRANT_PORT" "${QDRANT_PORT}"
|
||||||
patch_env "QDRANT_COLLECTION" "qa_vectors"
|
patch_env "QDRANT_COLLECTION" "qa_vectors_v2"
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_remote_data() {
|
ensure_remote_data() {
|
||||||
@@ -288,7 +294,7 @@ verify_stack() {
|
|||||||
curl -sf "http://127.0.0.1:${RAG_PORT}/health" | grep -q '"status"' || { log "❌ RAG health"; ok=false; }
|
curl -sf "http://127.0.0.1:${RAG_PORT}/health" | grep -q '"status"' || { log "❌ RAG health"; ok=false; }
|
||||||
wait_port "${WAS_PORT}" "chatbotApi" 5 || ok=false
|
wait_port "${WAS_PORT}" "chatbotApi" 5 || ok=false
|
||||||
wait_port "${SKILL_PORT}" "kakaoChatbotSkill" 5 || ok=false
|
wait_port "${SKILL_PORT}" "kakaoChatbotSkill" 5 || ok=false
|
||||||
curl -sf "http://127.0.0.1:${APP_PORT}/chatbot/app/" | grep -q 'data-chatbot-app' || { log "❌ chatbotApp UI"; ok=false; }
|
curl -sf "http://127.0.0.1:${APP_PORT}/chatbot/ai/" | grep -q 'data-chatbot-app' || { log "❌ chatbotApp UI"; ok=false; }
|
||||||
|
|
||||||
if $ok; then
|
if $ok; then
|
||||||
log "✅ 전체 스택 정상"
|
log "✅ 전체 스택 정상"
|
||||||
@@ -298,6 +304,32 @@ verify_stack() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build_chatbot_app() {
|
||||||
|
if $NO_BUILD && [[ -f "${APP_DIR}/public-ai/index.html" ]]; then
|
||||||
|
log "chatbotApp 빌드 생략 (--no-build)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log "chatbotApp Next.js 빌드 (수정사항 반영)..."
|
||||||
|
(
|
||||||
|
cd "${APP_DIR}/web"
|
||||||
|
npm ci --prefer-offline 2>/dev/null || npm install
|
||||||
|
)
|
||||||
|
# 로컬에는 운영 업무 DB가 없으므로 미납/환불 조회만 2초·1건 목업으로 빌드한다.
|
||||||
|
NEXT_PUBLIC_FARE_QUERY_MOCK=true bash "${APP_DIR}/build.sh"
|
||||||
|
[[ -f "${APP_DIR}/public-ai/index.html" ]] || fail "chatbotApp public-ai/ 빌드 실패"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_desktop_app() {
|
||||||
|
if $NO_BUILD || $SKIP_DESKTOP; then
|
||||||
|
log "데스크톱 앱 빌드 생략 (--no-build/--skip-desktop)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
[[ -d "${DESKTOP_DIR}" ]] || fail "데스크톱 앱 디렉터리 없음: ${DESKTOP_DIR}"
|
||||||
|
chmod +x "${DESKTOP_DIR}/build-and-publish.sh"
|
||||||
|
# 로컬은 Mac 위주 — Windows 크로스빌드는 시간이 길어 SKIP_WIN 기본 1 (서버 배포는 Win 포함)
|
||||||
|
SKIP_WIN="${SKIP_WIN:-1}" bash "${DESKTOP_DIR}/build-and-publish.sh"
|
||||||
|
}
|
||||||
|
|
||||||
# ── main ──
|
# ── main ──
|
||||||
mkdir -p "${RUN_DIR}" "${LOG_DIR}"
|
mkdir -p "${RUN_DIR}" "${LOG_DIR}"
|
||||||
|
|
||||||
@@ -332,12 +364,15 @@ if ! $SKIP_JAVA; then
|
|||||||
"RAG_AGENT_CHAT_URL=http://127.0.0.1:${RAG_PORT}/agent/chat" \
|
"RAG_AGENT_CHAT_URL=http://127.0.0.1:${RAG_PORT}/agent/chat" \
|
||||||
"CHATBOT_API_BASE_URL=http://127.0.0.1:${WAS_PORT}/api/" \
|
"CHATBOT_API_BASE_URL=http://127.0.0.1:${WAS_PORT}/api/" \
|
||||||
"INTERNAL_TOOL_API_KEY=${INTERNAL_TOOL_API_KEY}" \
|
"INTERNAL_TOOL_API_KEY=${INTERNAL_TOOL_API_KEY}" \
|
||||||
"CHATBOT_APP_URL=http://localhost:${APP_PORT}/chatbot/app/"
|
"CHATBOT_APP_URL=http://localhost:${APP_PORT}/chatbot/ai/"
|
||||||
|
|
||||||
wait_port "${WAS_PORT}" "chatbotApi" 240 || true
|
wait_port "${WAS_PORT}" "chatbotApi" 240 || true
|
||||||
wait_port "${SKILL_PORT}" "kakaoChatbotSkill" 240 || true
|
wait_port "${SKILL_PORT}" "kakaoChatbotSkill" 240 || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
build_chatbot_app
|
||||||
|
build_desktop_app
|
||||||
|
|
||||||
log "chatbotApp 기동..."
|
log "chatbotApp 기동..."
|
||||||
docker rm -f ex-chatbot-app-web 2>/dev/null || true
|
docker rm -f ex-chatbot-app-web 2>/dev/null || true
|
||||||
(
|
(
|
||||||
@@ -347,11 +382,11 @@ docker rm -f ex-chatbot-app-web 2>/dev/null || true
|
|||||||
docker compose up -d --force-recreate
|
docker compose up -d --force-recreate
|
||||||
)
|
)
|
||||||
|
|
||||||
wait_http "http://127.0.0.1:${APP_PORT}/chatbot/app/" "chatbotApp UI" 30 || true
|
wait_http "http://127.0.0.1:${APP_PORT}/chatbot/ai/" "chatbotApp UI" 30 || true
|
||||||
|
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
log "기동 완료"
|
log "기동 완료"
|
||||||
log " UI http://127.0.0.1:${APP_PORT}/chatbot/app/"
|
log " UI http://127.0.0.1:${APP_PORT}/chatbot/ai/"
|
||||||
log " RAG http://127.0.0.1:${RAG_PORT}/health"
|
log " RAG http://127.0.0.1:${RAG_PORT}/health"
|
||||||
log " Admin http://127.0.0.1:${ADMIN_PORT}/"
|
log " Admin http://127.0.0.1:${ADMIN_PORT}/"
|
||||||
log " Mongo ${EXDEV_DATA_HOST}:${MONGO_PORT} (원격, RAG+WAS)"
|
log " Mongo ${EXDEV_DATA_HOST}:${MONGO_PORT} (원격, RAG+WAS)"
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,526 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""간편조회 파라미터 분기(폼/부분선택/상세/위치/별칭) 구어체 테스트 → test.csv
|
||||||
|
|
||||||
|
운영 예:
|
||||||
|
PYTHONUNBUFFERED=1 python3 scripts/quick_inquiry_branch_test.py \\
|
||||||
|
--base https://chatbot.ex.co.kr/chatbot --insecure \\
|
||||||
|
--out test.csv --sleep-ask 2.0 --sleep-domain 1.2
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import ssl
|
||||||
|
import time
|
||||||
|
import urllib.error
|
||||||
|
import urllib.request
|
||||||
|
from collections import Counter
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
_SSL_CTX = ssl.create_default_context()
|
||||||
|
|
||||||
|
FIELDNAMES = [
|
||||||
|
"tested_at",
|
||||||
|
"feature",
|
||||||
|
"param_tier", # none | partial | full | alias | location
|
||||||
|
"expected_mode", # form | detail | clarify | list | location
|
||||||
|
"expected_intent",
|
||||||
|
"mode", # ask | domain-query
|
||||||
|
"question",
|
||||||
|
"params",
|
||||||
|
"http_status",
|
||||||
|
"elapsed_sec",
|
||||||
|
"actual_intent",
|
||||||
|
"actual_mode",
|
||||||
|
"api_status",
|
||||||
|
"route_type",
|
||||||
|
"form_flags",
|
||||||
|
"answer",
|
||||||
|
"result",
|
||||||
|
"reason",
|
||||||
|
"note",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def one_line(text: str, limit: int = 260) -> str:
|
||||||
|
t = re.sub(r"\s+", " ", (text or "").strip())
|
||||||
|
return (t[: limit - 1] + "…") if len(t) > limit else t
|
||||||
|
|
||||||
|
|
||||||
|
def post_json(url: str, body: Dict[str, Any], timeout: float) -> Tuple[Optional[int], Any, float]:
|
||||||
|
t0 = time.time()
|
||||||
|
data = json.dumps(body, ensure_ascii=False).encode("utf-8")
|
||||||
|
req = urllib.request.Request(
|
||||||
|
url, data=data, headers={"Content-Type": "application/json; charset=utf-8"}
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=timeout, context=_SSL_CTX) as resp:
|
||||||
|
raw = resp.read().decode("utf-8", errors="replace")
|
||||||
|
try:
|
||||||
|
return resp.status, json.loads(raw), time.time() - t0
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return resp.status, raw, time.time() - t0
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
try:
|
||||||
|
payload = e.read().decode("utf-8", errors="replace")
|
||||||
|
try:
|
||||||
|
return e.code, json.loads(payload), time.time() - t0
|
||||||
|
except Exception:
|
||||||
|
return e.code, payload, time.time() - t0
|
||||||
|
except Exception:
|
||||||
|
return e.code, str(e), time.time() - t0
|
||||||
|
except Exception as e:
|
||||||
|
return None, str(e), time.time() - t0
|
||||||
|
|
||||||
|
|
||||||
|
def extract_answer(body: Any) -> str:
|
||||||
|
if not isinstance(body, dict):
|
||||||
|
return one_line(str(body))
|
||||||
|
for key in ("answer", "message", "text", "statusMsg", "llmSummary"):
|
||||||
|
val = body.get(key)
|
||||||
|
if isinstance(val, str) and val.strip():
|
||||||
|
return one_line(val)
|
||||||
|
dd = body.get("domainData")
|
||||||
|
if isinstance(dd, dict):
|
||||||
|
for key in ("llmSummary", "statusMsg", "answer"):
|
||||||
|
val = dd.get(key)
|
||||||
|
if isinstance(val, str) and val.strip():
|
||||||
|
return one_line(val)
|
||||||
|
return one_line(json.dumps(body, ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
|
def form_flags(body: Any) -> str:
|
||||||
|
flags = []
|
||||||
|
if not isinstance(body, dict):
|
||||||
|
return ""
|
||||||
|
dd = body.get("domainData") if isinstance(body.get("domainData"), dict) else {}
|
||||||
|
raw = body.get("rawData") if isinstance(body.get("rawData"), dict) else {}
|
||||||
|
raw_dd = raw.get("domainData") if isinstance(raw.get("domainData"), dict) else {}
|
||||||
|
for src in (body, dd, raw, raw_dd):
|
||||||
|
for k, v in src.items():
|
||||||
|
if str(k).startswith("needs") and v:
|
||||||
|
flags.append(f"{k}={v}")
|
||||||
|
if src.get("needsClarification"):
|
||||||
|
flags.append("needsClarification=True")
|
||||||
|
if src.get("listMode"):
|
||||||
|
flags.append(f"listMode={src.get('listMode')}")
|
||||||
|
# dedupe
|
||||||
|
seen = set()
|
||||||
|
out = []
|
||||||
|
for f in flags:
|
||||||
|
if f not in seen:
|
||||||
|
seen.add(f)
|
||||||
|
out.append(f)
|
||||||
|
return ";".join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def detect_mode(body: Any, answer: str) -> str:
|
||||||
|
"""응답을 form/detail/clarify/list/location 으로 분류."""
|
||||||
|
if not isinstance(body, dict):
|
||||||
|
return "unknown"
|
||||||
|
flags = form_flags(body)
|
||||||
|
route = str(body.get("routeType") or "")
|
||||||
|
dd = body.get("domainData") if isinstance(body.get("domainData"), dict) else {}
|
||||||
|
ans = answer or ""
|
||||||
|
|
||||||
|
# 구체 데이터(전화·요금 등)가 있으면 form 플래그보다 detail 우선
|
||||||
|
if re.search(r"0\d{1,2}-\d{3,4}-\d{4}", ans) or "연락처입니다" in ans:
|
||||||
|
return "detail"
|
||||||
|
if route == "clarify" or "needsClarification=True" in flags:
|
||||||
|
return "clarify"
|
||||||
|
if "위치정보" in ans or ("동의" in ans and "위치" in ans):
|
||||||
|
return "location"
|
||||||
|
if any(p in ans for p in ("선택하면", "선택해 주세요", "알려주세요", "어느 노선", "어느 방향", "차량번호가 필요")):
|
||||||
|
if any(x in flags for x in ("needsRestAreaForm=True", "needsIcTelForm=True")):
|
||||||
|
return "form"
|
||||||
|
return "clarify"
|
||||||
|
if any(x in flags for x in ("needsRestAreaForm=True", "needsIcTelForm=True")):
|
||||||
|
return "form"
|
||||||
|
lst = dd.get("list") or dd.get("items")
|
||||||
|
if isinstance(lst, list) and len(lst) > 0:
|
||||||
|
return "list"
|
||||||
|
if any(
|
||||||
|
k in ans
|
||||||
|
for k in ("전화", "원", "km/h", "메뉴", "유가", "충전", "구조", "공사", "정체", "서행", "주소")
|
||||||
|
):
|
||||||
|
return "detail"
|
||||||
|
if body.get("status") is True and len(ans) > 15:
|
||||||
|
return "detail"
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
def scenarios() -> List[Dict[str, Any]]:
|
||||||
|
"""기능 × 파라미터 단계 × 구어체/별칭/위치."""
|
||||||
|
rows: List[Dict[str, Any]] = []
|
||||||
|
|
||||||
|
def ask(
|
||||||
|
feature: str,
|
||||||
|
tier: str,
|
||||||
|
expected_mode: str,
|
||||||
|
intent: str,
|
||||||
|
question: str,
|
||||||
|
note: str = "",
|
||||||
|
) -> None:
|
||||||
|
rows.append(
|
||||||
|
{
|
||||||
|
"mode": "ask",
|
||||||
|
"feature": feature,
|
||||||
|
"param_tier": tier,
|
||||||
|
"expected_mode": expected_mode,
|
||||||
|
"expected_intent": intent,
|
||||||
|
"question": question,
|
||||||
|
"params": {},
|
||||||
|
"note": note,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def domain(
|
||||||
|
feature: str,
|
||||||
|
tier: str,
|
||||||
|
expected_mode: str,
|
||||||
|
intent: str,
|
||||||
|
question: str,
|
||||||
|
params: Dict[str, str],
|
||||||
|
note: str = "",
|
||||||
|
) -> None:
|
||||||
|
rows.append(
|
||||||
|
{
|
||||||
|
"mode": "domain-query",
|
||||||
|
"feature": feature,
|
||||||
|
"param_tier": tier,
|
||||||
|
"expected_mode": expected_mode,
|
||||||
|
"expected_intent": intent,
|
||||||
|
"question": question,
|
||||||
|
"params": params,
|
||||||
|
"note": note,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---- 정체/혼잡 ----
|
||||||
|
ask("노선혼잡", "none", "clarify", "TROAD_CONGESTION", "고속도로 정체구간 알려줘")
|
||||||
|
ask("노선혼잡", "none", "clarify", "TROAD_CONGESTION", "지금 어디가 막혀?")
|
||||||
|
ask("노선혼잡", "partial", "detail", "TROAD_CONGESTION", "경부선에 정체구간 있어?")
|
||||||
|
ask("노선혼잡", "partial", "detail", "TROAD_CONGESTION", "영동선 지금 막혀?")
|
||||||
|
ask("노선혼잡", "alias", "detail", "TROAD_CONGESTION", "경부고속도로 정체 어때?")
|
||||||
|
ask(
|
||||||
|
"노선혼잡",
|
||||||
|
"location",
|
||||||
|
"location",
|
||||||
|
"TROAD_CONGESTION",
|
||||||
|
"이 근처에 정체되는 구간 있어?",
|
||||||
|
"GPS 동의/근처 영업소 파생 가능",
|
||||||
|
)
|
||||||
|
domain(
|
||||||
|
"노선혼잡",
|
||||||
|
"full",
|
||||||
|
"detail",
|
||||||
|
"TROAD_CONGESTION",
|
||||||
|
"경부선 정체 상세",
|
||||||
|
{"routeName": "경부선"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---- 영업소 정보 ----
|
||||||
|
ask("영업소정보", "none", "form", "IC_TEL", "영업소 전화번호 좀 알려줘")
|
||||||
|
ask("영업소정보", "full", "detail", "IC_TEL", "판교 톨게이트 전화번호 좀")
|
||||||
|
ask("영업소정보", "alias", "detail", "IC_TEL", "동김천 톨게이트 번호 뭐야?")
|
||||||
|
ask("영업소정보", "alias", "detail", "IC_TEL", "동김천ic 연락처 알려줘")
|
||||||
|
ask("영업소정보", "alias", "detail", "IC_TEL", "동감천 톨게이트 전화 있어?") # 오표기
|
||||||
|
ask("영업소정보", "alias", "detail", "IC_TEL", "판교영업소 대표번호")
|
||||||
|
ask(
|
||||||
|
"영업소정보",
|
||||||
|
"location",
|
||||||
|
"location",
|
||||||
|
"IC_TEL",
|
||||||
|
"여기 근처 영업소 전화번호 알려줘",
|
||||||
|
"위치기반 폼/상세",
|
||||||
|
)
|
||||||
|
domain("영업소정보", "none", "form", "IC_TEL", "영업소 조회 폼", {})
|
||||||
|
domain("영업소정보", "full", "detail", "IC_TEL", "동김천 상세", {"icName": "동김천"})
|
||||||
|
|
||||||
|
# ---- 통행요금 ----
|
||||||
|
ask("구간통행요금", "none", "clarify", "FARE_SEARCH", "톨비 얼마야?")
|
||||||
|
ask("구간통행요금", "partial", "clarify", "FARE_SEARCH", "서울에서 출발하면 요금 얼마야?")
|
||||||
|
ask("구간통행요금", "full", "detail", "FARE_SEARCH", "서울에서 부산까지 톨비 얼마 나와?")
|
||||||
|
ask("구간통행요금", "alias", "detail", "FARE_SEARCH", "판교IC에서 신갈 톨게이트까지 요금 어때?")
|
||||||
|
ask("구간통행요금", "alias", "detail", "FARE_SEARCH", "판교 영업소에서 수원까지 하이패스 얼마야?")
|
||||||
|
|
||||||
|
# ---- 통행시간 ----
|
||||||
|
ask("구간통행시간", "none", "clarify", "TROAD_TRAVEL_TIME", "지금 고속도로 얼마나 걸려?")
|
||||||
|
ask("구간통행시간", "full", "detail", "TROAD_TRAVEL_TIME", "서울에서 부산까지 지금 가면 얼마나 걸려?")
|
||||||
|
ask("구간통행시간", "alias", "detail", "TROAD_TRAVEL_TIME", "판교에서 신갈 지금 막혀? 몇 분 걸려?")
|
||||||
|
|
||||||
|
# ---- 교통속보 ----
|
||||||
|
ask("노선별교통속보", "none", "clarify", "TROAD_BREAKING_NEWS", "고속도로에 사고 났다는데 어디야?")
|
||||||
|
ask("노선별교통속보", "partial", "detail", "TROAD_BREAKING_NEWS", "경부선에 사고 났어?")
|
||||||
|
ask("노선별교통속보", "alias", "detail", "TROAD_BREAKING_NEWS", "영동고속도로 교통속보 있어?")
|
||||||
|
|
||||||
|
# ---- 차단계획 ----
|
||||||
|
ask("차단계획", "none", "clarify", "CONSTRUCTION_PLAN", "고속도로 공사하는 데 있어?")
|
||||||
|
ask("차단계획", "partial", "detail", "CONSTRUCTION_PLAN", "경부선 오늘 공사해서 막히는 데 있어?")
|
||||||
|
ask("차단계획", "alias", "detail", "CONSTRUCTION_PLAN", "경부고속도로 차로 막는 일정 있나?")
|
||||||
|
domain(
|
||||||
|
"차단계획",
|
||||||
|
"partial",
|
||||||
|
"detail",
|
||||||
|
"CONSTRUCTION_PLAN",
|
||||||
|
"영동선 차단계획",
|
||||||
|
{"routeName": "영동선"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---- 긴급구조 ----
|
||||||
|
ask("긴급구조기관", "none", "form", "EMERGENCY_HELP_ORG", "고속도로에서 사고 나면 어디로 연락해?")
|
||||||
|
ask("긴급구조기관", "partial", "form", "EMERGENCY_HELP_ORG", "경부선 긴급구조기관 알려줘")
|
||||||
|
ask("긴급구조기관", "alias", "form", "EMERGENCY_HELP_ORG", "경부고속도로 긴급구조대 어디야?")
|
||||||
|
domain("긴급구조기관", "none", "form", "EMERGENCY_HELP_ORG", "긴급구조 폼", {})
|
||||||
|
domain(
|
||||||
|
"긴급구조기관",
|
||||||
|
"partial",
|
||||||
|
"form",
|
||||||
|
"EMERGENCY_HELP_ORG",
|
||||||
|
"경부선 선택 폼",
|
||||||
|
{"routeName": "경부선"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---- 휴게소 음식/브랜드/시설 ----
|
||||||
|
ask("휴게소음식", "none", "clarify", "REST_AREA_FOOD_LIST", "휴게소에서 뭐 먹지?")
|
||||||
|
ask("휴게소음식", "full", "detail", "REST_AREA_FOOD_LIST", "죽전휴게소에서 뭐 먹을 거 있어?")
|
||||||
|
ask("휴게소음식", "alias", "detail", "REST_AREA_FOOD_LIST", "죽전 휴게소 밥 뭐 파나?")
|
||||||
|
|
||||||
|
ask("휴게소브랜드매장", "none", "clarify", "BRAND_SHOP", "휴게소에 카페 있어?")
|
||||||
|
ask("휴게소브랜드매장", "full", "detail", "BRAND_SHOP", "김천휴게소에 브랜드 매장 뭐 있어?")
|
||||||
|
ask("휴게소브랜드매장", "alias", "detail", "BRAND_SHOP", "안성 휴게소에 편의점 있나?")
|
||||||
|
|
||||||
|
ask("휴게소시설", "none", "clarify", "REST_AREA_FACILITY", "휴게소에 수유실 있어?")
|
||||||
|
ask("휴게소시설", "full", "detail", "REST_AREA_FACILITY", "죽전휴게소에 수유실 있나?")
|
||||||
|
ask("휴게소시설", "alias", "detail", "REST_AREA_FACILITY", "안성SA 샤워실 쓸 수 있어?")
|
||||||
|
|
||||||
|
# ---- 주유 ----
|
||||||
|
ask("휴게소주유", "none", "form", "GASSTATION", "고속도로 기름값 얼마야?")
|
||||||
|
ask("휴게소주유", "full", "detail", "GASSTATION", "죽전휴게소 기름값 얼마야?")
|
||||||
|
ask("휴게소주유", "partial", "detail", "GASSTATION", "경부선에서 기름 제일 싼 데 어디야?")
|
||||||
|
ask("휴게소주유", "alias", "detail", "GASSTATION", "안성 휴게소 휘발유값 어때?")
|
||||||
|
domain("휴게소주유", "none", "form", "GASSTATION", "주유 폼", {})
|
||||||
|
|
||||||
|
# ---- 충전 ----
|
||||||
|
ask("휴게소충전소", "none", "form", "REST_AREA_CHARGING", "고속도로에 전기차 충전소 있어?")
|
||||||
|
ask("휴게소충전소", "full", "detail", "REST_AREA_CHARGING", "죽전에서 전기차 충전돼?")
|
||||||
|
ask("휴게소충전소", "partial", "form", "REST_AREA_CHARGING", "경부선에 충전되는 휴게소 어디 있어?")
|
||||||
|
ask("휴게소충전소", "alias", "detail", "REST_AREA_CHARGING", "강릉휴게소충전소 있어?")
|
||||||
|
ask("휴게소충전소", "alias", "detail", "REST_AREA_CHARGING", "김천 휴게소에서 수소차 충전해?")
|
||||||
|
domain("휴게소충전소", "none", "form", "REST_AREA_CHARGING", "충전 폼", {})
|
||||||
|
domain(
|
||||||
|
"휴게소충전소",
|
||||||
|
"partial",
|
||||||
|
"form",
|
||||||
|
"REST_AREA_CHARGING",
|
||||||
|
"경부선 충전 폼",
|
||||||
|
{"routeName": "경부선"},
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---- 청년창업 ----
|
||||||
|
ask("휴게소청년창업매장", "none", "form", "REST_AREA_YOUTH_SHOP", "고속도로에 청년창업 매장 있어?")
|
||||||
|
ask("휴게소청년창업매장", "full", "detail", "REST_AREA_YOUTH_SHOP", "죽전휴게소에 청년들 장사하는 가게 있어?")
|
||||||
|
ask(
|
||||||
|
"휴게소청년창업매장",
|
||||||
|
"alias",
|
||||||
|
"detail",
|
||||||
|
"REST_AREA_YOUTH_SHOP",
|
||||||
|
"안성 휴게소 청년몰 있나?",
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---- 가까운 휴게소 ----
|
||||||
|
ask("가까운휴게소", "partial", "detail", "REST_AREA_NEAREST", "판교 근처 휴게소 어디 있어?")
|
||||||
|
ask(
|
||||||
|
"가까운휴게소",
|
||||||
|
"location",
|
||||||
|
"location",
|
||||||
|
"REST_AREA_NEAREST",
|
||||||
|
"여기 제일 가까운 휴게소 어디야?",
|
||||||
|
"GPS 경로",
|
||||||
|
)
|
||||||
|
ask("가까운휴게소", "alias", "detail", "REST_AREA_NEAREST", "기흥IC 근처에 쉴 데 있어?")
|
||||||
|
|
||||||
|
# ---- 미납/환불 (파라미터=차량번호) ----
|
||||||
|
ask("미납조회", "none", "clarify", "FARE_UNPAID", "미납요금 조회해줘")
|
||||||
|
ask("미납조회", "full", "detail", "FARE_UNPAID", "야 내 차 12가3456인데 미납 있어?")
|
||||||
|
ask("환불조회", "none", "clarify", "FARE_REFUND", "톨비 환불받을 거 있어?")
|
||||||
|
ask("환불조회", "full", "detail", "FARE_REFUND", "하이패스 환불금 들어왔나? 서울33하1122")
|
||||||
|
|
||||||
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
def mode_match(expected: str, actual: str) -> bool:
|
||||||
|
if expected == actual:
|
||||||
|
return True
|
||||||
|
# form↔clarify 는 둘 다 '추가 선택 유도'로 허용
|
||||||
|
if {expected, actual} <= {"form", "clarify"}:
|
||||||
|
return True
|
||||||
|
# location 질문은 form/clarify/detail 도 허용(클라이언트 GPS 없을 때)
|
||||||
|
if expected == "location" and actual in {"location", "form", "clarify", "detail"}:
|
||||||
|
return True
|
||||||
|
# list 는 detail 상위 개념으로 허용
|
||||||
|
if expected == "detail" and actual in {"detail", "list"}:
|
||||||
|
return True
|
||||||
|
if expected == "list" and actual in {"list", "form", "detail"}:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def intent_ok(expected: str, actual: str) -> bool:
|
||||||
|
if not actual:
|
||||||
|
return False
|
||||||
|
if actual == expected:
|
||||||
|
return True
|
||||||
|
aliases = {
|
||||||
|
"TROAD_BREAKING_NEWS": {"TROAD_BREAKING_NEWS", "TRAFFIC_NEWS"},
|
||||||
|
"TROAD_CONGESTION": {"TROAD_CONGESTION"},
|
||||||
|
"BRAND_SHOP": {"BRAND_SHOP", "REST_AREA_FACILITY"}, # 편의점 질문은 시설로도 갈 수 있음
|
||||||
|
}
|
||||||
|
return actual in aliases.get(expected, {expected})
|
||||||
|
|
||||||
|
|
||||||
|
def judge(
|
||||||
|
expected_intent: str,
|
||||||
|
actual_intent: str,
|
||||||
|
expected_mode: str,
|
||||||
|
actual_mode: str,
|
||||||
|
http_st: Optional[int],
|
||||||
|
answer: str,
|
||||||
|
) -> Tuple[str, str]:
|
||||||
|
if http_st != 200:
|
||||||
|
return "FAIL", f"HTTP {http_st}"
|
||||||
|
natural = len(answer or "") >= 6
|
||||||
|
i_ok = intent_ok(expected_intent, actual_intent)
|
||||||
|
m_ok = mode_match(expected_mode, actual_mode)
|
||||||
|
if i_ok and m_ok and natural:
|
||||||
|
return "PASS", "의도·응답모드 적합"
|
||||||
|
if i_ok and natural:
|
||||||
|
return "PARTIAL", f"모드상이 expected={expected_mode} actual={actual_mode}"
|
||||||
|
if m_ok and natural:
|
||||||
|
return "PARTIAL", f"의도상이 expected={expected_intent} actual={actual_intent or '-'}"
|
||||||
|
if natural:
|
||||||
|
return "PARTIAL", "응답만 존재"
|
||||||
|
return "FAIL", "응답 불량"
|
||||||
|
|
||||||
|
|
||||||
|
def append_row(path: str, row: Dict[str, str], write_header: bool) -> None:
|
||||||
|
with open(path, "a", newline="", encoding="utf-8-sig") as f:
|
||||||
|
w = csv.DictWriter(f, fieldnames=FIELDNAMES)
|
||||||
|
if write_header:
|
||||||
|
w.writeheader()
|
||||||
|
w.writerow(row)
|
||||||
|
f.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
global _SSL_CTX
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--base", default="https://chatbot.ex.co.kr/chatbot")
|
||||||
|
ap.add_argument("--out", default="test.csv")
|
||||||
|
ap.add_argument("--timeout-ask", type=float, default=90.0)
|
||||||
|
ap.add_argument("--timeout-domain", type=float, default=45.0)
|
||||||
|
ap.add_argument("--sleep-ask", type=float, default=2.0)
|
||||||
|
ap.add_argument("--sleep-domain", type=float, default=1.2)
|
||||||
|
ap.add_argument("--insecure", action="store_true")
|
||||||
|
ap.add_argument("--limit", type=int, default=0)
|
||||||
|
ap.add_argument("--skip-domain", action="store_true")
|
||||||
|
ap.add_argument("--skip-ask", action="store_true")
|
||||||
|
args = ap.parse_args()
|
||||||
|
if args.insecure:
|
||||||
|
_SSL_CTX = ssl._create_unverified_context()
|
||||||
|
|
||||||
|
base = args.base.rstrip("/")
|
||||||
|
ask_url = base + "/ask"
|
||||||
|
domain_url = base + "/domain-query"
|
||||||
|
started = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
open(args.out, "w", encoding="utf-8-sig").close()
|
||||||
|
header = True
|
||||||
|
results: List[str] = []
|
||||||
|
|
||||||
|
suite = scenarios()
|
||||||
|
if args.skip_ask:
|
||||||
|
suite = [c for c in suite if c["mode"] != "ask"]
|
||||||
|
if args.skip_domain:
|
||||||
|
suite = [c for c in suite if c["mode"] != "domain-query"]
|
||||||
|
if args.limit > 0:
|
||||||
|
suite = suite[: args.limit]
|
||||||
|
|
||||||
|
total = len(suite)
|
||||||
|
for i, case in enumerate(suite, 1):
|
||||||
|
print(f"({i}/{total}) {case['mode']} {case['feature']} [{case['param_tier']}] {case['question'][:40]}", flush=True)
|
||||||
|
if case["mode"] == "ask":
|
||||||
|
http_st, body, elapsed = post_json(
|
||||||
|
ask_url,
|
||||||
|
{"query": case["question"], "botId": f"branch-ask-{i}"},
|
||||||
|
args.timeout_ask,
|
||||||
|
)
|
||||||
|
sleep = args.sleep_ask
|
||||||
|
else:
|
||||||
|
http_st, body, elapsed = post_json(
|
||||||
|
domain_url,
|
||||||
|
{
|
||||||
|
"intentType": case["expected_intent"],
|
||||||
|
"params": case["params"],
|
||||||
|
"botId": f"branch-dom-{i}",
|
||||||
|
},
|
||||||
|
args.timeout_domain,
|
||||||
|
)
|
||||||
|
sleep = args.sleep_domain
|
||||||
|
|
||||||
|
answer = extract_answer(body)
|
||||||
|
actual_intent = ""
|
||||||
|
api_status = ""
|
||||||
|
route_type = ""
|
||||||
|
if isinstance(body, dict):
|
||||||
|
actual_intent = str(body.get("intentType") or "")
|
||||||
|
api_status = str(body.get("status"))
|
||||||
|
route_type = str(body.get("routeType") or "")
|
||||||
|
if case["mode"] == "domain-query" and not actual_intent:
|
||||||
|
actual_intent = case["expected_intent"]
|
||||||
|
actual_mode = detect_mode(body, answer)
|
||||||
|
result, reason = judge(
|
||||||
|
case["expected_intent"],
|
||||||
|
actual_intent,
|
||||||
|
case["expected_mode"],
|
||||||
|
actual_mode,
|
||||||
|
http_st,
|
||||||
|
answer,
|
||||||
|
)
|
||||||
|
row = {
|
||||||
|
"tested_at": started,
|
||||||
|
"feature": case["feature"],
|
||||||
|
"param_tier": case["param_tier"],
|
||||||
|
"expected_mode": case["expected_mode"],
|
||||||
|
"expected_intent": case["expected_intent"],
|
||||||
|
"mode": case["mode"],
|
||||||
|
"question": case["question"],
|
||||||
|
"params": json.dumps(case.get("params") or {}, ensure_ascii=False),
|
||||||
|
"http_status": str(http_st or ""),
|
||||||
|
"elapsed_sec": f"{elapsed:.2f}",
|
||||||
|
"actual_intent": actual_intent,
|
||||||
|
"actual_mode": actual_mode,
|
||||||
|
"api_status": api_status,
|
||||||
|
"route_type": route_type,
|
||||||
|
"form_flags": form_flags(body),
|
||||||
|
"answer": answer,
|
||||||
|
"result": result,
|
||||||
|
"reason": reason,
|
||||||
|
"note": case.get("note") or "",
|
||||||
|
}
|
||||||
|
append_row(args.out, row, header)
|
||||||
|
header = False
|
||||||
|
results.append(result)
|
||||||
|
print(f" → {result:7} intent={actual_intent or '-':22} mode={actual_mode:8} | {answer[:70]}", flush=True)
|
||||||
|
time.sleep(sleep)
|
||||||
|
|
||||||
|
print("---", flush=True)
|
||||||
|
print(f"saved={args.out} total={len(results)} {dict(Counter(results))}", flush=True)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,626 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""간편조회 기능 다양 질문 테스트 → test.csv
|
||||||
|
|
||||||
|
- domain-query: 간편조회 UI와 동일 경로 (다수 케이스, 빠름)
|
||||||
|
- /ask: 실제 고객 자연어 질문 (기능당 소수)
|
||||||
|
|
||||||
|
사용:
|
||||||
|
PYTHONUNBUFFERED=1 python3 scripts/quick_inquiry_nlu_test.py \\
|
||||||
|
--base http://127.0.0.1:8083/web --out test.csv
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import ssl
|
||||||
|
import time
|
||||||
|
import urllib.error
|
||||||
|
import urllib.request
|
||||||
|
from collections import Counter
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
# 운영 HTTPS 등에서 로컬 CA 이슈 시 사용
|
||||||
|
_SSL_CTX = ssl.create_default_context()
|
||||||
|
|
||||||
|
|
||||||
|
def one_line(text: str, limit: int = 280) -> str:
|
||||||
|
t = re.sub(r"\s+", " ", (text or "").strip())
|
||||||
|
return (t[: limit - 1] + "…") if len(t) > limit else t
|
||||||
|
|
||||||
|
|
||||||
|
def post_json(url: str, body: Dict[str, Any], timeout: float) -> Tuple[Optional[int], Any, float]:
|
||||||
|
t0 = time.time()
|
||||||
|
data = json.dumps(body, ensure_ascii=False).encode("utf-8")
|
||||||
|
req = urllib.request.Request(
|
||||||
|
url, data=data, headers={"Content-Type": "application/json; charset=utf-8"}
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=timeout, context=_SSL_CTX) as resp:
|
||||||
|
raw = resp.read().decode("utf-8", errors="replace")
|
||||||
|
try:
|
||||||
|
return resp.status, json.loads(raw), time.time() - t0
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return resp.status, raw, time.time() - t0
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
try:
|
||||||
|
payload = e.read().decode("utf-8", errors="replace")
|
||||||
|
try:
|
||||||
|
return e.code, json.loads(payload), time.time() - t0
|
||||||
|
except Exception:
|
||||||
|
return e.code, payload, time.time() - t0
|
||||||
|
except Exception:
|
||||||
|
return e.code, str(e), time.time() - t0
|
||||||
|
except Exception as e:
|
||||||
|
return None, str(e), time.time() - t0
|
||||||
|
|
||||||
|
|
||||||
|
def get_json(url: str, timeout: float) -> Tuple[Optional[int], Any, float]:
|
||||||
|
t0 = time.time()
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(url, timeout=timeout, context=_SSL_CTX) as resp:
|
||||||
|
return resp.status, json.loads(resp.read().decode("utf-8", errors="replace")), time.time() - t0
|
||||||
|
except Exception as e:
|
||||||
|
return None, str(e), time.time() - t0
|
||||||
|
|
||||||
|
|
||||||
|
def domain_cases_prod_light() -> List[Dict[str, Any]]:
|
||||||
|
"""운영용 — 기능당 1~2건만 (부하 최소화)."""
|
||||||
|
light: List[Tuple[str, str, str, Dict[str, str]]] = [
|
||||||
|
("미납조회", "FARE_UNPAID", "야 내 차 12가3456인데 미납 있어?", {"carNo": "12가3456"}),
|
||||||
|
("환불조회", "FARE_REFUND", "잘못 낸 톨비 환불받을 수 있어? 12가3456", {"carNo": "12가3456"}),
|
||||||
|
("구간통행요금", "FARE_SEARCH", "서울에서 부산까지 톨비 얼마 나와?", {"fromIc": "서울", "toIc": "부산"}),
|
||||||
|
("구간통행요금", "FARE_SEARCH", "판교에서 신갈 가면 요금이 어떻게 돼?", {"fromIc": "판교", "toIc": "신갈"}),
|
||||||
|
("구간통행시간", "TROAD_TRAVEL_TIME", "서울에서 부산까지 지금 가면 얼마나 걸려?",
|
||||||
|
{"fromIc": "서울", "toIc": "부산", "carType": "1"}),
|
||||||
|
("구간통행시간", "TROAD_TRAVEL_TIME", "판교에서 신갈 지금 막혀? 몇 분 걸려?",
|
||||||
|
{"fromIc": "판교", "toIc": "신갈", "carType": "1"}),
|
||||||
|
("차단계획", "CONSTRUCTION_PLAN", "경부선 오늘 공사해서 막히는 데 있어?", {"routeName": "경부선"}),
|
||||||
|
("차단계획", "CONSTRUCTION_PLAN", "영동선 차로 막는 일정 있나?", {"routeName": "영동선"}),
|
||||||
|
("영업소정보", "IC_TEL", "판교 톨게이트 전화번호 좀", {"icName": "판교"}),
|
||||||
|
("영업소정보", "IC_TEL", "기흥 톨게이트 주소랑 전화 좀", {"icName": "기흥"}),
|
||||||
|
("긴급구조기관", "EMERGENCY_HELP_ORG", "경부선에서 사고 나면 어디로 연락해?",
|
||||||
|
{"listMode": "true", "routeName": "경부선"}),
|
||||||
|
("휴게소음식", "REST_AREA_FOOD_LIST", "죽전휴게소에서 뭐 먹을 거 있어?", {"restAreaName": "죽전"}),
|
||||||
|
("휴게소브랜드매장", "BRAND_SHOP", "죽전에 편의점이나 카페 있어?", {"restAreaName": "죽전"}),
|
||||||
|
("휴게소시설", "REST_AREA_FACILITY", "죽전휴게소에 수유실 있나?", {"restAreaName": "죽전"}),
|
||||||
|
("휴게소주유", "GASSTATION", "죽전휴게소 기름값 얼마야?", {"restAreaName": "죽전"}),
|
||||||
|
("휴게소주유", "GASSTATION", "경부선에서 기름 제일 싼 데 어디야?",
|
||||||
|
{"compareMode": "cheapest", "fuelType": "휘발유", "routeName": "경부선"}),
|
||||||
|
("휴게소충전소", "REST_AREA_CHARGING", "죽전에서 전기차 충전돼?",
|
||||||
|
{"restAreaName": "죽전", "chargingType": "all"}),
|
||||||
|
("휴게소충전소", "REST_AREA_CHARGING", "강릉휴게소에 충전소 있어?",
|
||||||
|
{"restAreaName": "강릉", "chargingType": "all"}),
|
||||||
|
("휴게소청년창업매장", "REST_AREA_YOUTH_SHOP", "죽전휴게소에 청년들 장사하는 가게 있어?",
|
||||||
|
{"restAreaName": "죽전"}),
|
||||||
|
("가까운휴게소", "REST_AREA_NEAREST", "판교 근처 휴게소 어디 있어?", {"icName": "판교"}),
|
||||||
|
("노선혼잡", "TROAD_CONGESTION", "경부선 지금 막히는 구간 있어?", {"routeName": "경부선"}),
|
||||||
|
]
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"mode": "domain-query",
|
||||||
|
"feature": f,
|
||||||
|
"expected_intent": intent,
|
||||||
|
"question": q,
|
||||||
|
"params": params,
|
||||||
|
"note": "운영 경량 domain-query",
|
||||||
|
}
|
||||||
|
for f, intent, q, params in light
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def extract_answer(body: Any) -> str:
|
||||||
|
if not isinstance(body, dict):
|
||||||
|
return one_line(str(body))
|
||||||
|
for key in ("answer", "message", "text", "statusMsg", "llmSummary", "formattedAnswer"):
|
||||||
|
val = body.get(key)
|
||||||
|
if isinstance(val, str) and val.strip():
|
||||||
|
return one_line(val)
|
||||||
|
for nest_key in ("domainData", "data", "rawData"):
|
||||||
|
nest = body.get(nest_key)
|
||||||
|
if isinstance(nest, dict):
|
||||||
|
for key in ("llmSummary", "statusMsg", "answer", "message"):
|
||||||
|
val = nest.get(key)
|
||||||
|
if isinstance(val, str) and val.strip():
|
||||||
|
return one_line(val)
|
||||||
|
# list summary
|
||||||
|
lst = nest.get("list") or nest.get("items")
|
||||||
|
if isinstance(lst, list) and lst:
|
||||||
|
return one_line(f"건수={len(lst)} 예시={json.dumps(lst[0], ensure_ascii=False)}")
|
||||||
|
if body.get("needsRestAreaForm") or body.get("needsIcTelForm"):
|
||||||
|
return one_line(str(body.get("statusMsg") or "폼 유도 응답"))
|
||||||
|
return one_line(json.dumps(body, ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
|
def intent_of(body: Any, fallback: str = "") -> str:
|
||||||
|
if not isinstance(body, dict):
|
||||||
|
return fallback
|
||||||
|
return str(body.get("intentType") or fallback)
|
||||||
|
|
||||||
|
|
||||||
|
def status_of(body: Any) -> str:
|
||||||
|
if not isinstance(body, dict):
|
||||||
|
return ""
|
||||||
|
if "status" in body:
|
||||||
|
return str(body.get("status"))
|
||||||
|
dd = body.get("domainData")
|
||||||
|
if isinstance(dd, dict) and "status" in dd:
|
||||||
|
return str(dd.get("status"))
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
INTENT_OK = {
|
||||||
|
"FARE_UNPAID": {"FARE_UNPAID"},
|
||||||
|
"FARE_REFUND": {"FARE_REFUND"},
|
||||||
|
"FARE_SEARCH": {"FARE_SEARCH"},
|
||||||
|
"TROAD_TRAVEL_TIME": {"TROAD_TRAVEL_TIME"},
|
||||||
|
"TROAD_BREAKING_NEWS": {"TROAD_BREAKING_NEWS", "TRAFFIC_NEWS"},
|
||||||
|
"TRAFFIC_NEWS": {"TRAFFIC_NEWS", "TROAD_BREAKING_NEWS"},
|
||||||
|
"CONSTRUCTION_PLAN": {"CONSTRUCTION_PLAN"},
|
||||||
|
"IC_TEL": {"IC_TEL"},
|
||||||
|
"EMERGENCY_HELP_ORG": {"EMERGENCY_HELP_ORG"},
|
||||||
|
"REST_AREA_FOOD_LIST": {"REST_AREA_FOOD_LIST"},
|
||||||
|
"BRAND_SHOP": {"BRAND_SHOP"},
|
||||||
|
"REST_AREA_FACILITY": {"REST_AREA_FACILITY"},
|
||||||
|
"GASSTATION": {"GASSTATION"},
|
||||||
|
"REST_AREA_CHARGING": {"REST_AREA_CHARGING"},
|
||||||
|
"REST_AREA_YOUTH_SHOP": {"REST_AREA_YOUTH_SHOP"},
|
||||||
|
"REST_AREA_NEAREST": {"REST_AREA_NEAREST"},
|
||||||
|
"TROAD_CONGESTION": {"TROAD_CONGESTION"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def judge(expected: str, actual: str, status: str, answer: str, http_st: Optional[int]) -> Tuple[str, str]:
|
||||||
|
if http_st != 200:
|
||||||
|
return "FAIL", f"HTTP {http_st}"
|
||||||
|
natural = len(answer or "") >= 6 and "Traceback" not in (answer or "")
|
||||||
|
intent_ok = (actual or "") in INTENT_OK.get(expected, {expected}) or actual == expected
|
||||||
|
st_true = status in ("True", "true", "1")
|
||||||
|
infra = any(
|
||||||
|
h in (answer or "")
|
||||||
|
for h in ("일시적인 장애", "Failed to obtain", "Listener refused", "연결")
|
||||||
|
)
|
||||||
|
if intent_ok and st_true and natural:
|
||||||
|
return "PASS", "의도·응답 정상"
|
||||||
|
if intent_ok and natural and infra:
|
||||||
|
return "PARTIAL", "의도 일치, 인프라/DB 제약 안내"
|
||||||
|
if intent_ok and natural:
|
||||||
|
return "PARTIAL", "의도 일치, 데이터없음/안내성 응답"
|
||||||
|
if natural and actual:
|
||||||
|
return "PARTIAL", f"의도상이 expected={expected} actual={actual}"
|
||||||
|
if natural:
|
||||||
|
return "PARTIAL", "응답만 존재"
|
||||||
|
return "FAIL", f"의도/응답 불량 expected={expected} actual={actual or '-'}"
|
||||||
|
|
||||||
|
|
||||||
|
# ---- case builders ----
|
||||||
|
|
||||||
|
def domain_cases() -> List[Dict[str, Any]]:
|
||||||
|
"""간편조회 domain-query — 질문은 구어체, 호출은 폼/직조회 params."""
|
||||||
|
rows: List[Dict[str, Any]] = []
|
||||||
|
|
||||||
|
def add(feature: str, intent: str, question: str, params: Dict[str, str], note: str = "") -> None:
|
||||||
|
rows.append(
|
||||||
|
{
|
||||||
|
"mode": "domain-query",
|
||||||
|
"feature": feature,
|
||||||
|
"expected_intent": intent,
|
||||||
|
"question": question,
|
||||||
|
"params": params,
|
||||||
|
"note": note,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 미납/환불
|
||||||
|
add("미납조회", "FARE_UNPAID", "야 내 차 12가3456인데 미납 있어?", {"carNo": "12가3456"}, "Oracle 미연결 시 PARTIAL 가능")
|
||||||
|
add("미납조회", "FARE_UNPAID", "하이패스 미납금 좀 봐줘 서울12가3456", {"carNo": "서울12가3456"}, "Oracle 미연결 시 PARTIAL 가능")
|
||||||
|
add("미납조회", "FARE_UNPAID", "톨비 밀린 거 있어요? 차량번호 123가4567요", {"carNo": "123가4567"}, "Oracle 미연결 시 PARTIAL 가능")
|
||||||
|
add("미납조회", "FARE_UNPAID", "98나1234 미납통행료 나와요?", {"carNo": "98나1234"}, "Oracle 미연결 시 PARTIAL 가능")
|
||||||
|
add("환불조회", "FARE_REFUND", "12가3456으로 환불받을 돈 있어요?", {"carNo": "12가3456"}, "Oracle 미연결 시 PARTIAL 가능")
|
||||||
|
add("환불조회", "FARE_REFUND", "잘못 낸 톨비 환불 내역 좀 확인해줘 서울12가3456", {"carNo": "서울12가3456"}, "Oracle 미연결 시 PARTIAL 가능")
|
||||||
|
add("환불조회", "FARE_REFUND", "과오납 환불금 나왔나? 123가4567", {"carNo": "123가4567"}, "Oracle 미연결 시 PARTIAL 가능")
|
||||||
|
add("환불조회", "FARE_REFUND", "하이패스 환불받을 거 있는지 봐줘 98나1234", {"carNo": "98나1234"}, "Oracle 미연결 시 PARTIAL 가능")
|
||||||
|
|
||||||
|
# 통행요금
|
||||||
|
fare_qs = [
|
||||||
|
("서울에서 부산까지 톨비 얼마 나와?", "서울", "부산"),
|
||||||
|
("판교에서 신갈 가면 요금이 어떻게 돼?", "판교", "신갈"),
|
||||||
|
("판교IC에서 신갈IC까지 하이패스 얼마야?", "판교IC", "신갈IC"),
|
||||||
|
("판교 영업소에서 수원까지 통행료 좀", "판교영업소", "수원"),
|
||||||
|
("대전에서 대구 가는 데 톨비 얼마쯤 해?", "대전", "대구"),
|
||||||
|
("천안에서 남이IC까지 요금 알려줄래?", "천안", "남이"),
|
||||||
|
("서울 톨게이트에서 기흥까지 얼마야?", "서울영업소", "기흥"),
|
||||||
|
("김포에서 인천 쪽 고속도로 요금 궁금해", "김포", "인천"),
|
||||||
|
]
|
||||||
|
for q, a, b in fare_qs:
|
||||||
|
add("구간통행요금", "FARE_SEARCH", q, {"fromIc": a, "toIc": b})
|
||||||
|
|
||||||
|
# 통행시간
|
||||||
|
time_qs = [
|
||||||
|
("서울에서 부산까지 지금 가면 얼마나 걸려?", "서울", "부산"),
|
||||||
|
("판교에서 신갈 지금 막혀? 몇 분 걸려?", "판교", "신갈"),
|
||||||
|
("대전에서 대구까지 지금 소요시간 어때?", "대전", "대구"),
|
||||||
|
("서울IC에서 부산IC 지금 가면 몇 시간이야?", "서울IC", "부산IC"),
|
||||||
|
("기흥에서 천안까지 지금 얼마나 걸릴까?", "기흥", "천안"),
|
||||||
|
]
|
||||||
|
for q, a, b in time_qs:
|
||||||
|
add("구간통행시간", "TROAD_TRAVEL_TIME", q, {"fromIc": a, "toIc": b, "carType": "1"})
|
||||||
|
|
||||||
|
# 차단계획
|
||||||
|
for q, route in [
|
||||||
|
("경부선 오늘 공사해서 막히는 데 있어?", "경부선"),
|
||||||
|
("영동선 차로 막는 일정 있나?", "영동선"),
|
||||||
|
("서해안선 공사구간 좀 알려줘", "서해안선"),
|
||||||
|
("호남선 이번 주 차단계획 있어?", "호남선"),
|
||||||
|
("경부고속도로 공사한다던데 어디야?", "경부고속도로"),
|
||||||
|
("중부내륙선 차로통제 있어?", "중부내륙선"),
|
||||||
|
]:
|
||||||
|
add("차단계획", "CONSTRUCTION_PLAN", q, {"routeName": route})
|
||||||
|
|
||||||
|
# 영업소
|
||||||
|
for q, ic in [
|
||||||
|
("판교 톨게이트 전화번호 좀", "판교"),
|
||||||
|
("판교IC 전화 어떻게 걸어?", "판교IC"),
|
||||||
|
("판교 영업소 연락처 알려줘", "판교영업소"),
|
||||||
|
("서울 영업소 번호 뭐야?", "서울"),
|
||||||
|
("기흥 톨게이트 주소랑 전화 좀", "기흥"),
|
||||||
|
("부산IC 영업소 정보 있어?", "부산IC"),
|
||||||
|
("신갈 영업소 전화 받나?", "신갈"),
|
||||||
|
("경부선 판교 쪽 영업소 번호 알려줘", "경부선판교"),
|
||||||
|
]:
|
||||||
|
add("영업소정보", "IC_TEL", q, {"icName": ic})
|
||||||
|
|
||||||
|
# 긴급구조
|
||||||
|
for q, route in [
|
||||||
|
("경부선에서 사고 나면 어디로 연락해?", "경부선"),
|
||||||
|
("영동선 긴급구조 가능한 데 어디야?", "영동선"),
|
||||||
|
("서해안선 긴급구조기관 좀 알려줘", "서해안선"),
|
||||||
|
]:
|
||||||
|
add("긴급구조기관", "EMERGENCY_HELP_ORG", q, {"listMode": "true", "routeName": route})
|
||||||
|
add("긴급구조기관", "EMERGENCY_HELP_ORG", "판교 근처 고속도로 긴급구조대 있어?", {"icName": "판교"})
|
||||||
|
|
||||||
|
# 휴게소
|
||||||
|
rest_sets = [
|
||||||
|
("죽전", "죽전휴게소에서 뭐 먹을 거 있어?", "죽전에 편의점이나 카페 있어?",
|
||||||
|
"죽전휴게소에 수유실 있나?", "죽전휴게소 기름값 얼마야?",
|
||||||
|
"죽전에서 전기차 충전돼?", "죽전휴게소에 청년들 장사하는 가게 있어?"),
|
||||||
|
("안성", "안성휴게소 밥 뭐 파나?", "안성휴게소에 브랜드 매장 뭐 있어?",
|
||||||
|
"안성휴게소 샤워실 쓸 수 있어?", "안성 휘발유 얼마야?",
|
||||||
|
"안성휴게소 전기차 충전소 있어?", "안성에 청년창업 매장 있어?"),
|
||||||
|
("김천", "김천휴게소에서 뭐 먹지?", "김천휴게소 입점 매장 뭐 있어?",
|
||||||
|
"김천휴게소 편의시설 뭐 있어?", "김천 경유값 어때?",
|
||||||
|
"김천휴게소에 수소차 충전해?", "김천에 청년몰 있어?"),
|
||||||
|
("금강", "금강휴게소 메뉴 추천해줘", "금강휴게소에 카페 있어?",
|
||||||
|
"금강휴게소 시설 뭐 있어?", "금강휴게소 주유소 있어?",
|
||||||
|
"금강에서 전기차 충전 가능해?", "금강휴게소 청년창업매장 있나?"),
|
||||||
|
("죽전휴게소", "죽전 휴게소 식당 뭐 있어?", "죽전 휴게소에 쇼핑할 데 있어?",
|
||||||
|
"죽전 휴게소에 애완동물 시설 있어?", "죽전 휴게소 기름 넣어?",
|
||||||
|
"죽전 휴게소 EV 충전돼?", "죽전 휴게소 청년가게 있어?"),
|
||||||
|
("강릉", "강릉휴게소에서 뭐 먹을까?", "강릉휴게소 매장 뭐 있어?",
|
||||||
|
"강릉휴게소 편의시설 알려줘", "강릉휴게소 주유소 유가 궁금해",
|
||||||
|
"강릉휴게소 충전소 있어?", "강릉에 청년창업 매장 있어?"),
|
||||||
|
]
|
||||||
|
for name, q_food, q_brand, q_fac, q_gas, q_chg, q_youth in rest_sets:
|
||||||
|
add("휴게소음식", "REST_AREA_FOOD_LIST", q_food, {"restAreaName": name})
|
||||||
|
add("휴게소브랜드매장", "BRAND_SHOP", q_brand, {"restAreaName": name})
|
||||||
|
add("휴게소시설", "REST_AREA_FACILITY", q_fac, {"restAreaName": name})
|
||||||
|
add("휴게소주유", "GASSTATION", q_gas, {"restAreaName": name})
|
||||||
|
add("휴게소충전소", "REST_AREA_CHARGING", q_chg, {"restAreaName": name, "chargingType": "all"})
|
||||||
|
add("휴게소청년창업매장", "REST_AREA_YOUTH_SHOP", q_youth, {"restAreaName": name})
|
||||||
|
|
||||||
|
add("휴게소주유", "GASSTATION", "경부선에서 기름 제일 싼 데 어디야?",
|
||||||
|
{"compareMode": "cheapest", "fuelType": "휘발유", "routeName": "경부선"})
|
||||||
|
add("휴게소주유", "GASSTATION", "고속도로에서 경유 제일 싼 곳 알려줘",
|
||||||
|
{"compareMode": "cheapest", "fuelType": "경유"})
|
||||||
|
add("휴게소충전소", "REST_AREA_CHARGING", "경부선에 전기차 충전되는 휴게소 어디 있어?",
|
||||||
|
{"listMode": "true", "routeName": "경부선", "chargingType": "electric"})
|
||||||
|
add("휴게소충전소", "REST_AREA_CHARGING", "강릉휴게소충전소 있어?",
|
||||||
|
{"restAreaName": "강릉휴게소충전소", "chargingType": "all"})
|
||||||
|
|
||||||
|
for q, ic in [
|
||||||
|
("판교 근처 휴게소 어디 있어?", "판교"),
|
||||||
|
("서울 톨게이트 지나서 바로 나오는 휴게소 어디야?", "서울"),
|
||||||
|
("기흥IC 근처에 쉴 데 있어?", "기흥IC"),
|
||||||
|
]:
|
||||||
|
add("가까운휴게소", "REST_AREA_NEAREST", q, {"icName": ic})
|
||||||
|
|
||||||
|
for q, route in [
|
||||||
|
("경부선 지금 막히는 구간 있어?", "경부선"),
|
||||||
|
("영동선 어디가 막혀?", "영동선"),
|
||||||
|
("서해안선 정체 심한 데 알려줘", "서해안선"),
|
||||||
|
]:
|
||||||
|
add("노선혼잡", "TROAD_CONGESTION", q, {"routeName": route})
|
||||||
|
|
||||||
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
def ask_cases() -> List[Dict[str, Any]]:
|
||||||
|
"""자연어 /ask — 일반 이용자 구어체 질문."""
|
||||||
|
pairs = [
|
||||||
|
("미납조회", "FARE_UNPAID", [
|
||||||
|
"야 내 차 12가3456인데 미납 있어?",
|
||||||
|
"하이패스 미납금 나왔나 봐줘 서울12가3456",
|
||||||
|
"톨비 밀린 거 있어요? 45다6789요",
|
||||||
|
]),
|
||||||
|
("환불조회", "FARE_REFUND", [
|
||||||
|
"잘못 낸 톨비 환불받을 수 있어? 12가3456",
|
||||||
|
"하이패스 환불금 들어왔나? 서울33하1122",
|
||||||
|
]),
|
||||||
|
("구간통행요금", "FARE_SEARCH", [
|
||||||
|
"서울에서 부산까지 톨비 얼마 나와?",
|
||||||
|
"판교에서 신갈 가면 요금이 어떻게 돼?",
|
||||||
|
"판교IC에서 신갈IC까지 하이패스 얼마야?",
|
||||||
|
"대전에서 대구 가는 데 톨비 얼마쯤 해?",
|
||||||
|
]),
|
||||||
|
("구간통행시간", "TROAD_TRAVEL_TIME", [
|
||||||
|
"서울에서 부산까지 지금 가면 얼마나 걸려?",
|
||||||
|
"판교에서 신갈 지금 막혀? 몇 분 걸려?",
|
||||||
|
"지금 대전에서 대구까지 가면 몇 시간이야?",
|
||||||
|
]),
|
||||||
|
("노선별교통속보", "TROAD_BREAKING_NEWS", [
|
||||||
|
"고속도로에 사고 났다는데 어디야?",
|
||||||
|
"경부선에 사고 났어?",
|
||||||
|
"영동선 지금 교통상황 어때?",
|
||||||
|
]),
|
||||||
|
("차단계획", "CONSTRUCTION_PLAN", [
|
||||||
|
"경부선 오늘 공사해서 막히는 데 있어?",
|
||||||
|
"영동선 차로 막는 일정 있나?",
|
||||||
|
"서해안선 공사구간 좀 알려줘",
|
||||||
|
]),
|
||||||
|
("영업소정보", "IC_TEL", [
|
||||||
|
"판교 톨게이트 전화번호 좀",
|
||||||
|
"기흥 톨게이트 주소랑 전화 좀",
|
||||||
|
"판교 영업소 연락처 알려줘",
|
||||||
|
]),
|
||||||
|
("긴급구조기관", "EMERGENCY_HELP_ORG", [
|
||||||
|
"경부선에서 사고 나면 어디로 연락해?",
|
||||||
|
"고속도로에서 사고 났는데 가까운 구조대 어디야?",
|
||||||
|
]),
|
||||||
|
("휴게소음식", "REST_AREA_FOOD_LIST", [
|
||||||
|
"죽전휴게소에서 뭐 먹을 거 있어?",
|
||||||
|
"안성휴게소 밥 뭐 파나?",
|
||||||
|
]),
|
||||||
|
("휴게소브랜드매장", "BRAND_SHOP", [
|
||||||
|
"죽전에 편의점이나 카페 있어?",
|
||||||
|
"김천휴게소에 브랜드 매장 뭐 있어?",
|
||||||
|
]),
|
||||||
|
("휴게소시설", "REST_AREA_FACILITY", [
|
||||||
|
"죽전휴게소에 수유실 있나?",
|
||||||
|
"안성휴게소 샤워실 쓸 수 있어?",
|
||||||
|
]),
|
||||||
|
("휴게소주유", "GASSTATION", [
|
||||||
|
"죽전휴게소 기름값 얼마야?",
|
||||||
|
"경부선에서 기름 제일 싼 데 어디야?",
|
||||||
|
"고속도로에서 휘발유 제일 싼 곳 알려줘",
|
||||||
|
]),
|
||||||
|
("휴게소충전소", "REST_AREA_CHARGING", [
|
||||||
|
"죽전에서 전기차 충전돼?",
|
||||||
|
"강릉휴게소에 충전소 있어?",
|
||||||
|
"김천휴게소에서 수소차 충전해?",
|
||||||
|
]),
|
||||||
|
("휴게소청년창업매장", "REST_AREA_YOUTH_SHOP", [
|
||||||
|
"죽전휴게소에 청년들 장사하는 가게 있어?",
|
||||||
|
"고속도로에 청년창업 매장 있는 휴게소 어디야?",
|
||||||
|
]),
|
||||||
|
("가까운휴게소", "REST_AREA_NEAREST", [
|
||||||
|
"판교 근처 휴게소 어디 있어?",
|
||||||
|
"서울 톨게이트 지나서 바로 나오는 휴게소 어디야?",
|
||||||
|
]),
|
||||||
|
("노선혼잡", "TROAD_CONGESTION", [
|
||||||
|
"경부선 지금 막히는 구간 있어?",
|
||||||
|
"영동선 어디가 막혀?",
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
rows: List[Dict[str, Any]] = []
|
||||||
|
for feature, intent, qs in pairs:
|
||||||
|
for q in qs:
|
||||||
|
rows.append(
|
||||||
|
{
|
||||||
|
"mode": "ask",
|
||||||
|
"feature": feature,
|
||||||
|
"expected_intent": intent,
|
||||||
|
"question": q,
|
||||||
|
"params": {},
|
||||||
|
"note": "구어체 자연어 채팅",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
FIELDNAMES = [
|
||||||
|
"tested_at",
|
||||||
|
"mode",
|
||||||
|
"feature",
|
||||||
|
"expected_intent",
|
||||||
|
"question",
|
||||||
|
"params",
|
||||||
|
"http_status",
|
||||||
|
"elapsed_sec",
|
||||||
|
"actual_intent",
|
||||||
|
"api_status",
|
||||||
|
"answer",
|
||||||
|
"result",
|
||||||
|
"reason",
|
||||||
|
"route_type",
|
||||||
|
"note",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def append_row(path: str, row: Dict[str, str], write_header: bool) -> None:
|
||||||
|
with open(path, "a", newline="", encoding="utf-8-sig") as f:
|
||||||
|
w = csv.DictWriter(f, fieldnames=FIELDNAMES)
|
||||||
|
if write_header:
|
||||||
|
w.writeheader()
|
||||||
|
w.writerow(row)
|
||||||
|
f.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
global _SSL_CTX
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--base", default="http://127.0.0.1:8083/web")
|
||||||
|
ap.add_argument("--out", default="test.csv")
|
||||||
|
ap.add_argument("--timeout-domain", type=float, default=45.0)
|
||||||
|
ap.add_argument("--timeout-ask", type=float, default=90.0)
|
||||||
|
ap.add_argument("--sleep", type=float, default=0.15)
|
||||||
|
ap.add_argument("--sleep-ask", type=float, default=0.0, help="ask 전용 sleep(0이면 --sleep)")
|
||||||
|
ap.add_argument("--skip-ask", action="store_true")
|
||||||
|
ap.add_argument("--skip-domain", action="store_true")
|
||||||
|
ap.add_argument("--limit", type=int, default=0)
|
||||||
|
ap.add_argument(
|
||||||
|
"--profile",
|
||||||
|
choices=["full", "prod"],
|
||||||
|
default="full",
|
||||||
|
help="prod=기능당 소수 + 구어체(운영 부하 최소화)",
|
||||||
|
)
|
||||||
|
ap.add_argument("--insecure", action="store_true", help="SSL 검증 비활성화")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
if args.insecure:
|
||||||
|
_SSL_CTX = ssl._create_unverified_context()
|
||||||
|
|
||||||
|
base = args.base.rstrip("/")
|
||||||
|
domain_url = base + "/domain-query"
|
||||||
|
ask_url = base + "/ask"
|
||||||
|
traffic_url = base + "/traffic-news"
|
||||||
|
started = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
sleep_ask = args.sleep_ask if args.sleep_ask > 0 else max(args.sleep, 1.5)
|
||||||
|
|
||||||
|
# reset out
|
||||||
|
open(args.out, "w", encoding="utf-8-sig").close()
|
||||||
|
header_needed = True
|
||||||
|
results: List[str] = []
|
||||||
|
|
||||||
|
def emit(row: Dict[str, str]) -> None:
|
||||||
|
nonlocal header_needed
|
||||||
|
append_row(args.out, row, header_needed)
|
||||||
|
header_needed = False
|
||||||
|
results.append(row["result"])
|
||||||
|
print(
|
||||||
|
f"{row['result']:7} [{row['mode']:12}] {row['feature']:14} "
|
||||||
|
f"{row['expected_intent']:22} → {row['actual_intent'] or '-':22} | {row['question'][:42]}",
|
||||||
|
flush=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# traffic-news GET
|
||||||
|
http_st, body, elapsed = get_json(traffic_url, args.timeout_domain)
|
||||||
|
ans = extract_answer(body) if isinstance(body, (dict, list)) else one_line(str(body))
|
||||||
|
if isinstance(body, list):
|
||||||
|
ans = one_line(f"list={len(body)}")
|
||||||
|
ok = http_st == 200
|
||||||
|
else:
|
||||||
|
ok = http_st == 200 and (
|
||||||
|
(
|
||||||
|
isinstance(body, dict)
|
||||||
|
and (
|
||||||
|
body.get("status") is True
|
||||||
|
or "list" in body
|
||||||
|
or "items" in body
|
||||||
|
or "routes" in body
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or isinstance(body, list)
|
||||||
|
)
|
||||||
|
emit(
|
||||||
|
{
|
||||||
|
"tested_at": started,
|
||||||
|
"mode": "domain-api",
|
||||||
|
"feature": "노선별교통속보",
|
||||||
|
"expected_intent": "TRAFFIC_NEWS",
|
||||||
|
"question": "오늘 고속도로에 사고나 통제 소식 있어?",
|
||||||
|
"params": "",
|
||||||
|
"http_status": str(http_st or ""),
|
||||||
|
"elapsed_sec": f"{elapsed:.2f}",
|
||||||
|
"actual_intent": "TRAFFIC_NEWS",
|
||||||
|
"api_status": "True" if ok else "False",
|
||||||
|
"answer": ans,
|
||||||
|
"result": "PASS" if ok else "FAIL",
|
||||||
|
"reason": "GET /traffic-news" if ok else "GET 실패",
|
||||||
|
"route_type": "GET",
|
||||||
|
"note": "간편조회 UI 전용",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
suite: List[Dict[str, Any]] = []
|
||||||
|
if not args.skip_domain:
|
||||||
|
suite.extend(domain_cases_prod_light() if args.profile == "prod" else domain_cases())
|
||||||
|
if not args.skip_ask:
|
||||||
|
# prod: 기능당 질문 최대 2개로 축소
|
||||||
|
ask = ask_cases()
|
||||||
|
if args.profile == "prod":
|
||||||
|
by_feat: Dict[str, int] = {}
|
||||||
|
trimmed: List[Dict[str, Any]] = []
|
||||||
|
for c in ask:
|
||||||
|
n = by_feat.get(c["feature"], 0)
|
||||||
|
if n < 2:
|
||||||
|
trimmed.append(c)
|
||||||
|
by_feat[c["feature"]] = n + 1
|
||||||
|
ask = trimmed
|
||||||
|
suite.extend(ask)
|
||||||
|
if args.limit > 0:
|
||||||
|
suite = suite[: args.limit]
|
||||||
|
|
||||||
|
total = len(suite)
|
||||||
|
for i, case in enumerate(suite, 1):
|
||||||
|
mode = case["mode"]
|
||||||
|
print(f"({i}/{total}) …", flush=True)
|
||||||
|
if mode == "domain-query":
|
||||||
|
http_st, body, elapsed = post_json(
|
||||||
|
domain_url,
|
||||||
|
{
|
||||||
|
"intentType": case["expected_intent"],
|
||||||
|
"params": case["params"],
|
||||||
|
"botId": f"qi-dom-{i}",
|
||||||
|
},
|
||||||
|
args.timeout_domain,
|
||||||
|
)
|
||||||
|
actual = intent_of(body, case["expected_intent"])
|
||||||
|
# domain-query often echoes intent in request; keep expected if missing
|
||||||
|
if not actual:
|
||||||
|
actual = case["expected_intent"]
|
||||||
|
else:
|
||||||
|
http_st, body, elapsed = post_json(
|
||||||
|
ask_url,
|
||||||
|
{"query": case["question"], "botId": f"qi-ask-{i}"},
|
||||||
|
args.timeout_ask,
|
||||||
|
)
|
||||||
|
actual = intent_of(body)
|
||||||
|
|
||||||
|
status = status_of(body)
|
||||||
|
answer = extract_answer(body)
|
||||||
|
route_type = ""
|
||||||
|
if isinstance(body, dict):
|
||||||
|
route_type = str(body.get("routeType") or mode)
|
||||||
|
result, reason = judge(case["expected_intent"], actual, status, answer, http_st)
|
||||||
|
emit(
|
||||||
|
{
|
||||||
|
"tested_at": started,
|
||||||
|
"mode": mode,
|
||||||
|
"feature": case["feature"],
|
||||||
|
"expected_intent": case["expected_intent"],
|
||||||
|
"question": case["question"],
|
||||||
|
"params": json.dumps(case.get("params") or {}, ensure_ascii=False),
|
||||||
|
"http_status": str(http_st or ""),
|
||||||
|
"elapsed_sec": f"{elapsed:.2f}",
|
||||||
|
"actual_intent": actual,
|
||||||
|
"api_status": status,
|
||||||
|
"answer": answer,
|
||||||
|
"result": result,
|
||||||
|
"reason": reason,
|
||||||
|
"route_type": route_type,
|
||||||
|
"note": case.get("note") or "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
time.sleep(sleep_ask if mode == "ask" else args.sleep)
|
||||||
|
|
||||||
|
c = Counter(results)
|
||||||
|
print("---", flush=True)
|
||||||
|
print(f"saved={args.out} total={len(results)} {dict(c)}", flush=True)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Regular → Executable
Regular → Executable
+29
-5
@@ -4,12 +4,13 @@
|
|||||||
|
|
||||||
## GitHub upstream (submodule)
|
## GitHub upstream (submodule)
|
||||||
|
|
||||||
4개 서비스 소스는 GitHub `KoreaExpressWayCorp` 저장소를 **git submodule**로 연결합니다.
|
5개 소스는 GitHub `KoreaExpressWayCorp` 저장소를 **git submodule**로 연결합니다.
|
||||||
|
|
||||||
| monorepo 경로 | GitHub | 브랜치 |
|
| monorepo 경로 | GitHub | 브랜치 |
|
||||||
|---------------|--------|--------|
|
|---------------|--------|--------|
|
||||||
| `chatbotApp-chatbot2.0-agent` | https://github.com/KoreaExpressWayCorp/chatbotApp.git | `chatbot2.0-agent` |
|
| `chatbotApp-chatbot2.0-agent` | https://github.com/KoreaExpressWayCorp/chatbotApp.git | `chatbot2.0-agent` |
|
||||||
| `chatbotApi-chatbot2.0-agent` | https://github.com/KoreaExpressWayCorp/chatbotApi.git | `chatbot2.0-agent` |
|
| `chatbotApi-chatbot2.0-agent` | https://github.com/KoreaExpressWayCorp/chatbotApi.git | `chatbot2.0-agent` |
|
||||||
|
| `chatbotApp-test` | https://github.com/KoreaExpressWayCorp/chatbotApp-test.git | `chatbot2.0-agent` |
|
||||||
| `exAiChatBot-chatbot2.0-agent` | https://github.com/KoreaExpressWayCorp/exAiChatBot.git | `chatbot2.0-agent` |
|
| `exAiChatBot-chatbot2.0-agent` | https://github.com/KoreaExpressWayCorp/exAiChatBot.git | `chatbot2.0-agent` |
|
||||||
| `kakaoChatbotSkill-chatbot2.0-agent` | https://github.com/KoreaExpressWayCorp/kakaoChatbotSkill.git | `chatbot2.0-agent` |
|
| `kakaoChatbotSkill-chatbot2.0-agent` | https://github.com/KoreaExpressWayCorp/kakaoChatbotSkill.git | `chatbot2.0-agent` |
|
||||||
|
|
||||||
@@ -48,13 +49,21 @@ Gitea(`https://github.exdev.co.kr`)에서 **`exAichatbot_agent`** 저장소 생
|
|||||||
|
|
||||||
## 로컬 Mac → Gitea push → 서버 배포
|
## 로컬 Mac → Gitea push → 서버 배포
|
||||||
|
|
||||||
개발 Mac에서 **한 번에** GitHub 최신 반영 · Gitea push · 서버 빌드·배포:
|
개발 Mac에서 **한 번에** Gitea 최신 반영 · 로컬 변경 commit/push · 서버 빌드·배포:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./start-all-server.sh
|
./start-all-server.sh
|
||||||
# = git_fetch_all (GitHub) → push-to-gitea → post-receive 배포 대기
|
# = (push-to-gitea) Gitea fetch/merge → 로컬 commit → Gitea push → 원격 배포
|
||||||
|
# 공식 GitHub push 없음
|
||||||
|
|
||||||
|
./git_fetch_all.sh
|
||||||
|
# = 공식 GitHub(KoreaExpressWayCorp) submodule sync/commit/push 전용
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`push-to-gitea.sh` 는 `git_fetch_all.sh` 와 같이 **원격(Gitea) 변경을 먼저 merge** 한 뒤 로컬을 올립니다.
|
||||||
|
충돌 시 스크립트가 멈추므로 수동 해결 후 재실행하세요.
|
||||||
|
(서버 work tree에만 있고 Gitea에 없는 수정은 포함되지 않습니다 — 배포는 Gitea 기준입니다.)
|
||||||
|
|
||||||
| 옵션 | 설명 |
|
| 옵션 | 설명 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `--local` | 예전처럼 `local-dev/start-all.sh` 로컬 개발 모드 |
|
| `--local` | 예전처럼 `local-dev/start-all.sh` 로컬 개발 모드 |
|
||||||
@@ -69,7 +78,8 @@ Gitea(`https://github.exdev.co.kr`)에서 **`exAichatbot_agent`** 저장소 생
|
|||||||
./server-dev/push-to-gitea.sh --dry-run
|
./server-dev/push-to-gitea.sh --dry-run
|
||||||
```
|
```
|
||||||
|
|
||||||
**main push 시 자동:** `post-receive` → `deploy-exAichatbot_agent.sh` → checkout + `git_fetch_all --init` → `start-all-server.sh --no-pull --no-push`
|
**main push 시 자동:** `post-receive` → `deploy-exAichatbot_agent.sh` → Gitea checkout → `start-all-server.sh --no-pull --no-push`
|
||||||
|
(공식 GitHub `git_fetch_all` 은 deploy 경로에서 호출하지 않음)
|
||||||
|
|
||||||
서버에서 GitHub clone 이 안 되면 **로컬 `./start-all-server.sh`** 가 submodule rsync + chatbotApp 로컬 빌드 후 배포합니다.
|
서버에서 GitHub clone 이 안 되면 **로컬 `./start-all-server.sh`** 가 submodule rsync + chatbotApp 로컬 빌드 후 배포합니다.
|
||||||
|
|
||||||
@@ -106,13 +116,27 @@ cd /Users/aidev/dev/exAichatbot_agent
|
|||||||
|--------|------|-----|
|
|--------|------|-----|
|
||||||
| HTTPS UI (Caddy) | 443 | https://chatbot.exdev.co.kr/chatbot/app/ |
|
| HTTPS UI (Caddy) | 443 | https://chatbot.exdev.co.kr/chatbot/app/ |
|
||||||
| chatbotApp nginx | 8092 | 내부 |
|
| chatbotApp nginx | 8092 | 내부 |
|
||||||
| kakaoChatbotSkill | 8083 | /web/ask |
|
| kakaoChatbotSkill | 8083 | /web/ask, /kakao/skill (카카오 웹훅) |
|
||||||
| chatbotApi WAS | 8086 | /api |
|
| chatbotApi WAS | 8086 | /api |
|
||||||
| RAG API | 28012 | /agent/chat |
|
| RAG API | 28012 | /agent/chat |
|
||||||
| Vector Admin | 28013 | /chatbot/admin |
|
| Vector Admin | 28013 | /chatbot/admin |
|
||||||
| Qdrant | 6333 | REST |
|
| Qdrant | 6333 | REST |
|
||||||
|
| Oracle TROAD | 1521 | `localhost:1521/orcl2` (OPR_MAIN / test) |
|
||||||
| 호스트 AI | 16000~16002 | MLX LLM/Embed/Rerank |
|
| 호스트 AI | 16000~16002 | MLX LLM/Embed/Rerank |
|
||||||
|
|
||||||
|
## Oracle TROAD (교통정보)
|
||||||
|
|
||||||
|
- Docker Compose: `server-dev/docker-compose.oracle.yml` (`gvenzl/oracle-free:23-slim`, arm64 지원)
|
||||||
|
- 상세: [`server-dev/oracle/README.md`](oracle/README.md)
|
||||||
|
- `start-all-server.sh` 기동 시 Oracle 컨테이너 자동 시작 + WAS에
|
||||||
|
`SPRING_DATASOURCE_TROAD_URL/USERNAME/PASSWORD` 를 **localhost** 로 ENV 주입
|
||||||
|
(`application.yml` 운영 172.16.163.76 값은 파일에 그대로 둠 — `git_fetch_all.sh` push 시 복원·검증)
|
||||||
|
- `stop-all-server.sh` 중지 시 자동 중지(데이터 볼륨 유지)
|
||||||
|
- 업무 객체는 `server-dev/oracle/sql/*.sql` — 기동 후 비어 있으면 `oracle/apply-sql.sh` 가 자동 적용
|
||||||
|
- `OPR_MAIN.V_INCIDENT_FTMS` (돌발/정체 교통정보, 샘플 124건)
|
||||||
|
- `TROAD_APP.V_ROUTE_NEW_NM` / `V_ROUTE_TRFC_VER001` / `TLISDEV.T_TRMB_CD_INFO01M1` (노선별 혼잡 — **기존 chatbotApi 조회 SQL 그대로**)
|
||||||
|
- 옵션: `--skip-oracle`, `--keep-oracle`, `--purge-oracle`
|
||||||
|
|
||||||
## Qdrant 데이터
|
## Qdrant 데이터
|
||||||
|
|
||||||
- 최초 기동 시 `vector_count=0` 이면 레거시 `exAIChatbot2.0/exAiChatBot-chatbot2.0/qdrant_data` 를 자동 복사
|
- 최초 기동 시 `vector_count=0` 이면 레거시 `exAIChatbot2.0/exAiChatBot-chatbot2.0/qdrant_data` 를 자동 복사
|
||||||
|
|||||||
Regular → Executable
+30
-1
@@ -37,7 +37,7 @@ https://{$CHATBOT_DOMAIN:chatbot.exdev.co.kr} {
|
|||||||
import tls_certs
|
import tls_certs
|
||||||
|
|
||||||
# 업스트림 nginx 가 HTTP 로 absolute redirect 해서 http:// 로 떨어지지 않게 Caddy 에서 처리
|
# 업스트림 nginx 가 HTTP 로 absolute redirect 해서 http:// 로 떨어지지 않게 Caddy 에서 처리
|
||||||
redir / /chatbot/app/ 302
|
redir / /chatbot/ai/ 302
|
||||||
|
|
||||||
handle /agent/* {
|
handle /agent/* {
|
||||||
reverse_proxy host.docker.internal:{$RAG_API_PORT:28012} {
|
reverse_proxy host.docker.internal:{$RAG_API_PORT:28012} {
|
||||||
@@ -67,6 +67,35 @@ https://{$CHATBOT_DOMAIN:chatbot.exdev.co.kr} {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 카카오 오픈빌더 Skill 웹훅 (/kakao/skill, /oakak/skill)
|
||||||
|
handle /kakao/* {
|
||||||
|
reverse_proxy host.docker.internal:{$SKILL_PORT:8083} {
|
||||||
|
transport http {
|
||||||
|
read_timeout 120s
|
||||||
|
write_timeout 120s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle /oakak/* {
|
||||||
|
reverse_proxy host.docker.internal:{$SKILL_PORT:8083} {
|
||||||
|
transport http {
|
||||||
|
read_timeout 120s
|
||||||
|
write_timeout 120s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# iOS 홈화면 Web Clip — MIME 를 Caddy에서 강제 (인앱/프록시에서 text 로 깨지는 것 방지)
|
||||||
|
handle /chatbot/ai/downloads/*.mobileconfig {
|
||||||
|
header Content-Type application/x-apple-aspen-config
|
||||||
|
header Content-Disposition inline
|
||||||
|
header Cache-Control "no-cache, no-store, must-revalidate"
|
||||||
|
reverse_proxy host.docker.internal:{$CHATBOT_APP_PORT:8092} {
|
||||||
|
import proxy_std
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handle {
|
handle {
|
||||||
reverse_proxy host.docker.internal:{$CHATBOT_APP_PORT:8092} {
|
reverse_proxy host.docker.internal:{$CHATBOT_APP_PORT:8092} {
|
||||||
import proxy_std
|
import proxy_std
|
||||||
|
|||||||
+56
-12
@@ -29,7 +29,8 @@ if [[ -f "$LOCK_FILE" ]]; then
|
|||||||
rm -f "$LOCK_FILE"
|
rm -f "$LOCK_FILE"
|
||||||
fi
|
fi
|
||||||
echo $$ > "$LOCK_FILE"
|
echo $$ > "$LOCK_FILE"
|
||||||
trap 'rm -f "$LOCK_FILE"; log "락 해제"' EXIT
|
DEPLOY_OK=false
|
||||||
|
trap 'rm -f "$LOCK_FILE"; if ! $DEPLOY_OK; then log "[ERROR] 배포 실패"; fi; log "락 해제"' EXIT
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
@@ -64,31 +65,73 @@ sync_worktree_submodules() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [[ ${ready} -ge 4 ]]; then
|
if [[ ${ready} -ge 4 ]]; then
|
||||||
log "submodule 소스 이미 존재 (rsync 또는 clone 완료) — GitHub fetch 생략"
|
log "submodule 소스 이미 존재 (Gitea/rsync) — 공식 GitHub fetch 생략"
|
||||||
if [[ -f "${tree}/server-dev/docker-compose.rag.server.yml" ]]; then
|
if [[ -f "${tree}/server-dev/docker-compose.rag.server.yml" ]]; then
|
||||||
cp "${tree}/server-dev/docker-compose.rag.server.yml" \
|
cp "${tree}/server-dev/docker-compose.rag.server.yml" \
|
||||||
"${tree}/exAiChatBot-chatbot2.0-agent/docker-compose.server.yml" 2>/dev/null || true
|
"${tree}/exAiChatBot-chatbot2.0-agent/docker-compose.server.yml" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if [[ -x "${tree}/git_fetch_all.sh" ]]; then
|
# 공식 GitHub 는 deploy 경로에서 절대 동기화/push 하지 않음.
|
||||||
log "GitHub submodule 동기화 (git_fetch_all.sh --init)..."
|
# 소스가 비어 있으면 로컬 Mac 의 rsync (sync-submodules-rsync.sh) 가 필요.
|
||||||
MONOREPO_GIT_DIR="${GIT_DIR}" "${tree}/git_fetch_all.sh" --init || log "[WARN] git_fetch_all 실패 — 로컬 rsync 필요"
|
log "[WARN] submodule 소스 부족 (${ready}/4) — 공식 GitHub fetch 안 함. 로컬 rsync 필요"
|
||||||
else
|
|
||||||
log "[WARN] git_fetch_all.sh 없음 — 로컬 rsync 필요"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log "[Phase 1] stop-all-server.sh"
|
resolve_java17_home() {
|
||||||
"$WORK_TREE/server-dev/stop-all-server.sh" --keep-caddy || true
|
local home="" candidate
|
||||||
|
for candidate in \
|
||||||
|
"/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home" \
|
||||||
|
"/usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home"; do
|
||||||
|
if [[ -x "${candidate}/bin/java" ]]; then
|
||||||
|
home="${candidate}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -z "${home}" ]] && /usr/libexec/java_home -v 17 >/dev/null 2>&1; then
|
||||||
|
home="$(/usr/libexec/java_home -v 17)"
|
||||||
|
fi
|
||||||
|
[[ -n "${home}" ]] || fail "Java 17 필요 — brew install openjdk@17"
|
||||||
|
echo "${home}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 서비스 중지 전에 Java 컴파일만 검증 — 실패 시 가동 중인 스택을 유지한다.
|
||||||
|
# Gitea post-receive / 비로그인 SSH 는 PATH 에 brew java 가 없고 /usr/bin/java 는 stub 이므로
|
||||||
|
# JAVA_HOME 을 반드시 export 해야 gradlew 부트스트랩이 성공한다.
|
||||||
|
preflight_java_compile() {
|
||||||
|
local java_home dir
|
||||||
|
java_home="$(resolve_java17_home)"
|
||||||
|
export JAVA_HOME="${java_home}"
|
||||||
|
export PATH="${JAVA_HOME}/bin:/opt/homebrew/bin:/opt/homebrew/sbin:${PATH}"
|
||||||
|
log "[Phase 0] Java 사전 컴파일 검증 (Java 17: ${JAVA_HOME})"
|
||||||
|
for dir in \
|
||||||
|
"${WORK_TREE}/kakaoChatbotSkill-chatbot2.0-agent" \
|
||||||
|
"${WORK_TREE}/chatbotApi-chatbot2.0-agent"; do
|
||||||
|
[[ -x "${dir}/gradlew" ]] || fail "gradlew 없음: ${dir}"
|
||||||
|
log " compileJava: $(basename "${dir}")"
|
||||||
|
if ! (
|
||||||
|
cd "${dir}"
|
||||||
|
export JAVA_HOME
|
||||||
|
export PATH="${JAVA_HOME}/bin:${PATH}"
|
||||||
|
./gradlew -Dorg.gradle.java.home="${JAVA_HOME}" compileJava --quiet
|
||||||
|
); then
|
||||||
|
fail "사전 컴파일 실패: $(basename "${dir}") — 기존 서비스는 그대로 유지됨"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
log " ✅ Java 사전 컴파일 OK"
|
||||||
|
}
|
||||||
|
|
||||||
if ! $START_ONLY; then
|
if ! $START_ONLY; then
|
||||||
log "[Phase 2] checkout + GitHub submodule"
|
log "[Phase 2] checkout (Gitea work tree) — 공식 GitHub 미사용"
|
||||||
git --work-tree="$WORK_TREE" --git-dir="$GIT_DIR" checkout -f "$BRANCH"
|
git --work-tree="$WORK_TREE" --git-dir="$GIT_DIR" checkout -f "$BRANCH"
|
||||||
rm -f "$WORK_TREE/.git"
|
rm -f "$WORK_TREE/.git"
|
||||||
sync_worktree_submodules "$WORK_TREE"
|
sync_worktree_submodules "$WORK_TREE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
preflight_java_compile
|
||||||
|
|
||||||
|
log "[Phase 1] stop-all-server.sh"
|
||||||
|
"$WORK_TREE/server-dev/stop-all-server.sh" --keep-caddy || true
|
||||||
|
|
||||||
log "[Phase 3] .env 준비"
|
log "[Phase 3] .env 준비"
|
||||||
ENV_FILE="$WORK_TREE/exAiChatBot-chatbot2.0-agent/.env"
|
ENV_FILE="$WORK_TREE/exAiChatBot-chatbot2.0-agent/.env"
|
||||||
if [[ ! -f "$ENV_FILE" ]]; then
|
if [[ ! -f "$ENV_FILE" ]]; then
|
||||||
@@ -104,7 +147,8 @@ fi
|
|||||||
"$WORK_TREE/server-dev/start-all-server.sh" "${START_ARGS[@]}"
|
"$WORK_TREE/server-dev/start-all-server.sh" "${START_ARGS[@]}"
|
||||||
|
|
||||||
COMMIT="$(git --git-dir="$GIT_DIR" rev-parse --short HEAD 2>/dev/null || echo unknown)"
|
COMMIT="$(git --git-dir="$GIT_DIR" rev-parse --short HEAD 2>/dev/null || echo unknown)"
|
||||||
|
DEPLOY_OK=true
|
||||||
log "======================================================"
|
log "======================================================"
|
||||||
log " 배포 완료 — $COMMIT"
|
log " 배포 완료 — $COMMIT"
|
||||||
log " UI: https://chatbot.exdev.co.kr/chatbot/app/"
|
log " UI: https://chatbot.exdev.co.kr/chatbot/ai/"
|
||||||
log "======================================================"
|
log "======================================================"
|
||||||
|
|||||||
Regular → Executable
Executable
+39
@@ -0,0 +1,39 @@
|
|||||||
|
# exdev 개발서버 — TROAD용 Oracle (Docker)
|
||||||
|
#
|
||||||
|
# chatbotApi application.yml 의 troad datasource 와 맞춤:
|
||||||
|
# jdbc:oracle:thin:@localhost:1521/orcl2
|
||||||
|
# username: OPR_MAIN
|
||||||
|
# password: test
|
||||||
|
#
|
||||||
|
# 테이블 DDL 은 oracle/apply-sql.sh 로 적용한다.
|
||||||
|
#
|
||||||
|
# 이미지: Oracle Database Free 23ai (linux/arm64 지원).
|
||||||
|
# 개발서버가 Apple Silicon(arm64) 이라 amd64 전용인 oracle-xe:21 은 사용할 수 없다.
|
||||||
|
services:
|
||||||
|
oracle-troad:
|
||||||
|
image: gvenzl/oracle-free:23-slim
|
||||||
|
container_name: exaichatbot-agent-oracle-troad
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "1521:1521"
|
||||||
|
environment:
|
||||||
|
# SYS / SYSTEM
|
||||||
|
ORACLE_PASSWORD: ${ORACLE_SYS_PASSWORD:-OracleExdev!2026}
|
||||||
|
# PDB 서비스명 → JDBC .../orcl2
|
||||||
|
ORACLE_DATABASE: ORCL2
|
||||||
|
# chatbotApi troad 계정
|
||||||
|
APP_USER: OPR_MAIN
|
||||||
|
APP_USER_PASSWORD: ${ORACLE_TROAD_PASSWORD:-test}
|
||||||
|
volumes:
|
||||||
|
- oracle-troad-data:/opt/oracle/oradata
|
||||||
|
- ./oracle/init:/container-entrypoint-initdb.d:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "healthcheck.sh"]
|
||||||
|
interval: 20s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 30
|
||||||
|
start_period: 90s
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
oracle-troad-data:
|
||||||
|
name: exaichatbot-agent-oracle-troad-data
|
||||||
Regular → Executable
+5
@@ -34,6 +34,11 @@ services:
|
|||||||
LLM_BASE_URL: http://host.docker.internal:16000
|
LLM_BASE_URL: http://host.docker.internal:16000
|
||||||
TEI_EMBED_URL: http://host.docker.internal:16001
|
TEI_EMBED_URL: http://host.docker.internal:16001
|
||||||
TEI_RERANK_URL: http://host.docker.internal:16002
|
TEI_RERANK_URL: http://host.docker.internal:16002
|
||||||
|
# exdev: 호스트 chatbotApi. 운영 IP(172.16.180.130)는 git_fetch_all 커밋 기본값에만 유지.
|
||||||
|
EXDEV_LOCAL: ${EXDEV_LOCAL:-true}
|
||||||
|
CHATBOT_API_BASE_URL: ${CHATBOT_API_BASE_URL:-http://host.docker.internal:8086/api}
|
||||||
|
INTERNAL_TOOL_API_KEY: ${INTERNAL_TOOL_API_KEY:-exdev-agent-tool-key}
|
||||||
|
CHATBOT_TOOL_TIMEOUT: ${CHATBOT_TOOL_TIMEOUT:-60}
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
- ./scripts:/app/scripts
|
- ./scripts:/app/scripts
|
||||||
|
|||||||
Regular → Executable
+8
-2
@@ -21,6 +21,9 @@ MONGO_USER=exlink
|
|||||||
MONGO_PASSWORD=!wkcproqkf1
|
MONGO_PASSWORD=!wkcproqkf1
|
||||||
MONGO_DATABASE=chat_history
|
MONGO_DATABASE=chat_history
|
||||||
MONGO_COLLECTION=rag_conversations
|
MONGO_COLLECTION=rag_conversations
|
||||||
|
MONGO_FEEDBACK_DATABASE=chatbot
|
||||||
|
MONGO_FEEDBACK_COLLECTION=answer_feedback
|
||||||
|
MONGO_IMPROVEMENT_COLLECTION=improvement_suggestions
|
||||||
|
|
||||||
# ── Qdrant ──
|
# ── Qdrant ──
|
||||||
VECTOR_STORE=qdrant
|
VECTOR_STORE=qdrant
|
||||||
@@ -28,10 +31,13 @@ QDRANT_HOST=127.0.0.1
|
|||||||
QDRANT_PORT=6333
|
QDRANT_PORT=6333
|
||||||
QDRANT_COLLECTION=qa_vectors_v2
|
QDRANT_COLLECTION=qa_vectors_v2
|
||||||
|
|
||||||
# ── Agent / WAS ──
|
# ── Agent / WAS (Docker → 호스트 chatbotApi) ──
|
||||||
|
# EXDEV_LOCAL=true 이면 운영 WAS(172.16.180.130) 호출을 차단한다.
|
||||||
|
# (GitHub push 시 git_fetch_all.sh 가 커밋 파일의 운영 기본 주소를 복원한다.)
|
||||||
AGENT_MODE=agent
|
AGENT_MODE=agent
|
||||||
AGENT_MAX_ROUNDS=6
|
AGENT_MAX_ROUNDS=6
|
||||||
CHATBOT_API_BASE_URL=http://127.0.0.1:8086/api
|
EXDEV_LOCAL=true
|
||||||
|
CHATBOT_API_BASE_URL=http://host.docker.internal:8086/api
|
||||||
INTERNAL_TOOL_API_KEY=exdev-agent-tool-key
|
INTERNAL_TOOL_API_KEY=exdev-agent-tool-key
|
||||||
CHATBOT_TOOL_TIMEOUT=60
|
CHATBOT_TOOL_TIMEOUT=60
|
||||||
|
|
||||||
|
|||||||
Executable
+111
@@ -0,0 +1,111 @@
|
|||||||
|
# exdev TROAD Oracle (Docker)
|
||||||
|
|
||||||
|
개발서버(`chatbot.exdev.co.kr`)에서 교통정보(TROAD) 조회용 Oracle 을 Docker 로 기동합니다.
|
||||||
|
|
||||||
|
## 접속 정보 (chatbotApi 와 동일)
|
||||||
|
|
||||||
|
| 항목 | 값 |
|
||||||
|
|------|-----|
|
||||||
|
| JDBC URL | `jdbc:oracle:thin:@localhost:1521/orcl2` |
|
||||||
|
| Username | `OPR_MAIN` |
|
||||||
|
| Password | `test` |
|
||||||
|
| Image | `gvenzl/oracle-free:23-slim` (Oracle Database Free 23ai) |
|
||||||
|
| Container | `exaichatbot-agent-oracle-troad` |
|
||||||
|
| Volume | `exaichatbot-agent-oracle-troad-data` |
|
||||||
|
|
||||||
|
`application.yml` 의 기본값은 운영 TROAD(`172.16.163.76`)를 유지합니다.
|
||||||
|
개발서버에서는 `start-all-server.sh` 가 아래 ENV 로만 localhost Oracle 을 주입합니다
|
||||||
|
(`SPRING_DATASOURCE_TROAD_URL` / `_USERNAME` / `_PASSWORD`).
|
||||||
|
`git_fetch_all.sh` 는 커밋 전 yml 을 운영값으로 되돌리므로 exdev 설정이 GitHub에 반영되지 않습니다.
|
||||||
|
|
||||||
|
개발서버가 Apple Silicon(arm64) 이므로 amd64 전용인 `gvenzl/oracle-xe:21` 대신
|
||||||
|
arm64 를 지원하는 `gvenzl/oracle-free:23-slim` 을 사용합니다.
|
||||||
|
|
||||||
|
SYS/SYSTEM 비밀번호 기본값: `OracleExdev!2026`
|
||||||
|
(`ORACLE_SYS_PASSWORD` 환경변수로 변경 가능)
|
||||||
|
|
||||||
|
## 기동 / 중지
|
||||||
|
|
||||||
|
`start-all-server.sh` / `stop-all-server.sh` 에 포함됩니다.
|
||||||
|
기동 후 교통정보 뷰가 비어 있으면 `apply-sql.sh` 가 자동 실행됩니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 수동
|
||||||
|
cd /Users/aidev/dev/exAichatbot_agent/server-dev
|
||||||
|
docker compose -f docker-compose.oracle.yml up -d
|
||||||
|
docker compose -f docker-compose.oracle.yml down
|
||||||
|
|
||||||
|
# 데이터 볼륨까지 삭제
|
||||||
|
docker compose -f docker-compose.oracle.yml down -v
|
||||||
|
# 또는
|
||||||
|
./stop-all-server.sh --purge-oracle
|
||||||
|
```
|
||||||
|
|
||||||
|
옵션:
|
||||||
|
|
||||||
|
| 옵션 | 설명 |
|
||||||
|
|------|------|
|
||||||
|
| `start-all-server.sh --skip-oracle` | Oracle 기동 생략 |
|
||||||
|
| `stop-all-server.sh --purge-oracle` | 컨테이너 + 데이터 볼륨 삭제 |
|
||||||
|
|
||||||
|
## 디렉터리 구성
|
||||||
|
|
||||||
|
| 경로 | 설명 |
|
||||||
|
|------|------|
|
||||||
|
| `init/` | 컨테이너 최초 초기화 시 1회 실행 (OPR_MAIN 권한 부여) |
|
||||||
|
| `sql/` | 업무 객체 DDL + 데이터 (파일명 순서로 적용) |
|
||||||
|
| `data/` | 원본 CSV 덤프 |
|
||||||
|
| `tools/csv_to_insert.py` | CSV → INSERT 스크립트 변환 |
|
||||||
|
| `apply-sql.sh` | 컨테이너에 `sql/*.sql` 적용 + 결과 검증 |
|
||||||
|
|
||||||
|
## 업무 객체 적용
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/aidev/dev/exAichatbot_agent/server-dev/oracle
|
||||||
|
|
||||||
|
# sql/ 전체 적용
|
||||||
|
./apply-sql.sh
|
||||||
|
|
||||||
|
# 특정 파일만
|
||||||
|
./apply-sql.sh sql/10_v_incident_ftms.sql sql/20_v_incident_ftms_data.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### 적용된 객체
|
||||||
|
|
||||||
|
| 객체 | 설명 |
|
||||||
|
|------|------|
|
||||||
|
| `OPR_MAIN.T_INCIDENT_FTMS` | 뷰의 원본 데이터 테이블 (17 컬럼 + `LOADED_AT`) |
|
||||||
|
| `OPR_MAIN.V_INCIDENT_FTMS` | 운영과 동일한 컬럼·순서의 조회용 뷰 |
|
||||||
|
| `PUBLIC SYNONYM V_INCIDENT_FTMS` | 스키마 미지정 조회 지원 |
|
||||||
|
| `TLISDEV.T_TRMB_CD_INFO01M1` | 공통코드 (노선명 COM064 등) |
|
||||||
|
| `TROAD_APP.V_ROUTE_NEW_NM` | 노선명 조회 뷰 (`chatbotApi` 기존 쿼리 그대로 사용) |
|
||||||
|
| `TROAD_APP.V_ROUTE_TRFC_VER001` | 노선별 교통상황 뷰 (`chatbotApi` 기존 쿼리 그대로 사용) |
|
||||||
|
| `TROAD_APP.V_ACDT_BRNWS_VER001` | 교통속보 뷰 (`chatbotApi` 기존 쿼리 그대로 사용) |
|
||||||
|
| `OPR_MAIN.V_ROUTE_*` / `V_ACDT_*` | 스키마 미지정 조회용 미러 뷰 |
|
||||||
|
|
||||||
|
운영 뷰는 다수 기반 테이블을 참조하는 읽기 전용 뷰입니다. 개발서버에는 기반 테이블이
|
||||||
|
없으므로, 뷰 결과 CSV를 물리 테이블에 적재하고 동일 이름 뷰로 노출해
|
||||||
|
**기존 조회 로직/SQL을 변경하지 않고** 동작하게 합니다.
|
||||||
|
|
||||||
|
### 다른 CSV 덤프 추가
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/aidev/dev/exAichatbot_agent/server-dev/oracle
|
||||||
|
python3 tools/csv_to_insert.py data/<파일>.csv \
|
||||||
|
--table OPR_MAIN.<테이블> \
|
||||||
|
--numeric <숫자컬럼,콤마구분> \
|
||||||
|
--out sql/<번호>_<이름>_data.sql
|
||||||
|
./apply-sql.sh sql/<번호>_<이름>_data.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
## 검증
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -e NLS_LANG=.AL32UTF8 -it exaichatbot-agent-oracle-troad \
|
||||||
|
sqlplus OPR_MAIN/test@localhost:1521/ORCL2
|
||||||
|
|
||||||
|
SQL> SELECT COUNT(*) FROM V_INCIDENT_FTMS;
|
||||||
|
SQL> SELECT INCIDENT_TYPE, COUNT(*) FROM V_INCIDENT_FTMS GROUP BY INCIDENT_TYPE;
|
||||||
|
```
|
||||||
|
|
||||||
|
한글 데이터 조회 시 `NLS_LANG=.AL32UTF8` 을 지정해야 깨지지 않습니다.
|
||||||
Executable
+113
@@ -0,0 +1,113 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# TROAD Oracle 컨테이너에 sql/*.sql 을 순서대로 적용한다.
|
||||||
|
#
|
||||||
|
# 사용법:
|
||||||
|
# ./apply-sql.sh # sql/ 전체 (파일명 순)
|
||||||
|
# ./apply-sql.sh sql/10_v_incident_ftms.sql sql/20_v_incident_ftms_data.sql
|
||||||
|
#
|
||||||
|
# 컨테이너가 기동/healthy 상태여야 한다. (start-all-server.sh 또는 docker compose up)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
CONTAINER="${ORACLE_CONTAINER:-exaichatbot-agent-oracle-troad}"
|
||||||
|
PDB="${ORACLE_PDB:-ORCL2}"
|
||||||
|
SYS_PASSWORD="${ORACLE_SYS_PASSWORD:-OracleExdev!2026}"
|
||||||
|
REMOTE_DIR="/tmp/troad-sql"
|
||||||
|
|
||||||
|
log() { printf '\033[36m[oracle-sql]\033[0m %s\n' "$*"; }
|
||||||
|
err() { printf '\033[31m[oracle-sql]\033[0m %s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
if ! docker inspect "$CONTAINER" >/dev/null 2>&1; then
|
||||||
|
err "컨테이너를 찾을 수 없습니다: $CONTAINER"
|
||||||
|
err "먼저 기동하세요: docker compose -f docker-compose.oracle.yml up -d"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
state="$(docker inspect -f '{{.State.Status}}' "$CONTAINER")"
|
||||||
|
if [[ "$state" != "running" ]]; then
|
||||||
|
err "컨테이너가 running 상태가 아닙니다 (현재: $state)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# healthcheck 통과 대기 (최대 10분)
|
||||||
|
for _ in $(seq 1 120); do
|
||||||
|
health="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$CONTAINER")"
|
||||||
|
[[ "$health" == "healthy" || "$health" == "none" ]] && break
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
if [[ "${health:-}" != "healthy" && "${health:-}" != "none" ]]; then
|
||||||
|
err "Oracle 이 healthy 상태가 아닙니다 (현재: ${health:-unknown})"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $# -gt 0 ]]; then
|
||||||
|
FILES=("$@")
|
||||||
|
else
|
||||||
|
FILES=()
|
||||||
|
while IFS= read -r f; do FILES+=("$f"); done < <(find "$SCRIPT_DIR/sql" -maxdepth 1 -name '*.sql' | sort)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#FILES[@]} -eq 0 ]]; then
|
||||||
|
err "적용할 SQL 파일이 없습니다."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker exec "$CONTAINER" mkdir -p "$REMOTE_DIR"
|
||||||
|
|
||||||
|
for file in "${FILES[@]}"; do
|
||||||
|
path="$file"
|
||||||
|
[[ -f "$path" ]] || path="$SCRIPT_DIR/$file"
|
||||||
|
if [[ ! -f "$path" ]]; then
|
||||||
|
err "파일 없음: $file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
base="$(basename "$path")"
|
||||||
|
log "적용: $base"
|
||||||
|
docker cp "$path" "$CONTAINER:$REMOTE_DIR/$base"
|
||||||
|
|
||||||
|
# 한글 데이터를 위해 NLS_LANG 을 AL32UTF8 로 고정하고 PDB 에 접속한다.
|
||||||
|
output="$(docker exec -e NLS_LANG=.AL32UTF8 -i "$CONTAINER" bash -lc "
|
||||||
|
sqlplus -S -L sys/'${SYS_PASSWORD}'@localhost:1521/${PDB} as sysdba <<'EOSQL'
|
||||||
|
WHENEVER SQLERROR EXIT SQL.SQLCODE
|
||||||
|
WHENEVER OSERROR EXIT FAILURE
|
||||||
|
SET ECHO OFF
|
||||||
|
SET FEEDBACK OFF
|
||||||
|
SET PAGESIZE 0
|
||||||
|
SET LINESIZE 200
|
||||||
|
@${REMOTE_DIR}/${base}
|
||||||
|
EXIT
|
||||||
|
EOSQL
|
||||||
|
" 2>&1)" || {
|
||||||
|
err "실패: $base"
|
||||||
|
printf '%s\n' "$output" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -n "${output// /}" ]] && printf '%s\n' "$output"
|
||||||
|
done
|
||||||
|
|
||||||
|
log "검증"
|
||||||
|
docker exec -e NLS_LANG=.AL32UTF8 -i "$CONTAINER" bash -lc "
|
||||||
|
sqlplus -S -L sys/'${SYS_PASSWORD}'@localhost:1521/${PDB} as sysdba <<'EOSQL'
|
||||||
|
SET PAGESIZE 50
|
||||||
|
SET LINESIZE 200
|
||||||
|
COLUMN OWNER FORMAT A12
|
||||||
|
COLUMN OBJECT_NAME FORMAT A30
|
||||||
|
COLUMN OBJECT_TYPE FORMAT A12
|
||||||
|
SELECT OWNER, OBJECT_NAME, OBJECT_TYPE, STATUS
|
||||||
|
FROM ALL_OBJECTS
|
||||||
|
WHERE (OWNER = 'OPR_MAIN' AND OBJECT_NAME IN ('T_INCIDENT_FTMS', 'V_INCIDENT_FTMS', 'V_ROUTE_NEW_NM', 'V_ROUTE_TRFC_VER001', 'V_ACDT_BRNWS_VER001'))
|
||||||
|
OR (OWNER = 'TROAD_APP' AND OBJECT_NAME IN ('V_ROUTE_NEW_NM', 'V_ROUTE_TRFC_VER001', 'V_ACDT_BRNWS_VER001', 'T_ROUTE_NEW_NM', 'T_ROUTE_TRFC_VER001', 'T_ACDT_BRNWS_VER001'))
|
||||||
|
OR (OWNER = 'TLISDEV' AND OBJECT_NAME IN ('T_TRMB_CD_INFO01M1'))
|
||||||
|
ORDER BY OWNER, OBJECT_TYPE, OBJECT_NAME;
|
||||||
|
SELECT (SELECT COUNT(*) FROM OPR_MAIN.V_INCIDENT_FTMS) AS V_INCIDENT_FTMS_ROWS FROM DUAL;
|
||||||
|
SELECT (SELECT COUNT(*) FROM TROAD_APP.V_ROUTE_NEW_NM) AS V_ROUTE_NEW_NM_ROWS FROM DUAL;
|
||||||
|
SELECT (SELECT COUNT(*) FROM TROAD_APP.V_ROUTE_TRFC_VER001) AS V_ROUTE_TRFC_ROWS FROM DUAL;
|
||||||
|
SELECT (SELECT COUNT(*) FROM TROAD_APP.V_ACDT_BRNWS_VER001) AS V_ACDT_BRNWS_ROWS FROM DUAL;
|
||||||
|
SELECT (SELECT COUNT(*) FROM TLISDEV.T_TRMB_CD_INFO01M1) AS T_TRMB_CD_INFO_ROWS FROM DUAL;
|
||||||
|
EXIT
|
||||||
|
EOSQL
|
||||||
|
"
|
||||||
|
|
||||||
|
log "완료"
|
||||||
+9353
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
|||||||
|
"ROUTECD","GRPID","BOUND","ROADNM","ROUTESORT","ROADSHORTNO","BOUNDNM","INCIDENT_ID","INCI_TP_ORDER","INCI_TP","MSG","INCIDENT_POS_NAME","OCRN_DSTNC","CNGS_LNGT","LAT","LON","CCTV_ID","CCTV_NM","THUMBIMAGE","HLS_URL","ST_D","EN_D","VVALUE01","VVALUE02","VVALUE03","VVALUE04","VVALUE05","CRCM_TIME","CRCM_MSG"
|
||||||
|
"4004","1",S,수도권제2순환선(화성-광주),"5","400",화성방향,"20260521143800","03",작업,K (2차로) 비탈면보수 작업중 (14시 38분부터),동탄방향 26.0,"0","0","0","0",cctv00007433,동탄JC,https://exmobile4.hscdn.com/cctv7433image/ch00007433_20260730.154600.000.jpg,https://live18.exmobile.hscdn.com/exlive/cctv7433.stream/playlist.m3u8,0,0, , , , , ,(14시 38분부터),K (2차로) 비탈면보수 작업중
|
||||||
|
"0650","1",E,동해선(삼척-속초),"6","65",속초방향,"20260703074200","03",작업,(2차로)졸음쉼터 설치 작업중 (07시 42분부터),쇄운교(15K)-지흥1교(16.7K),"15",-1,"37.486292","129.090703",cctv00005829,쇄운교,https://exmobile4.hscdn.com/cctv5829image/ch00005829_20260730.154600.000.jpg,https://live7.exmobile.hscdn.com/exlive/cctv5829.stream/playlist.m3u8,15,15, , , , , ,(07시 42분부터),(2차로)졸음쉼터 설치 작업중
|
||||||
|
"0652","1",E,동해선(부산-포항),"6","65",포항방향,"20260720082502","03",작업,"(2차로)노면보강 공사 작업중, 장기차단 (08시 25분부터)",남경주부근(68K)-문무대왕1터널(74K),"68",-1,"35.724019","129.296973",cctv00005797,냉천3교,https://exmobile8.hscdn.com/cctv5797image/ch00005797_20260730.154600.000.jpg,https://live17.exmobile.hscdn.com/exlive/cctv5797.stream/playlist.m3u8,68,68, , , , , ,(08시 25분부터),"(2차로)노면보강 공사 작업중, 장기차단 "
|
||||||
|
"4004","1",S,수도권제2순환선(화성-광주),"5","400",화성방향,"20260723135200","03",작업,null (13시 52분부터),동탄방향 9.8,"0","0","0","0",cctv00007433,동탄JC,https://exmobile4.hscdn.com/cctv7433image/ch00007433_20260730.154600.000.jpg,https://live18.exmobile.hscdn.com/exlive/cctv7433.stream/playlist.m3u8,0,0, , , , , ,(13시 52분부터),null
|
||||||
|
"1100","1",S,제2경인선,"6","110",인천방향,"20260730065400","04",정체, (06시 54분부터),서창분기점(9K)-남동부근(6K),"9","3","37.433276","126.729185",cctv00000762,서창분기점,https://exmobile8.hscdn.com/cctv0762image/ch00000762_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0762.stream/playlist.m3u8,9,9, , , , , ,(06시 54분부터),
|
||||||
|
"0150","1",E,서해안선,"2","15",서울방향,"20260730065451","04",정체, (06시 54분부터),광명역(334K)-금천(340K),"334","6","37.407933","126.88693",cctv00000215,충훈대교,https://exmobile8.hscdn.com/cctv0215image/ch00000215_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0215.stream/playlist.m3u8,334,334, , , , , ,(06시 54분부터),
|
||||||
|
"1000","1",S,수도권제1순환선,"5","100",일산방향,"20260730072448","04",정체, (07시 24분부터),시흥요금소(96K)-중동(86K),"96","10","37.449284","126.805207",cctv00002060,시흥TG_일산,https://exmobile4.hscdn.com/cctv2060image/ch00002060_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv2060.stream/playlist.m3u8,96,96, , , , , ,(07시 24분부터),
|
||||||
|
"0351","1",S,통영대전선,"6","35",통영방향,"20260730081231","03",작업,(갓길) 시설물 보수 작업중 (08시 12분부터),오동터널부근(132K),"132",-1,"35.707033","127.624994",cctv00002182,오동2교,https://exmobile4.hscdn.com/cctv2182image/ch00002182_20260730.154600.000.jpg,https://live8.exmobile.hscdn.com/exlive/cctv2182.stream/playlist.m3u8,132,0, , , , , ,(08시 12분부터),(갓길) 시설물 보수 작업중
|
||||||
|
"0252","1",S,논산천안선,"6","25",논산방향,"20260730082406","04",정체,"3km 정체 (08시 24분부터)",차령터널 무학천교(266.0K)-차령터널 (263.0K),"269","0","36.72055","127.13463",cctv00007136,호정1교,https://exmobile4.hscdn.com/cctv7136image/ch00007136_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv7136.stream/playlist.m3u8,269,269, , , , , ,(08시 24분부터),"3km 정체"
|
||||||
|
"0201","1",S,익산장수선,"6","20",익산방향,"20260730084122","03",작업,(갓길) 덩쿨제거 작업중 (08시 41분부터),소양(16K)-소양부근(15K),"16",-1,"35.865021","127.230784",cctv00003867,소양,https://exmobile8.hscdn.com/cctv3867image/ch00003867_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv3867.stream/playlist.m3u8,16,16, , , , , ,(08시 41분부터),(갓길) 덩쿨제거 작업중
|
||||||
|
"0450","1",S,중부내륙선,"6","45",창원방향,"20260730094639","04",정체, (09시 46분부터),감곡부근(258K)-감곡부근(255K),"258","3","37.172225","127.622368",cctv00003204,삼승교,https://exmobile4.hscdn.com/cctv3204image/ch00003204_20260730.154600.000.jpg,https://live10.exmobile.hscdn.com/exlive/cctv3204.stream/playlist.m3u8,258,258, , , , , ,(09시 46분부터),
|
||||||
|
"0100","1",E,남해선(순천-부산),"6","10",부산방향,"20260730103250","04",정체, (10시 32분부터),함안2터널부근(119K)-함안2터널부근(120K),"119","1","35.288699","128.542006",cctv00000560,함안2터널(부산외부),https://exmobile4.hscdn.com/cctv0560image/ch00000560_20260730.154600.000.jpg,https://live13.exmobile.hscdn.com/exlive/cctv0560.stream/playlist.m3u8,119,119, , , , , ,(10시 32분부터),
|
||||||
|
"0252","1",S,논산천안선,"6","25",논산방향,"20260728140304","04",정체,"5km 정체 (14시 03분부터)",남풍세IC 호정 1교(268.0K)-차령터널 (263.0K),"269","0","36.72055","127.13463",cctv00007136,호정1교,https://exmobile4.hscdn.com/cctv7136image/ch00007136_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv7136.stream/playlist.m3u8,269,269, , , , , ,(14시 03분부터),"5km 정체"
|
||||||
|
"1000","1",E,수도권제1순환선,"5","100",구리방향,"20260730051106","04",정체, (05시 11분부터),노오지분기점(79K)-송내(88K),"79","9","37.570368","126.753178",cctv00000227,노오지분기점,https://exmobile4.hscdn.com/cctv0227image/ch00000227_20260730.154600.000.jpg,https://live15.exmobile.hscdn.com/exlive/cctv0227.stream/playlist.m3u8,79,79, , , , , ,(05시 11분부터),
|
||||||
|
"0010","1",E,경부선,"1","1",서울방향,"20260730062713","04",정체, (06시 27분부터),양재부근(415K)-반포(420K),"415","5","37.456747","127.046344",cctv00000002,양재,https://exmobile4.hscdn.com/cctv0002image/ch00000002_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0002.stream/playlist.m3u8,415,415, , , , , ,(06시 27분부터),
|
||||||
|
"0010","1",S,경부선,"1","1",부산방향,"20260730105038","04",정체, (10시 50분부터),천안분기점부근(332K)-천안호두(휴)(324K),"332","8","36.766668","127.196939",cctv00003848,응원고개,https://exmobile4.hscdn.com/cctv3848image/ch00003848_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv3848.stream/playlist.m3u8,332,332, , , , , ,(10시 50분부터),
|
||||||
|
"0450","1",E,중부내륙선,"6","45",양평방향,"20260730132759","04",정체, (13시 27분부터),충주분기점부근(238K)-충주분기점부근(241K),"238","3","37.041776","127.75111",cctv00003209,한포천,https://exmobile4.hscdn.com/cctv3209image/ch00003209_20260730.154600.000.jpg,https://live10.exmobile.hscdn.com/exlive/cctv3209.stream/playlist.m3u8,238,238, , , , , ,(13시 27분부터),
|
||||||
|
"0100","1",E,남해선(순천-부산),"6","10",부산방향,"20260730134538","04",정체, (13시 45분부터),대저분기점(163K)-덕천(166K),"163","3","35.219275","128.969671",cctv00003930,대저,https://exmobile4.hscdn.com/cctv3930image/ch00003930_20260730.154600.000.jpg,https://live15.exmobile.hscdn.com/exlive/cctv3930.stream/playlist.m3u8,163,163, , , , , ,(13시 45분부터),
|
||||||
|
"1100","1",E,제2경인선,"6","110",성남방향,"20260730135457","04",정체, (13시 54분부터),학익분기점(3K)-남동(8K),"3","5","37.438267","126.662356",cctv00001535,학익대교1,https://exmobile4.hscdn.com/cctv1535image/ch00001535_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv1535.stream/playlist.m3u8,3,3, , , , , ,(13시 54분부터),
|
||||||
|
"0500","1",S,영동선,"4","50",인천방향,"20260730135951","04",정체, (13시 59분부터),군자분기점(7K)-월곶분기점부근(4K),"7","3","37.382693","126.762417",cctv00000854,군자분기점,https://exmobile4.hscdn.com/cctv0854image/ch00000854_20260730.154600.000.jpg,https://live2.exmobile.hscdn.com/exlive/cctv0854.stream/playlist.m3u8,7,7, , , , , ,(13시 59분부터),
|
||||||
|
"0150","1",E,서해안선,"2","15",서울방향,"20260730140943","04",정체, (14시 09분부터),서평택분기점부근(295K)-화성(휴)부근(303K),"295","8","37.08446","126.886438",cctv00000054,상신2교,https://exmobile4.hscdn.com/cctv0054image/ch00000054_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0054.stream/playlist.m3u8,295,295, , , , , ,(14시 09분부터),
|
||||||
|
"0150","1",E,서해안선,"2","15",서울방향,"20260730141000","04",정체, (14시 10분부터),매송(휴)부근(315K)-용담터널(319K),"315","4","37.260631","126.887041",cctv00002409,야목2교,https://exmobile8.hscdn.com/cctv2409image/ch00002409_20260730.154600.000.jpg,https://live3.exmobile.hscdn.com/exlive/cctv2409.stream/playlist.m3u8,315,315, , , , , ,(14시 10분부터),
|
||||||
|
"0352","1",S,중부선,"3","35",남이방향,"20260730141034","04",정체, (14시 10분부터),진천터널부근(277K)-진천터널부근(274K),"277","3","36.835086","127.494366",cctv00003845,백곡천교,https://exmobile8.hscdn.com/cctv3845image/ch00003845_20260730.154600.000.jpg,https://live9.exmobile.hscdn.com/exlive/cctv3845.stream/playlist.m3u8,277,277, , , , , ,(14시 10분부터),
|
||||||
|
"0202","1",E,새만금전주선,"6","202",새만금방향,"20260730141437","01",기타,(갓길)소형화물차 고장 처리중 (14시 14분부터),석구터널(46.1K),"46.1",-1,"35.773544","127.153308",cctv00002613,원은육교2,https://exmobile4.hscdn.com/cctv2613image/ch00002613_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv2613.stream/playlist.m3u8,46.1,0, , , , , ,(14시 14분부터),(갓길)소형화물차 고장 처리중
|
||||||
|
"0500","1",S,영동선,"4","50",인천방향,"20260730142623","04",정체, (14시 26분부터),동수원(37K)-북수원(30K),"37","7","37.299117","127.051361",cctv00002415,동수원,https://exmobile4.hscdn.com/cctv2415image/ch00002415_20260730.154500.000.jpg,https://live3.exmobile.hscdn.com/exlive/cctv2415.stream/playlist.m3u8,37,37, , , , , ,(14시 26분부터),
|
||||||
|
"0010","1",E,경부선,"1","1",서울방향,"20260730143713","04",정체, (14시 37분부터),안성분기점(364K)-안성(휴)부근(368K),"364","4","37.028613","127.140833",cctv00000037,안성분기점2,https://exmobile8.hscdn.com/cctv0037image/ch00000037_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv0037.stream/playlist.m3u8,364,364, , , , , ,(14시 37분부터),
|
||||||
|
"1100","1",S,제2경인선,"6","110",인천방향,"20260730143718","04",정체, (14시 37분부터),삼막(25.98K)-광명터널(22K),"25.98","4","37.425507","126.912049",cctv00000767,석수,https://exmobile8.hscdn.com/cctv0767image/ch00000767_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0767.stream/playlist.m3u8,25.98,25.98, , , , , ,(14시 37분부터),
|
||||||
|
"0651","1",S,부산울산선,"6","65",부산방향,"20260730144311","04",정체, (14시 43분부터),해운대터널부근(3K)-부산울산선시점(0K),"3","3","35.190683","129.201783",cctv00000728,고래진2교,https://exmobile8.hscdn.com/cctv0728image/ch00000728_20260730.154600.000.jpg,https://live17.exmobile.hscdn.com/exlive/cctv0728.stream/playlist.m3u8,3,3, , , , , ,(14시 43분부터),
|
||||||
|
"0010","1",E,경부선,"1","1",서울방향,"20260730144715","00",사고,"(3차로,갓길)화물차관련 사고 처리중 (14시 47분부터)",영천분기점(91.5K),"91.5",-1,"35.924733","128.998642",cctv00000819,반정1교,https://exmobile4.hscdn.com/cctv0819image/ch00000819_20260730.154600.000.jpg,https://live10.exmobile.hscdn.com/exlive/cctv0819.stream/playlist.m3u8,91.5,0, , , , , ,(14시 47분부터),"(3차로,갓길)화물차관련 사고 처리중"
|
||||||
|
"1000","1",E,수도권제1순환선,"5","100",구리방향,"20260730145917","04",정체, (14시 59분부터),자유로(72K)-김포(74K),"72","2","37.618882","126.799826",cctv00000224,자유로분기점,https://exmobile4.hscdn.com/cctv0224image/ch00000224_20260730.154600.000.jpg,https://live15.exmobile.hscdn.com/exlive/cctv0224.stream/playlist.m3u8,72,72, , , , , ,(14시 59분부터),
|
||||||
|
"0400","1",S,평택제천선,"6","40",평택방향,"20260730150604","04",정체, (15시 06분부터),서안성(25K)-안성분기점(24K),"25","1","37.036583","127.153094",cctv00005947,강문교,https://exmobile4.hscdn.com/cctv5947image/ch00005947_20260730.154600.000.jpg,https://live14.exmobile.hscdn.com/exlive/cctv5947.stream/playlist.m3u8,25,25, , , , , ,(15시 06분부터),
|
||||||
|
"1200","1",S,경인선,"6","120",인천방향,"20260730150911","04",정체, (15시 09분부터),인천요금소(16K)-서인천(11K),"16","5","37.523954","126.742937",cctv00005038,인천영업소,https://exmobile8.hscdn.com/cctv5038image/ch00005038_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv5038.stream/playlist.m3u8,16,16, , , , , ,(15시 09분부터),
|
||||||
|
"0010","1",E,경부선,"1","1",서울방향,"20260730152029","04",정체, (15시 20분부터),입장거봉포도(휴)부근(355K)-안성(360K),"355","5","36.955513","127.181906",cctv00003102,연곡,https://exmobile8.hscdn.com/cctv3102image/ch00003102_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv3102.stream/playlist.m3u8,355,355, , , , , ,(15시 20분부터),
|
||||||
|
"1200","1",E,경인선,"6","120",서울방향,"20260730152128","04",정체, (15시 21분부터),신월(23K)-신월(24K),"23","1","37.523394","126.821631",cctv00001451,신월-1,https://exmobile4.hscdn.com/cctv1451image/ch00001451_20260730.154600.000.jpg,https://live8.exmobile.hscdn.com/exlive/cctv1451.stream/playlist.m3u8,23,23, , , , , ,(15시 21분부터),
|
||||||
|
"1040","1",E,남해2지선,"6","104",서부산방향,"20260730152500","04",정체, (15시 25분부터),서부산(휴)(18K)-사상(20K),"18","2","35.156477","128.948907",cctv00003718,서부산,https://exmobile4.hscdn.com/cctv3718image/ch00003718_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv3718.stream/playlist.m3u8,18,18, , , , , ,(15시 25분부터),
|
||||||
|
"0010","1",S,경부선,"1","1",부산방향,"20260730152539","01",기타,(갓길) 승용 고장차 처리중 (15시 25분부터),청주분기점(297K),"297",-1,"36.568675","127.429435",cctv00002129,청주분기점2,https://exmobile4.hscdn.com/cctv2129image/ch00002129_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv2129.stream/playlist.m3u8,297,0, , , , , ,(15시 25분부터),(갓길) 승용 고장차 처리중
|
||||||
|
"0252","1",E,논산천안선,"6","25",천안방향,"20260730152731","04",정체,"3km 정체 (15시 27분부터)",남공주IC 오룡교(232.0K)-남공주IC 검상천교(235.0K),"225","0","36.34541","127.06794",cctv00007164,이인SA/남,https://exmobile4.hscdn.com/cctv7164image/ch00007164_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv7164.stream/playlist.m3u8,225,225, , , , , ,(15시 27분부터),"3km 정체"
|
||||||
|
"6000","1",S,부산외곽선,"6","600",창원방향,"20260730152946","04",정체, (15시 29분부터),기장분기점(48K)-기장분기점부근(47K),"48","1","35.281987","129.2089",cctv00000517,용천교,https://exmobile4.hscdn.com/cctv0517image/ch00000517_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv0517.stream/playlist.m3u8,48,48, , , , , ,(15시 29분부터),
|
||||||
|
"1300","1",S,인천공항선,"6","130",공항방향,"20260730153000","04",정체,청라IC 진출 1km 정체 (15시 30분부터),[본선-공항] 20.8Km,"20.8","0","37.569859","126.670011",cctv00007097,인천공항영업소,https://exmobile4.hscdn.com/cctv7097image/ch00007097_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv7097.stream/playlist.m3u8,20.8,20.8, , , , , ,(15시 30분부터),청라IC 진출 1km 정체
|
||||||
|
"1000","1",S,수도권제1순환선,"5","100",일산방향,"20260730153338","04",정체, (15시 33분부터),안양터널(114K)-수리터널(112K),"114","2","37.37919","126.946985",cctv00000292,안양터널,https://exmobile4.hscdn.com/cctv0292image/ch00000292_20260730.154600.000.jpg,https://live15.exmobile.hscdn.com/exlive/cctv0292.stream/playlist.m3u8,114,114, , , , , ,(15시 33분부터),
|
||||||
|
"0500","1",S,영동선,"4","50",인천방향,"20260730153400","04",정체, (15시 34분부터),덕평부근(66K)-양지터널부근(58K),"66","8","37.250668","127.352923",cctv00000371,오천교,https://exmobile8.hscdn.com/cctv0371image/ch00000371_20260730.154600.000.jpg,https://live16.exmobile.hscdn.com/exlive/cctv0371.stream/playlist.m3u8,66,66, , , , , ,(15시 34분부터),
|
||||||
|
"2510","1",S,호남지선,"6","251",논산방향,"20260730154509","04",정체, (15시 45분부터),회덕분기점(54K)-북대전부근(52K),"54","2","0","0",cctv00000297,전민,https://exmobile4.hscdn.com/cctv0297image/ch00000297_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv0297.stream/playlist.m3u8,54,54, , , , , ,(15시 45분부터),
|
||||||
|
"0400","1",S,평택제천선,"6","40",평택방향,"20260730155518","04",정체, (15시 55분부터),대소분기점(57K)-안진터널(52K),"57","5","36.941808","127.463959",cctv00003794,대소분기점,https://exmobile4.hscdn.com/cctv3794image/ch00003794_20260730.154600.000.jpg,https://live14.exmobile.hscdn.com/exlive/cctv3794.stream/playlist.m3u8,57,57, , , , , ,(15시 55분부터),
|
||||||
|
"0600","1",S,서울양양선,"6","60",서울방향,"20260730155707","04",정체, (15시 57분부터),화도(15K)-화도부근(13K),"15","2","37.63154","127.312837",cctv00000400,화도영업소,https://exmobile8.hscdn.com/cctv0400image/ch00000400_20260730.154600.000.jpg,https://live17.exmobile.hscdn.com/exlive/cctv0400.stream/playlist.m3u8,15,15, , , , , ,(15시 57분부터),
|
||||||
|
"0010","1",E,경부선,"1","1",서울방향,"20260730160049","04",정체,(순환선 진출로) (16시 00분부터),판교분기점(408K),"408","1","37.406461","127.09392",cctv00000006,판교분기점_경부,https://exmobile4.hscdn.com/cctv0006image/ch00000006_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0006.stream/playlist.m3u8,408,0, , , , , ,(16시 00분부터),(순환선 진출로)
|
||||||
|
"0251","1",E,호남선,"6","25",천안방향,"20260730160618","04",정체,교통량 증가 (16시 06분부터),동광주(74K),"74","1","35.183438","126.926925",cctv00003382,동광주,https://exmobile4.hscdn.com/cctv3382image/ch00003382_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv3382.stream/playlist.m3u8,74,0, , , , , ,(16시 06분부터),교통량 증가
|
||||||
|
"1000","1",E,수도권제1순환선,"5","100",구리방향,"20260730160627","04",정체, (16시 06분부터),조남분기점(107K)-수암터널(108K),"107","1","37.368655","126.869846",cctv00000238,조남분기점,https://exmobile4.hscdn.com/cctv0238image/ch00000238_20260730.154600.000.jpg,https://live15.exmobile.hscdn.com/exlive/cctv0238.stream/playlist.m3u8,107,107, , , , , ,(16시 06분부터),
|
||||||
|
"0352","1",E,중부선,"3","35",하남방향,"20260730160933","04",정체, (16시 09분부터),일죽부근(304K)-일죽부근(309K),"304","5","37.070051","127.468948",cctv00000667,장암1,https://exmobile4.hscdn.com/cctv0667image/ch00000667_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv0667.stream/playlist.m3u8,304,304, , , , , ,(16시 09분부터),
|
||||||
|
"0500","1",S,영동선,"4","50",인천방향,"20260730161003","04",정체, (16시 10분부터),서창분기점(1K)-서창(0K),"1","1","37.428961","126.737875",cctv00005669,서창,https://exmobile8.hscdn.com/cctv5669image/ch00005669_20260730.154600.000.jpg,https://live16.exmobile.hscdn.com/exlive/cctv5669.stream/playlist.m3u8,1,1, , , , , ,(16시 10분부터),
|
||||||
|
"0450","1",E,중부내륙선,"6","45",양평방향,"20260730161104","01",기타,(갓길)승합차고장 처리중 (16시 11분부터),감곡부근(252.1K),"252.1",-1,"37.129423","127.66049",cctv00005386,상우1교,https://exmobile8.hscdn.com/cctv5386image/ch00005386_20260730.154600.000.jpg,https://live14.exmobile.hscdn.com/exlive/cctv5386.stream/playlist.m3u8,252.1,0, , , , , ,(16시 11분부터),(갓길)승합차고장 처리중
|
||||||
|
"0150","1",E,서해안선,"2","15",서울방향,"20260730161342","01",기타,(갓길)중형화물차 고장 처리중 (16시 13분부터),서천(휴)부근(166.5K),"166.5",-1,"36.119755","126.636626",cctv00002043,종천1교,https://exmobile4.hscdn.com/cctv2043image/ch00002043_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv2043.stream/playlist.m3u8,166.5,0, , , , , ,(16시 13분부터),(갓길)중형화물차 고장 처리중
|
||||||
|
"0500","1",S,영동선,"4","50",인천방향,"20260730161727","04",정체, (16시 17분부터),둔대분기점(23K)-반월터널부근(21K),"23","2","37.322581","126.907065",cctv00005041,둔대분기점,https://exmobile8.hscdn.com/cctv5041image/ch00005041_20260730.154600.000.jpg,https://live16.exmobile.hscdn.com/exlive/cctv5041.stream/playlist.m3u8,23,23, , , , , ,(16시 17분부터),
|
||||||
|
"0270","1",E,순천완주선,"6","27",완주방향,"20260730161748","01",기타,(갓길) 화물차 고장 처리중 (16시 17분부터),서면2터널부근(10.7K),"10.7",-1,"35.028166","127.507502",cctv00005578,서면2터널(완주외부1),https://exmobile8.hscdn.com/cctv5578image/ch00005578_20260730.154600.000.jpg,https://live14.exmobile.hscdn.com/exlive/cctv5578.stream/playlist.m3u8,10.7,0, , , , , ,(16시 17분부터),(갓길) 화물차 고장 처리중
|
||||||
|
"0160","1",E,울산선,"6","16",울산방향,"20260730161750","01",기타,(갓길)화물차 고장처리 중 (16시 17분부터),범서하이패스(10.3K),"10.3",-1,"35.570555","129.227118",cctv00005346,입암,https://exmobile4.hscdn.com/cctv5346image/ch00005346_20260730.154600.000.jpg,https://live14.exmobile.hscdn.com/exlive/cctv5346.stream/playlist.m3u8,10.3,0, , , , , ,(16시 17분부터),(갓길)화물차 고장처리 중
|
||||||
|
"0500","1",S,영동선,"4","50",인천방향,"20260730161757","04",정체,진출로 (16시 17분부터),서용인분기점(50K),"50","1","37.268988","127.186046",cctv00000363,마성터널(강릉),https://exmobile8.hscdn.com/cctv0363image/ch00000363_20260730.154600.000.jpg,https://live16.exmobile.hscdn.com/exlive/cctv0363.stream/playlist.m3u8,50,0, , , , , ,(16시 17분부터),진출로
|
||||||
|
"0150","1",E,서해안선,"2","15",서울방향,"20260730161803","01",기타,(갓길) 화물 고장차 처리중 (16시 18분부터),당진부근(267.3K),"267.3",-1,"36.906553","126.733865",cctv00000626,영천교(고정),https://exmobile4.hscdn.com/cctv0626image/ch00000626_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv0626.stream/playlist.m3u8,267.3,0, , , , , ,(16시 18분부터),(갓길) 화물 고장차 처리중
|
||||||
|
"0550","2",S,중앙선,"6","55",부산방향,"20260730161902","04",정체, (16시 19분부터),초정(5K)-삼락(0K),"5","5","35.235254","128.980641",cctv00003672,초정,https://exmobile8.hscdn.com/cctv3672image/ch00003672_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv3672.stream/playlist.m3u8,5,5, , , , , ,(16시 19분부터),
|
||||||
|
"0500","1",E,영동선,"4","50",강릉방향,"20260730161916","04",정체, (16시 19분부터),둔대분기점(22K)-부곡(27K),"22","5","37.322957","126.895948",cctv00000220,둔대교,https://exmobile8.hscdn.com/cctv0220image/ch00000220_20260730.154600.000.jpg,https://live2.exmobile.hscdn.com/exlive/cctv0220.stream/playlist.m3u8,22,22, , , , , ,(16시 19분부터),
|
||||||
|
"0252","1",E,논산천안선,"6","25",천안방향,"20260730162057","00",사고,"1차로 승용차 관련 사고발생 (16시 20분부터)",남공주IC 오룡교(232.1K),"225","0","36.34541","127.06794",cctv00007164,이인SA/남,https://exmobile4.hscdn.com/cctv7164image/ch00007164_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv7164.stream/playlist.m3u8,225,225, , , , , ,(16시 20분부터),"1차로 승용차 관련 사고발생"
|
||||||
|
"1000","1",S,수도권제1순환선,"5","100",일산방향,"20260730162117","04",정체, (16시 21분부터),성남부근(3K)-판교분기점(0K),"3","3","37.416928","127.122446",cctv00005932,성남삼평교2,https://exmobile4.hscdn.com/cctv5932image/ch00005932_20260730.154600.000.jpg,https://live5.exmobile.hscdn.com/exlive/cctv5932.stream/playlist.m3u8,3,3, , , , , ,(16시 21분부터),
|
||||||
|
"1000","1",S,수도권제1순환선,"5","100",일산방향,"20260730162134","04",정체, (16시 21분부터),판교분기점(128K)-판교분기점부근(126K),"128","2","37.405686","127.094436",cctv00005666,금토,https://exmobile8.hscdn.com/cctv5666image/ch00005666_20260730.154600.000.jpg,https://live11.exmobile.hscdn.com/exlive/cctv5666.stream/playlist.m3u8,128,128, , , , , ,(16시 21분부터),
|
||||||
|
"1000","1",S,수도권제1순환선,"5","100",일산방향,"20260730162214","04",정체, (16시 22분부터),서하남분기점(16K)-송파부근(7K),"16","9","37.515281","127.169685",cctv00000251,광암터널2,https://exmobile4.hscdn.com/cctv0251image/ch00000251_20260730.154600.000.jpg,https://live15.exmobile.hscdn.com/exlive/cctv0251.stream/playlist.m3u8,16,16, , , , , ,(16시 22분부터),
|
||||||
|
"0600","1",S,서울양양선,"6","60",서울방향,"20260730162324","04",정체, (16시 23분부터),덕소삼패(3K)-강일(0K),"3","3","37.587067","127.199448",cctv00000427,미사대교종점,https://exmobile8.hscdn.com/cctv0427image/ch00000427_20260730.154600.000.jpg,https://live17.exmobile.hscdn.com/exlive/cctv0427.stream/playlist.m3u8,3,3, , , , , ,(16시 23분부터),
|
||||||
|
"0450","1",E,중부내륙선,"6","45",양평방향,"20260730162343","04",정체, (16시 23분부터),감곡(251K)-감곡부근(255K),"251","4","37.124313","127.670833",cctv00003206,감곡,https://exmobile4.hscdn.com/cctv3206image/ch00003206_20260730.154600.000.jpg,https://live10.exmobile.hscdn.com/exlive/cctv3206.stream/playlist.m3u8,251,251, , , , , ,(16시 23분부터),
|
||||||
|
"1000","1",E,수도권제1순환선,"5","100",구리방향,"20260730162344","04",정체, (16시 23분부터),강일(24K)-구리남양주요금소(27K),"24","3","37.566883","127.170658",cctv00000143,강일육교,https://exmobile8.hscdn.com/cctv0143image/ch00000143_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0143.stream/playlist.m3u8,24,24, , , , , ,(16시 23분부터),
|
||||||
|
"1100","1",E,제2경인선,"6","110",성남방향,"20260730162409","04",정체, (16시 24분부터),안현분기점(17K)-안현분기점(18K),"17","1","37.437119","126.816192",cctv00001536,안현분기점1,https://exmobile4.hscdn.com/cctv1536image/ch00001536_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv1536.stream/playlist.m3u8,17,17, , , , , ,(16시 24분부터),
|
||||||
|
"0010","1",S,경부선,"1","1",부산방향,"20260730163326","04",정체, (16시 33분부터),회덕분기점(277K)-회덕분기점부근(276K),"277","1","36.396149","127.419059",cctv00000873,신대철교,https://exmobile4.hscdn.com/cctv0873image/ch00000873_20260730.154600.000.jpg,https://live4.exmobile.hscdn.com/exlive/cctv0873.stream/playlist.m3u8,277,277, , , , , ,(16시 33분부터),
|
||||||
|
"0270","1",E,순천완주선,"6","27",완주방향,"20260730163357","03",작업,(갓길) 노면보수 작업중 (16시 33분부터),황전(25.4K),"25.4",-1,"35.149569","127.455096",cctv00001436,황전,https://exmobile8.hscdn.com/cctv1436image/ch00001436_20260730.154600.000.jpg,https://live14.exmobile.hscdn.com/exlive/cctv1436.stream/playlist.m3u8,25.4,0, , , , , ,(16시 33분부터),(갓길) 노면보수 작업중
|
||||||
|
"0500","1",S,영동선,"4","50",인천방향,"20260730163548","04",정체, (16시 35분부터),이천부근(82K)-호법분기점부근(75K),"82","7","37.242627","127.522886",cctv00000359,가산리,https://exmobile4.hscdn.com/cctv0359image/ch00000359_20260730.154600.000.jpg,https://live16.exmobile.hscdn.com/exlive/cctv0359.stream/playlist.m3u8,82,82, , , , , ,(16시 35분부터),
|
||||||
|
"0352","1",E,중부선,"3","35",하남방향,"20260730164203","04",정체, (16시 42분부터),경기광주IC(352K)-중부1터널부근(355K),"352","3","37.447946","127.269718",cctv00000267,광주,https://exmobile4.hscdn.com/cctv0267image/ch00000267_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0267.stream/playlist.m3u8,352,352, , , , , ,(16시 42분부터),
|
||||||
|
"0600","1",S,서울양양선,"6","60",서울방향,"20260730164308","01",기타,(갓길) 승용차 고장 처리중 (16시 43분부터),남춘천부근(53.6K),"53.6",-1,"37.745234","127.694504",cctv00000172,행촌2교,https://exmobile4.hscdn.com/cctv0172image/ch00000172_20260730.154600.000.jpg,https://live17.exmobile.hscdn.com/exlive/cctv0172.stream/playlist.m3u8,53.6,0, , , , , ,(16시 43분부터),(갓길) 승용차 고장 처리중
|
||||||
|
"0500","1",E,영동선,"4","50",강릉방향,"20260730164416","00",사고,(인천 진출로)사고 처리중 (16시 44분부터),서창분기점(0.5K),.5,-1,"37.433432","126.738571",cctv00005927,서창JC,https://exmobile4.hscdn.com/cctv5927image/ch00005927_20260730.154600.000.jpg,https://live8.exmobile.hscdn.com/exlive/cctv5927.stream/playlist.m3u8,0.5,0, , , , , ,(16시 44분부터),(인천 진출로)사고 처리중
|
||||||
|
"0500","1",S,영동선,"4","50",인천방향,"20260730164625","01",기타,(2차로)고장차 처리중 (16시 46분부터),월곶분기점부근(6.3K),"6.3",-1,"37.386135","126.755797",cctv00000336,월곶,https://exmobile4.hscdn.com/cctv0336image/ch00000336_20260730.154600.000.jpg,https://live16.exmobile.hscdn.com/exlive/cctv0336.stream/playlist.m3u8,6.3,0, , , , , ,(16시 46분부터),(2차로)고장차 처리중
|
||||||
|
"0351","1",S,통영대전선,"6","35",통영방향,"20260730164648","01",기타,"(2차로,갓길)승용차 고장 처리중 (16시 46분부터)",마달터널부근(202.5K),"202.5",-1,"36.248086","127.474032",cctv00000463,공주교,https://exmobile8.hscdn.com/cctv0463image/ch00000463_20260730.154600.000.jpg,https://live17.exmobile.hscdn.com/exlive/cctv0463.stream/playlist.m3u8,202.5,0, , , , , ,(16시 46분부터),"(2차로,갓길)승용차 고장 처리중"
|
||||||
|
"1000","1",E,수도권제1순환선,"5","100",구리방향,"20260730164727","00",사고,"(3,4차로) 사고 처리중 (16시 47분부터)",자유로(72K),"72","2","37.618882","126.799826",cctv00000224,자유로분기점,https://exmobile4.hscdn.com/cctv0224image/ch00000224_20260730.154600.000.jpg,https://live15.exmobile.hscdn.com/exlive/cctv0224.stream/playlist.m3u8,72,0, , , , , ,(16시 47분부터),"(3,4차로) 사고 처리중"
|
||||||
|
"0010","1",E,경부선,"1","1",서울방향,"20260730164739","04",정체, (16시 47분부터),기흥(388K)-신갈분기점(394K),"388","6","37.228626","127.105739",cctv00000700,보정교,https://exmobile4.hscdn.com/cctv0700image/ch00000700_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv0700.stream/playlist.m3u8,388,388, , , , , ,(16시 47분부터),
|
||||||
|
"0010","1",S,경부선,"1","1",부산방향,"20260730164817","04",정체, (16시 48분부터),신갈분기점부근(397K)-신갈분기점(394K),"397","3","37.309238","127.103578",cctv00000008,죽전,https://exmobile4.hscdn.com/cctv0008image/ch00000008_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv0008.stream/playlist.m3u8,397,397, , , , , ,(16시 48분부터),
|
||||||
|
"0351","1",S,통영대전선,"6","35",통영방향,"20260730165102","01",기타,(갓길)화물차 고장 처리중 (16시 51분부터),동고성(14.3K),"14.3",-1,"34.970155","128.385918",cctv00001582,송산,https://exmobile4.hscdn.com/cctv1582image/ch00001582_20260730.154600.000.jpg,https://live14.exmobile.hscdn.com/exlive/cctv1582.stream/playlist.m3u8,14.3,0, , , , , ,(16시 51분부터),(갓길)화물차 고장 처리중
|
||||||
|
"0400","1",E,평택제천선,"6","40",제천방향,"20260730165135","04",정체, (16시 51분부터),안성분기점(23K)-안성분기점(24K),"23","1","37.034317","127.131112",cctv00000388,안성분기점_평택제천,https://exmobile4.hscdn.com/cctv0388image/ch00000388_20260730.154600.000.jpg,https://live14.exmobile.hscdn.com/exlive/cctv0388.stream/playlist.m3u8,23,23, , , , , ,(16시 51분부터),
|
||||||
|
"0010","1",S,경부선,"1","1",부산방향,"20260730165504","01",기타,(갓길)승용차 고장처리중 (16시 55분부터),동대구분기점(122.5K),"122.5",-1,"35.887948","128.690911",cctv00002300,동대구,https://exmobile8.hscdn.com/cctv2300image/ch00002300_20260730.154600.000.jpg,https://live1.exmobile.hscdn.com/exlive/cctv2300.stream/playlist.m3u8,122.5,0, , , , , ,(16시 55분부터),(갓길)승용차 고장처리중
|
||||||
|
"0600","1",S,서울양양선,"6","60",서울방향,"20260730165618","00",사고,"(2,3차로)승용차관련 사고처리중 (16시 56분부터)",남춘천부근(53.8K),"53.8","3","37.745877","127.696623",cctv00000172,행촌2교,https://exmobile4.hscdn.com/cctv0172image/ch00000172_20260730.154600.000.jpg,https://live17.exmobile.hscdn.com/exlive/cctv0172.stream/playlist.m3u8,53.8,0, , , , , ,(16시 56분부터),"(2,3차로)승용차관련 사고처리중"
|
||||||
|
"0010","1",E,경부선,"1","1",서울방향,"20260730165638","22",기타,(갓길)보행자 조치중 (16시 56분부터),안성(휴)(370K),"370",-1,"37.080963","127.127648",cctv00000097,산하,https://exmobile8.hscdn.com/cctv0097image/ch00000097_20260730.154600.000.jpg,https://live15.exmobile.hscdn.com/exlive/cctv0097.stream/playlist.m3u8,370,0, , , , , ,(16시 56분부터),(갓길)보행자 조치중
|
||||||
|
"1200","1",S,경인선,"6","120",인천방향,"20260730165724","04",정체, (16시 57분부터),부천(20K)-부천(19K),"20","1","37.523066","126.788085",cctv00005937,도당육교,https://exmobile4.hscdn.com/cctv5937image/ch00005937_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv5937.stream/playlist.m3u8,20,20, , , , , ,(16시 57분부터),
|
||||||
|
"0450","1",E,중부내륙선,"6","45",양평방향,"20260730165823","01",기타,(진입로 갓길) 화물차 고장 처리 중 (16시 58분부터),영산(24K),"24",-1,"35.450343","128.508937",cctv00001539,봉산,https://exmobile4.hscdn.com/cctv1539image/ch00001539_20260730.154600.000.jpg,https://live3.exmobile.hscdn.com/exlive/cctv1539.stream/playlist.m3u8,24,0, , , , , ,(16시 58분부터),(진입로 갓길) 화물차 고장 처리 중
|
||||||
|
"0150","1",E,서해안선,"2","15",서울방향,"20260730165846","00",사고,(1차로)사고 처리중 (16시 58분부터),화성(휴)(301.5K),"301.5","1","37.141864","126.880157",cctv00002406,화성휴게소2,https://exmobile8.hscdn.com/cctv2406image/ch00002406_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv2406.stream/playlist.m3u8,301.5,0, , , , , ,(16시 58분부터),(1차로)사고 처리중
|
||||||
|
"1100","1",S,제2경인선,"6","110",인천방향,"20260730170117","04",정체, (17시 01분부터),안현분기점(18K)-신천(14K),"18","4","37.440082","126.826665",cctv00001537,안현분기점2,https://exmobile4.hscdn.com/cctv1537image/ch00001537_20260730.154600.000.jpg,https://live12.exmobile.hscdn.com/exlive/cctv1537.stream/playlist.m3u8,18,18, , , , , ,(17시 01분부터),
|
||||||
|
"0450","1",E,중부내륙선,"6","45",양평방향,"20260730170123","01",기타,(갓길)승용차고장 처리중 (17시 01분부터),여주분기점부근(261K),"261",-1,"37.196645","127.61217",cctv00005146,금당교_중부내륙,https://exmobile8.hscdn.com/cctv5146image/ch00005146_20260730.154600.000.jpg,https://live5.exmobile.hscdn.com/exlive/cctv5146.stream/playlist.m3u8,261,0, , , , , ,(17시 01분부터),(갓길)승용차고장 처리중
|
||||||
|
"2510","1",E,호남지선,"6","251",대전방향,"20260730170212","04",정체, (17시 02분부터),북대전부근(52K)-회덕분기점(54K),"52","2","36.409214","127.399012",cctv00005468,탑립육교,https://exmobile4.hscdn.com/cctv5468image/ch00005468_20260730.154600.000.jpg,https://live7.exmobile.hscdn.com/exlive/cctv5468.stream/playlist.m3u8,52,52, , , , , ,(17시 02분부터),
|
||||||
|
+125
@@ -0,0 +1,125 @@
|
|||||||
|
"ROUTE","ROAD_NO","ROUTE_ID","WEATHER","UPDWNAME","UPDOWN","MILEPOST","CONTENTS","RAISE_TIME","INCIDENT_TYPE","REGION_ID","REGION_NAME","START_MILEPOST","INITIALCHAR","SEQ_NO","INCIDENT_ID","CONGZONE_ID"
|
||||||
|
경인선,120,"12001",,서울방향,E,신월(23K)-신월(24K),"1km정체[2026-07-30 15:21- ]","20260730152128",차량증가,"250000",,"23","1200","120","20260730152128",
|
||||||
|
울산선,16,"01601",,울산방향,E,범서하이패스(10.3K),(갓길)화물차 고장처리 중[2026-07-30 16:17- ],"20260730161750",고장,"700000",,"10.3","0160","16","20260730161750",
|
||||||
|
경인선,120,"12001",,인천방향,S,부천(20K)-부천(19K),"1km정체[2026-07-30 16:57- ]","20260730165724",차량증가,"250000",,"20","1200","120","20260730165724",
|
||||||
|
경부선,1,"00101",,부산방향,S,동대구분기점(122.5K),(갓길)승용차 고장처리중[2026-07-30 16:55- ],"20260730165504",고장,"600000",,"122.5","0010","1","20260730165504",
|
||||||
|
서울양양선,60,"06001",,서울방향,S,남춘천부근(53.8K),"(2,3차로)승용차관련 사고처리중[2026-07-30 16:56- ] ==> 남춘천IC~남춘천IC, 3km정체","20260730165618",사고,"300000",,"53.8","0600","60","20260730165618",
|
||||||
|
통영대전선,35,"03511",,통영방향,S,오동터널부근(132K),(갓길) 시설물 보수 작업중[2026-07-30 08:12- ],"20260730081231",작업,"800000",,"132","0351","35","20260730081231",
|
||||||
|
경부선,1,"00101",,부산방향,S,천안분기점부근(332K)-천안호두(휴)(324K),"8km정체[2026-07-30 10:50- ]","20260730105038",차량증가,"400000",,"332","0010","1","20260730105038",
|
||||||
|
영동선,50,"05001",,인천방향,S,둔대분기점(23K)-반월터널부근(21K),"2km정체[2026-07-30 16:17- ]","20260730161727",차량증가,"250000",,"23","0500","50","20260730161727",
|
||||||
|
청주영덕선,30,"03001",,영덕방향,E,수한터널부근(28K)-탄부터널부근(31K),"3km정체[2026-07-30 17:04- ]","20260730170451",차량증가,"900000",,"28","0300","30","20260730170451",
|
||||||
|
논산천안선,25,"02521",,논산방향,S,차령터널 무학천교(266.0K)-차령터널 (263.0K),"3km 정체[2026-07-30 08:24- ]","20260730082406",차량증가,"400000",,"269","0252","25","20260730082406",
|
||||||
|
경부선,1,"00101",,서울방향,E,양재부근(415K)-반포(420K),"5km정체[2026-07-30 06:27- ]","20260730062713",차량증가,"200000",,"415","0010","1","20260730062713",
|
||||||
|
제2경인선,110,"11001",,성남방향,E,안현분기점(17K)-안현분기점(18K),"1km정체[2026-07-30 16:24- ]","20260730162409",차량증가,"250000",,"17","1100","110","20260730162409",
|
||||||
|
영동선,50,"05001",,인천방향,S,이천부근(82K)-호법분기점부근(75K),"7km정체[2026-07-30 16:35- ]","20260730163548",차량증가,"200000",,"82","0500","50","20260730163548",
|
||||||
|
수도권제1순환선,100,"10001",,판교방향,E,자유로(72K)-김포(74K),"2km정체[2026-07-30 14:59- ]","20260730145917",차량증가,"250000",,"72","1000","100","20260730145917",
|
||||||
|
순천완주선,27,"02701",,완주방향,E,황전(25.4K),(갓길) 노면보수 작업중[2026-07-30 16:33- ],"20260730163357",작업,"500000",,"25.4","0270","27","20260730163357",
|
||||||
|
수도권제1순환선,100,"10001",,일산방향,S,안양터널(114K)-수리터널(112K),"2km정체[2026-07-30 15:33- ]","20260730153338",차량증가,"250000",,"114","1000","100","20260730153338",
|
||||||
|
수도권제2순환선(화성-광주),400,"40041",,화성방향,S,동탄방향 9.8,null[2026-07-23 13:52- ],"20260723135200",작업,"200000",,"0","4004","400","20260723135200",
|
||||||
|
영동선,50,"05001",,인천방향,S,덕평부근(66K)-양지터널부근(58K),"8km정체[2026-07-30 15:34- ]","20260730153400",차량증가,"200000",,"66","0500","50","20260730153400",
|
||||||
|
호남선,25,"02511",,천안방향,E,동광주(74K),"1km정체[2026-07-30 16:06- ]","20260730160618",차량증가,"500000",,"74","0251","25","20260730160618",
|
||||||
|
영동선,50,"05001",,인천방향,S,서용인분기점(50K),"1km정체[2026-07-30 16:17- ]","20260730161757",차량증가,"250000",,"50","0500","50","20260730161757",
|
||||||
|
영동선,50,"05001",,강릉방향,E,둔대분기점(22K)-부곡(27K),"5km정체[2026-07-30 16:19- ]","20260730161916",차량증가,"250000",,"22","0500","50","20260730161916",
|
||||||
|
동해선(부산-포항),65,"06521",,포항방향,E,남경주(69.5K)-문무대왕1터널(74.1K),"** (포항방향 1,2차로교대) 장기차단 보강공사 7.20(월) ~ 9.18(금) **","20260714121717",홍보,"700000",,"69.5","0652","65","20260714121717",
|
||||||
|
제2경인선,110,"11001",,인천방향,S,삼막(25.98K)-광명터널(22K),"4km정체[2026-07-30 14:37- ]","20260730143718",차량증가,"250000",,"25.98","1100","110","20260730143718",
|
||||||
|
중부내륙선,45,"04501",,양평방향,E,여주분기점부근(261K),(갓길)승용차고장 처리중[2026-07-30 17:01- ],"20260730170123",고장,"900000",,"261","0450","45","20260730170123",
|
||||||
|
남해선(순천-부산),10,"01001",,부산방향,E,칠원분기점부근(117K)-함안2터널부근(120K),"3km정체[2026-07-30 10:32- ]","20260730103250",차량증가,"700000",,"117","0100","10","20260730103250",
|
||||||
|
부산외곽선,600,"60001",,창원방향,S,기장분기점(48K)-기장분기점부근(47K),"1km정체[2026-07-30 15:29- ]","20260730152946",차량증가,"700000",,"48","6000","600","20260730152946",
|
||||||
|
호남지선,251,"25101",,논산방향,S,회덕분기점(54K)-북대전부근(52K),"2km정체[2026-07-30 15:45- ]","20260730154509",차량증가,"400000",,"54","2510","251","20260730154509",
|
||||||
|
영동선,50,"05001",,인천방향,S,서창분기점(1K)-서창(0K),"1km정체[2026-07-30 16:10- ]","20260730161003",차량증가,"250000",,"1","0500","50","20260730161003",
|
||||||
|
수도권제1순환선,100,"10001",,판교방향,E,자유로(72K),"(3,4차로) 사고 처리중[2026-07-30 16:47- ] ==> 일산IC~자유로IC, 2km정체","20260730164727",사고,"250000",,"72","1000","100","20260730164727",
|
||||||
|
서울양양선,60,"06001",,서울방향,S,남춘천부근(53.6K),(갓길) 승용차 고장 처리중[2026-07-30 16:43- ],"20260730164308",고장,"300000",,"53.6","0600","60","20260730164308",
|
||||||
|
경부선,1,"00101",,서울방향,E,안성분기점(364K)-안성(휴)부근(368K),"4km정체[2026-07-30 14:37- ]","20260730143713",차량증가,"200000",,"364","0010","1","20260730143713",
|
||||||
|
동해선(포항-영덕),65,"06531",,영덕방향,E, ,** (영덕방향) 30k 영덕분기점 차로 증설 공사중 - 차로 좁아짐 주의(~12월) **,"20260721112431",홍보,"600000",,"0","0653","65","20260721112431",
|
||||||
|
서해안선,15,"01501",,서울방향,E,광명역(334K)-금천(340K),"6km정체[2026-07-30 06:54- ]","20260730065451",차량증가,"250000",,"334","0150","15","20260730065451",
|
||||||
|
통영대전선,35,"03511",,통영방향,S,마달터널부근(202.5K),"(2차로,갓길)승용차 고장 처리중[2026-07-30 16:46- ]","20260730164648",고장,"800000",,"202.5","0351","35","20260730164648",
|
||||||
|
통영대전선,35,"03511",,대전방향,E,진주졸음쉼터(57.3K),** (대전방향) 화장실 이용불가 **,"20260725060945",홍보,"700000",,"57.3","0351","35","20260725060945",
|
||||||
|
경부선,1,"00101",,부산방향,S,신갈분기점부근(397K)-신갈분기점(394K),"3km정체[2026-07-30 16:48- ]","20260730164817",차량증가,"200000",,"397","0010","1","20260730164817",
|
||||||
|
영동선,50,"05001",,강릉방향,E,서창분기점(0.5K),(인천 진출로)사고 처리중[2026-07-30 16:44- ],"20260730164416",사고,"250000",,.5,"0500","50","20260730164416",
|
||||||
|
평택제천선,40,"04001",,제천방향,E,안성분기점(23K)-안성분기점(24K),"1km정체[2026-07-30 16:51- ]","20260730165135",차량증가,"250000",,"23","0400","40","20260730165135",
|
||||||
|
광주대구선,12,"01201",,대구방향,E, ,** (광주방향)112k 남상졸음쉼터 폐쇄(~12월) **,"20260422234627",홍보,"600000",,"0","0120","12","20260422234627",
|
||||||
|
수도권제2순환선(화성-광주),400,"40041",,화성방향,S,동탄방향 26.0,K (2차로) 비탈면보수 작업중[2026-05-21 14:38- ],"20260521143800",작업,"200000",,"0","4004","400","20260521143800",
|
||||||
|
동해선(삼척-속초),65,"06501",,속초방향,E, ,** (속초방향) 동해 졸음쉼터 신설공사 [ ~ 8.13] **,"20260416171758",홍보,"300000",,"0","0650","65","20260416171758",
|
||||||
|
서천공주선,151,"15101",,공주방향,E, ,** 동서천분기점 공주방향 연결로 갓길 장기차단 26.5월~26.10월 **,"20260519074906",홍보,"400000",,"0","1510","151","20260519074906",
|
||||||
|
서해안선,15,"01501",,서울방향,E, ,** 서산(목포)주유소 영업중단(5.6~10.6)/휴게소 및 LPG충전소는 정상영업/행담도주유소 이용바람 **,"20260429135010",홍보,"400000",,"0","0150","15","20260429135010",
|
||||||
|
경부선,1,"00101",,서울방향,E, ,"** (부산)남사졸음쉼터 임시폐쇄(26.06.15~26.10.31),안성휴게소 이용바람 **","20260605215733",홍보,"200000",,"0","0010","1","20260605215733",
|
||||||
|
남해선(순천-부산),10,"01001",,부산방향,E,대저분기점(163K)-덕천(166K),"3km정체[2026-07-30 13:45- ]","20260730134538",차량증가,"700000",,"163","0100","10","20260730134538",
|
||||||
|
부산울산선,65,"06511",,부산방향,S,해운대터널부근(3K)-부산울산선시점(0K),"3km정체[2026-07-30 14:43- ]","20260730144311",차량증가,"700000",,"3","0651","65","20260730144311",
|
||||||
|
경부선,1,"00101",,부산방향,S,청주분기점(297K),(갓길) 승용 고장차 처리중[2026-07-30 15:25- ],"20260730152539",고장,"400000",,"297","0010","1","20260730152539",
|
||||||
|
남해2지선,104,"10401",,서부산방향,E,서부산(휴)(18K)-사상(20K),"2km정체[2026-07-30 15:25- ]","20260730152500",차량증가,"700000",,"18","1040","104","20260730152500",
|
||||||
|
동해선(삼척-속초),65,"06501",,속초방향,E,쇄운교(15K)-지흥1교(16.7K),(2차로)졸음쉼터 설치 작업중[2026-07-03 07:42- ],"20260703074200",작업,"300000",,"15","0650","65","20260703074200",
|
||||||
|
수도권제1순환선,100,"10001",,일산방향,S,시흥요금소(96K)-중동(86K),"10km정체[2026-07-30 07:24- ]","20260730072448",차량증가,"250000",,"96","1000","100","20260730072448",
|
||||||
|
논산천안선,25,"02521",,천안방향,E,남공주IC 오룡교(232.0K)-남공주IC 검상천교(235.0K),"3km 정체[2026-07-30 15:27- ]","20260730152731",차량증가,"400000",,"225","0252","25","20260730152731",
|
||||||
|
인천공항선,130,"13001",,공항방향,S,[본선-공항] 20.8Km,청라IC 진출 1km 정체[2026-07-30 15:30- ],"20260730153000",차량증가,"200000",,"20.8","1300","130","20260730153000",
|
||||||
|
수도권제1순환선,100,"10001",,판교방향,E,조남분기점(107K)-수암터널(108K),"1km정체[2026-07-30 16:06- ]","20260730160627",차량증가,"250000",,"107","1000","100","20260730160627",
|
||||||
|
서울양양선,60,"06001",,서울방향,S,화도(15K)-화도부근(13K),"2km정체[2026-07-30 15:57- ]","20260730155707",차량증가,"300000",,"15","0600","60","20260730155707",
|
||||||
|
경부선,1,"00101",,서울방향,E,영천분기점(91.5K),"(3차로,갓길)화물차관련 사고 처리중[2026-07-30 14:47- ]","20260730144715",사고,"600000",,"91.5","0010","1","20260730144715",
|
||||||
|
서해안선,15,"01501",,서울방향,E,서천(휴)부근(166.5K),(갓길)중형화물차 고장 처리중[2026-07-30 16:13- ],"20260730161342",고장,"800000",,"166.5","0150","15","20260730161342",
|
||||||
|
서해안선,15,"01501",,서울방향,E, ,** 서해대교(양방향) 정밀안전진단 3차로 주간 차단예정(6~10월) **,"20260605085938",홍보,"400000",,"0","0150","15","20260605085938",
|
||||||
|
논산천안선,25,"02521",,천안방향,E,남공주IC 오룡교(232.1K),"1차로 승용차 관련 사고발생[2026-07-30 16:20- ]","20260730162057",사고,"400000",,"225","0252","25","20260730162057",
|
||||||
|
호남지선,251,"25101",,대전방향,E,북대전부근(52K)-회덕분기점(54K),"2km정체[2026-07-30 17:02- ]","20260730170212",차량증가,"400000",,"52","2510","251","20260730170212",
|
||||||
|
인천대교선,110,"11021",,송도방향,E, ,** (민자 고속도로구간) 인천대교선 상황실 전화번호 032-745-8100 문의 바랍니다 **,"20250910001933",홍보,"250000",,"0","1102","110","20250910001933",
|
||||||
|
경인선,120,"12001",,서울방향,E, ,** 경인1지하차도 홍익병원사거리 1차로 통제 2025.7.9 (수)~공사완료시까지 **,"20250910001852",홍보,"250000",,"0","1200","120","20250910001852",
|
||||||
|
수도권제2순환선(인천-김포),400,"40011",,김포방향,E, ,** (민자 고속도로구간) 인천김포선 상황실 전화번호 032-292-7164 문의 바랍니다 **,"20251119153617",홍보,"250000",,"0","4001","400","20251119153617",
|
||||||
|
제3경인선,330,"33001",,시흥방향,E, ,** (민자 고속도로구간) 제3경인고속도로 상황실 031-8084-8901 문의바랍니다 **,"20240725161924",홍보,"200000",,"0","3300","330","20240725161924",
|
||||||
|
경부선,1,"00101",,서울방향,E, ,"** 천안IC-천안분기점(부산) 방음시설 작업/4차로 21시~06시, 5차로 06시~21시 차단 25.9월~26.12월 **","20250919075529",홍보,"400000",,"0","0010","1","20250919075529",
|
||||||
|
경인선,120,"12001",,서울방향,E, ,** 인천대로 일반화 공사중(2단계)[주안산단고가교~서인천IC]2025.11.17~2031.03 **,"20251016103404",홍보,"250000",,"0","1200","120","20251016103404",
|
||||||
|
영동선,50,"05001",,강릉방향,E, ,** (강릉방향) 생태습지 졸음쉼터 화장실 폐쇄 **,"20251117153247",홍보,"300000",,"0","0500","50","20251117153247",
|
||||||
|
수도권제1순환선,100,"10001",,일산방향,S,판교분기점(128K)-판교분기점부근(126K),"2km정체[2026-07-30 16:21- ]","20260730162134",차량증가,"200000",,"128","1000","100","20260730162134",
|
||||||
|
경부선,1,"00101",,서울방향,E,기흥(388K)-신갈분기점(394K),"6km정체[2026-07-30 16:47- ]","20260730164739",차량증가,"200000",,"388","0010","1","20260730164739",
|
||||||
|
수도권제1순환선,100,"10001",,일산방향,S,성남부근(3K)-판교분기점(0K),"3km정체[2026-07-30 16:21- ]","20260730162117",차량증가,"200000",,"3","1000","100","20260730162117",
|
||||||
|
중부내륙선,45,"04501",,양평방향,E,현풍졸음쉼터(51.4K),** (창원방향) 시설물 작업 중 쉼터이용불가 **,"20260710150735",홍보,"700000",,"51.4","0450","45","20260710150735",
|
||||||
|
수도권제1순환선,100,"10001",,일산방향,S,서하남분기점(16K)-송파부근(7K),"9km정체[2026-07-30 16:22- ]","20260730162214",차량증가,"200000",,"16","1000","100","20260730162214",
|
||||||
|
서해안선,15,"01501",,서울방향,E, ,** 서산(서울)주유소 영업중단(5.6~10.6)/휴게소 및 LPG충전소는 정상영업/홍성주유소 이용바람 **,"20260429075501",홍보,"400000",,"0","0150","15","20260429075501",
|
||||||
|
새만금전주선,20,"02021",,새만금방향,E,석구터널(46.1K),(갓길)소형화물차 고장 처리중[2026-07-30 14:14- ],"20260730141437",고장,"800000",,"46.1","0202","20","20260730141437",
|
||||||
|
영동선,50,"05001",,인천방향,S,동수원(37K)-북수원(30K),"7km정체[2026-07-30 14:26- ]","20260730142623",차량증가,"250000",,"37","0500","50","20260730142623",
|
||||||
|
경인선,120,"12001",,인천방향,S,인천요금소(16K)-서인천(11K),"5km정체[2026-07-30 15:09- ]","20260730150911",차량증가,"250000",,"16","1200","120","20260730150911",
|
||||||
|
제2경인선,110,"11001",,인천방향,S,서창분기점(9K)-남동부근(6K),"3km정체[2026-07-30 06:54- ]","20260730065400",차량증가,"250000",,"9","1100","110","20260730065400",
|
||||||
|
제2경인선,110,"11001",,인천방향,S,안현분기점(18K)-신천(14K),"4km정체[2026-07-30 17:01- ]","20260730170117",차량증가,"250000",,"18","1100","110","20260730170117",
|
||||||
|
서해안선,15,"01501",,서울방향,E, ,** 대천휴게소(양방향) 주유소 개선공사 이용불가 6. 1(월)~11.27(금) **,"20260531090003",홍보,"800000",,"0","0150","15","20260531090003",
|
||||||
|
영동선,50,"05001",,강릉방향,E, ,** 서안산~북수원 확장공사 제한속도변경 100- 80km/h (8.30~26.12.31 ) **,"20250828051816",홍보,"250000",,"0","0500","50","20250828051816",
|
||||||
|
평택시흥선,15,"01531",,시흥방향,E, ,** (민자 고속도로구간) 평택시흥선 상황실 전화번호 1661-5688 문의 바랍니다 **,"20250912112159",홍보,"250000",,"0","0153","153","20250912112159",
|
||||||
|
영동선,50,"05001",,강릉방향,E, ,** 영동선 이목졸음쉼터(강릉) 임시폐쇄 '24.07.15. ~ '26.08.29. **,"20251013121202",홍보,"250000",,"0","0500","50","20251013121202",
|
||||||
|
영동선,50,"05001",,강릉방향,E, ,** 영동선 이천졸음쉼터(인천방향) 폐쇄 (2025.8월~2027.5월 31. (23개월간) **,"20250814135609",홍보,"200000",,"0","0500","50","20250814135609",
|
||||||
|
인천공항선,130,"13001",,서울방향,E, ,** (민자 고속도로구간) 인천공항선 상황실 전화번호 032-560-6100 문의 바랍니다 **,"20250623050208",홍보,"200000",,"0","1300","130","20250623050208",
|
||||||
|
대전남부선,300,"30001",,산내방향,E, ,** 서대전부근(양방향) 방음벽 설치작업 26.7.10(금)~27.7.10(토) **,"20250910112809",홍보,"400000",,"0","3000","300","20250910112809",
|
||||||
|
수도권제1순환선,100,"10001",,판교방향,E,노오지분기점(79K)-송내(88K),"9km정체[2026-07-30 05:11- ]","20260730051106",차량증가,"250000",,"79","1000","100","20260730051106",
|
||||||
|
중부선,35,"03521",,하남방향,E,일죽부근(304K)-일죽부근(309K),"5km정체[2026-07-30 16:09- ]","20260730160933",차량증가,"900000",,"304","0352","35","20260730160933",
|
||||||
|
익산장수선,20,"02011",,익산방향,S,소양(16K)-소양부근(15K),(갓길) 덩쿨제거 작업중[2026-07-30 08:41- ],"20260730084122",작업,"800000",,"16","0201","20","20260730084122",
|
||||||
|
남해선(순천-부산),10,"01001",,부산방향,E, ,"** 섬진강휴게소(순천방향)주유소 영업중단, 개선공사 2026. 7.02~공사완료시까지 **","20260624020608",홍보,"500000",,"0","0100","10","20260624020608",
|
||||||
|
영동선,50,"05001",,인천방향,S,월곶분기점부근(6.3K),(2차로)고장차 처리중[2026-07-30 16:46- ],"20260730164625",고장,"250000",,"6.3","0500","50","20260730164625",
|
||||||
|
중앙선,55,"05502",,부산방향,S,초정(5K)-삼락(0K),"5km정체[2026-07-30 16:19- ]","20260730161902",차량증가,"700000",,"5","0550","55","20260730161902",
|
||||||
|
중부선,35,"03521",,하남방향,E, ,** 번천(통영)졸음쉼터 화장실 개선 공사로 인한 임시폐쇄 (2026.07.22(수)~2026.12.08(화)) **,"20260710122323",홍보,"200000",,"0","0352","35","20260710122323",
|
||||||
|
중부선,35,"03521",,남이방향,S,진천터널부근(277K)-진천터널부근(274K),"3km정체[2026-07-30 14:10- ]","20260730141034",차량증가,"900000",,"277","0352","35","20260730141034",
|
||||||
|
중부내륙선,45,"04501",,창원방향,S,감곡부근(258K)-감곡부근(255K),"3km정체[2026-07-30 09:46- ]","20260730094639",차량증가,"900000",,"258","0450","45","20260730094639",
|
||||||
|
서해안선,15,"01501",,서울방향,E,서평택분기점부근(295K)-화성(휴)부근(303K),"8km정체[2026-07-30 14:09- ]","20260730140943",차량증가,"250000",,"295","0150","15","20260730140943",
|
||||||
|
경부선,1,"00101",,서울방향,E, ,** 판교분기점-금토분기점(양방향) 갓길 개량공사중(2026.05.26~2027.11.30) **,"20260526065333",홍보,"200000",,"0","0010","1","20260526065333",
|
||||||
|
중부내륙선,45,"04501",,양평방향,E, ,** (양평방향) 96.5km 성주휴게소 수소충전소 이용불가 **,"20260725224834",홍보,"600000",,"0","0450","45","20260725224834",
|
||||||
|
통영대전선,35,"03511",,대전방향,E, ,** 통영대전선 111.9k~115.4k(양방향)갓길 장기차단(5.28(목)~9.30(수)) **,"20260521081134",홍보,"700000",,"0","0351","35","20260521081134",
|
||||||
|
중부내륙선,45,"04501",,양평방향,E,충주분기점부근(238K)-충주분기점부근(241K),"3km정체[2026-07-30 13:27- ]","20260730132759",차량증가,"900000",,"238","0450","45","20260730132759",
|
||||||
|
논산천안선,25,"02521",,논산방향,S,남풍세IC 호정 1교(268.0K)-차령터널 (263.0K),"5km 정체[2026-07-28 14:03- ]","20260728140304",차량증가,"400000",,"269","0252","25","20260728140304",
|
||||||
|
서해안선,15,"01501",,서울방향,E, ,** (갓길)동서천JCT(서울) 정체개선공사(2026. 5. 19 ~ 2026. 10. 30) **,"20260519113903",홍보,"800000",,"0","0150","15","20260519113903",
|
||||||
|
중부내륙선,45,"04501",,양평방향,E,영산(24K),(진입로 갓길) 화물차 고장 처리 중[2026-07-30 16:58- ],"20260730165823",고장,"700000",,"24","0450","45","20260730165823",
|
||||||
|
서해안선,15,"01501",,서울방향,E, ,"** 기상악화시 ""당진IC~서평택IC"" 제한속도 하향 단속(구간, 암행순찰) 시행 **","20260128113835",홍보,"400000",,"0","0150","15","20260128113835",
|
||||||
|
서해안선,15,"01501",,서울방향,E,당진부근(267.3K),(갓길) 화물 고장차 처리중[2026-07-30 16:18- ],"20260730161803",고장,"400000",,"267.3","0150","15","20260730161803",
|
||||||
|
수도권제1순환선,100,"10001",,판교방향,E,강일(24K)-구리남양주요금소(27K),"3km정체[2026-07-30 16:23- ]","20260730162344",차량증가,"200000",,"24","1000","100","20260730162344",
|
||||||
|
평택제천선,40,"04001",,평택방향,S,대소분기점(57K)-안진터널(52K),"5km정체[2026-07-30 15:55- ]","20260730155518",차량증가,"900000",,"57","0400","40","20260730155518",
|
||||||
|
평택제천선,40,"04001",,평택방향,S,서안성(25K)-안성분기점(24K),"1km정체[2026-07-30 15:06- ]","20260730150604",차량증가,"250000",,"25","0400","40","20260730150604",
|
||||||
|
경부선,1,"00101",,서울방향,E,판교분기점(408K),"1km정체[2026-07-30 16:00- ]","20260730160049",차량증가,"200000",,"408","0010","1","20260730160049",
|
||||||
|
동해선(부산-포항),65,"06521",,포항방향,E,남경주부근(68K)-문무대왕1터널(74K),"(2차로)노면보강 공사 작업중, 장기차단[2026-07-20 08:25- ]","20260720082502",작업,"700000",,"68","0652","65","20260720082502",
|
||||||
|
서울양양선,60,"06001",,서울방향,S,덕소삼패(3K)-강일(0K),"3km정체[2026-07-30 16:23- ]","20260730162324",차량증가,"300000",,"3","0600","60","20260730162324",
|
||||||
|
중부내륙선,45,"04501",,양평방향,E,감곡(251K)-감곡부근(255K),"4km정체[2026-07-30 16:23- ]","20260730162343",차량증가,"900000",,"251","0450","45","20260730162343",
|
||||||
|
경부선,1,"00101",,부산방향,S,회덕분기점(277K)-회덕분기점부근(276K),"1km정체[2026-07-30 16:33- ]","20260730163326",차량증가,"400000",,"277","0010","1","20260730163326",
|
||||||
|
호남선,25,"02511",,천안방향,E, ,** 백양사휴게소(천안)수소충전소 운영중단(2026.7.27~수리완료시까지) **,"20260727035539",홍보,"500000",,"0","0251","25","20260727035539",
|
||||||
|
경부선,1,"00101",,서울방향,E, ,** 평일 버스전용차로제 시행 중 (양방향) 한남-안성 (07시-21시) **,"20260704055541",홍보,"200000",,"0","0010","1","20260704055541",
|
||||||
|
남해선(순천-부산),10,"01001",,부산방향,E,김해졸음쉼터(153K),** (양방향) 화장실 이용불가 **,"20260616194929",홍보,"700000",,"153","0100","10","20260616194929",
|
||||||
|
경부선,1,"00101",,서울방향,E,입장거봉포도(휴)부근(355K)-안성(360K),"5km정체[2026-07-30 15:20- ]","20260730152029",차량증가,"400000",,"355","0010","1","20260730152029",
|
||||||
|
중부내륙선,45,"04501",,양평방향,E,감곡부근(252.1K),(갓길)승합차고장 처리중[2026-07-30 16:11- ],"20260730161104",고장,"900000",,"252.1","0450","45","20260730161104",
|
||||||
|
순천완주선,27,"02701",,완주방향,E,서면2터널부근(10.7K),(갓길) 화물차 고장 처리중[2026-07-30 16:17- ],"20260730161748",고장,"500000",,"10.7","0270","27","20260730161748",
|
||||||
|
서해안선,15,"01501",,서울방향,E, ,** 화성휴게소(목포) 수소충전소 이용 불가 2026.7.29(수)~2026.7.31(금) **,"20260729140605",홍보,"250000",,"0","0150","15","20260729140605",
|
||||||
|
통영대전선,35,"03511",,통영방향,S,동고성(14.3K),(갓길)화물차 고장 처리중[2026-07-30 16:51- ],"20260730165102",고장,"700000",,"14.3","0351","35","20260730165102",
|
||||||
|
경부선,1,"00101",,서울방향,E,안성(휴)(370K),(갓길)보행자 조치중[2026-07-30 16:56- ],"20260730165638",기타,"200000",,"370","0010","1","20260730165638",
|
||||||
|
영동선,50,"05001",,인천방향,S,군자분기점(7K)-월곶분기점부근(4K),"3km정체[2026-07-30 13:59- ]","20260730135951",차량증가,"250000",,"7","0500","50","20260730135951",
|
||||||
|
제2경인선,110,"11001",,성남방향,E,학익분기점(3K)-남동(8K),"5km정체[2026-07-30 13:54- ]","20260730135457",차량증가,"250000",,"3","1100","110","20260730135457",
|
||||||
|
서해안선,15,"01501",,서울방향,E,매송(휴)부근(315K)-용담터널(319K),"4km정체[2026-07-30 14:10- ]","20260730141000",차량증가,"250000",,"315","0150","15","20260730141000",
|
||||||
|
중부선,35,"03521",,하남방향,E,경기광주IC(352K)-중부1터널부근(355K),"3km정체[2026-07-30 16:42- ]","20260730164203",차량증가,"200000",,"352","0352","35","20260730164203",
|
||||||
|
+139
@@ -0,0 +1,139 @@
|
|||||||
|
"ROUTECD","GRPID","ROUTESHORTNO","ROUTENM","ROUTESORT","UPDOWNDIR","ROUTEDIRNM","ROUTELAYOVERNM","OPER","HOINSTNM","RPRSTELNO","CLSSCD"
|
||||||
|
"0170","1","17",평택화성선,"6",S,오성,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0200","1","20",대구포항선,"6",S,대구,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0201","1","20",익산장수선,"6",S,익산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0251","1","25",호남선,"6",S,순천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0270","1","27",순천완주선,"6",S,순천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0290","1","29",세종포천선(안성-포천),"6",S,안성,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0300","1","30",청주영덕선,"6",S,청주,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0301","1","30",당진대전선,"6",S,당진,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0351","1","35",통영대전선,"6",S,통영,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0352","1","35",중부선,"3",S,남이,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0370","1","37",제2중부선,"6",S,이천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0400","1","40",평택제천선,"6",S,평택,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0450","1","45",중부내륙선,"6",S,창원,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0500","1","50",영동선,"4",S,인천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0520","1","52",광주원주선,"6",S,광주,,공영,제이영동고속도로㈜,"1877-0200","109"
|
||||||
|
"0550","2","55",중앙선,"6",S,부산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0552","1","55",대구부산선,"6",S,부산,,공영,신대구부산고속도로㈜,"1688-7003","109"
|
||||||
|
"0600","1","60",서울양양선,"6",S,서울,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0650","1","65",동해선(삼척-속초),"6",S,삼척,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0651","1","65",부산울산선,"6",S,부산,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0652","1","65",동해선(부산-포항),"6",S,부산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1000","1","100",수도권제1순환선,"5",S,일산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1020","1","102",남해1지선,"6",S,함안,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1040","1","104",남해2지선,"6",S,김해,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1100","1","110",제2경인선,"6",S,인천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1102","1","110",인천대교선,"6",S,공항,,공영,인천대교㈜,"032-745-8000","109"
|
||||||
|
"1200","1","120",경인선,"6",S,인천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1300","1","130",인천공항선,"6",S,공항,,공영,신공항하이웨이㈜,"032-560-6114","109"
|
||||||
|
"1510","1","151",서천공주선,"6",S,서천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1710","1","171",용인서울선,"6",S,용인,,공영,경수고속도로㈜,"1599-2505","109"
|
||||||
|
"2510","1","251",호남지선,"6",S,논산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"3000","1","300",대전남부선,"6",S,서대전,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"3010","1","301",상주영천선,"6",S,상주,,공영,상주영천고속도로㈜,"1877-1925","109"
|
||||||
|
"3300","1","330",제3경인선,"6",S,인천,,공영,제삼경인고속도로㈜,"031-8084-8900","109"
|
||||||
|
"4000","1","400",수도권제2순환선(봉담-동탄),"6",S,동탄,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"4001","1","400",수도권제2순환선(인천-김포),"6",S,인천,,공영,인천김포고속도로㈜,"1566-7069","109"
|
||||||
|
"4002","1","400",수도권제2순환선(파주-포천),"6",S,포천,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"4510","1","451",중부내륙지선,"6",S,창원,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"5510","1","551",중앙선지선,"6",S,김해,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0252","1","25",논산천안선,"6",S,논산,,공영,천안논산고속도로㈜,"041-850-6700","109"
|
||||||
|
"0320","1","32",당진청주선(옥산-오창),"6",S,옥산,,공영,옥산오창고속도로㈜,"1877-1108","109"
|
||||||
|
"6000","1","600",부산외곽선,"6",S,창원,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0173","1","173",서울문산지선,"6",S,서울,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0172","1","17",서울문산선,"6",S,서울,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0141","1","14",함양울산선,"6",S,함양,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"4003","1","400",수도권제2순환선(송산-봉담),"6",S,봉담,,공영,경기동서순환고속도로㈜,"1877-0427","109"
|
||||||
|
"4004","1","400",수도권제2순환선(화성-광주),"6",S,화성,,공영,화성광주고속도로㈜,"1877-0380","109"
|
||||||
|
"0700","1","700",대구외곽선,"6",S,달서,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"4005","1","400",수도권제2순환선(화도-양평),"6",S,양평,,공영,포천화도고속도로㈜,"1877-1140","109"
|
||||||
|
"5000","1","500",광주외곽선,"6",S,광주,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0010","1","1",경부선,"1",S,부산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0100","1","10",남해선(순천-부산),"6",S,순천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0101","1","101",남해선(영암-순천),"6",S,영암,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0105","1","105",부산신항선,"6",S,신항,,공영,부산신항제이배후도로㈜,"055-339-7164","109"
|
||||||
|
"0120","1","12",광주대구선,"6",S,광주,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0121","1","12",무안광주선,"6",S,무안,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0140","1","253",고창담양선,"6",S,고창,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0150","1","15",서해안선,"2",S,목포,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0153","1","153",평택시흥선,"6",S,평택,,공영,제2서해안고속도로㈜,"1661-5688","109"
|
||||||
|
"0160","1","16",울산선,"6",S,언양,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0170","3","171",오산화성선,"6",S,서오산,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0170","2","17",수원광명선,"6",S,봉담,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0321","1","32",당진청주선(아산-천안),"6",S,천안,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"4006","1","400",수도권제2순환선(시화-남안산),"6",S,남안산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"4007","1","400",수도권제2순환선(포천-화도),"6",S,포천,,공영,포천화도고속도로㈜,"1877-1140","109"
|
||||||
|
"1730","1","173",익산평택지선,"6",S,현덕,,공영,서부내륙고속도로㈜,"070-7460-3896","109"
|
||||||
|
"0175","1","17",익산평택선,"6",S,익산,,공영,서부내륙고속도로㈜,"070-7460-3896","109"
|
||||||
|
"0653","1","65",동해선(포항-영덕),"6",S,포항,,공영,,,"101"
|
||||||
|
"0202","1","20",새만금전주선,"6",S,전주,,공영,,,"101"
|
||||||
|
"0170","1","17",평택화성선,"6",E,봉담,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0200","1","20",대구포항선,"6",E,포항,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0201","1","20",익산장수선,"6",E,장수,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0251","1","25",호남선,"6",E,천안,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0270","1","27",순천완주선,"6",E,완주,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0290","1","29",세종포천선(안성-포천),"6",E,포천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0300","1","30",청주영덕선,"6",E,영덕,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0301","1","30",당진대전선,"6",E,대전,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0351","1","35",통영대전선,"6",E,대전,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0352","1","35",중부선,"3",E,하남,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0370","1","37",제2중부선,"6",E,하남,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0400","1","40",평택제천선,"6",E,제천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0450","1","45",중부내륙선,"6",E,양평,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0500","1","50",영동선,"4",E,강릉,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0520","1","52",광주원주선,"6",E,원주,,공영,제이영동고속도로㈜,"1877-0200","109"
|
||||||
|
"0550","2","55",중앙선,"6",E,춘천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0552","1","55",대구부산선,"6",E,대구,,공영,신대구부산고속도로㈜,"1688-7003","109"
|
||||||
|
"0600","1","60",서울양양선,"6",E,양양,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0650","1","65",동해선(삼척-속초),"6",E,속초,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0651","1","65",부산울산선,"6",E,울산,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0652","1","65",동해선(부산-포항),"6",E,포항,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1000","1","100",수도권제1순환선,"5",E,판교,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1020","1","102",남해1지선,"6",E,창원,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1040","1","104",남해2지선,"6",E,서부산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1100","1","110",제2경인선,"6",E,성남,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1102","1","110",인천대교선,"6",E,송도,,공영,인천대교㈜,"032-745-8000","109"
|
||||||
|
"1200","1","120",경인선,"6",E,서울,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1300","1","130",인천공항선,"6",E,서울,,공영,신공항하이웨이㈜,"032-560-6114","109"
|
||||||
|
"1510","1","151",서천공주선,"6",E,공주,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"1710","1","171",용인서울선,"6",E,서울,,공영,경수고속도로㈜,"1599-2505","109"
|
||||||
|
"2510","1","251",호남지선,"6",E,대전,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"3000","1","300",대전남부선,"6",E,산내,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"3010","1","301",상주영천선,"6",E,영천,,공영,상주영천고속도로㈜,"1877-1925","109"
|
||||||
|
"3300","1","330",제3경인선,"6",E,시흥,,공영,제삼경인고속도로㈜,"031-8084-8900","109"
|
||||||
|
"4000","1","400",수도권제2순환선(봉담-동탄),"6",E,봉담,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"4001","1","400",수도권제2순환선(인천-김포),"6",E,김포,,공영,인천김포고속도로㈜,"1566-7069","109"
|
||||||
|
"4002","1","400",수도권제2순환선(파주-포천),"6",E,파주,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"4510","1","451",중부내륙지선,"6",E,대구,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"5510","1","551",중앙선지선,"6",E,양산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0252","1","25",논산천안선,"6",E,천안,,공영,천안논산고속도로㈜,"041-850-6700","109"
|
||||||
|
"0320","1","32",당진청주선(옥산-오창),"6",E,오창,,공영,옥산오창고속도로㈜,"1877-1108","109"
|
||||||
|
"6000","1","600",부산외곽선,"6",E,기장,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0173","1","173",서울문산지선,"6",E,문산,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0172","1","17",서울문산선,"6",E,문산,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0141","1","14",함양울산선,"6",E,울산,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"4003","1","400",수도권제2순환선(송산-봉담),"6",E,송산,,공영,경기동서순환고속도로㈜,"1877-0427","109"
|
||||||
|
"4004","1","400",수도권제2순환선(화성-광주),"6",E,광주,,공영,화성광주고속도로㈜,"1877-0380","109"
|
||||||
|
"0700","1","700",대구외곽선,"6",E,상매,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"4005","1","400",수도권제2순환선(화도-양평),"6",E,화도,,공영,포천화도고속도로㈜,"1877-1140","109"
|
||||||
|
"5000","1","500",광주외곽선,"6",E,장성,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0010","1","1",경부선,"1",E,서울,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0100","1","10",남해선(순천-부산),"6",E,부산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0101","1","101",남해선(영암-순천),"6",E,순천,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0105","1","105",부산신항선,"6",E,김해,,공영,부산신항제이배후도로㈜,"055-339-7164","109"
|
||||||
|
"0120","1","12",광주대구선,"6",E,대구,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0121","1","12",무안광주선,"6",E,광주,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0140","1","253",고창담양선,"6",E,담양,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0150","1","15",서해안선,"2",E,서울,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0153","1","153",평택시흥선,"6",E,시흥,,공영,제2서해안고속도로㈜,"1661-5688","109"
|
||||||
|
"0160","1","16",울산선,"6",E,울산,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"0170","3","171",오산화성선,"6",E,안녕,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0170","2","17",수원광명선,"6",E,소하,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"0321","1","32",당진청주선(아산-천안),"6",E,아산,,공영,한국도로공사,"1588-2504","108"
|
||||||
|
"4006","1","400",수도권제2순환선(시화-남안산),"6",E,시화,,공영,한국도로공사,"1588-2504","101"
|
||||||
|
"4007","1","400",수도권제2순환선(포천-화도),"6",E,화도,,공영,포천화도고속도로㈜,"1877-1140","109"
|
||||||
|
"1730","1","173",익산평택지선,"6",E,포승,,공영,서부내륙고속도로㈜,"070-7460-3896","109"
|
||||||
|
"0175","1","17",익산평택선,"6",E,평택,,공영,서부내륙고속도로㈜,"070-7460-3896","109"
|
||||||
|
"0653","1","65",동해선(포항-영덕),"6",E,영덕,,공영,,,"101"
|
||||||
|
"0202","1","20",새만금전주선,"6",E,새만금,,공영,,,"101"
|
||||||
|
+8519
File diff suppressed because it is too large
Load Diff
+33
@@ -0,0 +1,33 @@
|
|||||||
|
-- TROAD 개발용 부트스트랩 (컨테이너 최초 초기화 시 1회 실행)
|
||||||
|
--
|
||||||
|
-- gvenzl 이미지는 이 스크립트를 CDB root 에서 실행할 수 있으므로
|
||||||
|
-- OPR_MAIN 이 있는 PDB(ORCL2)로 세션을 옮긴 뒤 권한을 부여한다.
|
||||||
|
-- 업무 뷰/데이터는 oracle/apply-sql.sh (sql/*.sql) 로 적용한다.
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'ALTER SESSION SET CONTAINER = ORCL2';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN NULL; -- 이미 PDB 세션이면 무시
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
DECLARE
|
||||||
|
TYPE t_privs IS TABLE OF VARCHAR2(60);
|
||||||
|
l_privs t_privs := t_privs (
|
||||||
|
'CREATE SESSION',
|
||||||
|
'CREATE TABLE',
|
||||||
|
'CREATE VIEW',
|
||||||
|
'CREATE SEQUENCE',
|
||||||
|
'CREATE SYNONYM',
|
||||||
|
'UNLIMITED TABLESPACE'
|
||||||
|
);
|
||||||
|
BEGIN
|
||||||
|
FOR i IN 1 .. l_privs.COUNT LOOP
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'GRANT ' || l_privs (i) || ' TO OPR_MAIN';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN NULL;
|
||||||
|
END;
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
/
|
||||||
Executable
+99
@@ -0,0 +1,99 @@
|
|||||||
|
-- V_INCIDENT_FTMS (교통정보 돌발/정체) — 개발서버용 구성
|
||||||
|
--
|
||||||
|
-- 운영 DDL 은 TROAD_APP.V_INCIDENT_FTMS 로, 다수 기반 테이블(V_TRMB_ACDT_BRNWS_INFO01L1,
|
||||||
|
-- T_TRMB_ROUTE01M1, TLISDEV.T_TRMB_CD_INFO01M1 ...)을 union all 로 가공하는 읽기 전용 뷰다.
|
||||||
|
-- 개발서버에는 기반 테이블이 없고 뷰 자체에는 INSERT 가 불가하므로,
|
||||||
|
-- 뷰 결과와 동일한 17개 컬럼을 갖는 물리 테이블을 두고 그 위에 같은 이름의 뷰를 만든다.
|
||||||
|
-- 소유자는 chatbotApi 가 실제 접속하는 계정(OPR_MAIN)으로 맞춘다.
|
||||||
|
-- jdbc:oracle:thin:@localhost:1521/orcl2 / OPR_MAIN
|
||||||
|
|
||||||
|
SET DEFINE OFF
|
||||||
|
SET SERVEROUTPUT ON
|
||||||
|
|
||||||
|
-- 기존 뷰 제거 (테이블 재정의 순서 보장)
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'DROP VIEW OPR_MAIN.V_INCIDENT_FTMS';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -942 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
-- 뷰의 원본 데이터 테이블
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE q'[
|
||||||
|
CREATE TABLE OPR_MAIN.T_INCIDENT_FTMS (
|
||||||
|
ROUTE VARCHAR2(100),
|
||||||
|
ROAD_NO NUMBER,
|
||||||
|
ROUTE_ID VARCHAR2(20),
|
||||||
|
WEATHER VARCHAR2(100),
|
||||||
|
UPDWNAME VARCHAR2(50),
|
||||||
|
UPDOWN VARCHAR2(1),
|
||||||
|
MILEPOST VARCHAR2(400),
|
||||||
|
CONTENTS VARCHAR2(2000),
|
||||||
|
RAISE_TIME VARCHAR2(14),
|
||||||
|
INCIDENT_TYPE VARCHAR2(20),
|
||||||
|
REGION_ID VARCHAR2(20),
|
||||||
|
REGION_NAME VARCHAR2(100),
|
||||||
|
START_MILEPOST NUMBER,
|
||||||
|
INITIALCHAR VARCHAR2(10),
|
||||||
|
SEQ_NO VARCHAR2(10),
|
||||||
|
INCIDENT_ID VARCHAR2(30),
|
||||||
|
CONGZONE_ID VARCHAR2(30),
|
||||||
|
LOADED_AT TIMESTAMP DEFAULT SYSTIMESTAMP
|
||||||
|
)
|
||||||
|
]';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -955 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'CREATE INDEX OPR_MAIN.IX_INCIDENT_FTMS_ROUTE ON OPR_MAIN.T_INCIDENT_FTMS (ROAD_NO, UPDOWN)';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -955 AND SQLCODE != -1408 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'CREATE INDEX OPR_MAIN.IX_INCIDENT_FTMS_TYPE ON OPR_MAIN.T_INCIDENT_FTMS (INCIDENT_TYPE)';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -955 AND SQLCODE != -1408 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
-- 운영과 동일한 컬럼·순서의 뷰
|
||||||
|
CREATE OR REPLACE FORCE VIEW OPR_MAIN.V_INCIDENT_FTMS (
|
||||||
|
"ROUTE", "ROAD_NO", "ROUTE_ID", "WEATHER", "UPDWNAME", "UPDOWN", "MILEPOST",
|
||||||
|
"CONTENTS", "RAISE_TIME", "INCIDENT_TYPE", "REGION_ID", "REGION_NAME",
|
||||||
|
"START_MILEPOST", "INITIALCHAR", "SEQ_NO", "INCIDENT_ID", "CONGZONE_ID"
|
||||||
|
) AS
|
||||||
|
SELECT ROUTE,
|
||||||
|
ROAD_NO,
|
||||||
|
ROUTE_ID,
|
||||||
|
WEATHER,
|
||||||
|
UPDWNAME,
|
||||||
|
UPDOWN,
|
||||||
|
MILEPOST,
|
||||||
|
CONTENTS,
|
||||||
|
RAISE_TIME,
|
||||||
|
INCIDENT_TYPE,
|
||||||
|
REGION_ID,
|
||||||
|
REGION_NAME,
|
||||||
|
START_MILEPOST,
|
||||||
|
INITIALCHAR,
|
||||||
|
SEQ_NO,
|
||||||
|
INCIDENT_ID,
|
||||||
|
CONGZONE_ID
|
||||||
|
FROM OPR_MAIN.T_INCIDENT_FTMS;
|
||||||
|
|
||||||
|
-- 운영 스키마명(TROAD_APP)으로도 접근할 수 있게 동의어 제공
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'CREATE OR REPLACE PUBLIC SYNONYM V_INCIDENT_FTMS FOR OPR_MAIN.V_INCIDENT_FTMS';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN NULL;
|
||||||
|
END;
|
||||||
|
/
|
||||||
+137
@@ -0,0 +1,137 @@
|
|||||||
|
-- 자동 생성: V_INCIDENT_FTMS_202607301706.csv -> OPR_MAIN.T_INCIDENT_FTMS
|
||||||
|
-- 행 수: 124
|
||||||
|
-- 생성 도구: server-dev/oracle/tools/csv_to_insert.py
|
||||||
|
|
||||||
|
SET DEFINE OFF
|
||||||
|
SET SQLBLANKLINES ON
|
||||||
|
|
||||||
|
DELETE FROM OPR_MAIN.T_INCIDENT_FTMS;
|
||||||
|
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경인선', 120, '12001', NULL, '서울방향', 'E', '신월(23K)-신월(24K)', '1km정체[2026-07-30 15:21- ]', '20260730152128', '차량증가', '250000', NULL, 23, '1200', '120', '20260730152128', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('울산선', 16, '01601', NULL, '울산방향', 'E', '범서하이패스(10.3K)', '(갓길)화물차 고장처리 중[2026-07-30 16:17- ]', '20260730161750', '고장', '700000', NULL, 10.3, '0160', '16', '20260730161750', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경인선', 120, '12001', NULL, '인천방향', 'S', '부천(20K)-부천(19K)', '1km정체[2026-07-30 16:57- ]', '20260730165724', '차량증가', '250000', NULL, 20, '1200', '120', '20260730165724', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '부산방향', 'S', '동대구분기점(122.5K)', '(갓길)승용차 고장처리중[2026-07-30 16:55- ]', '20260730165504', '고장', '600000', NULL, 122.5, '0010', '1', '20260730165504', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서울양양선', 60, '06001', NULL, '서울방향', 'S', '남춘천부근(53.8K)', '(2,3차로)승용차관련 사고처리중[2026-07-30 16:56- ] ==> 남춘천IC~남춘천IC, 3km정체', '20260730165618', '사고', '300000', NULL, 53.8, '0600', '60', '20260730165618', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('통영대전선', 35, '03511', NULL, '통영방향', 'S', '오동터널부근(132K)', '(갓길) 시설물 보수 작업중[2026-07-30 08:12- ]', '20260730081231', '작업', '800000', NULL, 132, '0351', '35', '20260730081231', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '부산방향', 'S', '천안분기점부근(332K)-천안호두(휴)(324K)', '8km정체[2026-07-30 10:50- ]', '20260730105038', '차량증가', '400000', NULL, 332, '0010', '1', '20260730105038', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '인천방향', 'S', '둔대분기점(23K)-반월터널부근(21K)', '2km정체[2026-07-30 16:17- ]', '20260730161727', '차량증가', '250000', NULL, 23, '0500', '50', '20260730161727', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('청주영덕선', 30, '03001', NULL, '영덕방향', 'E', '수한터널부근(28K)-탄부터널부근(31K)', '3km정체[2026-07-30 17:04- ]', '20260730170451', '차량증가', '900000', NULL, 28, '0300', '30', '20260730170451', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('논산천안선', 25, '02521', NULL, '논산방향', 'S', '차령터널 무학천교(266.0K)-차령터널 (263.0K)', '3km 정체[2026-07-30 08:24- ]', '20260730082406', '차량증가', '400000', NULL, 269, '0252', '25', '20260730082406', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', '양재부근(415K)-반포(420K)', '5km정체[2026-07-30 06:27- ]', '20260730062713', '차량증가', '200000', NULL, 415, '0010', '1', '20260730062713', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('제2경인선', 110, '11001', NULL, '성남방향', 'E', '안현분기점(17K)-안현분기점(18K)', '1km정체[2026-07-30 16:24- ]', '20260730162409', '차량증가', '250000', NULL, 17, '1100', '110', '20260730162409', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '인천방향', 'S', '이천부근(82K)-호법분기점부근(75K)', '7km정체[2026-07-30 16:35- ]', '20260730163548', '차량증가', '200000', NULL, 82, '0500', '50', '20260730163548', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '판교방향', 'E', '자유로(72K)-김포(74K)', '2km정체[2026-07-30 14:59- ]', '20260730145917', '차량증가', '250000', NULL, 72, '1000', '100', '20260730145917', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('순천완주선', 27, '02701', NULL, '완주방향', 'E', '황전(25.4K)', '(갓길) 노면보수 작업중[2026-07-30 16:33- ]', '20260730163357', '작업', '500000', NULL, 25.4, '0270', '27', '20260730163357', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '일산방향', 'S', '안양터널(114K)-수리터널(112K)', '2km정체[2026-07-30 15:33- ]', '20260730153338', '차량증가', '250000', NULL, 114, '1000', '100', '20260730153338', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제2순환선(화성-광주)', 400, '40041', NULL, '화성방향', 'S', '동탄방향 9.8', 'null[2026-07-23 13:52- ]', '20260723135200', '작업', '200000', NULL, 0, '4004', '400', '20260723135200', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '인천방향', 'S', '덕평부근(66K)-양지터널부근(58K)', '8km정체[2026-07-30 15:34- ]', '20260730153400', '차량증가', '200000', NULL, 66, '0500', '50', '20260730153400', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('호남선', 25, '02511', NULL, '천안방향', 'E', '동광주(74K)', '1km정체[2026-07-30 16:06- ]', '20260730160618', '차량증가', '500000', NULL, 74, '0251', '25', '20260730160618', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '인천방향', 'S', '서용인분기점(50K)', '1km정체[2026-07-30 16:17- ]', '20260730161757', '차량증가', '250000', NULL, 50, '0500', '50', '20260730161757', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '강릉방향', 'E', '둔대분기점(22K)-부곡(27K)', '5km정체[2026-07-30 16:19- ]', '20260730161916', '차량증가', '250000', NULL, 22, '0500', '50', '20260730161916', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('동해선(부산-포항)', 65, '06521', NULL, '포항방향', 'E', '남경주(69.5K)-문무대왕1터널(74.1K)', '** (포항방향 1,2차로교대) 장기차단 보강공사 7.20(월) ~ 9.18(금) **', '20260714121717', '홍보', '700000', NULL, 69.5, '0652', '65', '20260714121717', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('제2경인선', 110, '11001', NULL, '인천방향', 'S', '삼막(25.98K)-광명터널(22K)', '4km정체[2026-07-30 14:37- ]', '20260730143718', '차량증가', '250000', NULL, 25.98, '1100', '110', '20260730143718', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부내륙선', 45, '04501', NULL, '양평방향', 'E', '여주분기점부근(261K)', '(갓길)승용차고장 처리중[2026-07-30 17:01- ]', '20260730170123', '고장', '900000', NULL, 261, '0450', '45', '20260730170123', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('남해선(순천-부산)', 10, '01001', NULL, '부산방향', 'E', '칠원분기점부근(117K)-함안2터널부근(120K)', '3km정체[2026-07-30 10:32- ]', '20260730103250', '차량증가', '700000', NULL, 117, '0100', '10', '20260730103250', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('부산외곽선', 600, '60001', NULL, '창원방향', 'S', '기장분기점(48K)-기장분기점부근(47K)', '1km정체[2026-07-30 15:29- ]', '20260730152946', '차량증가', '700000', NULL, 48, '6000', '600', '20260730152946', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('호남지선', 251, '25101', NULL, '논산방향', 'S', '회덕분기점(54K)-북대전부근(52K)', '2km정체[2026-07-30 15:45- ]', '20260730154509', '차량증가', '400000', NULL, 54, '2510', '251', '20260730154509', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '인천방향', 'S', '서창분기점(1K)-서창(0K)', '1km정체[2026-07-30 16:10- ]', '20260730161003', '차량증가', '250000', NULL, 1, '0500', '50', '20260730161003', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '판교방향', 'E', '자유로(72K)', '(3,4차로) 사고 처리중[2026-07-30 16:47- ] ==> 일산IC~자유로IC, 2km정체', '20260730164727', '사고', '250000', NULL, 72, '1000', '100', '20260730164727', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서울양양선', 60, '06001', NULL, '서울방향', 'S', '남춘천부근(53.6K)', '(갓길) 승용차 고장 처리중[2026-07-30 16:43- ]', '20260730164308', '고장', '300000', NULL, 53.6, '0600', '60', '20260730164308', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', '안성분기점(364K)-안성(휴)부근(368K)', '4km정체[2026-07-30 14:37- ]', '20260730143713', '차량증가', '200000', NULL, 364, '0010', '1', '20260730143713', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('동해선(포항-영덕)', 65, '06531', NULL, '영덕방향', 'E', NULL, '** (영덕방향) 30k 영덕분기점 차로 증설 공사중 - 차로 좁아짐 주의(~12월) **', '20260721112431', '홍보', '600000', NULL, 0, '0653', '65', '20260721112431', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', '광명역(334K)-금천(340K)', '6km정체[2026-07-30 06:54- ]', '20260730065451', '차량증가', '250000', NULL, 334, '0150', '15', '20260730065451', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('통영대전선', 35, '03511', NULL, '통영방향', 'S', '마달터널부근(202.5K)', '(2차로,갓길)승용차 고장 처리중[2026-07-30 16:46- ]', '20260730164648', '고장', '800000', NULL, 202.5, '0351', '35', '20260730164648', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('통영대전선', 35, '03511', NULL, '대전방향', 'E', '진주졸음쉼터(57.3K)', '** (대전방향) 화장실 이용불가 **', '20260725060945', '홍보', '700000', NULL, 57.3, '0351', '35', '20260725060945', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '부산방향', 'S', '신갈분기점부근(397K)-신갈분기점(394K)', '3km정체[2026-07-30 16:48- ]', '20260730164817', '차량증가', '200000', NULL, 397, '0010', '1', '20260730164817', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '강릉방향', 'E', '서창분기점(0.5K)', '(인천 진출로)사고 처리중[2026-07-30 16:44- ]', '20260730164416', '사고', '250000', NULL, .5, '0500', '50', '20260730164416', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('평택제천선', 40, '04001', NULL, '제천방향', 'E', '안성분기점(23K)-안성분기점(24K)', '1km정체[2026-07-30 16:51- ]', '20260730165135', '차량증가', '250000', NULL, 23, '0400', '40', '20260730165135', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('광주대구선', 12, '01201', NULL, '대구방향', 'E', NULL, '** (광주방향)112k 남상졸음쉼터 폐쇄(~12월) **', '20260422234627', '홍보', '600000', NULL, 0, '0120', '12', '20260422234627', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제2순환선(화성-광주)', 400, '40041', NULL, '화성방향', 'S', '동탄방향 26.0', 'K (2차로) 비탈면보수 작업중[2026-05-21 14:38- ]', '20260521143800', '작업', '200000', NULL, 0, '4004', '400', '20260521143800', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('동해선(삼척-속초)', 65, '06501', NULL, '속초방향', 'E', NULL, '** (속초방향) 동해 졸음쉼터 신설공사 [ ~ 8.13] **', '20260416171758', '홍보', '300000', NULL, 0, '0650', '65', '20260416171758', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서천공주선', 151, '15101', NULL, '공주방향', 'E', NULL, '** 동서천분기점 공주방향 연결로 갓길 장기차단 26.5월~26.10월 **', '20260519074906', '홍보', '400000', NULL, 0, '1510', '151', '20260519074906', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', NULL, '** 서산(목포)주유소 영업중단(5.6~10.6)/휴게소 및 LPG충전소는 정상영업/행담도주유소 이용바람 **', '20260429135010', '홍보', '400000', NULL, 0, '0150', '15', '20260429135010', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', NULL, '** (부산)남사졸음쉼터 임시폐쇄(26.06.15~26.10.31),안성휴게소 이용바람 **', '20260605215733', '홍보', '200000', NULL, 0, '0010', '1', '20260605215733', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('남해선(순천-부산)', 10, '01001', NULL, '부산방향', 'E', '대저분기점(163K)-덕천(166K)', '3km정체[2026-07-30 13:45- ]', '20260730134538', '차량증가', '700000', NULL, 163, '0100', '10', '20260730134538', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('부산울산선', 65, '06511', NULL, '부산방향', 'S', '해운대터널부근(3K)-부산울산선시점(0K)', '3km정체[2026-07-30 14:43- ]', '20260730144311', '차량증가', '700000', NULL, 3, '0651', '65', '20260730144311', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '부산방향', 'S', '청주분기점(297K)', '(갓길) 승용 고장차 처리중[2026-07-30 15:25- ]', '20260730152539', '고장', '400000', NULL, 297, '0010', '1', '20260730152539', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('남해2지선', 104, '10401', NULL, '서부산방향', 'E', '서부산(휴)(18K)-사상(20K)', '2km정체[2026-07-30 15:25- ]', '20260730152500', '차량증가', '700000', NULL, 18, '1040', '104', '20260730152500', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('동해선(삼척-속초)', 65, '06501', NULL, '속초방향', 'E', '쇄운교(15K)-지흥1교(16.7K)', '(2차로)졸음쉼터 설치 작업중[2026-07-03 07:42- ]', '20260703074200', '작업', '300000', NULL, 15, '0650', '65', '20260703074200', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '일산방향', 'S', '시흥요금소(96K)-중동(86K)', '10km정체[2026-07-30 07:24- ]', '20260730072448', '차량증가', '250000', NULL, 96, '1000', '100', '20260730072448', NULL);
|
||||||
|
COMMIT;
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('논산천안선', 25, '02521', NULL, '천안방향', 'E', '남공주IC 오룡교(232.0K)-남공주IC 검상천교(235.0K)', '3km 정체[2026-07-30 15:27- ]', '20260730152731', '차량증가', '400000', NULL, 225, '0252', '25', '20260730152731', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('인천공항선', 130, '13001', NULL, '공항방향', 'S', '[본선-공항] 20.8Km', '청라IC 진출 1km 정체[2026-07-30 15:30- ]', '20260730153000', '차량증가', '200000', NULL, 20.8, '1300', '130', '20260730153000', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '판교방향', 'E', '조남분기점(107K)-수암터널(108K)', '1km정체[2026-07-30 16:06- ]', '20260730160627', '차량증가', '250000', NULL, 107, '1000', '100', '20260730160627', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서울양양선', 60, '06001', NULL, '서울방향', 'S', '화도(15K)-화도부근(13K)', '2km정체[2026-07-30 15:57- ]', '20260730155707', '차량증가', '300000', NULL, 15, '0600', '60', '20260730155707', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', '영천분기점(91.5K)', '(3차로,갓길)화물차관련 사고 처리중[2026-07-30 14:47- ]', '20260730144715', '사고', '600000', NULL, 91.5, '0010', '1', '20260730144715', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', '서천(휴)부근(166.5K)', '(갓길)중형화물차 고장 처리중[2026-07-30 16:13- ]', '20260730161342', '고장', '800000', NULL, 166.5, '0150', '15', '20260730161342', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', NULL, '** 서해대교(양방향) 정밀안전진단 3차로 주간 차단예정(6~10월) **', '20260605085938', '홍보', '400000', NULL, 0, '0150', '15', '20260605085938', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('논산천안선', 25, '02521', NULL, '천안방향', 'E', '남공주IC 오룡교(232.1K)', '1차로 승용차 관련 사고발생[2026-07-30 16:20- ]', '20260730162057', '사고', '400000', NULL, 225, '0252', '25', '20260730162057', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('호남지선', 251, '25101', NULL, '대전방향', 'E', '북대전부근(52K)-회덕분기점(54K)', '2km정체[2026-07-30 17:02- ]', '20260730170212', '차량증가', '400000', NULL, 52, '2510', '251', '20260730170212', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('인천대교선', 110, '11021', NULL, '송도방향', 'E', NULL, '** (민자 고속도로구간) 인천대교선 상황실 전화번호 032-745-8100 문의 바랍니다 **', '20250910001933', '홍보', '250000', NULL, 0, '1102', '110', '20250910001933', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경인선', 120, '12001', NULL, '서울방향', 'E', NULL, '** 경인1지하차도 홍익병원사거리 1차로 통제 2025.7.9 (수)~공사완료시까지 **', '20250910001852', '홍보', '250000', NULL, 0, '1200', '120', '20250910001852', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제2순환선(인천-김포)', 400, '40011', NULL, '김포방향', 'E', NULL, '** (민자 고속도로구간) 인천김포선 상황실 전화번호 032-292-7164 문의 바랍니다 **', '20251119153617', '홍보', '250000', NULL, 0, '4001', '400', '20251119153617', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('제3경인선', 330, '33001', NULL, '시흥방향', 'E', NULL, '** (민자 고속도로구간) 제3경인고속도로 상황실 031-8084-8901 문의바랍니다 **', '20240725161924', '홍보', '200000', NULL, 0, '3300', '330', '20240725161924', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', NULL, '** 천안IC-천안분기점(부산) 방음시설 작업/4차로 21시~06시, 5차로 06시~21시 차단 25.9월~26.12월 **', '20250919075529', '홍보', '400000', NULL, 0, '0010', '1', '20250919075529', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경인선', 120, '12001', NULL, '서울방향', 'E', NULL, '** 인천대로 일반화 공사중(2단계)[주안산단고가교~서인천IC]2025.11.17~2031.03 **', '20251016103404', '홍보', '250000', NULL, 0, '1200', '120', '20251016103404', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '강릉방향', 'E', NULL, '** (강릉방향) 생태습지 졸음쉼터 화장실 폐쇄 **', '20251117153247', '홍보', '300000', NULL, 0, '0500', '50', '20251117153247', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '일산방향', 'S', '판교분기점(128K)-판교분기점부근(126K)', '2km정체[2026-07-30 16:21- ]', '20260730162134', '차량증가', '200000', NULL, 128, '1000', '100', '20260730162134', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', '기흥(388K)-신갈분기점(394K)', '6km정체[2026-07-30 16:47- ]', '20260730164739', '차량증가', '200000', NULL, 388, '0010', '1', '20260730164739', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '일산방향', 'S', '성남부근(3K)-판교분기점(0K)', '3km정체[2026-07-30 16:21- ]', '20260730162117', '차량증가', '200000', NULL, 3, '1000', '100', '20260730162117', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부내륙선', 45, '04501', NULL, '양평방향', 'E', '현풍졸음쉼터(51.4K)', '** (창원방향) 시설물 작업 중 쉼터이용불가 **', '20260710150735', '홍보', '700000', NULL, 51.4, '0450', '45', '20260710150735', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '일산방향', 'S', '서하남분기점(16K)-송파부근(7K)', '9km정체[2026-07-30 16:22- ]', '20260730162214', '차량증가', '200000', NULL, 16, '1000', '100', '20260730162214', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', NULL, '** 서산(서울)주유소 영업중단(5.6~10.6)/휴게소 및 LPG충전소는 정상영업/홍성주유소 이용바람 **', '20260429075501', '홍보', '400000', NULL, 0, '0150', '15', '20260429075501', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('새만금전주선', 20, '02021', NULL, '새만금방향', 'E', '석구터널(46.1K)', '(갓길)소형화물차 고장 처리중[2026-07-30 14:14- ]', '20260730141437', '고장', '800000', NULL, 46.1, '0202', '20', '20260730141437', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '인천방향', 'S', '동수원(37K)-북수원(30K)', '7km정체[2026-07-30 14:26- ]', '20260730142623', '차량증가', '250000', NULL, 37, '0500', '50', '20260730142623', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경인선', 120, '12001', NULL, '인천방향', 'S', '인천요금소(16K)-서인천(11K)', '5km정체[2026-07-30 15:09- ]', '20260730150911', '차량증가', '250000', NULL, 16, '1200', '120', '20260730150911', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('제2경인선', 110, '11001', NULL, '인천방향', 'S', '서창분기점(9K)-남동부근(6K)', '3km정체[2026-07-30 06:54- ]', '20260730065400', '차량증가', '250000', NULL, 9, '1100', '110', '20260730065400', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('제2경인선', 110, '11001', NULL, '인천방향', 'S', '안현분기점(18K)-신천(14K)', '4km정체[2026-07-30 17:01- ]', '20260730170117', '차량증가', '250000', NULL, 18, '1100', '110', '20260730170117', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', NULL, '** 대천휴게소(양방향) 주유소 개선공사 이용불가 6. 1(월)~11.27(금) **', '20260531090003', '홍보', '800000', NULL, 0, '0150', '15', '20260531090003', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '강릉방향', 'E', NULL, '** 서안산~북수원 확장공사 제한속도변경 100- 80km/h (8.30~26.12.31 ) **', '20250828051816', '홍보', '250000', NULL, 0, '0500', '50', '20250828051816', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('평택시흥선', 15, '01531', NULL, '시흥방향', 'E', NULL, '** (민자 고속도로구간) 평택시흥선 상황실 전화번호 1661-5688 문의 바랍니다 **', '20250912112159', '홍보', '250000', NULL, 0, '0153', '153', '20250912112159', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '강릉방향', 'E', NULL, '** 영동선 이목졸음쉼터(강릉) 임시폐쇄 ''24.07.15. ~ ''26.08.29. **', '20251013121202', '홍보', '250000', NULL, 0, '0500', '50', '20251013121202', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '강릉방향', 'E', NULL, '** 영동선 이천졸음쉼터(인천방향) 폐쇄 (2025.8월~2027.5월 31. (23개월간) **', '20250814135609', '홍보', '200000', NULL, 0, '0500', '50', '20250814135609', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('인천공항선', 130, '13001', NULL, '서울방향', 'E', NULL, '** (민자 고속도로구간) 인천공항선 상황실 전화번호 032-560-6100 문의 바랍니다 **', '20250623050208', '홍보', '200000', NULL, 0, '1300', '130', '20250623050208', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('대전남부선', 300, '30001', NULL, '산내방향', 'E', NULL, '** 서대전부근(양방향) 방음벽 설치작업 26.7.10(금)~27.7.10(토) **', '20250910112809', '홍보', '400000', NULL, 0, '3000', '300', '20250910112809', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '판교방향', 'E', '노오지분기점(79K)-송내(88K)', '9km정체[2026-07-30 05:11- ]', '20260730051106', '차량증가', '250000', NULL, 79, '1000', '100', '20260730051106', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부선', 35, '03521', NULL, '하남방향', 'E', '일죽부근(304K)-일죽부근(309K)', '5km정체[2026-07-30 16:09- ]', '20260730160933', '차량증가', '900000', NULL, 304, '0352', '35', '20260730160933', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('익산장수선', 20, '02011', NULL, '익산방향', 'S', '소양(16K)-소양부근(15K)', '(갓길) 덩쿨제거 작업중[2026-07-30 08:41- ]', '20260730084122', '작업', '800000', NULL, 16, '0201', '20', '20260730084122', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('남해선(순천-부산)', 10, '01001', NULL, '부산방향', 'E', NULL, '** 섬진강휴게소(순천방향)주유소 영업중단, 개선공사 2026. 7.02~공사완료시까지 **', '20260624020608', '홍보', '500000', NULL, 0, '0100', '10', '20260624020608', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '인천방향', 'S', '월곶분기점부근(6.3K)', '(2차로)고장차 처리중[2026-07-30 16:46- ]', '20260730164625', '고장', '250000', NULL, 6.3, '0500', '50', '20260730164625', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중앙선', 55, '05502', NULL, '부산방향', 'S', '초정(5K)-삼락(0K)', '5km정체[2026-07-30 16:19- ]', '20260730161902', '차량증가', '700000', NULL, 5, '0550', '55', '20260730161902', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부선', 35, '03521', NULL, '하남방향', 'E', NULL, '** 번천(통영)졸음쉼터 화장실 개선 공사로 인한 임시폐쇄 (2026.07.22(수)~2026.12.08(화)) **', '20260710122323', '홍보', '200000', NULL, 0, '0352', '35', '20260710122323', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부선', 35, '03521', NULL, '남이방향', 'S', '진천터널부근(277K)-진천터널부근(274K)', '3km정체[2026-07-30 14:10- ]', '20260730141034', '차량증가', '900000', NULL, 277, '0352', '35', '20260730141034', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부내륙선', 45, '04501', NULL, '창원방향', 'S', '감곡부근(258K)-감곡부근(255K)', '3km정체[2026-07-30 09:46- ]', '20260730094639', '차량증가', '900000', NULL, 258, '0450', '45', '20260730094639', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', '서평택분기점부근(295K)-화성(휴)부근(303K)', '8km정체[2026-07-30 14:09- ]', '20260730140943', '차량증가', '250000', NULL, 295, '0150', '15', '20260730140943', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', NULL, '** 판교분기점-금토분기점(양방향) 갓길 개량공사중(2026.05.26~2027.11.30) **', '20260526065333', '홍보', '200000', NULL, 0, '0010', '1', '20260526065333', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부내륙선', 45, '04501', NULL, '양평방향', 'E', NULL, '** (양평방향) 96.5km 성주휴게소 수소충전소 이용불가 **', '20260725224834', '홍보', '600000', NULL, 0, '0450', '45', '20260725224834', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('통영대전선', 35, '03511', NULL, '대전방향', 'E', NULL, '** 통영대전선 111.9k~115.4k(양방향)갓길 장기차단(5.28(목)~9.30(수)) **', '20260521081134', '홍보', '700000', NULL, 0, '0351', '35', '20260521081134', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부내륙선', 45, '04501', NULL, '양평방향', 'E', '충주분기점부근(238K)-충주분기점부근(241K)', '3km정체[2026-07-30 13:27- ]', '20260730132759', '차량증가', '900000', NULL, 238, '0450', '45', '20260730132759', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('논산천안선', 25, '02521', NULL, '논산방향', 'S', '남풍세IC 호정 1교(268.0K)-차령터널 (263.0K)', '5km 정체[2026-07-28 14:03- ]', '20260728140304', '차량증가', '400000', NULL, 269, '0252', '25', '20260728140304', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', NULL, '** (갓길)동서천JCT(서울) 정체개선공사(2026. 5. 19 ~ 2026. 10. 30) **', '20260519113903', '홍보', '800000', NULL, 0, '0150', '15', '20260519113903', NULL);
|
||||||
|
COMMIT;
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부내륙선', 45, '04501', NULL, '양평방향', 'E', '영산(24K)', '(진입로 갓길) 화물차 고장 처리 중[2026-07-30 16:58- ]', '20260730165823', '고장', '700000', NULL, 24, '0450', '45', '20260730165823', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', NULL, '** 기상악화시 "당진IC~서평택IC" 제한속도 하향 단속(구간, 암행순찰) 시행 **', '20260128113835', '홍보', '400000', NULL, 0, '0150', '15', '20260128113835', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', '당진부근(267.3K)', '(갓길) 화물 고장차 처리중[2026-07-30 16:18- ]', '20260730161803', '고장', '400000', NULL, 267.3, '0150', '15', '20260730161803', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('수도권제1순환선', 100, '10001', NULL, '판교방향', 'E', '강일(24K)-구리남양주요금소(27K)', '3km정체[2026-07-30 16:23- ]', '20260730162344', '차량증가', '200000', NULL, 24, '1000', '100', '20260730162344', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('평택제천선', 40, '04001', NULL, '평택방향', 'S', '대소분기점(57K)-안진터널(52K)', '5km정체[2026-07-30 15:55- ]', '20260730155518', '차량증가', '900000', NULL, 57, '0400', '40', '20260730155518', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('평택제천선', 40, '04001', NULL, '평택방향', 'S', '서안성(25K)-안성분기점(24K)', '1km정체[2026-07-30 15:06- ]', '20260730150604', '차량증가', '250000', NULL, 25, '0400', '40', '20260730150604', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', '판교분기점(408K)', '1km정체[2026-07-30 16:00- ]', '20260730160049', '차량증가', '200000', NULL, 408, '0010', '1', '20260730160049', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('동해선(부산-포항)', 65, '06521', NULL, '포항방향', 'E', '남경주부근(68K)-문무대왕1터널(74K)', '(2차로)노면보강 공사 작업중, 장기차단[2026-07-20 08:25- ]', '20260720082502', '작업', '700000', NULL, 68, '0652', '65', '20260720082502', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서울양양선', 60, '06001', NULL, '서울방향', 'S', '덕소삼패(3K)-강일(0K)', '3km정체[2026-07-30 16:23- ]', '20260730162324', '차량증가', '300000', NULL, 3, '0600', '60', '20260730162324', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부내륙선', 45, '04501', NULL, '양평방향', 'E', '감곡(251K)-감곡부근(255K)', '4km정체[2026-07-30 16:23- ]', '20260730162343', '차량증가', '900000', NULL, 251, '0450', '45', '20260730162343', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '부산방향', 'S', '회덕분기점(277K)-회덕분기점부근(276K)', '1km정체[2026-07-30 16:33- ]', '20260730163326', '차량증가', '400000', NULL, 277, '0010', '1', '20260730163326', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('호남선', 25, '02511', NULL, '천안방향', 'E', NULL, '** 백양사휴게소(천안)수소충전소 운영중단(2026.7.27~수리완료시까지) **', '20260727035539', '홍보', '500000', NULL, 0, '0251', '25', '20260727035539', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', NULL, '** 평일 버스전용차로제 시행 중 (양방향) 한남-안성 (07시-21시) **', '20260704055541', '홍보', '200000', NULL, 0, '0010', '1', '20260704055541', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('남해선(순천-부산)', 10, '01001', NULL, '부산방향', 'E', '김해졸음쉼터(153K)', '** (양방향) 화장실 이용불가 **', '20260616194929', '홍보', '700000', NULL, 153, '0100', '10', '20260616194929', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', '입장거봉포도(휴)부근(355K)-안성(360K)', '5km정체[2026-07-30 15:20- ]', '20260730152029', '차량증가', '400000', NULL, 355, '0010', '1', '20260730152029', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부내륙선', 45, '04501', NULL, '양평방향', 'E', '감곡부근(252.1K)', '(갓길)승합차고장 처리중[2026-07-30 16:11- ]', '20260730161104', '고장', '900000', NULL, 252.1, '0450', '45', '20260730161104', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('순천완주선', 27, '02701', NULL, '완주방향', 'E', '서면2터널부근(10.7K)', '(갓길) 화물차 고장 처리중[2026-07-30 16:17- ]', '20260730161748', '고장', '500000', NULL, 10.7, '0270', '27', '20260730161748', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', NULL, '** 화성휴게소(목포) 수소충전소 이용 불가 2026.7.29(수)~2026.7.31(금) **', '20260729140605', '홍보', '250000', NULL, 0, '0150', '15', '20260729140605', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('통영대전선', 35, '03511', NULL, '통영방향', 'S', '동고성(14.3K)', '(갓길)화물차 고장 처리중[2026-07-30 16:51- ]', '20260730165102', '고장', '700000', NULL, 14.3, '0351', '35', '20260730165102', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('경부선', 1, '00101', NULL, '서울방향', 'E', '안성(휴)(370K)', '(갓길)보행자 조치중[2026-07-30 16:56- ]', '20260730165638', '기타', '200000', NULL, 370, '0010', '1', '20260730165638', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('영동선', 50, '05001', NULL, '인천방향', 'S', '군자분기점(7K)-월곶분기점부근(4K)', '3km정체[2026-07-30 13:59- ]', '20260730135951', '차량증가', '250000', NULL, 7, '0500', '50', '20260730135951', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('제2경인선', 110, '11001', NULL, '성남방향', 'E', '학익분기점(3K)-남동(8K)', '5km정체[2026-07-30 13:54- ]', '20260730135457', '차량증가', '250000', NULL, 3, '1100', '110', '20260730135457', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('서해안선', 15, '01501', NULL, '서울방향', 'E', '매송(휴)부근(315K)-용담터널(319K)', '4km정체[2026-07-30 14:10- ]', '20260730141000', '차량증가', '250000', NULL, 315, '0150', '15', '20260730141000', NULL);
|
||||||
|
INSERT INTO OPR_MAIN.T_INCIDENT_FTMS (ROUTE, ROAD_NO, ROUTE_ID, WEATHER, UPDWNAME, UPDOWN, MILEPOST, CONTENTS, RAISE_TIME, INCIDENT_TYPE, REGION_ID, REGION_NAME, START_MILEPOST, INITIALCHAR, SEQ_NO, INCIDENT_ID, CONGZONE_ID) VALUES ('중부선', 35, '03521', NULL, '하남방향', 'E', '경기광주IC(352K)-중부1터널부근(355K)', '3km정체[2026-07-30 16:42- ]', '20260730164203', '차량증가', '200000', NULL, 352, '0352', '35', '20260730164203', NULL);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
+196
@@ -0,0 +1,196 @@
|
|||||||
|
-- 노선별 교통정보 개발서버용 스키마
|
||||||
|
--
|
||||||
|
-- 운영 뷰는 개발 Oracle에 없는 다수의 원천 테이블을 참조하므로,
|
||||||
|
-- 제공받은 뷰 결과 CSV를 물리 테이블에 적재하고 동일한 이름의 뷰로 노출한다.
|
||||||
|
|
||||||
|
SET DEFINE OFF
|
||||||
|
SET SERVEROUTPUT ON
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'CREATE USER TROAD_APP NO AUTHENTICATION';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -1920 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'CREATE USER TLISDEV NO AUTHENTICATION';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -1920 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW, UNLIMITED TABLESPACE TO TROAD_APP;
|
||||||
|
GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW, UNLIMITED TABLESPACE TO TLISDEV;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE q'[
|
||||||
|
CREATE TABLE TLISDEV.T_TRMB_CD_INFO01M1 (
|
||||||
|
HGRN_CD_ID VARCHAR2(50) NOT NULL,
|
||||||
|
CMMN_CD VARCHAR2(20) NOT NULL,
|
||||||
|
USE_XN VARCHAR2(1),
|
||||||
|
CMMN_CD_NM VARCHAR2(200),
|
||||||
|
DETL_CTNT VARCHAR2(1000),
|
||||||
|
FSTTM_RGSR_ID VARCHAR2(30),
|
||||||
|
FSTTM_RGST_DTTM DATE,
|
||||||
|
LSTTM_MODFR_ID VARCHAR2(30),
|
||||||
|
LSTTM_ALTR_DTTM DATE
|
||||||
|
)
|
||||||
|
]';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -955 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE
|
||||||
|
'CREATE INDEX TLISDEV.IX_TRMB_CD_INFO_HGRN_CMMN ' ||
|
||||||
|
'ON TLISDEV.T_TRMB_CD_INFO01M1 (HGRN_CD_ID, CMMN_CD)';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE NOT IN (-955, -1408) THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE q'[
|
||||||
|
CREATE TABLE TROAD_APP.T_ROUTE_NEW_NM (
|
||||||
|
ROUTECD VARCHAR2(4),
|
||||||
|
GRPID VARCHAR2(2),
|
||||||
|
ROUTESHORTNO NUMBER,
|
||||||
|
ROUTENM VARCHAR2(100),
|
||||||
|
ROUTESORT NUMBER,
|
||||||
|
UPDOWNDIR VARCHAR2(1),
|
||||||
|
ROUTEDIRNM VARCHAR2(100),
|
||||||
|
ROUTELAYOVERNM VARCHAR2(200),
|
||||||
|
OPER VARCHAR2(30),
|
||||||
|
HOINSTNM VARCHAR2(100),
|
||||||
|
RPRSTELNO VARCHAR2(30),
|
||||||
|
CLSSCD VARCHAR2(10)
|
||||||
|
)
|
||||||
|
]';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -955 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE
|
||||||
|
'CREATE INDEX TROAD_APP.IX_ROUTE_NEW_NM_NAME ' ||
|
||||||
|
'ON TROAD_APP.T_ROUTE_NEW_NM (ROUTENM)';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE NOT IN (-955, -1408) THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE
|
||||||
|
'CREATE INDEX TROAD_APP.IX_ROUTE_NEW_NM_KEY ' ||
|
||||||
|
'ON TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, UPDOWNDIR)';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE NOT IN (-955, -1408) THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE q'[
|
||||||
|
CREATE TABLE TROAD_APP.T_ROUTE_TRFC_VER001 (
|
||||||
|
NODE_NM VARCHAR2(100),
|
||||||
|
CONZONE_ID VARCHAR2(30),
|
||||||
|
ROUTE_NO_LIST VARCHAR2(100),
|
||||||
|
LINK_LEN_KM NUMBER,
|
||||||
|
BUS_YN VARCHAR2(1),
|
||||||
|
ROUTESORT NUMBER,
|
||||||
|
SPEED NUMBER,
|
||||||
|
SPEED_BUS NUMBER,
|
||||||
|
TRAFFIC_GRADE VARCHAR2(1),
|
||||||
|
TRAFFIC_GRADE_BUS VARCHAR2(1),
|
||||||
|
CCTV_ID VARCHAR2(30),
|
||||||
|
CCTV_AREA VARCHAR2(200),
|
||||||
|
HLS_URL VARCHAR2(500),
|
||||||
|
FILEURL_IMG VARCHAR2(500),
|
||||||
|
INCIDENT_TYPE_CD VARCHAR2(10),
|
||||||
|
INCIDENT_DESC VARCHAR2(200),
|
||||||
|
MSG VARCHAR2(2000),
|
||||||
|
INCIDENT_POS_NAME VARCHAR2(500),
|
||||||
|
DETR_ID VARCHAR2(30),
|
||||||
|
SPEED_DETR NUMBER,
|
||||||
|
TRAFFIC_GRADE_DETR VARCHAR2(1),
|
||||||
|
RESTAREA_ID VARCHAR2(30),
|
||||||
|
RESTAREA_NM VARCHAR2(200),
|
||||||
|
CONZONE_X NUMBER,
|
||||||
|
CONZONE_Y NUMBER,
|
||||||
|
DRIVE_DRCT_CD VARCHAR2(1),
|
||||||
|
SECT_SQNO NUMBER,
|
||||||
|
ROUTE_CD VARCHAR2(4),
|
||||||
|
GRP_ID VARCHAR2(2),
|
||||||
|
WORK_CD VARCHAR2(10),
|
||||||
|
VVALUE01 VARCHAR2(2000),
|
||||||
|
VVALUE02 VARCHAR2(2000),
|
||||||
|
VVALUE03 VARCHAR2(2000),
|
||||||
|
VVALUE04 VARCHAR2(2000),
|
||||||
|
VVALUE05 VARCHAR2(2000),
|
||||||
|
VVALUE06 VARCHAR2(2000),
|
||||||
|
VVALUE07 VARCHAR2(2000),
|
||||||
|
VVALUE08 VARCHAR2(2000),
|
||||||
|
VVALUE09 VARCHAR2(2000)
|
||||||
|
)
|
||||||
|
]';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -955 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE
|
||||||
|
'CREATE INDEX TROAD_APP.IX_ROUTE_TRFC_ROUTE ' ||
|
||||||
|
'ON TROAD_APP.T_ROUTE_TRFC_VER001 ' ||
|
||||||
|
'(ROUTE_CD, GRP_ID, DRIVE_DRCT_CD, SECT_SQNO)';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE NOT IN (-955, -1408) THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE
|
||||||
|
'CREATE INDEX TROAD_APP.IX_ROUTE_TRFC_CONZONE ' ||
|
||||||
|
'ON TROAD_APP.T_ROUTE_TRFC_VER001 (CONZONE_ID, DRIVE_DRCT_CD)';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE NOT IN (-955, -1408) THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW TROAD_APP.V_ROUTE_NEW_NM AS
|
||||||
|
SELECT ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR,
|
||||||
|
ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD
|
||||||
|
FROM TROAD_APP.T_ROUTE_NEW_NM;
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW TROAD_APP.V_ROUTE_TRFC_VER001 AS
|
||||||
|
SELECT NODE_NM, CONZONE_ID, ROUTE_NO_LIST, LINK_LEN_KM, BUS_YN, ROUTESORT,
|
||||||
|
SPEED, SPEED_BUS, TRAFFIC_GRADE, TRAFFIC_GRADE_BUS, CCTV_ID, CCTV_AREA,
|
||||||
|
HLS_URL, FILEURL_IMG, INCIDENT_TYPE_CD, INCIDENT_DESC, MSG,
|
||||||
|
INCIDENT_POS_NAME, DETR_ID, SPEED_DETR, TRAFFIC_GRADE_DETR,
|
||||||
|
RESTAREA_ID, RESTAREA_NM, CONZONE_X, CONZONE_Y, DRIVE_DRCT_CD,
|
||||||
|
SECT_SQNO, ROUTE_CD, GRP_ID, WORK_CD, VVALUE01, VVALUE02, VVALUE03,
|
||||||
|
VVALUE04, VVALUE05, VVALUE06, VVALUE07, VVALUE08, VVALUE09
|
||||||
|
FROM TROAD_APP.T_ROUTE_TRFC_VER001;
|
||||||
|
|
||||||
|
GRANT SELECT ON TLISDEV.T_TRMB_CD_INFO01M1 TO OPR_MAIN;
|
||||||
|
GRANT SELECT ON TROAD_APP.V_ROUTE_NEW_NM TO OPR_MAIN;
|
||||||
|
GRANT SELECT ON TROAD_APP.V_ROUTE_TRFC_VER001 TO OPR_MAIN;
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW OPR_MAIN.V_ROUTE_NEW_NM AS
|
||||||
|
SELECT * FROM TROAD_APP.V_ROUTE_NEW_NM;
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW OPR_MAIN.V_ROUTE_TRFC_VER001 AS
|
||||||
|
SELECT * FROM TROAD_APP.V_ROUTE_TRFC_VER001;
|
||||||
|
|
||||||
+9548
File diff suppressed because it is too large
Load Diff
+151
@@ -0,0 +1,151 @@
|
|||||||
|
-- 자동 생성: V_ROUTE_NEW_NM_202607310912.csv -> TROAD_APP.T_ROUTE_NEW_NM
|
||||||
|
-- 행 수: 138
|
||||||
|
-- 생성 도구: server-dev/oracle/tools/csv_to_insert.py
|
||||||
|
|
||||||
|
SET DEFINE OFF
|
||||||
|
SET SQLBLANKLINES ON
|
||||||
|
|
||||||
|
DELETE FROM TROAD_APP.T_ROUTE_NEW_NM;
|
||||||
|
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0170', '1', 17, '평택화성선', 6, 'S', '오성', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0200', '1', 20, '대구포항선', 6, 'S', '대구', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0201', '1', 20, '익산장수선', 6, 'S', '익산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0251', '1', 25, '호남선', 6, 'S', '순천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0270', '1', 27, '순천완주선', 6, 'S', '순천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0290', '1', 29, '세종포천선(안성-포천)', 6, 'S', '안성', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0300', '1', 30, '청주영덕선', 6, 'S', '청주', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0301', '1', 30, '당진대전선', 6, 'S', '당진', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0351', '1', 35, '통영대전선', 6, 'S', '통영', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0352', '1', 35, '중부선', 3, 'S', '남이', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0370', '1', 37, '제2중부선', 6, 'S', '이천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0400', '1', 40, '평택제천선', 6, 'S', '평택', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0450', '1', 45, '중부내륙선', 6, 'S', '창원', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0500', '1', 50, '영동선', 4, 'S', '인천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0520', '1', 52, '광주원주선', 6, 'S', '광주', NULL, '공영', '제이영동고속도로㈜', '1877-0200', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0550', '2', 55, '중앙선', 6, 'S', '부산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0552', '1', 55, '대구부산선', 6, 'S', '부산', NULL, '공영', '신대구부산고속도로㈜', '1688-7003', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0600', '1', 60, '서울양양선', 6, 'S', '서울', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0650', '1', 65, '동해선(삼척-속초)', 6, 'S', '삼척', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0651', '1', 65, '부산울산선', 6, 'S', '부산', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0652', '1', 65, '동해선(부산-포항)', 6, 'S', '부산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1000', '1', 100, '수도권제1순환선', 5, 'S', '일산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1020', '1', 102, '남해1지선', 6, 'S', '함안', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1040', '1', 104, '남해2지선', 6, 'S', '김해', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1100', '1', 110, '제2경인선', 6, 'S', '인천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1102', '1', 110, '인천대교선', 6, 'S', '공항', NULL, '공영', '인천대교㈜', '032-745-8000', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1200', '1', 120, '경인선', 6, 'S', '인천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1300', '1', 130, '인천공항선', 6, 'S', '공항', NULL, '공영', '신공항하이웨이㈜', '032-560-6114', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1510', '1', 151, '서천공주선', 6, 'S', '서천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1710', '1', 171, '용인서울선', 6, 'S', '용인', NULL, '공영', '경수고속도로㈜', '1599-2505', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('2510', '1', 251, '호남지선', 6, 'S', '논산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('3000', '1', 300, '대전남부선', 6, 'S', '서대전', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('3010', '1', 301, '상주영천선', 6, 'S', '상주', NULL, '공영', '상주영천고속도로㈜', '1877-1925', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('3300', '1', 330, '제3경인선', 6, 'S', '인천', NULL, '공영', '제삼경인고속도로㈜', '031-8084-8900', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4000', '1', 400, '수도권제2순환선(봉담-동탄)', 6, 'S', '동탄', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4001', '1', 400, '수도권제2순환선(인천-김포)', 6, 'S', '인천', NULL, '공영', '인천김포고속도로㈜', '1566-7069', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4002', '1', 400, '수도권제2순환선(파주-포천)', 6, 'S', '포천', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4510', '1', 451, '중부내륙지선', 6, 'S', '창원', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('5510', '1', 551, '중앙선지선', 6, 'S', '김해', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0252', '1', 25, '논산천안선', 6, 'S', '논산', NULL, '공영', '천안논산고속도로㈜', '041-850-6700', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0320', '1', 32, '당진청주선(옥산-오창)', 6, 'S', '옥산', NULL, '공영', '옥산오창고속도로㈜', '1877-1108', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('6000', '1', 600, '부산외곽선', 6, 'S', '창원', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0173', '1', 173, '서울문산지선', 6, 'S', '서울', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0172', '1', 17, '서울문산선', 6, 'S', '서울', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0141', '1', 14, '함양울산선', 6, 'S', '함양', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4003', '1', 400, '수도권제2순환선(송산-봉담)', 6, 'S', '봉담', NULL, '공영', '경기동서순환고속도로㈜', '1877-0427', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4004', '1', 400, '수도권제2순환선(화성-광주)', 6, 'S', '화성', NULL, '공영', '화성광주고속도로㈜', '1877-0380', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0700', '1', 700, '대구외곽선', 6, 'S', '달서', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4005', '1', 400, '수도권제2순환선(화도-양평)', 6, 'S', '양평', NULL, '공영', '포천화도고속도로㈜', '1877-1140', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('5000', '1', 500, '광주외곽선', 6, 'S', '광주', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
COMMIT;
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0010', '1', 1, '경부선', 1, 'S', '부산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0100', '1', 10, '남해선(순천-부산)', 6, 'S', '순천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0101', '1', 101, '남해선(영암-순천)', 6, 'S', '영암', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0105', '1', 105, '부산신항선', 6, 'S', '신항', NULL, '공영', '부산신항제이배후도로㈜', '055-339-7164', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0120', '1', 12, '광주대구선', 6, 'S', '광주', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0121', '1', 12, '무안광주선', 6, 'S', '무안', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0140', '1', 253, '고창담양선', 6, 'S', '고창', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0150', '1', 15, '서해안선', 2, 'S', '목포', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0153', '1', 153, '평택시흥선', 6, 'S', '평택', NULL, '공영', '제2서해안고속도로㈜', '1661-5688', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0160', '1', 16, '울산선', 6, 'S', '언양', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0170', '3', 171, '오산화성선', 6, 'S', '서오산', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0170', '2', 17, '수원광명선', 6, 'S', '봉담', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0321', '1', 32, '당진청주선(아산-천안)', 6, 'S', '천안', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4006', '1', 400, '수도권제2순환선(시화-남안산)', 6, 'S', '남안산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4007', '1', 400, '수도권제2순환선(포천-화도)', 6, 'S', '포천', NULL, '공영', '포천화도고속도로㈜', '1877-1140', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1730', '1', 173, '익산평택지선', 6, 'S', '현덕', NULL, '공영', '서부내륙고속도로㈜', '070-7460-3896', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0175', '1', 17, '익산평택선', 6, 'S', '익산', NULL, '공영', '서부내륙고속도로㈜', '070-7460-3896', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0653', '1', 65, '동해선(포항-영덕)', 6, 'S', '포항', NULL, '공영', NULL, NULL, '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0202', '1', 20, '새만금전주선', 6, 'S', '전주', NULL, '공영', NULL, NULL, '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0170', '1', 17, '평택화성선', 6, 'E', '봉담', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0200', '1', 20, '대구포항선', 6, 'E', '포항', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0201', '1', 20, '익산장수선', 6, 'E', '장수', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0251', '1', 25, '호남선', 6, 'E', '천안', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0270', '1', 27, '순천완주선', 6, 'E', '완주', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0290', '1', 29, '세종포천선(안성-포천)', 6, 'E', '포천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0300', '1', 30, '청주영덕선', 6, 'E', '영덕', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0301', '1', 30, '당진대전선', 6, 'E', '대전', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0351', '1', 35, '통영대전선', 6, 'E', '대전', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0352', '1', 35, '중부선', 3, 'E', '하남', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0370', '1', 37, '제2중부선', 6, 'E', '하남', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0400', '1', 40, '평택제천선', 6, 'E', '제천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0450', '1', 45, '중부내륙선', 6, 'E', '양평', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0500', '1', 50, '영동선', 4, 'E', '강릉', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0520', '1', 52, '광주원주선', 6, 'E', '원주', NULL, '공영', '제이영동고속도로㈜', '1877-0200', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0550', '2', 55, '중앙선', 6, 'E', '춘천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0552', '1', 55, '대구부산선', 6, 'E', '대구', NULL, '공영', '신대구부산고속도로㈜', '1688-7003', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0600', '1', 60, '서울양양선', 6, 'E', '양양', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0650', '1', 65, '동해선(삼척-속초)', 6, 'E', '속초', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0651', '1', 65, '부산울산선', 6, 'E', '울산', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0652', '1', 65, '동해선(부산-포항)', 6, 'E', '포항', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1000', '1', 100, '수도권제1순환선', 5, 'E', '판교', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1020', '1', 102, '남해1지선', 6, 'E', '창원', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1040', '1', 104, '남해2지선', 6, 'E', '서부산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1100', '1', 110, '제2경인선', 6, 'E', '성남', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1102', '1', 110, '인천대교선', 6, 'E', '송도', NULL, '공영', '인천대교㈜', '032-745-8000', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1200', '1', 120, '경인선', 6, 'E', '서울', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1300', '1', 130, '인천공항선', 6, 'E', '서울', NULL, '공영', '신공항하이웨이㈜', '032-560-6114', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1510', '1', 151, '서천공주선', 6, 'E', '공주', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1710', '1', 171, '용인서울선', 6, 'E', '서울', NULL, '공영', '경수고속도로㈜', '1599-2505', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('2510', '1', 251, '호남지선', 6, 'E', '대전', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
COMMIT;
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('3000', '1', 300, '대전남부선', 6, 'E', '산내', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('3010', '1', 301, '상주영천선', 6, 'E', '영천', NULL, '공영', '상주영천고속도로㈜', '1877-1925', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('3300', '1', 330, '제3경인선', 6, 'E', '시흥', NULL, '공영', '제삼경인고속도로㈜', '031-8084-8900', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4000', '1', 400, '수도권제2순환선(봉담-동탄)', 6, 'E', '봉담', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4001', '1', 400, '수도권제2순환선(인천-김포)', 6, 'E', '김포', NULL, '공영', '인천김포고속도로㈜', '1566-7069', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4002', '1', 400, '수도권제2순환선(파주-포천)', 6, 'E', '파주', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4510', '1', 451, '중부내륙지선', 6, 'E', '대구', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('5510', '1', 551, '중앙선지선', 6, 'E', '양산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0252', '1', 25, '논산천안선', 6, 'E', '천안', NULL, '공영', '천안논산고속도로㈜', '041-850-6700', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0320', '1', 32, '당진청주선(옥산-오창)', 6, 'E', '오창', NULL, '공영', '옥산오창고속도로㈜', '1877-1108', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('6000', '1', 600, '부산외곽선', 6, 'E', '기장', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0173', '1', 173, '서울문산지선', 6, 'E', '문산', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0172', '1', 17, '서울문산선', 6, 'E', '문산', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0141', '1', 14, '함양울산선', 6, 'E', '울산', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4003', '1', 400, '수도권제2순환선(송산-봉담)', 6, 'E', '송산', NULL, '공영', '경기동서순환고속도로㈜', '1877-0427', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4004', '1', 400, '수도권제2순환선(화성-광주)', 6, 'E', '광주', NULL, '공영', '화성광주고속도로㈜', '1877-0380', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0700', '1', 700, '대구외곽선', 6, 'E', '상매', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4005', '1', 400, '수도권제2순환선(화도-양평)', 6, 'E', '화도', NULL, '공영', '포천화도고속도로㈜', '1877-1140', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('5000', '1', 500, '광주외곽선', 6, 'E', '장성', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0010', '1', 1, '경부선', 1, 'E', '서울', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0100', '1', 10, '남해선(순천-부산)', 6, 'E', '부산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0101', '1', 101, '남해선(영암-순천)', 6, 'E', '순천', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0105', '1', 105, '부산신항선', 6, 'E', '김해', NULL, '공영', '부산신항제이배후도로㈜', '055-339-7164', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0120', '1', 12, '광주대구선', 6, 'E', '대구', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0121', '1', 12, '무안광주선', 6, 'E', '광주', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0140', '1', 253, '고창담양선', 6, 'E', '담양', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0150', '1', 15, '서해안선', 2, 'E', '서울', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0153', '1', 153, '평택시흥선', 6, 'E', '시흥', NULL, '공영', '제2서해안고속도로㈜', '1661-5688', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0160', '1', 16, '울산선', 6, 'E', '울산', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0170', '3', 171, '오산화성선', 6, 'E', '안녕', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0170', '2', 17, '수원광명선', 6, 'E', '소하', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0321', '1', 32, '당진청주선(아산-천안)', 6, 'E', '아산', NULL, '공영', '한국도로공사', '1588-2504', '108');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4006', '1', 400, '수도권제2순환선(시화-남안산)', 6, 'E', '시화', NULL, '공영', '한국도로공사', '1588-2504', '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('4007', '1', 400, '수도권제2순환선(포천-화도)', 6, 'E', '화도', NULL, '공영', '포천화도고속도로㈜', '1877-1140', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('1730', '1', 173, '익산평택지선', 6, 'E', '포승', NULL, '공영', '서부내륙고속도로㈜', '070-7460-3896', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0175', '1', 17, '익산평택선', 6, 'E', '평택', NULL, '공영', '서부내륙고속도로㈜', '070-7460-3896', '109');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0653', '1', 65, '동해선(포항-영덕)', 6, 'E', '영덕', NULL, '공영', NULL, NULL, '101');
|
||||||
|
INSERT INTO TROAD_APP.T_ROUTE_NEW_NM (ROUTECD, GRPID, ROUTESHORTNO, ROUTENM, ROUTESORT, UPDOWNDIR, ROUTEDIRNM, ROUTELAYOVERNM, OPER, HOINSTNM, RPRSTELNO, CLSSCD) VALUES ('0202', '1', 20, '새만금전주선', 6, 'E', '새만금', NULL, '공영', NULL, NULL, '101');
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
Executable
+8697
File diff suppressed because it is too large
Load Diff
+88
@@ -0,0 +1,88 @@
|
|||||||
|
-- 교통속보(V_ACDT_BRNWS_VER001) 개발서버용 스키마
|
||||||
|
-- chatbotApi TroadService.getBreakingNews 기존 SQL 그대로 사용
|
||||||
|
|
||||||
|
SET DEFINE OFF
|
||||||
|
SET SERVEROUTPUT ON
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE 'CREATE USER TROAD_APP NO AUTHENTICATION';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -1920 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW, UNLIMITED TABLESPACE TO TROAD_APP;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE q'[
|
||||||
|
CREATE TABLE TROAD_APP.T_ACDT_BRNWS_VER001 (
|
||||||
|
ROUTECD VARCHAR2(4),
|
||||||
|
GRPID VARCHAR2(2),
|
||||||
|
BOUND VARCHAR2(1),
|
||||||
|
ROADNM VARCHAR2(100),
|
||||||
|
ROUTESORT NUMBER,
|
||||||
|
ROADSHORTNO NUMBER,
|
||||||
|
BOUNDNM VARCHAR2(100),
|
||||||
|
INCIDENT_ID VARCHAR2(30),
|
||||||
|
INCI_TP_ORDER VARCHAR2(10),
|
||||||
|
INCI_TP VARCHAR2(50),
|
||||||
|
MSG VARCHAR2(2000),
|
||||||
|
INCIDENT_POS_NAME VARCHAR2(500),
|
||||||
|
OCRN_DSTNC NUMBER,
|
||||||
|
CNGS_LNGT NUMBER,
|
||||||
|
LAT NUMBER,
|
||||||
|
LON NUMBER,
|
||||||
|
CCTV_ID VARCHAR2(30),
|
||||||
|
CCTV_NM VARCHAR2(200),
|
||||||
|
THUMBIMAGE VARCHAR2(500),
|
||||||
|
HLS_URL VARCHAR2(500),
|
||||||
|
ST_D NUMBER,
|
||||||
|
EN_D NUMBER,
|
||||||
|
VVALUE01 VARCHAR2(2000),
|
||||||
|
VVALUE02 VARCHAR2(2000),
|
||||||
|
VVALUE03 VARCHAR2(2000),
|
||||||
|
VVALUE04 VARCHAR2(2000),
|
||||||
|
VVALUE05 VARCHAR2(2000),
|
||||||
|
CRCM_TIME VARCHAR2(100),
|
||||||
|
CRCM_MSG VARCHAR2(2000)
|
||||||
|
)
|
||||||
|
]';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE != -955 THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE
|
||||||
|
'CREATE INDEX TROAD_APP.IX_ACDT_BRNWS_ROUTE ' ||
|
||||||
|
'ON TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, BOUND, ROADNM)';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
IF SQLCODE NOT IN (-955, -1408) THEN RAISE; END IF;
|
||||||
|
END;
|
||||||
|
/
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW TROAD_APP.V_ACDT_BRNWS_VER001 AS
|
||||||
|
SELECT ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM,
|
||||||
|
INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME,
|
||||||
|
OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE,
|
||||||
|
HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04,
|
||||||
|
VVALUE05, CRCM_TIME, CRCM_MSG
|
||||||
|
FROM TROAD_APP.T_ACDT_BRNWS_VER001;
|
||||||
|
|
||||||
|
GRANT SELECT ON TROAD_APP.V_ACDT_BRNWS_VER001 TO OPR_MAIN;
|
||||||
|
GRANT SELECT ON TLISDEV.T_TRMB_CD_INFO01M1 TO OPR_MAIN;
|
||||||
|
|
||||||
|
CREATE OR REPLACE VIEW OPR_MAIN.V_ACDT_BRNWS_VER001 AS
|
||||||
|
SELECT * FROM TROAD_APP.V_ACDT_BRNWS_VER001;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE
|
||||||
|
'CREATE OR REPLACE PUBLIC SYNONYM V_ACDT_BRNWS_VER001 ' ||
|
||||||
|
'FOR TROAD_APP.V_ACDT_BRNWS_VER001';
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN NULL;
|
||||||
|
END;
|
||||||
|
/
|
||||||
Executable
+100
@@ -0,0 +1,100 @@
|
|||||||
|
-- 자동 생성: V_ACDT_BRNWS_VER001_202607301705.csv -> TROAD_APP.T_ACDT_BRNWS_VER001
|
||||||
|
-- 행 수: 88
|
||||||
|
-- 생성 도구: server-dev/oracle/tools/csv_to_insert.py
|
||||||
|
|
||||||
|
SET DEFINE OFF
|
||||||
|
SET SQLBLANKLINES ON
|
||||||
|
|
||||||
|
DELETE FROM TROAD_APP.T_ACDT_BRNWS_VER001;
|
||||||
|
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('4004', '1', 'S', '수도권제2순환선(화성-광주)', 5, 400, '화성방향', '20260521143800', '03', '작업', 'K (2차로) 비탈면보수 작업중 (14시 38분부터)', '동탄방향 26.0', 0, 0, 0, 0, 'cctv00007433', '동탄JC', 'https://exmobile4.hscdn.com/cctv7433image/ch00007433_20260730.154600.000.jpg', 'https://live18.exmobile.hscdn.com/exlive/cctv7433.stream/playlist.m3u8', 0, 0, NULL, NULL, NULL, NULL, NULL, '(14시 38분부터)', 'K (2차로) 비탈면보수 작업중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0650', '1', 'E', '동해선(삼척-속초)', 6, 65, '속초방향', '20260703074200', '03', '작업', '(2차로)졸음쉼터 설치 작업중 (07시 42분부터)', '쇄운교(15K)-지흥1교(16.7K)', 15, -1, 37.486292, 129.090703, 'cctv00005829', '쇄운교', 'https://exmobile4.hscdn.com/cctv5829image/ch00005829_20260730.154600.000.jpg', 'https://live7.exmobile.hscdn.com/exlive/cctv5829.stream/playlist.m3u8', 15, 15, NULL, NULL, NULL, NULL, NULL, '(07시 42분부터)', '(2차로)졸음쉼터 설치 작업중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0652', '1', 'E', '동해선(부산-포항)', 6, 65, '포항방향', '20260720082502', '03', '작업', '(2차로)노면보강 공사 작업중, 장기차단 (08시 25분부터)', '남경주부근(68K)-문무대왕1터널(74K)', 68, -1, 35.724019, 129.296973, 'cctv00005797', '냉천3교', 'https://exmobile8.hscdn.com/cctv5797image/ch00005797_20260730.154600.000.jpg', 'https://live17.exmobile.hscdn.com/exlive/cctv5797.stream/playlist.m3u8', 68, 68, NULL, NULL, NULL, NULL, NULL, '(08시 25분부터)', '(2차로)노면보강 공사 작업중, 장기차단');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('4004', '1', 'S', '수도권제2순환선(화성-광주)', 5, 400, '화성방향', '20260723135200', '03', '작업', 'null (13시 52분부터)', '동탄방향 9.8', 0, 0, 0, 0, 'cctv00007433', '동탄JC', 'https://exmobile4.hscdn.com/cctv7433image/ch00007433_20260730.154600.000.jpg', 'https://live18.exmobile.hscdn.com/exlive/cctv7433.stream/playlist.m3u8', 0, 0, NULL, NULL, NULL, NULL, NULL, '(13시 52분부터)', 'null');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1100', '1', 'S', '제2경인선', 6, 110, '인천방향', '20260730065400', '04', '정체', '(06시 54분부터)', '서창분기점(9K)-남동부근(6K)', 9, 3, 37.433276, 126.729185, 'cctv00000762', '서창분기점', 'https://exmobile8.hscdn.com/cctv0762image/ch00000762_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0762.stream/playlist.m3u8', 9, 9, NULL, NULL, NULL, NULL, NULL, '(06시 54분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0150', '1', 'E', '서해안선', 2, 15, '서울방향', '20260730065451', '04', '정체', '(06시 54분부터)', '광명역(334K)-금천(340K)', 334, 6, 37.407933, 126.88693, 'cctv00000215', '충훈대교', 'https://exmobile8.hscdn.com/cctv0215image/ch00000215_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0215.stream/playlist.m3u8', 334, 334, NULL, NULL, NULL, NULL, NULL, '(06시 54분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'S', '수도권제1순환선', 5, 100, '일산방향', '20260730072448', '04', '정체', '(07시 24분부터)', '시흥요금소(96K)-중동(86K)', 96, 10, 37.449284, 126.805207, 'cctv00002060', '시흥TG_일산', 'https://exmobile4.hscdn.com/cctv2060image/ch00002060_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv2060.stream/playlist.m3u8', 96, 96, NULL, NULL, NULL, NULL, NULL, '(07시 24분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0351', '1', 'S', '통영대전선', 6, 35, '통영방향', '20260730081231', '03', '작업', '(갓길) 시설물 보수 작업중 (08시 12분부터)', '오동터널부근(132K)', 132, -1, 35.707033, 127.624994, 'cctv00002182', '오동2교', 'https://exmobile4.hscdn.com/cctv2182image/ch00002182_20260730.154600.000.jpg', 'https://live8.exmobile.hscdn.com/exlive/cctv2182.stream/playlist.m3u8', 132, 0, NULL, NULL, NULL, NULL, NULL, '(08시 12분부터)', '(갓길) 시설물 보수 작업중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0252', '1', 'S', '논산천안선', 6, 25, '논산방향', '20260730082406', '04', '정체', '3km 정체 (08시 24분부터)', '차령터널 무학천교(266.0K)-차령터널 (263.0K)', 269, 0, 36.72055, 127.13463, 'cctv00007136', '호정1교', 'https://exmobile4.hscdn.com/cctv7136image/ch00007136_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv7136.stream/playlist.m3u8', 269, 269, NULL, NULL, NULL, NULL, NULL, '(08시 24분부터)', '3km 정체');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0201', '1', 'S', '익산장수선', 6, 20, '익산방향', '20260730084122', '03', '작업', '(갓길) 덩쿨제거 작업중 (08시 41분부터)', '소양(16K)-소양부근(15K)', 16, -1, 35.865021, 127.230784, 'cctv00003867', '소양', 'https://exmobile8.hscdn.com/cctv3867image/ch00003867_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv3867.stream/playlist.m3u8', 16, 16, NULL, NULL, NULL, NULL, NULL, '(08시 41분부터)', '(갓길) 덩쿨제거 작업중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0450', '1', 'S', '중부내륙선', 6, 45, '창원방향', '20260730094639', '04', '정체', '(09시 46분부터)', '감곡부근(258K)-감곡부근(255K)', 258, 3, 37.172225, 127.622368, 'cctv00003204', '삼승교', 'https://exmobile4.hscdn.com/cctv3204image/ch00003204_20260730.154600.000.jpg', 'https://live10.exmobile.hscdn.com/exlive/cctv3204.stream/playlist.m3u8', 258, 258, NULL, NULL, NULL, NULL, NULL, '(09시 46분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0100', '1', 'E', '남해선(순천-부산)', 6, 10, '부산방향', '20260730103250', '04', '정체', '(10시 32분부터)', '함안2터널부근(119K)-함안2터널부근(120K)', 119, 1, 35.288699, 128.542006, 'cctv00000560', '함안2터널(부산외부)', 'https://exmobile4.hscdn.com/cctv0560image/ch00000560_20260730.154600.000.jpg', 'https://live13.exmobile.hscdn.com/exlive/cctv0560.stream/playlist.m3u8', 119, 119, NULL, NULL, NULL, NULL, NULL, '(10시 32분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0252', '1', 'S', '논산천안선', 6, 25, '논산방향', '20260728140304', '04', '정체', '5km 정체 (14시 03분부터)', '남풍세IC 호정 1교(268.0K)-차령터널 (263.0K)', 269, 0, 36.72055, 127.13463, 'cctv00007136', '호정1교', 'https://exmobile4.hscdn.com/cctv7136image/ch00007136_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv7136.stream/playlist.m3u8', 269, 269, NULL, NULL, NULL, NULL, NULL, '(14시 03분부터)', '5km 정체');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'E', '수도권제1순환선', 5, 100, '구리방향', '20260730051106', '04', '정체', '(05시 11분부터)', '노오지분기점(79K)-송내(88K)', 79, 9, 37.570368, 126.753178, 'cctv00000227', '노오지분기점', 'https://exmobile4.hscdn.com/cctv0227image/ch00000227_20260730.154600.000.jpg', 'https://live15.exmobile.hscdn.com/exlive/cctv0227.stream/playlist.m3u8', 79, 79, NULL, NULL, NULL, NULL, NULL, '(05시 11분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'E', '경부선', 1, 1, '서울방향', '20260730062713', '04', '정체', '(06시 27분부터)', '양재부근(415K)-반포(420K)', 415, 5, 37.456747, 127.046344, 'cctv00000002', '양재', 'https://exmobile4.hscdn.com/cctv0002image/ch00000002_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0002.stream/playlist.m3u8', 415, 415, NULL, NULL, NULL, NULL, NULL, '(06시 27분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'S', '경부선', 1, 1, '부산방향', '20260730105038', '04', '정체', '(10시 50분부터)', '천안분기점부근(332K)-천안호두(휴)(324K)', 332, 8, 36.766668, 127.196939, 'cctv00003848', '응원고개', 'https://exmobile4.hscdn.com/cctv3848image/ch00003848_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv3848.stream/playlist.m3u8', 332, 332, NULL, NULL, NULL, NULL, NULL, '(10시 50분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0450', '1', 'E', '중부내륙선', 6, 45, '양평방향', '20260730132759', '04', '정체', '(13시 27분부터)', '충주분기점부근(238K)-충주분기점부근(241K)', 238, 3, 37.041776, 127.75111, 'cctv00003209', '한포천', 'https://exmobile4.hscdn.com/cctv3209image/ch00003209_20260730.154600.000.jpg', 'https://live10.exmobile.hscdn.com/exlive/cctv3209.stream/playlist.m3u8', 238, 238, NULL, NULL, NULL, NULL, NULL, '(13시 27분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0100', '1', 'E', '남해선(순천-부산)', 6, 10, '부산방향', '20260730134538', '04', '정체', '(13시 45분부터)', '대저분기점(163K)-덕천(166K)', 163, 3, 35.219275, 128.969671, 'cctv00003930', '대저', 'https://exmobile4.hscdn.com/cctv3930image/ch00003930_20260730.154600.000.jpg', 'https://live15.exmobile.hscdn.com/exlive/cctv3930.stream/playlist.m3u8', 163, 163, NULL, NULL, NULL, NULL, NULL, '(13시 45분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1100', '1', 'E', '제2경인선', 6, 110, '성남방향', '20260730135457', '04', '정체', '(13시 54분부터)', '학익분기점(3K)-남동(8K)', 3, 5, 37.438267, 126.662356, 'cctv00001535', '학익대교1', 'https://exmobile4.hscdn.com/cctv1535image/ch00001535_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv1535.stream/playlist.m3u8', 3, 3, NULL, NULL, NULL, NULL, NULL, '(13시 54분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'S', '영동선', 4, 50, '인천방향', '20260730135951', '04', '정체', '(13시 59분부터)', '군자분기점(7K)-월곶분기점부근(4K)', 7, 3, 37.382693, 126.762417, 'cctv00000854', '군자분기점', 'https://exmobile4.hscdn.com/cctv0854image/ch00000854_20260730.154600.000.jpg', 'https://live2.exmobile.hscdn.com/exlive/cctv0854.stream/playlist.m3u8', 7, 7, NULL, NULL, NULL, NULL, NULL, '(13시 59분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0150', '1', 'E', '서해안선', 2, 15, '서울방향', '20260730140943', '04', '정체', '(14시 09분부터)', '서평택분기점부근(295K)-화성(휴)부근(303K)', 295, 8, 37.08446, 126.886438, 'cctv00000054', '상신2교', 'https://exmobile4.hscdn.com/cctv0054image/ch00000054_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0054.stream/playlist.m3u8', 295, 295, NULL, NULL, NULL, NULL, NULL, '(14시 09분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0150', '1', 'E', '서해안선', 2, 15, '서울방향', '20260730141000', '04', '정체', '(14시 10분부터)', '매송(휴)부근(315K)-용담터널(319K)', 315, 4, 37.260631, 126.887041, 'cctv00002409', '야목2교', 'https://exmobile8.hscdn.com/cctv2409image/ch00002409_20260730.154600.000.jpg', 'https://live3.exmobile.hscdn.com/exlive/cctv2409.stream/playlist.m3u8', 315, 315, NULL, NULL, NULL, NULL, NULL, '(14시 10분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0352', '1', 'S', '중부선', 3, 35, '남이방향', '20260730141034', '04', '정체', '(14시 10분부터)', '진천터널부근(277K)-진천터널부근(274K)', 277, 3, 36.835086, 127.494366, 'cctv00003845', '백곡천교', 'https://exmobile8.hscdn.com/cctv3845image/ch00003845_20260730.154600.000.jpg', 'https://live9.exmobile.hscdn.com/exlive/cctv3845.stream/playlist.m3u8', 277, 277, NULL, NULL, NULL, NULL, NULL, '(14시 10분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0202', '1', 'E', '새만금전주선', 6, 202, '새만금방향', '20260730141437', '01', '기타', '(갓길)소형화물차 고장 처리중 (14시 14분부터)', '석구터널(46.1K)', 46.1, -1, 35.773544, 127.153308, 'cctv00002613', '원은육교2', 'https://exmobile4.hscdn.com/cctv2613image/ch00002613_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv2613.stream/playlist.m3u8', 46.1, 0, NULL, NULL, NULL, NULL, NULL, '(14시 14분부터)', '(갓길)소형화물차 고장 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'S', '영동선', 4, 50, '인천방향', '20260730142623', '04', '정체', '(14시 26분부터)', '동수원(37K)-북수원(30K)', 37, 7, 37.299117, 127.051361, 'cctv00002415', '동수원', 'https://exmobile4.hscdn.com/cctv2415image/ch00002415_20260730.154500.000.jpg', 'https://live3.exmobile.hscdn.com/exlive/cctv2415.stream/playlist.m3u8', 37, 37, NULL, NULL, NULL, NULL, NULL, '(14시 26분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'E', '경부선', 1, 1, '서울방향', '20260730143713', '04', '정체', '(14시 37분부터)', '안성분기점(364K)-안성(휴)부근(368K)', 364, 4, 37.028613, 127.140833, 'cctv00000037', '안성분기점2', 'https://exmobile8.hscdn.com/cctv0037image/ch00000037_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv0037.stream/playlist.m3u8', 364, 364, NULL, NULL, NULL, NULL, NULL, '(14시 37분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1100', '1', 'S', '제2경인선', 6, 110, '인천방향', '20260730143718', '04', '정체', '(14시 37분부터)', '삼막(25.98K)-광명터널(22K)', 25.98, 4, 37.425507, 126.912049, 'cctv00000767', '석수', 'https://exmobile8.hscdn.com/cctv0767image/ch00000767_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0767.stream/playlist.m3u8', 25.98, 25.98, NULL, NULL, NULL, NULL, NULL, '(14시 37분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0651', '1', 'S', '부산울산선', 6, 65, '부산방향', '20260730144311', '04', '정체', '(14시 43분부터)', '해운대터널부근(3K)-부산울산선시점(0K)', 3, 3, 35.190683, 129.201783, 'cctv00000728', '고래진2교', 'https://exmobile8.hscdn.com/cctv0728image/ch00000728_20260730.154600.000.jpg', 'https://live17.exmobile.hscdn.com/exlive/cctv0728.stream/playlist.m3u8', 3, 3, NULL, NULL, NULL, NULL, NULL, '(14시 43분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'E', '경부선', 1, 1, '서울방향', '20260730144715', '00', '사고', '(3차로,갓길)화물차관련 사고 처리중 (14시 47분부터)', '영천분기점(91.5K)', 91.5, -1, 35.924733, 128.998642, 'cctv00000819', '반정1교', 'https://exmobile4.hscdn.com/cctv0819image/ch00000819_20260730.154600.000.jpg', 'https://live10.exmobile.hscdn.com/exlive/cctv0819.stream/playlist.m3u8', 91.5, 0, NULL, NULL, NULL, NULL, NULL, '(14시 47분부터)', '(3차로,갓길)화물차관련 사고 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'E', '수도권제1순환선', 5, 100, '구리방향', '20260730145917', '04', '정체', '(14시 59분부터)', '자유로(72K)-김포(74K)', 72, 2, 37.618882, 126.799826, 'cctv00000224', '자유로분기점', 'https://exmobile4.hscdn.com/cctv0224image/ch00000224_20260730.154600.000.jpg', 'https://live15.exmobile.hscdn.com/exlive/cctv0224.stream/playlist.m3u8', 72, 72, NULL, NULL, NULL, NULL, NULL, '(14시 59분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0400', '1', 'S', '평택제천선', 6, 40, '평택방향', '20260730150604', '04', '정체', '(15시 06분부터)', '서안성(25K)-안성분기점(24K)', 25, 1, 37.036583, 127.153094, 'cctv00005947', '강문교', 'https://exmobile4.hscdn.com/cctv5947image/ch00005947_20260730.154600.000.jpg', 'https://live14.exmobile.hscdn.com/exlive/cctv5947.stream/playlist.m3u8', 25, 25, NULL, NULL, NULL, NULL, NULL, '(15시 06분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1200', '1', 'S', '경인선', 6, 120, '인천방향', '20260730150911', '04', '정체', '(15시 09분부터)', '인천요금소(16K)-서인천(11K)', 16, 5, 37.523954, 126.742937, 'cctv00005038', '인천영업소', 'https://exmobile8.hscdn.com/cctv5038image/ch00005038_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv5038.stream/playlist.m3u8', 16, 16, NULL, NULL, NULL, NULL, NULL, '(15시 09분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'E', '경부선', 1, 1, '서울방향', '20260730152029', '04', '정체', '(15시 20분부터)', '입장거봉포도(휴)부근(355K)-안성(360K)', 355, 5, 36.955513, 127.181906, 'cctv00003102', '연곡', 'https://exmobile8.hscdn.com/cctv3102image/ch00003102_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv3102.stream/playlist.m3u8', 355, 355, NULL, NULL, NULL, NULL, NULL, '(15시 20분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1200', '1', 'E', '경인선', 6, 120, '서울방향', '20260730152128', '04', '정체', '(15시 21분부터)', '신월(23K)-신월(24K)', 23, 1, 37.523394, 126.821631, 'cctv00001451', '신월-1', 'https://exmobile4.hscdn.com/cctv1451image/ch00001451_20260730.154600.000.jpg', 'https://live8.exmobile.hscdn.com/exlive/cctv1451.stream/playlist.m3u8', 23, 23, NULL, NULL, NULL, NULL, NULL, '(15시 21분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1040', '1', 'E', '남해2지선', 6, 104, '서부산방향', '20260730152500', '04', '정체', '(15시 25분부터)', '서부산(휴)(18K)-사상(20K)', 18, 2, 35.156477, 128.948907, 'cctv00003718', '서부산', 'https://exmobile4.hscdn.com/cctv3718image/ch00003718_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv3718.stream/playlist.m3u8', 18, 18, NULL, NULL, NULL, NULL, NULL, '(15시 25분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'S', '경부선', 1, 1, '부산방향', '20260730152539', '01', '기타', '(갓길) 승용 고장차 처리중 (15시 25분부터)', '청주분기점(297K)', 297, -1, 36.568675, 127.429435, 'cctv00002129', '청주분기점2', 'https://exmobile4.hscdn.com/cctv2129image/ch00002129_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv2129.stream/playlist.m3u8', 297, 0, NULL, NULL, NULL, NULL, NULL, '(15시 25분부터)', '(갓길) 승용 고장차 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0252', '1', 'E', '논산천안선', 6, 25, '천안방향', '20260730152731', '04', '정체', '3km 정체 (15시 27분부터)', '남공주IC 오룡교(232.0K)-남공주IC 검상천교(235.0K)', 225, 0, 36.34541, 127.06794, 'cctv00007164', '이인SA/남', 'https://exmobile4.hscdn.com/cctv7164image/ch00007164_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv7164.stream/playlist.m3u8', 225, 225, NULL, NULL, NULL, NULL, NULL, '(15시 27분부터)', '3km 정체');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('6000', '1', 'S', '부산외곽선', 6, 600, '창원방향', '20260730152946', '04', '정체', '(15시 29분부터)', '기장분기점(48K)-기장분기점부근(47K)', 48, 1, 35.281987, 129.2089, 'cctv00000517', '용천교', 'https://exmobile4.hscdn.com/cctv0517image/ch00000517_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv0517.stream/playlist.m3u8', 48, 48, NULL, NULL, NULL, NULL, NULL, '(15시 29분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1300', '1', 'S', '인천공항선', 6, 130, '공항방향', '20260730153000', '04', '정체', '청라IC 진출 1km 정체 (15시 30분부터)', '[본선-공항] 20.8Km', 20.8, 0, 37.569859, 126.670011, 'cctv00007097', '인천공항영업소', 'https://exmobile4.hscdn.com/cctv7097image/ch00007097_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv7097.stream/playlist.m3u8', 20.8, 20.8, NULL, NULL, NULL, NULL, NULL, '(15시 30분부터)', '청라IC 진출 1km 정체');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'S', '수도권제1순환선', 5, 100, '일산방향', '20260730153338', '04', '정체', '(15시 33분부터)', '안양터널(114K)-수리터널(112K)', 114, 2, 37.37919, 126.946985, 'cctv00000292', '안양터널', 'https://exmobile4.hscdn.com/cctv0292image/ch00000292_20260730.154600.000.jpg', 'https://live15.exmobile.hscdn.com/exlive/cctv0292.stream/playlist.m3u8', 114, 114, NULL, NULL, NULL, NULL, NULL, '(15시 33분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'S', '영동선', 4, 50, '인천방향', '20260730153400', '04', '정체', '(15시 34분부터)', '덕평부근(66K)-양지터널부근(58K)', 66, 8, 37.250668, 127.352923, 'cctv00000371', '오천교', 'https://exmobile8.hscdn.com/cctv0371image/ch00000371_20260730.154600.000.jpg', 'https://live16.exmobile.hscdn.com/exlive/cctv0371.stream/playlist.m3u8', 66, 66, NULL, NULL, NULL, NULL, NULL, '(15시 34분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('2510', '1', 'S', '호남지선', 6, 251, '논산방향', '20260730154509', '04', '정체', '(15시 45분부터)', '회덕분기점(54K)-북대전부근(52K)', 54, 2, 0, 0, 'cctv00000297', '전민', 'https://exmobile4.hscdn.com/cctv0297image/ch00000297_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv0297.stream/playlist.m3u8', 54, 54, NULL, NULL, NULL, NULL, NULL, '(15시 45분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0400', '1', 'S', '평택제천선', 6, 40, '평택방향', '20260730155518', '04', '정체', '(15시 55분부터)', '대소분기점(57K)-안진터널(52K)', 57, 5, 36.941808, 127.463959, 'cctv00003794', '대소분기점', 'https://exmobile4.hscdn.com/cctv3794image/ch00003794_20260730.154600.000.jpg', 'https://live14.exmobile.hscdn.com/exlive/cctv3794.stream/playlist.m3u8', 57, 57, NULL, NULL, NULL, NULL, NULL, '(15시 55분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0600', '1', 'S', '서울양양선', 6, 60, '서울방향', '20260730155707', '04', '정체', '(15시 57분부터)', '화도(15K)-화도부근(13K)', 15, 2, 37.63154, 127.312837, 'cctv00000400', '화도영업소', 'https://exmobile8.hscdn.com/cctv0400image/ch00000400_20260730.154600.000.jpg', 'https://live17.exmobile.hscdn.com/exlive/cctv0400.stream/playlist.m3u8', 15, 15, NULL, NULL, NULL, NULL, NULL, '(15시 57분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'E', '경부선', 1, 1, '서울방향', '20260730160049', '04', '정체', '(순환선 진출로) (16시 00분부터)', '판교분기점(408K)', 408, 1, 37.406461, 127.09392, 'cctv00000006', '판교분기점_경부', 'https://exmobile4.hscdn.com/cctv0006image/ch00000006_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0006.stream/playlist.m3u8', 408, 0, NULL, NULL, NULL, NULL, NULL, '(16시 00분부터)', '(순환선 진출로)');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0251', '1', 'E', '호남선', 6, 25, '천안방향', '20260730160618', '04', '정체', '교통량 증가 (16시 06분부터)', '동광주(74K)', 74, 1, 35.183438, 126.926925, 'cctv00003382', '동광주', 'https://exmobile4.hscdn.com/cctv3382image/ch00003382_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv3382.stream/playlist.m3u8', 74, 0, NULL, NULL, NULL, NULL, NULL, '(16시 06분부터)', '교통량 증가');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'E', '수도권제1순환선', 5, 100, '구리방향', '20260730160627', '04', '정체', '(16시 06분부터)', '조남분기점(107K)-수암터널(108K)', 107, 1, 37.368655, 126.869846, 'cctv00000238', '조남분기점', 'https://exmobile4.hscdn.com/cctv0238image/ch00000238_20260730.154600.000.jpg', 'https://live15.exmobile.hscdn.com/exlive/cctv0238.stream/playlist.m3u8', 107, 107, NULL, NULL, NULL, NULL, NULL, '(16시 06분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0352', '1', 'E', '중부선', 3, 35, '하남방향', '20260730160933', '04', '정체', '(16시 09분부터)', '일죽부근(304K)-일죽부근(309K)', 304, 5, 37.070051, 127.468948, 'cctv00000667', '장암1', 'https://exmobile4.hscdn.com/cctv0667image/ch00000667_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv0667.stream/playlist.m3u8', 304, 304, NULL, NULL, NULL, NULL, NULL, '(16시 09분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'S', '영동선', 4, 50, '인천방향', '20260730161003', '04', '정체', '(16시 10분부터)', '서창분기점(1K)-서창(0K)', 1, 1, 37.428961, 126.737875, 'cctv00005669', '서창', 'https://exmobile8.hscdn.com/cctv5669image/ch00005669_20260730.154600.000.jpg', 'https://live16.exmobile.hscdn.com/exlive/cctv5669.stream/playlist.m3u8', 1, 1, NULL, NULL, NULL, NULL, NULL, '(16시 10분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0450', '1', 'E', '중부내륙선', 6, 45, '양평방향', '20260730161104', '01', '기타', '(갓길)승합차고장 처리중 (16시 11분부터)', '감곡부근(252.1K)', 252.1, -1, 37.129423, 127.66049, 'cctv00005386', '상우1교', 'https://exmobile8.hscdn.com/cctv5386image/ch00005386_20260730.154600.000.jpg', 'https://live14.exmobile.hscdn.com/exlive/cctv5386.stream/playlist.m3u8', 252.1, 0, NULL, NULL, NULL, NULL, NULL, '(16시 11분부터)', '(갓길)승합차고장 처리중');
|
||||||
|
COMMIT;
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0150', '1', 'E', '서해안선', 2, 15, '서울방향', '20260730161342', '01', '기타', '(갓길)중형화물차 고장 처리중 (16시 13분부터)', '서천(휴)부근(166.5K)', 166.5, -1, 36.119755, 126.636626, 'cctv00002043', '종천1교', 'https://exmobile4.hscdn.com/cctv2043image/ch00002043_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv2043.stream/playlist.m3u8', 166.5, 0, NULL, NULL, NULL, NULL, NULL, '(16시 13분부터)', '(갓길)중형화물차 고장 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'S', '영동선', 4, 50, '인천방향', '20260730161727', '04', '정체', '(16시 17분부터)', '둔대분기점(23K)-반월터널부근(21K)', 23, 2, 37.322581, 126.907065, 'cctv00005041', '둔대분기점', 'https://exmobile8.hscdn.com/cctv5041image/ch00005041_20260730.154600.000.jpg', 'https://live16.exmobile.hscdn.com/exlive/cctv5041.stream/playlist.m3u8', 23, 23, NULL, NULL, NULL, NULL, NULL, '(16시 17분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0270', '1', 'E', '순천완주선', 6, 27, '완주방향', '20260730161748', '01', '기타', '(갓길) 화물차 고장 처리중 (16시 17분부터)', '서면2터널부근(10.7K)', 10.7, -1, 35.028166, 127.507502, 'cctv00005578', '서면2터널(완주외부1)', 'https://exmobile8.hscdn.com/cctv5578image/ch00005578_20260730.154600.000.jpg', 'https://live14.exmobile.hscdn.com/exlive/cctv5578.stream/playlist.m3u8', 10.7, 0, NULL, NULL, NULL, NULL, NULL, '(16시 17분부터)', '(갓길) 화물차 고장 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0160', '1', 'E', '울산선', 6, 16, '울산방향', '20260730161750', '01', '기타', '(갓길)화물차 고장처리 중 (16시 17분부터)', '범서하이패스(10.3K)', 10.3, -1, 35.570555, 129.227118, 'cctv00005346', '입암', 'https://exmobile4.hscdn.com/cctv5346image/ch00005346_20260730.154600.000.jpg', 'https://live14.exmobile.hscdn.com/exlive/cctv5346.stream/playlist.m3u8', 10.3, 0, NULL, NULL, NULL, NULL, NULL, '(16시 17분부터)', '(갓길)화물차 고장처리 중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'S', '영동선', 4, 50, '인천방향', '20260730161757', '04', '정체', '진출로 (16시 17분부터)', '서용인분기점(50K)', 50, 1, 37.268988, 127.186046, 'cctv00000363', '마성터널(강릉)', 'https://exmobile8.hscdn.com/cctv0363image/ch00000363_20260730.154600.000.jpg', 'https://live16.exmobile.hscdn.com/exlive/cctv0363.stream/playlist.m3u8', 50, 0, NULL, NULL, NULL, NULL, NULL, '(16시 17분부터)', '진출로');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0150', '1', 'E', '서해안선', 2, 15, '서울방향', '20260730161803', '01', '기타', '(갓길) 화물 고장차 처리중 (16시 18분부터)', '당진부근(267.3K)', 267.3, -1, 36.906553, 126.733865, 'cctv00000626', '영천교(고정)', 'https://exmobile4.hscdn.com/cctv0626image/ch00000626_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv0626.stream/playlist.m3u8', 267.3, 0, NULL, NULL, NULL, NULL, NULL, '(16시 18분부터)', '(갓길) 화물 고장차 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0550', '2', 'S', '중앙선', 6, 55, '부산방향', '20260730161902', '04', '정체', '(16시 19분부터)', '초정(5K)-삼락(0K)', 5, 5, 35.235254, 128.980641, 'cctv00003672', '초정', 'https://exmobile8.hscdn.com/cctv3672image/ch00003672_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv3672.stream/playlist.m3u8', 5, 5, NULL, NULL, NULL, NULL, NULL, '(16시 19분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'E', '영동선', 4, 50, '강릉방향', '20260730161916', '04', '정체', '(16시 19분부터)', '둔대분기점(22K)-부곡(27K)', 22, 5, 37.322957, 126.895948, 'cctv00000220', '둔대교', 'https://exmobile8.hscdn.com/cctv0220image/ch00000220_20260730.154600.000.jpg', 'https://live2.exmobile.hscdn.com/exlive/cctv0220.stream/playlist.m3u8', 22, 22, NULL, NULL, NULL, NULL, NULL, '(16시 19분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0252', '1', 'E', '논산천안선', 6, 25, '천안방향', '20260730162057', '00', '사고', '1차로 승용차 관련 사고발생 (16시 20분부터)', '남공주IC 오룡교(232.1K)', 225, 0, 36.34541, 127.06794, 'cctv00007164', '이인SA/남', 'https://exmobile4.hscdn.com/cctv7164image/ch00007164_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv7164.stream/playlist.m3u8', 225, 225, NULL, NULL, NULL, NULL, NULL, '(16시 20분부터)', '1차로 승용차 관련 사고발생');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'S', '수도권제1순환선', 5, 100, '일산방향', '20260730162117', '04', '정체', '(16시 21분부터)', '성남부근(3K)-판교분기점(0K)', 3, 3, 37.416928, 127.122446, 'cctv00005932', '성남삼평교2', 'https://exmobile4.hscdn.com/cctv5932image/ch00005932_20260730.154600.000.jpg', 'https://live5.exmobile.hscdn.com/exlive/cctv5932.stream/playlist.m3u8', 3, 3, NULL, NULL, NULL, NULL, NULL, '(16시 21분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'S', '수도권제1순환선', 5, 100, '일산방향', '20260730162134', '04', '정체', '(16시 21분부터)', '판교분기점(128K)-판교분기점부근(126K)', 128, 2, 37.405686, 127.094436, 'cctv00005666', '금토', 'https://exmobile8.hscdn.com/cctv5666image/ch00005666_20260730.154600.000.jpg', 'https://live11.exmobile.hscdn.com/exlive/cctv5666.stream/playlist.m3u8', 128, 128, NULL, NULL, NULL, NULL, NULL, '(16시 21분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'S', '수도권제1순환선', 5, 100, '일산방향', '20260730162214', '04', '정체', '(16시 22분부터)', '서하남분기점(16K)-송파부근(7K)', 16, 9, 37.515281, 127.169685, 'cctv00000251', '광암터널2', 'https://exmobile4.hscdn.com/cctv0251image/ch00000251_20260730.154600.000.jpg', 'https://live15.exmobile.hscdn.com/exlive/cctv0251.stream/playlist.m3u8', 16, 16, NULL, NULL, NULL, NULL, NULL, '(16시 22분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0600', '1', 'S', '서울양양선', 6, 60, '서울방향', '20260730162324', '04', '정체', '(16시 23분부터)', '덕소삼패(3K)-강일(0K)', 3, 3, 37.587067, 127.199448, 'cctv00000427', '미사대교종점', 'https://exmobile8.hscdn.com/cctv0427image/ch00000427_20260730.154600.000.jpg', 'https://live17.exmobile.hscdn.com/exlive/cctv0427.stream/playlist.m3u8', 3, 3, NULL, NULL, NULL, NULL, NULL, '(16시 23분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0450', '1', 'E', '중부내륙선', 6, 45, '양평방향', '20260730162343', '04', '정체', '(16시 23분부터)', '감곡(251K)-감곡부근(255K)', 251, 4, 37.124313, 127.670833, 'cctv00003206', '감곡', 'https://exmobile4.hscdn.com/cctv3206image/ch00003206_20260730.154600.000.jpg', 'https://live10.exmobile.hscdn.com/exlive/cctv3206.stream/playlist.m3u8', 251, 251, NULL, NULL, NULL, NULL, NULL, '(16시 23분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'E', '수도권제1순환선', 5, 100, '구리방향', '20260730162344', '04', '정체', '(16시 23분부터)', '강일(24K)-구리남양주요금소(27K)', 24, 3, 37.566883, 127.170658, 'cctv00000143', '강일육교', 'https://exmobile8.hscdn.com/cctv0143image/ch00000143_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0143.stream/playlist.m3u8', 24, 24, NULL, NULL, NULL, NULL, NULL, '(16시 23분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1100', '1', 'E', '제2경인선', 6, 110, '성남방향', '20260730162409', '04', '정체', '(16시 24분부터)', '안현분기점(17K)-안현분기점(18K)', 17, 1, 37.437119, 126.816192, 'cctv00001536', '안현분기점1', 'https://exmobile4.hscdn.com/cctv1536image/ch00001536_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv1536.stream/playlist.m3u8', 17, 17, NULL, NULL, NULL, NULL, NULL, '(16시 24분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'S', '경부선', 1, 1, '부산방향', '20260730163326', '04', '정체', '(16시 33분부터)', '회덕분기점(277K)-회덕분기점부근(276K)', 277, 1, 36.396149, 127.419059, 'cctv00000873', '신대철교', 'https://exmobile4.hscdn.com/cctv0873image/ch00000873_20260730.154600.000.jpg', 'https://live4.exmobile.hscdn.com/exlive/cctv0873.stream/playlist.m3u8', 277, 277, NULL, NULL, NULL, NULL, NULL, '(16시 33분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0270', '1', 'E', '순천완주선', 6, 27, '완주방향', '20260730163357', '03', '작업', '(갓길) 노면보수 작업중 (16시 33분부터)', '황전(25.4K)', 25.4, -1, 35.149569, 127.455096, 'cctv00001436', '황전', 'https://exmobile8.hscdn.com/cctv1436image/ch00001436_20260730.154600.000.jpg', 'https://live14.exmobile.hscdn.com/exlive/cctv1436.stream/playlist.m3u8', 25.4, 0, NULL, NULL, NULL, NULL, NULL, '(16시 33분부터)', '(갓길) 노면보수 작업중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'S', '영동선', 4, 50, '인천방향', '20260730163548', '04', '정체', '(16시 35분부터)', '이천부근(82K)-호법분기점부근(75K)', 82, 7, 37.242627, 127.522886, 'cctv00000359', '가산리', 'https://exmobile4.hscdn.com/cctv0359image/ch00000359_20260730.154600.000.jpg', 'https://live16.exmobile.hscdn.com/exlive/cctv0359.stream/playlist.m3u8', 82, 82, NULL, NULL, NULL, NULL, NULL, '(16시 35분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0352', '1', 'E', '중부선', 3, 35, '하남방향', '20260730164203', '04', '정체', '(16시 42분부터)', '경기광주IC(352K)-중부1터널부근(355K)', 352, 3, 37.447946, 127.269718, 'cctv00000267', '광주', 'https://exmobile4.hscdn.com/cctv0267image/ch00000267_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0267.stream/playlist.m3u8', 352, 352, NULL, NULL, NULL, NULL, NULL, '(16시 42분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0600', '1', 'S', '서울양양선', 6, 60, '서울방향', '20260730164308', '01', '기타', '(갓길) 승용차 고장 처리중 (16시 43분부터)', '남춘천부근(53.6K)', 53.6, -1, 37.745234, 127.694504, 'cctv00000172', '행촌2교', 'https://exmobile4.hscdn.com/cctv0172image/ch00000172_20260730.154600.000.jpg', 'https://live17.exmobile.hscdn.com/exlive/cctv0172.stream/playlist.m3u8', 53.6, 0, NULL, NULL, NULL, NULL, NULL, '(16시 43분부터)', '(갓길) 승용차 고장 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'E', '영동선', 4, 50, '강릉방향', '20260730164416', '00', '사고', '(인천 진출로)사고 처리중 (16시 44분부터)', '서창분기점(0.5K)', .5, -1, 37.433432, 126.738571, 'cctv00005927', '서창JC', 'https://exmobile4.hscdn.com/cctv5927image/ch00005927_20260730.154600.000.jpg', 'https://live8.exmobile.hscdn.com/exlive/cctv5927.stream/playlist.m3u8', 0.5, 0, NULL, NULL, NULL, NULL, NULL, '(16시 44분부터)', '(인천 진출로)사고 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0500', '1', 'S', '영동선', 4, 50, '인천방향', '20260730164625', '01', '기타', '(2차로)고장차 처리중 (16시 46분부터)', '월곶분기점부근(6.3K)', 6.3, -1, 37.386135, 126.755797, 'cctv00000336', '월곶', 'https://exmobile4.hscdn.com/cctv0336image/ch00000336_20260730.154600.000.jpg', 'https://live16.exmobile.hscdn.com/exlive/cctv0336.stream/playlist.m3u8', 6.3, 0, NULL, NULL, NULL, NULL, NULL, '(16시 46분부터)', '(2차로)고장차 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0351', '1', 'S', '통영대전선', 6, 35, '통영방향', '20260730164648', '01', '기타', '(2차로,갓길)승용차 고장 처리중 (16시 46분부터)', '마달터널부근(202.5K)', 202.5, -1, 36.248086, 127.474032, 'cctv00000463', '공주교', 'https://exmobile8.hscdn.com/cctv0463image/ch00000463_20260730.154600.000.jpg', 'https://live17.exmobile.hscdn.com/exlive/cctv0463.stream/playlist.m3u8', 202.5, 0, NULL, NULL, NULL, NULL, NULL, '(16시 46분부터)', '(2차로,갓길)승용차 고장 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1000', '1', 'E', '수도권제1순환선', 5, 100, '구리방향', '20260730164727', '00', '사고', '(3,4차로) 사고 처리중 (16시 47분부터)', '자유로(72K)', 72, 2, 37.618882, 126.799826, 'cctv00000224', '자유로분기점', 'https://exmobile4.hscdn.com/cctv0224image/ch00000224_20260730.154600.000.jpg', 'https://live15.exmobile.hscdn.com/exlive/cctv0224.stream/playlist.m3u8', 72, 0, NULL, NULL, NULL, NULL, NULL, '(16시 47분부터)', '(3,4차로) 사고 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'E', '경부선', 1, 1, '서울방향', '20260730164739', '04', '정체', '(16시 47분부터)', '기흥(388K)-신갈분기점(394K)', 388, 6, 37.228626, 127.105739, 'cctv00000700', '보정교', 'https://exmobile4.hscdn.com/cctv0700image/ch00000700_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv0700.stream/playlist.m3u8', 388, 388, NULL, NULL, NULL, NULL, NULL, '(16시 47분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'S', '경부선', 1, 1, '부산방향', '20260730164817', '04', '정체', '(16시 48분부터)', '신갈분기점부근(397K)-신갈분기점(394K)', 397, 3, 37.309238, 127.103578, 'cctv00000008', '죽전', 'https://exmobile4.hscdn.com/cctv0008image/ch00000008_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv0008.stream/playlist.m3u8', 397, 397, NULL, NULL, NULL, NULL, NULL, '(16시 48분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0351', '1', 'S', '통영대전선', 6, 35, '통영방향', '20260730165102', '01', '기타', '(갓길)화물차 고장 처리중 (16시 51분부터)', '동고성(14.3K)', 14.3, -1, 34.970155, 128.385918, 'cctv00001582', '송산', 'https://exmobile4.hscdn.com/cctv1582image/ch00001582_20260730.154600.000.jpg', 'https://live14.exmobile.hscdn.com/exlive/cctv1582.stream/playlist.m3u8', 14.3, 0, NULL, NULL, NULL, NULL, NULL, '(16시 51분부터)', '(갓길)화물차 고장 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0400', '1', 'E', '평택제천선', 6, 40, '제천방향', '20260730165135', '04', '정체', '(16시 51분부터)', '안성분기점(23K)-안성분기점(24K)', 23, 1, 37.034317, 127.131112, 'cctv00000388', '안성분기점_평택제천', 'https://exmobile4.hscdn.com/cctv0388image/ch00000388_20260730.154600.000.jpg', 'https://live14.exmobile.hscdn.com/exlive/cctv0388.stream/playlist.m3u8', 23, 23, NULL, NULL, NULL, NULL, NULL, '(16시 51분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'S', '경부선', 1, 1, '부산방향', '20260730165504', '01', '기타', '(갓길)승용차 고장처리중 (16시 55분부터)', '동대구분기점(122.5K)', 122.5, -1, 35.887948, 128.690911, 'cctv00002300', '동대구', 'https://exmobile8.hscdn.com/cctv2300image/ch00002300_20260730.154600.000.jpg', 'https://live1.exmobile.hscdn.com/exlive/cctv2300.stream/playlist.m3u8', 122.5, 0, NULL, NULL, NULL, NULL, NULL, '(16시 55분부터)', '(갓길)승용차 고장처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0600', '1', 'S', '서울양양선', 6, 60, '서울방향', '20260730165618', '00', '사고', '(2,3차로)승용차관련 사고처리중 (16시 56분부터)', '남춘천부근(53.8K)', 53.8, 3, 37.745877, 127.696623, 'cctv00000172', '행촌2교', 'https://exmobile4.hscdn.com/cctv0172image/ch00000172_20260730.154600.000.jpg', 'https://live17.exmobile.hscdn.com/exlive/cctv0172.stream/playlist.m3u8', 53.8, 0, NULL, NULL, NULL, NULL, NULL, '(16시 56분부터)', '(2,3차로)승용차관련 사고처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0010', '1', 'E', '경부선', 1, 1, '서울방향', '20260730165638', '22', '기타', '(갓길)보행자 조치중 (16시 56분부터)', '안성(휴)(370K)', 370, -1, 37.080963, 127.127648, 'cctv00000097', '산하', 'https://exmobile8.hscdn.com/cctv0097image/ch00000097_20260730.154600.000.jpg', 'https://live15.exmobile.hscdn.com/exlive/cctv0097.stream/playlist.m3u8', 370, 0, NULL, NULL, NULL, NULL, NULL, '(16시 56분부터)', '(갓길)보행자 조치중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1200', '1', 'S', '경인선', 6, 120, '인천방향', '20260730165724', '04', '정체', '(16시 57분부터)', '부천(20K)-부천(19K)', 20, 1, 37.523066, 126.788085, 'cctv00005937', '도당육교', 'https://exmobile4.hscdn.com/cctv5937image/ch00005937_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv5937.stream/playlist.m3u8', 20, 20, NULL, NULL, NULL, NULL, NULL, '(16시 57분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0450', '1', 'E', '중부내륙선', 6, 45, '양평방향', '20260730165823', '01', '기타', '(진입로 갓길) 화물차 고장 처리 중 (16시 58분부터)', '영산(24K)', 24, -1, 35.450343, 128.508937, 'cctv00001539', '봉산', 'https://exmobile4.hscdn.com/cctv1539image/ch00001539_20260730.154600.000.jpg', 'https://live3.exmobile.hscdn.com/exlive/cctv1539.stream/playlist.m3u8', 24, 0, NULL, NULL, NULL, NULL, NULL, '(16시 58분부터)', '(진입로 갓길) 화물차 고장 처리 중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0150', '1', 'E', '서해안선', 2, 15, '서울방향', '20260730165846', '00', '사고', '(1차로)사고 처리중 (16시 58분부터)', '화성(휴)(301.5K)', 301.5, 1, 37.141864, 126.880157, 'cctv00002406', '화성휴게소2', 'https://exmobile8.hscdn.com/cctv2406image/ch00002406_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv2406.stream/playlist.m3u8', 301.5, 0, NULL, NULL, NULL, NULL, NULL, '(16시 58분부터)', '(1차로)사고 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('1100', '1', 'S', '제2경인선', 6, 110, '인천방향', '20260730170117', '04', '정체', '(17시 01분부터)', '안현분기점(18K)-신천(14K)', 18, 4, 37.440082, 126.826665, 'cctv00001537', '안현분기점2', 'https://exmobile4.hscdn.com/cctv1537image/ch00001537_20260730.154600.000.jpg', 'https://live12.exmobile.hscdn.com/exlive/cctv1537.stream/playlist.m3u8', 18, 18, NULL, NULL, NULL, NULL, NULL, '(17시 01분부터)', NULL);
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('0450', '1', 'E', '중부내륙선', 6, 45, '양평방향', '20260730170123', '01', '기타', '(갓길)승용차고장 처리중 (17시 01분부터)', '여주분기점부근(261K)', 261, -1, 37.196645, 127.61217, 'cctv00005146', '금당교_중부내륙', 'https://exmobile8.hscdn.com/cctv5146image/ch00005146_20260730.154600.000.jpg', 'https://live5.exmobile.hscdn.com/exlive/cctv5146.stream/playlist.m3u8', 261, 0, NULL, NULL, NULL, NULL, NULL, '(17시 01분부터)', '(갓길)승용차고장 처리중');
|
||||||
|
INSERT INTO TROAD_APP.T_ACDT_BRNWS_VER001 (ROUTECD, GRPID, BOUND, ROADNM, ROUTESORT, ROADSHORTNO, BOUNDNM, INCIDENT_ID, INCI_TP_ORDER, INCI_TP, MSG, INCIDENT_POS_NAME, OCRN_DSTNC, CNGS_LNGT, LAT, LON, CCTV_ID, CCTV_NM, THUMBIMAGE, HLS_URL, ST_D, EN_D, VVALUE01, VVALUE02, VVALUE03, VVALUE04, VVALUE05, CRCM_TIME, CRCM_MSG) VALUES ('2510', '1', 'E', '호남지선', 6, 251, '대전방향', '20260730170212', '04', '정체', '(17시 02분부터)', '북대전부근(52K)-회덕분기점(54K)', 52, 2, 36.409214, 127.399012, 'cctv00005468', '탑립육교', 'https://exmobile4.hscdn.com/cctv5468image/ch00005468_20260730.154600.000.jpg', 'https://live7.exmobile.hscdn.com/exlive/cctv5468.stream/playlist.m3u8', 52, 52, NULL, NULL, NULL, NULL, NULL, '(17시 02분부터)', NULL);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
Executable
+110
@@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""TROAD CSV 덤프를 Oracle INSERT 스크립트로 변환한다.
|
||||||
|
|
||||||
|
사용법:
|
||||||
|
python3 csv_to_insert.py <csv> --table OPR_MAIN.T_INCIDENT_FTMS \
|
||||||
|
--numeric ROAD_NO,START_MILEPOST --out ../sql/20_v_incident_ftms_data.sql
|
||||||
|
|
||||||
|
CSV 헤더가 대상 테이블의 컬럼명과 같아야 한다.
|
||||||
|
공백만 있는 값은 NULL 로 넣는다.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BATCH_COMMIT = 50
|
||||||
|
|
||||||
|
|
||||||
|
def sql_literal(value: str, numeric: bool, date: bool) -> str:
|
||||||
|
text = value.strip()
|
||||||
|
if not text:
|
||||||
|
return "NULL"
|
||||||
|
if date:
|
||||||
|
escaped = text.replace("'", "''")
|
||||||
|
return (
|
||||||
|
f"TO_TIMESTAMP('{escaped}', "
|
||||||
|
"'YYYY-MM-DD HH24:MI:SS.FF')"
|
||||||
|
)
|
||||||
|
if numeric:
|
||||||
|
try:
|
||||||
|
float(text)
|
||||||
|
except ValueError:
|
||||||
|
return "NULL"
|
||||||
|
return text
|
||||||
|
return "'" + text.replace("'", "''") + "'"
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("csv_path")
|
||||||
|
parser.add_argument("--table", required=True)
|
||||||
|
parser.add_argument("--numeric", default="", help="숫자 컬럼 목록(콤마 구분)")
|
||||||
|
parser.add_argument(
|
||||||
|
"--date",
|
||||||
|
default="",
|
||||||
|
help="날짜/시간 컬럼 목록(콤마 구분, YYYY-MM-DD HH24:MI:SS.FF)",
|
||||||
|
)
|
||||||
|
parser.add_argument("--encoding", default="utf-8")
|
||||||
|
parser.add_argument("--out", required=True)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-truncate",
|
||||||
|
action="store_true",
|
||||||
|
help="기존 데이터 삭제 구문을 생략한다",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
numeric_cols = {c.strip().upper() for c in args.numeric.split(",") if c.strip()}
|
||||||
|
date_cols = {c.strip().upper() for c in args.date.split(",") if c.strip()}
|
||||||
|
overlap = numeric_cols & date_cols
|
||||||
|
if overlap:
|
||||||
|
parser.error(f"--numeric과 --date에 중복된 컬럼: {', '.join(sorted(overlap))}")
|
||||||
|
csv_path = Path(args.csv_path)
|
||||||
|
|
||||||
|
with csv_path.open(newline="", encoding=args.encoding) as fp:
|
||||||
|
rows = list(csv.reader(fp))
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
print(f"빈 CSV: {csv_path}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
header = [h.strip().strip('"').upper() for h in rows[0]]
|
||||||
|
data = [r for r in rows[1:] if any(v.strip() for v in r)]
|
||||||
|
bad = [i for i, r in enumerate(data, start=2) if len(r) != len(header)]
|
||||||
|
if bad:
|
||||||
|
print(f"컬럼 수 불일치 라인: {bad[:10]}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
out_path = Path(args.out)
|
||||||
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with out_path.open("w", encoding="utf-8") as out:
|
||||||
|
out.write(f"-- 자동 생성: {csv_path.name} -> {args.table}\n")
|
||||||
|
out.write(f"-- 행 수: {len(data)}\n")
|
||||||
|
out.write("-- 생성 도구: server-dev/oracle/tools/csv_to_insert.py\n\n")
|
||||||
|
out.write("SET DEFINE OFF\n")
|
||||||
|
out.write("SET SQLBLANKLINES ON\n\n")
|
||||||
|
if not args.no_truncate:
|
||||||
|
out.write(f"DELETE FROM {args.table};\n\n")
|
||||||
|
|
||||||
|
cols = ", ".join(header)
|
||||||
|
for idx, row in enumerate(data, start=1):
|
||||||
|
values = ", ".join(
|
||||||
|
sql_literal(v, h in numeric_cols, h in date_cols)
|
||||||
|
for h, v in zip(header, row)
|
||||||
|
)
|
||||||
|
out.write(f"INSERT INTO {args.table} ({cols}) VALUES ({values});\n")
|
||||||
|
if idx % BATCH_COMMIT == 0:
|
||||||
|
out.write("COMMIT;\n")
|
||||||
|
|
||||||
|
out.write("\nCOMMIT;\n")
|
||||||
|
|
||||||
|
print(f"{len(data)} rows -> {out_path}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
+98
-16
@@ -1,8 +1,17 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# 로컬 monorepo + GitHub submodule 포인터 → Gitea push (post-receive 배포 트리거)
|
# 로컬 monorepo → Gitea(exdev) 동기화 후 push (post-receive / 원격 배포 트리거)
|
||||||
#
|
#
|
||||||
# ./server-dev/push-to-gitea.sh
|
# ./server-dev/push-to-gitea.sh
|
||||||
# ./server-dev/push-to-gitea.sh --dry-run
|
# ./server-dev/push-to-gitea.sh --dry-run
|
||||||
|
#
|
||||||
|
# 흐름 (git_fetch_all.sh 와 유사):
|
||||||
|
# 1) Gitea(main) fetch
|
||||||
|
# 2) 원격 변경을 현재 소스에 merge
|
||||||
|
# 3) 로컬 변경 commit
|
||||||
|
# 4) Gitea push
|
||||||
|
#
|
||||||
|
# 공식 GitHub(KoreaExpressWayCorp) 에는 push 하지 않음.
|
||||||
|
# 공식 GitHub 반영은 ./git_fetch_all.sh 전용.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
@@ -14,7 +23,7 @@ for arg in "$@"; do
|
|||||||
case "$arg" in
|
case "$arg" in
|
||||||
--dry-run) DRY_RUN=true ;;
|
--dry-run) DRY_RUN=true ;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
sed -n '2,6p' "$0"
|
sed -n '2,16p' "$0"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -36,16 +45,7 @@ if [[ ! -f .gitmodules ]]; then
|
|||||||
fail ".gitmodules 없음 — submodule 설정 후 다시 실행"
|
fail ".gitmodules 없음 — submodule 설정 후 다시 실행"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -x "${ROOT_DIR}/git_fetch_all.sh" ]]; then
|
log "공식 GitHub 동기화/push 생략 (Gitea 전용 배포)"
|
||||||
log "GitHub submodule 동기화..."
|
|
||||||
if ! $DRY_RUN; then
|
|
||||||
"${ROOT_DIR}/git_fetch_all.sh"
|
|
||||||
else
|
|
||||||
"${ROOT_DIR}/git_fetch_all.sh" --dry-run
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "git_fetch_all.sh 없음 — submodule GitHub 동기화 생략"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 서버 env.template·overlay와 중복되는 submodule 작업트리 변경은 되돌림
|
# 서버 env.template·overlay와 중복되는 submodule 작업트리 변경은 되돌림
|
||||||
reset_submodule_noise() {
|
reset_submodule_noise() {
|
||||||
@@ -71,6 +71,72 @@ reset_submodule_noise "exAiChatBot-chatbot2.0-agent" \
|
|||||||
reset_submodule_noise "chatbotApi-chatbot2.0-agent" gradlew
|
reset_submodule_noise "chatbotApi-chatbot2.0-agent" gradlew
|
||||||
reset_submodule_noise "kakaoChatbotSkill-chatbot2.0-agent" gradlew
|
reset_submodule_noise "kakaoChatbotSkill-chatbot2.0-agent" gradlew
|
||||||
|
|
||||||
|
working_tree_dirty() {
|
||||||
|
! git diff --quiet || ! git diff --cached --quiet
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gitea 원격 변경을 현재 브랜치에 반영 (commit 전에 수행)
|
||||||
|
sync_from_gitea() {
|
||||||
|
log "Gitea fetch ${GITEA_REMOTE}/${GIT_BRANCH}..."
|
||||||
|
if ! git fetch "${GITEA_REMOTE}" "${GIT_BRANCH}"; then
|
||||||
|
warn "Gitea fetch 실패 — 네트워크/원격 확인 필요. 로컬만으로 계속합니다."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git rev-parse "${GITEA_REMOTE}/${GIT_BRANCH}" >/dev/null 2>&1; then
|
||||||
|
log "원격 브랜치 없음 — 최초 push 대상"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local local_rev remote_rev
|
||||||
|
local_rev="$(git rev-parse HEAD)"
|
||||||
|
remote_rev="$(git rev-parse "${GITEA_REMOTE}/${GIT_BRANCH}")"
|
||||||
|
|
||||||
|
if [[ "${local_rev}" == "${remote_rev}" ]]; then
|
||||||
|
log "Gitea 와 HEAD 동일 (${local_rev:0:7}) — merge 생략"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if git merge-base --is-ancestor "${remote_rev}" "${local_rev}" 2>/dev/null; then
|
||||||
|
log "로컬이 Gitea 보다 앞섬 (${local_rev:0:7} → 원격 ${remote_rev:0:7}) — merge 생략"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Gitea 변경 반영: merge ${GITEA_REMOTE}/${GIT_BRANCH} (${remote_rev:0:7})"
|
||||||
|
if $DRY_RUN; then
|
||||||
|
log "[dry-run] git merge --no-edit ${GITEA_REMOTE}/${GIT_BRANCH}"
|
||||||
|
git log --oneline "HEAD..${GITEA_REMOTE}/${GIT_BRANCH}" | head -20 || true
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local stashed=false
|
||||||
|
if working_tree_dirty; then
|
||||||
|
log "로컬 미커밋 변경 stash 후 merge..."
|
||||||
|
git stash push -u -m "push-to-gitea: pre-merge $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
|
stashed=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git merge --no-edit "${GITEA_REMOTE}/${GIT_BRANCH}"; then
|
||||||
|
if $stashed; then
|
||||||
|
warn "merge 충돌 — stash 는 유지됨. 해결 후: git stash pop && ./server-dev/push-to-gitea.sh"
|
||||||
|
else
|
||||||
|
warn "merge 충돌 — 해결 후 ./server-dev/push-to-gitea.sh 재실행"
|
||||||
|
fi
|
||||||
|
fail "Gitea merge 실패 (충돌 수동 해결 필요)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $stashed; then
|
||||||
|
log "stash 복원..."
|
||||||
|
if ! git stash pop; then
|
||||||
|
fail "stash pop 충돌 — git status 확인 후 해결·재실행"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "✅ Gitea 변경 merge 완료"
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_from_gitea
|
||||||
|
|
||||||
if $DRY_RUN; then
|
if $DRY_RUN; then
|
||||||
log "[dry-run] git add / commit / push 생략"
|
log "[dry-run] git add / commit / push 생략"
|
||||||
git status -sb
|
git status -sb
|
||||||
@@ -86,7 +152,8 @@ git add local-dev/ server-dev/ scripts/ git_fetch_all.sh 2>/dev/null || true
|
|||||||
git add start-all-server.sh stop-all-server.sh 2>/dev/null || true
|
git add start-all-server.sh stop-all-server.sh 2>/dev/null || true
|
||||||
|
|
||||||
for path in chatbotApp-chatbot2.0-agent chatbotApi-chatbot2.0-agent \
|
for path in chatbotApp-chatbot2.0-agent chatbotApi-chatbot2.0-agent \
|
||||||
exAiChatBot-chatbot2.0-agent kakaoChatbotSkill-chatbot2.0-agent; do
|
exAiChatBot-chatbot2.0-agent kakaoChatbotSkill-chatbot2.0-agent \
|
||||||
|
chatbotDesktopApp-chatbot2.0; do
|
||||||
[[ -d "${path}" ]] && git add "${path}" 2>/dev/null || true
|
[[ -d "${path}" ]] && git add "${path}" 2>/dev/null || true
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -94,14 +161,13 @@ done
|
|||||||
git add -u
|
git add -u
|
||||||
|
|
||||||
if ! git diff --cached --quiet; then
|
if ! git diff --cached --quiet; then
|
||||||
msg="Deploy: GitHub submodule sync $(date '+%Y-%m-%d %H:%M:%S')"
|
msg="Deploy: exdev sync $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
log "monorepo 커밋: ${msg}"
|
log "monorepo 커밋: ${msg}"
|
||||||
git commit -m "${msg}"
|
git commit -m "${msg}"
|
||||||
else
|
else
|
||||||
log "monorepo 스테이징 변경 없음"
|
log "monorepo 스테이징 변경 없음"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git fetch "${GITEA_REMOTE}" "${GIT_BRANCH}" 2>/dev/null || true
|
|
||||||
local_rev="$(git rev-parse HEAD)"
|
local_rev="$(git rev-parse HEAD)"
|
||||||
remote_rev=""
|
remote_rev=""
|
||||||
if git rev-parse "${GITEA_REMOTE}/${GIT_BRANCH}" >/dev/null 2>&1; then
|
if git rev-parse "${GITEA_REMOTE}/${GIT_BRANCH}" >/dev/null 2>&1; then
|
||||||
@@ -113,6 +179,22 @@ if [[ -n "${remote_rev}" && "${local_rev}" == "${remote_rev}" ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# push 직전 한 번 더 원격 확인 (동시 배포 대비)
|
||||||
|
git fetch "${GITEA_REMOTE}" "${GIT_BRANCH}" 2>/dev/null || true
|
||||||
|
if git rev-parse "${GITEA_REMOTE}/${GIT_BRANCH}" >/dev/null 2>&1; then
|
||||||
|
remote_rev="$(git rev-parse "${GITEA_REMOTE}/${GIT_BRANCH}")"
|
||||||
|
if [[ "${local_rev}" != "${remote_rev}" ]] \
|
||||||
|
&& ! git merge-base --is-ancestor "${remote_rev}" "${local_rev}" 2>/dev/null; then
|
||||||
|
log "push 직전 원격 추가 커밋 발견 — 재 merge..."
|
||||||
|
if ! git merge --no-edit "${GITEA_REMOTE}/${GIT_BRANCH}"; then
|
||||||
|
fail "push 직전 merge 실패 — 충돌 해결 후 재실행"
|
||||||
|
fi
|
||||||
|
local_rev="$(git rev-parse HEAD)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
log "Gitea push ${GITEA_REMOTE} ${GIT_BRANCH} (${local_rev:0:7})..."
|
log "Gitea push ${GITEA_REMOTE} ${GIT_BRANCH} (${local_rev:0:7})..."
|
||||||
git push "${GITEA_REMOTE}" "${GIT_BRANCH}"
|
if ! git push "${GITEA_REMOTE}" "${GIT_BRANCH}"; then
|
||||||
|
fail "Gitea push 실패 — 다른 사람이 먼저 push 했을 수 있음. 재실행: ./server-dev/push-to-gitea.sh"
|
||||||
|
fi
|
||||||
log "✅ Gitea push 완료 — post-receive 배포 트리거됨"
|
log "✅ Gitea push 완료 — post-receive 배포 트리거됨"
|
||||||
|
|||||||
Regular → Executable
+297
-59
@@ -3,11 +3,24 @@
|
|||||||
#
|
#
|
||||||
# ./server-dev/start-all-server.sh
|
# ./server-dev/start-all-server.sh
|
||||||
# ./server-dev/start-all-server.sh --no-build
|
# ./server-dev/start-all-server.sh --no-build
|
||||||
|
# ./server-dev/start-all-server.sh --skip-desktop
|
||||||
# ./server-dev/start-all-server.sh --skip-java
|
# ./server-dev/start-all-server.sh --skip-java
|
||||||
# ./server-dev/start-all-server.sh --skip-legacy-stop
|
# ./server-dev/start-all-server.sh --skip-legacy-stop
|
||||||
# ./server-dev/start-all-server.sh --no-pull # git 동기화 생략
|
# ./server-dev/start-all-server.sh --no-pull # git 동기화 생략
|
||||||
# ./server-dev/start-all-server.sh --no-push # Gitea push 생략
|
# ./server-dev/start-all-server.sh --no-push # Gitea push 생략
|
||||||
|
# ./server-dev/start-all-server.sh --skip-oracle # TROAD Oracle 기동 생략
|
||||||
# ./server-dev/start-all-server.sh --local # 로컬 Mac 개발 모드 (local-dev 위임)
|
# ./server-dev/start-all-server.sh --local # 로컬 Mac 개발 모드 (local-dev 위임)
|
||||||
|
#
|
||||||
|
# ★ 개발서버(exdev) 주소/설정은 이 스크립트가 런타임 ENV 로만 적용한다.
|
||||||
|
# - WAS Mongo → 127.0.0.1 (SPRING_DATA_MONGODB_URI)
|
||||||
|
# - WAS TROAD Oracle → 127.0.0.1:1521/ORCL2 (SPRING_DATASOURCE_TROAD_*)
|
||||||
|
# - Skill → 로컬 WAS/RAG (CHATBOT_API_BASE_URL, RAG_AGENT_CHAT_URL)
|
||||||
|
# - RAG .env → host.docker.internal + EXDEV_LOCAL=true
|
||||||
|
# application.yml 등 커밋 파일은 운영 기본값(172.16.*)을 유지한다.
|
||||||
|
# 공식 GitHub 반영은 ./git_fetch_all.sh 전용 (exdev 주소를 push 하지 않음).
|
||||||
|
#
|
||||||
|
# 로컬 Mac 실행 시: Gitea(exdev) 최신 merge → 현재 소스 commit/push → 원격 배포.
|
||||||
|
# 공식 GitHub(KoreaExpressWayCorp) push 는 하지 않음 — ./git_fetch_all.sh 전용.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
@@ -23,16 +36,25 @@ RAG_DIR="${ROOT_DIR}/exAiChatBot-chatbot2.0-agent"
|
|||||||
API_DIR="${ROOT_DIR}/chatbotApi-chatbot2.0-agent"
|
API_DIR="${ROOT_DIR}/chatbotApi-chatbot2.0-agent"
|
||||||
SKILL_DIR="${ROOT_DIR}/kakaoChatbotSkill-chatbot2.0-agent"
|
SKILL_DIR="${ROOT_DIR}/kakaoChatbotSkill-chatbot2.0-agent"
|
||||||
APP_DIR="${ROOT_DIR}/chatbotApp-chatbot2.0-agent"
|
APP_DIR="${ROOT_DIR}/chatbotApp-chatbot2.0-agent"
|
||||||
|
DESKTOP_DIR="${ROOT_DIR}/chatbotDesktopApp-chatbot2.0"
|
||||||
|
|
||||||
ENV_TEMPLATE="${SERVER_DEV_DIR}/env.exdev-server.template"
|
ENV_TEMPLATE="${SERVER_DEV_DIR}/env.exdev-server.template"
|
||||||
RAG_ENV="${RAG_DIR}/.env"
|
RAG_ENV="${RAG_DIR}/.env"
|
||||||
COMPOSE_SERVER="${RAG_DIR}/docker-compose.server.yml"
|
COMPOSE_SERVER="${RAG_DIR}/docker-compose.server.yml"
|
||||||
COMPOSE_CADDY="${SERVER_DEV_DIR}/docker-compose.caddy.yml"
|
COMPOSE_CADDY="${SERVER_DEV_DIR}/docker-compose.caddy.yml"
|
||||||
|
COMPOSE_ORACLE="${SERVER_DEV_DIR}/docker-compose.oracle.yml"
|
||||||
LEGACY_STACK_DIR="${LEGACY_STACK_DIR:-/Users/aidev/dev/exAIChatbot2.0}"
|
LEGACY_STACK_DIR="${LEGACY_STACK_DIR:-/Users/aidev/dev/exAIChatbot2.0}"
|
||||||
|
|
||||||
MONGO_CONTAINER="${MONGO_CONTAINER:-exaichatbot-agent-mongo}"
|
MONGO_CONTAINER="${MONGO_CONTAINER:-exaichatbot-agent-mongo}"
|
||||||
|
ORACLE_CONTAINER="${ORACLE_CONTAINER:-exaichatbot-agent-oracle-troad}"
|
||||||
INTERNAL_TOOL_API_KEY="${INTERNAL_TOOL_API_KEY:-exdev-agent-tool-key}"
|
INTERNAL_TOOL_API_KEY="${INTERNAL_TOOL_API_KEY:-exdev-agent-tool-key}"
|
||||||
PUBLIC_BASE_URL="${PUBLIC_BASE_URL:-https://chatbot.exdev.co.kr}"
|
PUBLIC_BASE_URL="${PUBLIC_BASE_URL:-https://chatbot.exdev.co.kr}"
|
||||||
|
# exdev 전용 — 소스(application.yml)를 수정하지 않고 ENV 로만 주입
|
||||||
|
EXDEV_MONGO_URI="${EXDEV_MONGO_URI:-mongodb://127.0.0.1:27017/chatbot?heartbeatFrequencyMS=30000&minPoolSize=8&maxIdleTimeMS=18000000}"
|
||||||
|
# Docker Oracle (server-dev/docker-compose.oracle.yml) — 운영 172.16.163.76 대신 로컬
|
||||||
|
EXDEV_TROAD_JDBC_URL="${EXDEV_TROAD_JDBC_URL:-jdbc:oracle:thin:@127.0.0.1:1521/ORCL2}"
|
||||||
|
EXDEV_TROAD_USERNAME="${EXDEV_TROAD_USERNAME:-OPR_MAIN}"
|
||||||
|
EXDEV_TROAD_PASSWORD="${EXDEV_TROAD_PASSWORD:-${ORACLE_TROAD_PASSWORD:-test}}"
|
||||||
|
|
||||||
LLM_PORT="${LLM_PORT:-16000}"
|
LLM_PORT="${LLM_PORT:-16000}"
|
||||||
EMBED_PORT="${EMBED_PORT:-16001}"
|
EMBED_PORT="${EMBED_PORT:-16001}"
|
||||||
@@ -47,6 +69,8 @@ NO_BUILD=false
|
|||||||
SKIP_JAVA=false
|
SKIP_JAVA=false
|
||||||
SKIP_LEGACY_STOP=false
|
SKIP_LEGACY_STOP=false
|
||||||
SKIP_CADDY=false
|
SKIP_CADDY=false
|
||||||
|
SKIP_DESKTOP=false
|
||||||
|
SKIP_ORACLE=false
|
||||||
NO_PULL=false
|
NO_PULL=false
|
||||||
NO_PUSH=false
|
NO_PUSH=false
|
||||||
LOCAL_DEV=false
|
LOCAL_DEV=false
|
||||||
@@ -58,11 +82,13 @@ for arg in "$@"; do
|
|||||||
--skip-java) SKIP_JAVA=true ;;
|
--skip-java) SKIP_JAVA=true ;;
|
||||||
--skip-legacy-stop) SKIP_LEGACY_STOP=true ;;
|
--skip-legacy-stop) SKIP_LEGACY_STOP=true ;;
|
||||||
--skip-caddy) SKIP_CADDY=true ;;
|
--skip-caddy) SKIP_CADDY=true ;;
|
||||||
|
--skip-desktop) SKIP_DESKTOP=true ;;
|
||||||
|
--skip-oracle) SKIP_ORACLE=true ;;
|
||||||
--no-pull) NO_PULL=true ;;
|
--no-pull) NO_PULL=true ;;
|
||||||
--no-push) NO_PUSH=true ;;
|
--no-push) NO_PUSH=true ;;
|
||||||
--local) LOCAL_DEV=true ;;
|
--local) LOCAL_DEV=true ;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
sed -n '2,12p' "$0"
|
sed -n '2,15p' "$0"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -78,29 +104,8 @@ log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
|||||||
fail() { log "ERROR: $*"; exit 1; }
|
fail() { log "ERROR: $*"; exit 1; }
|
||||||
warn() { log "⚠️ $*"; }
|
warn() { log "⚠️ $*"; }
|
||||||
|
|
||||||
sync_github_submodules() {
|
# 공식 GitHub 동기화/push 는 start-all-server 경로에서 절대 수행하지 않음.
|
||||||
local tree="$1"
|
# (과거: git_fetch_all.sh 호출 → 로컬 수정이 공식 GitHub 로 올라가던 문제 방지)
|
||||||
local fetch_script="${tree}/git_fetch_all.sh"
|
|
||||||
local -a fetch_args=()
|
|
||||||
if is_exdev_server; then
|
|
||||||
fetch_args+=(--init)
|
|
||||||
fi
|
|
||||||
if [[ ! -x "${fetch_script}" ]]; then
|
|
||||||
log "git_fetch_all.sh 없음 — submodule GitHub 동기화 생략"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
log "GitHub submodule 최신 동기화 (git_fetch_all.sh)..."
|
|
||||||
if [[ ${#fetch_args[@]} -gt 0 ]]; then
|
|
||||||
if ! "${fetch_script}" "${fetch_args[@]}"; then
|
|
||||||
warn "GitHub submodule 동기화 실패 — ./git_fetch_all.sh 수동 실행"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
elif ! "${fetch_script}"; then
|
|
||||||
warn "GitHub submodule 동기화 실패 — ./git_fetch_all.sh 수동 실행"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
push_source_to_gitea() {
|
push_source_to_gitea() {
|
||||||
if $NO_PUSH; then
|
if $NO_PUSH; then
|
||||||
@@ -126,7 +131,7 @@ wait_remote_deploy() {
|
|||||||
EXDEV_SSH="${EXDEV_SSH}" PUBLIC_BASE_URL="${PUBLIC_BASE_URL}" "${wait_script}" || \
|
EXDEV_SSH="${EXDEV_SSH}" PUBLIC_BASE_URL="${PUBLIC_BASE_URL}" "${wait_script}" || \
|
||||||
warn "원격 배포 대기 실패 — ssh ${EXDEV_SSH} tail /Volumes/ADATA/logs/deploy/exAichatbot_agent.log"
|
warn "원격 배포 대기 실패 — ssh ${EXDEV_SSH} tail /Volumes/ADATA/logs/deploy/exAichatbot_agent.log"
|
||||||
else
|
else
|
||||||
warn "wait-remote-deploy.sh 없음 — https://chatbot.exdev.co.kr/chatbot/app/ 수동 확인"
|
warn "wait-remote-deploy.sh 없음 — https://chatbot.exdev.co.kr/chatbot/ai/ 수동 확인"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,12 +151,14 @@ trigger_remote_deploy() {
|
|||||||
rm -f \"\${WT}/.git\" /tmp/exAichatbot_agent_deploy.lock"
|
rm -f \"\${WT}/.git\" /tmp/exAichatbot_agent_deploy.lock"
|
||||||
sync_submodules_to_server
|
sync_submodules_to_server
|
||||||
log "원격 deploy (빌드 + 기동)..."
|
log "원격 deploy (빌드 + 기동)..."
|
||||||
ssh -o BatchMode=yes "${EXDEV_SSH}" \
|
# SSH 세션에서 deploy 가 끝나므로, 실패 시 즉시 중단 (wait 900s 방지)
|
||||||
|
if ! ssh -o BatchMode=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=120 "${EXDEV_SSH}" \
|
||||||
"cp /Users/aidev/dev/exAichatbot_agent/server-dev/deploy.sh /Volumes/ADATA/git/deploy-exAichatbot_agent.sh 2>/dev/null || true; \
|
"cp /Users/aidev/dev/exAichatbot_agent/server-dev/deploy.sh /Volumes/ADATA/git/deploy-exAichatbot_agent.sh 2>/dev/null || true; \
|
||||||
chmod +x /Volumes/ADATA/git/deploy-exAichatbot_agent.sh; \
|
chmod +x /Volumes/ADATA/git/deploy-exAichatbot_agent.sh; \
|
||||||
export PATH=\"/opt/homebrew/bin:/Applications/Docker.app/Contents/Resources/bin:\$PATH\"; \
|
export PATH=\"/opt/homebrew/bin:/Applications/Docker.app/Contents/Resources/bin:\$PATH\"; \
|
||||||
bash /Volumes/ADATA/git/deploy-exAichatbot_agent.sh --start-only" \
|
bash /Volumes/ADATA/git/deploy-exAichatbot_agent.sh --start-only"; then
|
||||||
|| warn "원격 deploy 실패"
|
fail "원격 deploy 실패 — ssh ${EXDEV_SSH} 'tail -80 /Volumes/ADATA/logs/deploy/exAichatbot_agent.log'"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
build_chatbot_app_for_deploy() {
|
build_chatbot_app_for_deploy() {
|
||||||
@@ -162,22 +169,35 @@ build_chatbot_app_for_deploy() {
|
|||||||
cd "${APP_DIR}/web"
|
cd "${APP_DIR}/web"
|
||||||
npm ci --prefer-offline 2>/dev/null || npm install
|
npm ci --prefer-offline 2>/dev/null || npm install
|
||||||
)
|
)
|
||||||
bash "${APP_DIR}/build.sh"
|
NEXT_PUBLIC_FARE_QUERY_MOCK=true bash "${APP_DIR}/build.sh"
|
||||||
[[ -f "${APP_DIR}/public/index.html" ]] || fail "chatbotApp public/ 빌드 실패"
|
[[ -f "${APP_DIR}/public/index.html" ]] || fail "chatbotApp public/ 빌드 실패"
|
||||||
|
[[ -f "${APP_DIR}/public-ai/index.html" ]] || fail "chatbotApp public-ai/ 빌드 실패"
|
||||||
|
build_desktop_app
|
||||||
|
}
|
||||||
|
|
||||||
|
build_desktop_app() {
|
||||||
|
if $NO_BUILD || $SKIP_DESKTOP; then
|
||||||
|
log "데스크톱 앱 빌드 생략 (--no-build/--skip-desktop)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
[[ -d "${DESKTOP_DIR}" ]] || fail "데스크톱 앱 디렉터리 없음: ${DESKTOP_DIR}"
|
||||||
|
chmod +x "${DESKTOP_DIR}/build-and-publish.sh"
|
||||||
|
log "chatbotDesktopApp Electron 재빌드 + downloads 배포..."
|
||||||
|
# 서버/원격 배포용: Mac + Windows 모두 생성
|
||||||
|
SKIP_WIN="${SKIP_WIN:-0}" SKIP_MAC="${SKIP_MAC:-0}" \
|
||||||
|
bash "${DESKTOP_DIR}/build-and-publish.sh"
|
||||||
}
|
}
|
||||||
|
|
||||||
deploy_from_local_mac() {
|
deploy_from_local_mac() {
|
||||||
log "로컬 Mac → Gitea push → chatbot.exdev.co.kr 배포"
|
log "로컬 Mac → Gitea(exdev) sync(merge) → push → chatbot.exdev.co.kr 배포"
|
||||||
if ! $NO_PULL; then
|
log "공식 GitHub push 생략 (필요 시 ./git_fetch_all.sh)"
|
||||||
sync_github_submodules "${ROOT_DIR}" || true
|
|
||||||
fi
|
|
||||||
build_chatbot_app_for_deploy
|
build_chatbot_app_for_deploy
|
||||||
push_source_to_gitea
|
push_source_to_gitea
|
||||||
trigger_remote_deploy
|
trigger_remote_deploy
|
||||||
wait_remote_deploy
|
wait_remote_deploy
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
log "원격 배포 요청 완료"
|
log "원격 배포 요청 완료"
|
||||||
log " UI ${PUBLIC_BASE_URL}/chatbot/app/"
|
log " UI ${PUBLIC_BASE_URL}/chatbot/ai/"
|
||||||
log " 로그 ssh ${EXDEV_SSH} tail -f /Volumes/ADATA/logs/deploy/exAichatbot_agent.log"
|
log " 로그 ssh ${EXDEV_SSH} tail -f /Volumes/ADATA/logs/deploy/exAichatbot_agent.log"
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
exit 0
|
exit 0
|
||||||
@@ -199,19 +219,23 @@ sync_source_from_git() {
|
|||||||
fail "브랜치 없음: ${branch} (GIT_DIR=${GIT_DIR})"
|
fail "브랜치 없음: ${branch} (GIT_DIR=${GIT_DIR})"
|
||||||
fi
|
fi
|
||||||
git --work-tree="${tree}" --git-dir="${GIT_DIR}" checkout -f "${branch}"
|
git --work-tree="${tree}" --git-dir="${GIT_DIR}" checkout -f "${branch}"
|
||||||
sync_github_submodules "${tree}" || true
|
# Gitea work tree 만 사용 — 공식 GitHub fetch/push 없음
|
||||||
|
if [[ -f "${tree}/.gitmodules" ]]; then
|
||||||
|
log "Gitea submodule 포인터 checkout..."
|
||||||
|
git -C "${tree}" submodule update --init --recursive 2>/dev/null || \
|
||||||
|
warn "submodule update 실패 — rsync/배포 산출물로 계속"
|
||||||
|
fi
|
||||||
local commit
|
local commit
|
||||||
commit="$(git --git-dir="${GIT_DIR}" rev-parse --short HEAD)"
|
commit="$(git --git-dir="${GIT_DIR}" rev-parse --short HEAD)"
|
||||||
log "✅ 소스 동기화: ${commit} (${branch})"
|
log "✅ 소스 동기화(Gitea): ${commit} (${branch})"
|
||||||
elif [[ -d "${ROOT_DIR}/.git" ]]; then
|
elif [[ -d "${ROOT_DIR}/.git" ]]; then
|
||||||
log "git pull origin ${branch}..."
|
log "git pull origin ${branch} (Gitea/monorepo)..."
|
||||||
(
|
(
|
||||||
cd "${ROOT_DIR}"
|
cd "${ROOT_DIR}"
|
||||||
git fetch origin "${branch}"
|
git fetch origin "${branch}"
|
||||||
git checkout "${branch}"
|
git checkout "${branch}"
|
||||||
git pull --ff-only origin "${branch}"
|
git pull --ff-only origin "${branch}"
|
||||||
)
|
)
|
||||||
sync_github_submodules "${ROOT_DIR}" || true
|
|
||||||
log "✅ git pull 완료: $(git -C "${ROOT_DIR}" rev-parse --short HEAD)"
|
log "✅ git pull 완료: $(git -C "${ROOT_DIR}" rev-parse --short HEAD)"
|
||||||
tree="${ROOT_DIR}"
|
tree="${ROOT_DIR}"
|
||||||
else
|
else
|
||||||
@@ -222,7 +246,8 @@ sync_source_from_git() {
|
|||||||
chmod +x "${tree}/server-dev/"*.sh 2>/dev/null || true
|
chmod +x "${tree}/server-dev/"*.sh 2>/dev/null || true
|
||||||
chmod +x "${tree}/git_fetch_all.sh" 2>/dev/null || true
|
chmod +x "${tree}/git_fetch_all.sh" 2>/dev/null || true
|
||||||
chmod +x "${tree}/chatbotApp-chatbot2.0-agent/build.sh" 2>/dev/null || true
|
chmod +x "${tree}/chatbotApp-chatbot2.0-agent/build.sh" 2>/dev/null || true
|
||||||
chmod +x "${tree}/start-all-server.sh" "${tree}/stop-all-server.sh" 2>/dev/null || true
|
chmod +x "${tree}/chatbotDesktopApp-chatbot2.0/build-and-publish.sh" 2>/dev/null || true
|
||||||
|
chmod +x "${tree}/start-all-server.sh" "${tree}/stop-all-server.sh" "${tree}/start-all.sh" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
is_exdev_server() {
|
is_exdev_server() {
|
||||||
@@ -235,6 +260,7 @@ run_local_dev() {
|
|||||||
local -a args=()
|
local -a args=()
|
||||||
$NO_BUILD && args+=(--no-build)
|
$NO_BUILD && args+=(--no-build)
|
||||||
$SKIP_JAVA && args+=(--skip-java)
|
$SKIP_JAVA && args+=(--skip-java)
|
||||||
|
$SKIP_DESKTOP && args+=(--skip-desktop)
|
||||||
if ((${#args[@]} > 0)); then
|
if ((${#args[@]} > 0)); then
|
||||||
exec "${ROOT_DIR}/local-dev/start-all.sh" "${args[@]}"
|
exec "${ROOT_DIR}/local-dev/start-all.sh" "${args[@]}"
|
||||||
else
|
else
|
||||||
@@ -318,10 +344,34 @@ stop_legacy_stack() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ensure_rag_env() {
|
ensure_rag_env() {
|
||||||
|
# .env 키=값 갱신 (없으면 append)
|
||||||
|
patch_env() {
|
||||||
|
local key="$1" value="$2" tmp
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
if [[ -f "${RAG_ENV}" ]]; then
|
||||||
|
grep -vE "^${key}=" "${RAG_ENV}" > "${tmp}" || true
|
||||||
|
else
|
||||||
|
: > "${tmp}"
|
||||||
|
fi
|
||||||
|
printf '%s\n%s=%s\n' "$(cat "${tmp}")" "${key}" "${value}" > "${RAG_ENV}"
|
||||||
|
rm -f "${tmp}"
|
||||||
|
}
|
||||||
|
|
||||||
if [[ ! -f "${RAG_ENV}" ]]; then
|
if [[ ! -f "${RAG_ENV}" ]]; then
|
||||||
log ".env 없음 → env.exdev-server.template 복사"
|
log ".env 없음 → env.exdev-server.template 복사"
|
||||||
cp "${ENV_TEMPLATE}" "${RAG_ENV}"
|
cp "${ENV_TEMPLATE}" "${RAG_ENV}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# RAG(Docker) → 호스트 chatbotApi (exdev 로컬 WAS). 운영 IP(172.16.180.130) 사용 금지.
|
||||||
|
# GitHub 커밋 기본값은 운영 IP 유지 — git_fetch_all.sh 가 push 전 복원.
|
||||||
|
patch_env "EXDEV_LOCAL" "true"
|
||||||
|
patch_env "CHATBOT_API_BASE_URL" "http://host.docker.internal:${WAS_PORT}/api"
|
||||||
|
patch_env "INTERNAL_TOOL_API_KEY" "${INTERNAL_TOOL_API_KEY}"
|
||||||
|
patch_env "CHATBOT_TOOL_TIMEOUT" "60"
|
||||||
|
if grep -qE 'CHATBOT_API_BASE_URL=.*172\.16\.180\.130' "${RAG_ENV}" 2>/dev/null; then
|
||||||
|
fail "exdev RAG .env 에 운영 WAS(172.16.180.130) 가 남아 있습니다"
|
||||||
|
fi
|
||||||
|
log "RAG .env WAS: host.docker.internal:${WAS_PORT} (로컬 chatbotApi, EXDEV_LOCAL=true)"
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_mongo() {
|
ensure_mongo() {
|
||||||
@@ -340,6 +390,91 @@ ensure_mongo() {
|
|||||||
wait_port 27017 "MongoDB" 30 || true
|
wait_port 27017 "MongoDB" 30 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oracle_container_running() {
|
||||||
|
docker ps --format '{{.Names}}' 2>/dev/null | grep -qx "${ORACLE_CONTAINER}"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_oracle_ready() {
|
||||||
|
local max="${1:-300}" i=0
|
||||||
|
log "Oracle TROAD 준비 대기 (최대 ${max}s)..."
|
||||||
|
while (( i < max )); do
|
||||||
|
if oracle_container_running && docker exec "${ORACLE_CONTAINER}" healthcheck.sh >/dev/null 2>&1; then
|
||||||
|
log "✅ Oracle TROAD ready (localhost:1521/orcl2, OPR_MAIN)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
i=$((i + 5))
|
||||||
|
done
|
||||||
|
warn "Oracle TROAD 타임아웃 — docker logs ${ORACLE_CONTAINER}"
|
||||||
|
docker logs --tail 40 "${ORACLE_CONTAINER}" 2>/dev/null | sed 's/^/ /' || true
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 교통정보 뷰가 비어 있으면 oracle/apply-sql.sh 로 적용한다.
|
||||||
|
# (기존 chatbotApi SQL: TROAD_APP.V_ROUTE_NEW_NM / V_ROUTE_TRFC_VER001 등 — 앱 로직 변경 없음)
|
||||||
|
ensure_troad_schema() {
|
||||||
|
local apply="${SERVER_DEV_DIR}/oracle/apply-sql.sh"
|
||||||
|
[[ -x "$apply" ]] || return 0
|
||||||
|
|
||||||
|
local rows route_rows
|
||||||
|
rows="$(docker exec -e NLS_LANG=.AL32UTF8 "${ORACLE_CONTAINER}" bash -lc \
|
||||||
|
"sqlplus -S -L OPR_MAIN/${ORACLE_TROAD_PASSWORD:-test}@localhost:1521/ORCL2 <<'EOSQL'
|
||||||
|
SET HEADING OFF
|
||||||
|
SET FEEDBACK OFF
|
||||||
|
SET PAGESIZE 0
|
||||||
|
SELECT COUNT(*) FROM V_INCIDENT_FTMS;
|
||||||
|
EXIT
|
||||||
|
EOSQL" 2>/dev/null | tr -dc '0-9')"
|
||||||
|
route_rows="$(docker exec -e NLS_LANG=.AL32UTF8 "${ORACLE_CONTAINER}" bash -lc \
|
||||||
|
"sqlplus -S -L OPR_MAIN/${ORACLE_TROAD_PASSWORD:-test}@localhost:1521/ORCL2 <<'EOSQL'
|
||||||
|
SET HEADING OFF
|
||||||
|
SET FEEDBACK OFF
|
||||||
|
SET PAGESIZE 0
|
||||||
|
SELECT COUNT(*) FROM TROAD_APP.V_ROUTE_NEW_NM;
|
||||||
|
EXIT
|
||||||
|
EOSQL" 2>/dev/null | tr -dc '0-9')"
|
||||||
|
|
||||||
|
if [[ -n "$rows" && "$rows" -gt 0 && -n "$route_rows" && "$route_rows" -gt 0 ]]; then
|
||||||
|
log "✅ TROAD 교통정보 뷰 확인 (V_INCIDENT_FTMS ${rows}건, V_ROUTE_NEW_NM ${route_rows}건)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "TROAD 교통정보 뷰/데이터 적용 (oracle/apply-sql.sh)..."
|
||||||
|
"$apply" >/dev/null 2>&1 \
|
||||||
|
&& log "✅ TROAD 교통정보 뷰 적용 완료" \
|
||||||
|
|| warn "TROAD 스키마 적용 실패 — server-dev/oracle/apply-sql.sh 를 직접 실행해 확인하세요"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_oracle() {
|
||||||
|
if $SKIP_ORACLE; then
|
||||||
|
log "Oracle TROAD 기동 생략 (--skip-oracle)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
[[ -f "${COMPOSE_ORACLE}" ]] || fail "server-dev/docker-compose.oracle.yml 없음"
|
||||||
|
|
||||||
|
# 이미 다른 프로세스가 1521 을 쓰는 경우(비-Oracle 컨테이너)만 경고
|
||||||
|
if ! oracle_container_running && lsof -iTCP:1521 -sTCP:LISTEN >/dev/null 2>&1; then
|
||||||
|
if docker ps --format '{{.Names}} {{.Ports}}' 2>/dev/null | grep -qE '1521'; then
|
||||||
|
log "Oracle :1521 이미 Docker 로 사용 중 — 기존 인스턴스 재사용"
|
||||||
|
wait_oracle_ready 120 && ensure_troad_schema || true
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
warn "호스트 :1521 이 이미 점유됨 — TROAD Oracle 기동 실패 가능"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Oracle TROAD 기동 (docker-compose.oracle.yml)..."
|
||||||
|
(
|
||||||
|
cd "${SERVER_DEV_DIR}"
|
||||||
|
docker compose -f docker-compose.oracle.yml up -d
|
||||||
|
) || fail "Oracle TROAD docker compose up 실패"
|
||||||
|
|
||||||
|
if wait_oracle_ready 360; then
|
||||||
|
ensure_troad_schema
|
||||||
|
else
|
||||||
|
warn "Oracle 미준비 — chatbotApi TROAD 조회가 실패할 수 있음"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
bootstrap_qdrant_if_empty() {
|
bootstrap_qdrant_if_empty() {
|
||||||
local collection="${QDRANT_COLLECTION:-qa_vectors_v2}"
|
local collection="${QDRANT_COLLECTION:-qa_vectors_v2}"
|
||||||
if [[ -f "${RAG_ENV}" ]]; then
|
if [[ -f "${RAG_ENV}" ]]; then
|
||||||
@@ -371,17 +506,38 @@ start_rag() {
|
|||||||
ensure_rag_env
|
ensure_rag_env
|
||||||
ensure_rag_compose
|
ensure_rag_compose
|
||||||
[[ -f "${COMPOSE_SERVER}" ]] || fail "docker-compose.server.yml 없음"
|
[[ -f "${COMPOSE_SERVER}" ]] || fail "docker-compose.server.yml 없음"
|
||||||
|
# compose environment 보간 + 컨테이너 env (로컬 WAS)
|
||||||
|
export EXDEV_LOCAL=true
|
||||||
|
export CHATBOT_API_BASE_URL="http://host.docker.internal:${WAS_PORT}/api"
|
||||||
|
export INTERNAL_TOOL_API_KEY="${INTERNAL_TOOL_API_KEY}"
|
||||||
|
export CHATBOT_TOOL_TIMEOUT="${CHATBOT_TOOL_TIMEOUT:-60}"
|
||||||
cd "${RAG_DIR}"
|
cd "${RAG_DIR}"
|
||||||
docker compose -f "${COMPOSE_SERVER}" down --remove-orphans 2>/dev/null || true
|
docker compose -f "${COMPOSE_SERVER}" down --remove-orphans 2>/dev/null || true
|
||||||
local -a up_flags=(-d)
|
local -a up_flags=(-d)
|
||||||
if $NO_BUILD; then up_flags+=(--no-build); else up_flags+=(--build); fi
|
if $NO_BUILD; then up_flags+=(--no-build); else up_flags+=(--build); fi
|
||||||
log "RAG 스택 기동 (docker-compose.server.yml)..."
|
log "RAG 스택 기동 (docker-compose.server.yml)..."
|
||||||
|
log " EXDEV_LOCAL=${EXDEV_LOCAL} CHATBOT_API_BASE_URL=${CHATBOT_API_BASE_URL}"
|
||||||
docker compose -f "${COMPOSE_SERVER}" up "${up_flags[@]}"
|
docker compose -f "${COMPOSE_SERVER}" up "${up_flags[@]}"
|
||||||
wait_http "http://127.0.0.1:6333/collections" "Qdrant" 30 || true
|
wait_http "http://127.0.0.1:6333/collections" "Qdrant" 30 || true
|
||||||
bootstrap_qdrant_if_empty
|
bootstrap_qdrant_if_empty
|
||||||
(cd "${RAG_DIR}" && docker compose -f "${COMPOSE_SERVER}" up -d) || true
|
(cd "${RAG_DIR}" && docker compose -f "${COMPOSE_SERVER}" up -d) || true
|
||||||
wait_http "http://127.0.0.1:${RAG_PORT}/health" "RAG API" 180 || true
|
wait_http "http://127.0.0.1:${RAG_PORT}/health" "RAG API" 180 || true
|
||||||
wait_port "${ADMIN_PORT}" "Vector Admin" 30 || true
|
wait_port "${ADMIN_PORT}" "Vector Admin" 30 || true
|
||||||
|
ensure_mongo_schema
|
||||||
|
}
|
||||||
|
|
||||||
|
# 새 소스에만 있는 Mongo 컬렉션(예: usage_sessions)이 배포 대상 DB 에 없을 수 있다.
|
||||||
|
# 기동 시 API 가 스스로 만들지만, 배포 로그에 결과를 남겨 누락을 바로 확인한다.
|
||||||
|
ensure_mongo_schema() {
|
||||||
|
local container="exaichatbot-agent-api-1"
|
||||||
|
if ! docker ps --format '{{.Names}}' | grep -qx "${container}"; then
|
||||||
|
warn "Mongo 스키마 점검 생략 — ${container} 미기동"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log "Mongo 컬렉션·인덱스 점검..."
|
||||||
|
if ! docker exec "${container}" python /app/scripts/mongo_schema.py 2>&1 | sed 's/^/ /'; then
|
||||||
|
warn "Mongo 컬렉션·인덱스 일부 누락 — 위 로그 확인 (챗봇 기동은 계속됨)"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_java() {
|
ensure_java() {
|
||||||
@@ -403,16 +559,50 @@ ensure_java() {
|
|||||||
start_java_service() {
|
start_java_service() {
|
||||||
local name="$1" dir="$2" pid_file="$3" log_file="$4"
|
local name="$1" dir="$2" pid_file="$3" log_file="$4"
|
||||||
shift 4
|
shift 4
|
||||||
|
local port=""
|
||||||
|
case "${name}" in
|
||||||
|
chatbotApi) port="${WAS_PORT}" ;;
|
||||||
|
kakaoChatbotSkill) port="${SKILL_PORT}" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# exdev ENV(로컬 Mongo/WAS/RAG) 재적용을 위해 기존 프로세스는 항상 재기동한다.
|
||||||
if [[ -f "${pid_file}" ]]; then
|
if [[ -f "${pid_file}" ]]; then
|
||||||
local old_pid
|
local old_pid
|
||||||
old_pid="$(cat "${pid_file}")"
|
old_pid="$(cat "${pid_file}")"
|
||||||
if kill -0 "$old_pid" 2>/dev/null; then
|
if kill -0 "$old_pid" 2>/dev/null; then
|
||||||
log "${name} 이미 실행 중 (PID ${old_pid})"
|
log "${name} 재기동 (기존 PID ${old_pid})"
|
||||||
return 0
|
kill "$old_pid" 2>/dev/null || true
|
||||||
|
sleep 2
|
||||||
|
kill -9 "$old_pid" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
rm -f "${pid_file}"
|
rm -f "${pid_file}"
|
||||||
fi
|
fi
|
||||||
|
if [[ -n "${port}" ]]; then
|
||||||
|
local pids
|
||||||
|
pids="$(lsof -tiTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true)"
|
||||||
|
if [[ -n "${pids}" ]]; then
|
||||||
|
log "${name} :${port} 점유 프로세스 종료"
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
kill ${pids} 2>/dev/null || true
|
||||||
|
sleep 1
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
kill -9 ${pids} 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -n "${JAVA_HOME}" ]] || ensure_java
|
||||||
chmod +x "${dir}/gradlew"
|
chmod +x "${dir}/gradlew"
|
||||||
|
|
||||||
|
# release=8 프로젝트는 Java 8 API만 허용. 기동 전 컴파일로 실패를 즉시 드러낸다.
|
||||||
|
log "${name} 컴파일 확인 (Java ${JAVA_HOME})..."
|
||||||
|
if ! (
|
||||||
|
cd "${dir}"
|
||||||
|
export JAVA_HOME
|
||||||
|
./gradlew -Dorg.gradle.java.home="${JAVA_HOME}" compileJava --quiet
|
||||||
|
); then
|
||||||
|
fail "${name} 컴파일 실패 — ${dir} 소스/JDK 확인 (Java 8 API만 사용, isBlank/List.of 금지)"
|
||||||
|
fi
|
||||||
|
|
||||||
log "${name} 기동 중..."
|
log "${name} 기동 중..."
|
||||||
: > "${log_file}"
|
: > "${log_file}"
|
||||||
(
|
(
|
||||||
@@ -423,6 +613,15 @@ start_java_service() {
|
|||||||
echo $! > "${pid_file}"
|
echo $! > "${pid_file}"
|
||||||
)
|
)
|
||||||
log "${name} PID $(cat "${pid_file}") → ${log_file}"
|
log "${name} PID $(cat "${pid_file}") → ${log_file}"
|
||||||
|
|
||||||
|
if [[ -n "${port}" ]]; then
|
||||||
|
if ! wait_port "${port}" "${name}" 240; then
|
||||||
|
warn "${name} :${port} 미개방 — 최근 로그:"
|
||||||
|
tail -40 "${log_file}" 2>/dev/null | sed 's/^/ /' || true
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
build_chatbot_app() {
|
build_chatbot_app() {
|
||||||
@@ -435,7 +634,8 @@ build_chatbot_app() {
|
|||||||
cd "${APP_DIR}/web"
|
cd "${APP_DIR}/web"
|
||||||
npm ci --prefer-offline 2>/dev/null || npm install
|
npm ci --prefer-offline 2>/dev/null || npm install
|
||||||
)
|
)
|
||||||
bash "${APP_DIR}/build.sh"
|
NEXT_PUBLIC_FARE_QUERY_MOCK=true bash "${APP_DIR}/build.sh"
|
||||||
|
build_desktop_app
|
||||||
}
|
}
|
||||||
|
|
||||||
start_chatbot_app() {
|
start_chatbot_app() {
|
||||||
@@ -448,7 +648,7 @@ start_chatbot_app() {
|
|||||||
export CHATBOT_API_HOST="host.docker.internal"
|
export CHATBOT_API_HOST="host.docker.internal"
|
||||||
docker compose up -d --force-recreate
|
docker compose up -d --force-recreate
|
||||||
)
|
)
|
||||||
wait_http "http://127.0.0.1:${APP_PORT}/chatbot/app/" "chatbotApp UI" 60 || true
|
wait_http "http://127.0.0.1:${APP_PORT}/chatbot/ai/" "chatbotApp UI" 60 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
start_caddy() {
|
start_caddy() {
|
||||||
@@ -466,7 +666,7 @@ start_caddy() {
|
|||||||
export LEGACY_CERTS_DIR="${cert_dir}"
|
export LEGACY_CERTS_DIR="${cert_dir}"
|
||||||
docker compose -f docker-compose.caddy.yml up -d --force-recreate
|
docker compose -f docker-compose.caddy.yml up -d --force-recreate
|
||||||
)
|
)
|
||||||
wait_http "https://chatbot.exdev.co.kr/chatbot/app/" "HTTPS UI" 30 || true
|
wait_http "https://chatbot.exdev.co.kr/chatbot/ai/" "HTTPS UI" 30 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_stack() {
|
verify_stack() {
|
||||||
@@ -475,7 +675,36 @@ verify_stack() {
|
|||||||
curl -sf "http://127.0.0.1:${RAG_PORT}/health" | grep -q '"status"' || { log "❌ RAG health"; ok=false; }
|
curl -sf "http://127.0.0.1:${RAG_PORT}/health" | grep -q '"status"' || { log "❌ RAG health"; ok=false; }
|
||||||
wait_port "${WAS_PORT}" "chatbotApi" 5 || ok=false
|
wait_port "${WAS_PORT}" "chatbotApi" 5 || ok=false
|
||||||
wait_port "${SKILL_PORT}" "kakaoChatbotSkill" 5 || ok=false
|
wait_port "${SKILL_PORT}" "kakaoChatbotSkill" 5 || ok=false
|
||||||
curl -sf "http://127.0.0.1:${APP_PORT}/chatbot/app/" | grep -q 'data-chatbot-app' || { log "❌ chatbotApp UI"; ok=false; }
|
curl -sf "http://127.0.0.1:${APP_PORT}/chatbot/ai/" | grep -q 'data-chatbot-app="ai-mode"' || { log "❌ chatbotApp UI"; ok=false; }
|
||||||
|
# exdev 는 운영 WAS IP 를 절대 참조하지 않아야 한다
|
||||||
|
local rag_was
|
||||||
|
rag_was="$(docker exec exaichatbot-agent-api-1 printenv CHATBOT_API_BASE_URL 2>/dev/null || true)"
|
||||||
|
if [[ "${rag_was}" == *172.16.180.130* ]]; then
|
||||||
|
log "❌ RAG 가 운영 WAS(172.16.180.130) 를 참조 중: ${rag_was}"
|
||||||
|
ok=false
|
||||||
|
fi
|
||||||
|
# 로컬 WAS tool 정의 로드 (음식메뉴 등 WEB tool 전제)
|
||||||
|
local tools_json
|
||||||
|
tools_json="$(curl -sf -m 8 -H "X-Internal-Tool-Key: ${INTERNAL_TOOL_API_KEY}" \
|
||||||
|
"http://127.0.0.1:${WAS_PORT}/api/v1/tools/definitions" 2>/dev/null || true)"
|
||||||
|
if ! echo "${tools_json}" | grep -q 'REST_AREA_FOOD_LIST'; then
|
||||||
|
log "❌ chatbotApi tool 정의에 REST_AREA_FOOD_LIST 없음 (WAS 미기동/연동 실패)"
|
||||||
|
ok=false
|
||||||
|
else
|
||||||
|
log "✅ chatbotApi domain tools OK"
|
||||||
|
fi
|
||||||
|
# TROAD Oracle 은 반드시 로컬 Docker(127.0.0.1:1521) — 운영 172.16.163.76 타임아웃 방지
|
||||||
|
if ! $SKIP_ORACLE && ! $SKIP_JAVA; then
|
||||||
|
local cong_code
|
||||||
|
cong_code="$(curl -sS -m 25 -o /tmp/exdev-cong.json -w '%{http_code}' \
|
||||||
|
"http://127.0.0.1:${WAS_PORT}/api/troad/congestion?routeName=%EA%B2%BD%EB%B6%80%EC%84%A0" 2>/dev/null || echo 000)"
|
||||||
|
if [[ "${cong_code}" != "200" ]] || ! grep -q '"status"[[:space:]]*:[[:space:]]*true' /tmp/exdev-cong.json 2>/dev/null; then
|
||||||
|
log "❌ TROAD 정체 조회 실패 (http=${cong_code}) — WAS 가 localhost Oracle 을 보는지 확인"
|
||||||
|
ok=false
|
||||||
|
else
|
||||||
|
log "✅ TROAD Oracle(localhost) congestion OK"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
if $ok; then log "✅ 전체 스택 정상"; return 0; fi
|
if $ok; then log "✅ 전체 스택 정상"; return 0; fi
|
||||||
log "⚠️ 일부 서비스 미응답 — ${LOG_DIR}/ 확인"
|
log "⚠️ 일부 서비스 미응답 — ${LOG_DIR}/ 확인"
|
||||||
return 1
|
return 1
|
||||||
@@ -505,27 +734,34 @@ log "exdev 서버 모드"
|
|||||||
stop_legacy_stack
|
stop_legacy_stack
|
||||||
ensure_host_ai
|
ensure_host_ai
|
||||||
ensure_mongo
|
ensure_mongo
|
||||||
|
ensure_oracle
|
||||||
start_rag
|
start_rag
|
||||||
|
|
||||||
if ! $SKIP_JAVA; then
|
if ! $SKIP_JAVA; then
|
||||||
ensure_java
|
ensure_java
|
||||||
|
# Skill 먼저 (WAS WEB tool 이 Skill data-portal 을 역호출)
|
||||||
|
log "exdev Java ENV: Skill→127.0.0.1 WAS/RAG, WAS Mongo/TROAD Oracle→127.0.0.1 (소스 yml 미변경)"
|
||||||
|
start_java_service "kakaoChatbotSkill" "${SKILL_DIR}" \
|
||||||
|
"${RUN_DIR}/kakao-skill.pid" "${LOG_DIR}/kakao-skill.log" \
|
||||||
|
"EXDEV_LOCAL=true" \
|
||||||
|
"AGENT_MODE=agent" \
|
||||||
|
"RAG_AGENT_CHAT_URL=http://127.0.0.1:${RAG_PORT}/agent/chat" \
|
||||||
|
"CHATBOT_API_BASE_URL=http://127.0.0.1:${WAS_PORT}/api/" \
|
||||||
|
"INTERNAL_TOOL_API_KEY=${INTERNAL_TOOL_API_KEY}" \
|
||||||
|
"CHATBOT_APP_URL=${PUBLIC_BASE_URL}/chatbot/ai/" \
|
||||||
|
|| warn "kakaoChatbotSkill 기동 실패"
|
||||||
|
|
||||||
start_java_service "chatbotApi" "${API_DIR}" \
|
start_java_service "chatbotApi" "${API_DIR}" \
|
||||||
"${RUN_DIR}/chatbot-api.pid" "${LOG_DIR}/chatbot-api.log" \
|
"${RUN_DIR}/chatbot-api.pid" "${LOG_DIR}/chatbot-api.log" \
|
||||||
"INTERNAL_TOOL_API_KEY=${INTERNAL_TOOL_API_KEY}" \
|
"INTERNAL_TOOL_API_KEY=${INTERNAL_TOOL_API_KEY}" \
|
||||||
"SKILL_INTERNAL_BASE_URL=http://127.0.0.1:${SKILL_PORT}" \
|
"SKILL_INTERNAL_BASE_URL=http://127.0.0.1:${SKILL_PORT}" \
|
||||||
"RAG_SERVER_HOST=127.0.0.1" \
|
"RAG_SERVER_HOST=127.0.0.1" \
|
||||||
"RAG_SERVER_PORT=${RAG_PORT}"
|
"RAG_SERVER_PORT=${RAG_PORT}" \
|
||||||
|
"SPRING_DATA_MONGODB_URI=${EXDEV_MONGO_URI}" \
|
||||||
start_java_service "kakaoChatbotSkill" "${SKILL_DIR}" \
|
"SPRING_DATASOURCE_TROAD_URL=${EXDEV_TROAD_JDBC_URL}" \
|
||||||
"${RUN_DIR}/kakao-skill.pid" "${LOG_DIR}/kakao-skill.log" \
|
"SPRING_DATASOURCE_TROAD_USERNAME=${EXDEV_TROAD_USERNAME}" \
|
||||||
"AGENT_MODE=agent" \
|
"SPRING_DATASOURCE_TROAD_PASSWORD=${EXDEV_TROAD_PASSWORD}" \
|
||||||
"RAG_AGENT_CHAT_URL=http://127.0.0.1:${RAG_PORT}/agent/chat" \
|
|| warn "chatbotApi 기동 실패"
|
||||||
"CHATBOT_API_BASE_URL=http://127.0.0.1:${WAS_PORT}/api/" \
|
|
||||||
"INTERNAL_TOOL_API_KEY=${INTERNAL_TOOL_API_KEY}" \
|
|
||||||
"CHATBOT_APP_URL=${PUBLIC_BASE_URL}/chatbot/app/"
|
|
||||||
|
|
||||||
wait_port "${WAS_PORT}" "chatbotApi" 240 || true
|
|
||||||
wait_port "${SKILL_PORT}" "kakaoChatbotSkill" 240 || true
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
start_chatbot_app
|
start_chatbot_app
|
||||||
@@ -533,11 +769,13 @@ start_caddy
|
|||||||
|
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
log "기동 완료"
|
log "기동 완료"
|
||||||
log " HTTPS UI ${PUBLIC_BASE_URL}/chatbot/app/"
|
log " HTTPS UI ${PUBLIC_BASE_URL}/chatbot/ai/"
|
||||||
log " RAG http://127.0.0.1:${RAG_PORT}/health"
|
log " RAG http://127.0.0.1:${RAG_PORT}/health"
|
||||||
log " Admin http://127.0.0.1:${ADMIN_PORT}/"
|
log " Admin http://127.0.0.1:${ADMIN_PORT}/"
|
||||||
log " WAS http://127.0.0.1:${WAS_PORT}/"
|
log " WAS http://127.0.0.1:${WAS_PORT}/"
|
||||||
log " Skill http://127.0.0.1:${SKILL_PORT}/web/ask"
|
log " Skill http://127.0.0.1:${SKILL_PORT}/web/ask"
|
||||||
|
log " Oracle localhost:1521/orcl2 (OPR_MAIN / TROAD)"
|
||||||
|
log " Kakao ${PUBLIC_BASE_URL}/kakao/skill"
|
||||||
log " 로그 ${LOG_DIR}/"
|
log " 로그 ${LOG_DIR}/"
|
||||||
log " 종료 ./server-dev/stop-all-server.sh"
|
log " 종료 ./server-dev/stop-all-server.sh"
|
||||||
log "=========================================="
|
log "=========================================="
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
# ./server-dev/stop-all-server.sh
|
# ./server-dev/stop-all-server.sh
|
||||||
# ./server-dev/stop-all-server.sh --keep-caddy
|
# ./server-dev/stop-all-server.sh --keep-caddy
|
||||||
# ./server-dev/stop-all-server.sh --purge-mongo
|
# ./server-dev/stop-all-server.sh --purge-mongo
|
||||||
|
# ./server-dev/stop-all-server.sh --purge-oracle
|
||||||
|
# ./server-dev/stop-all-server.sh --keep-oracle
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
@@ -14,21 +16,27 @@ RAG_DIR="${ROOT_DIR}/exAiChatBot-chatbot2.0-agent"
|
|||||||
APP_DIR="${ROOT_DIR}/chatbotApp-chatbot2.0-agent"
|
APP_DIR="${ROOT_DIR}/chatbotApp-chatbot2.0-agent"
|
||||||
COMPOSE_SERVER="${RAG_DIR}/docker-compose.server.yml"
|
COMPOSE_SERVER="${RAG_DIR}/docker-compose.server.yml"
|
||||||
COMPOSE_CADDY="${SERVER_DEV_DIR}/docker-compose.caddy.yml"
|
COMPOSE_CADDY="${SERVER_DEV_DIR}/docker-compose.caddy.yml"
|
||||||
|
COMPOSE_ORACLE="${SERVER_DEV_DIR}/docker-compose.oracle.yml"
|
||||||
|
|
||||||
MONGO_CONTAINER="${MONGO_CONTAINER:-exaichatbot-agent-mongo}"
|
MONGO_CONTAINER="${MONGO_CONTAINER:-exaichatbot-agent-mongo}"
|
||||||
|
ORACLE_CONTAINER="${ORACLE_CONTAINER:-exaichatbot-agent-oracle-troad}"
|
||||||
LEGACY_STACK_DIR="${LEGACY_STACK_DIR:-/Users/aidev/dev/exAIChatbot2.0}"
|
LEGACY_STACK_DIR="${LEGACY_STACK_DIR:-/Users/aidev/dev/exAIChatbot2.0}"
|
||||||
|
|
||||||
KEEP_CADDY=false
|
KEEP_CADDY=false
|
||||||
|
KEEP_ORACLE=false
|
||||||
PURGE_MONGO=false
|
PURGE_MONGO=false
|
||||||
|
PURGE_ORACLE=false
|
||||||
STOP_HOST_AI=false
|
STOP_HOST_AI=false
|
||||||
|
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--keep-caddy) KEEP_CADDY=true ;;
|
--keep-caddy) KEEP_CADDY=true ;;
|
||||||
|
--keep-oracle) KEEP_ORACLE=true ;;
|
||||||
--purge-mongo) PURGE_MONGO=true ;;
|
--purge-mongo) PURGE_MONGO=true ;;
|
||||||
|
--purge-oracle) PURGE_ORACLE=true ;;
|
||||||
--stop-host-ai) STOP_HOST_AI=true ;;
|
--stop-host-ai) STOP_HOST_AI=true ;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
sed -n '2,8p' "$0"
|
sed -n '2,10p' "$0"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -87,6 +95,20 @@ if ! $KEEP_CADDY && [[ -f "${COMPOSE_CADDY}" ]]; then
|
|||||||
log "Caddy(HTTPS) 중지"
|
log "Caddy(HTTPS) 중지"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if $KEEP_ORACLE; then
|
||||||
|
log "Oracle TROAD 유지 (--keep-oracle)"
|
||||||
|
elif [[ -f "${COMPOSE_ORACLE}" ]]; then
|
||||||
|
if $PURGE_ORACLE; then
|
||||||
|
(cd "${SERVER_DEV_DIR}" && docker compose -f docker-compose.oracle.yml down -v --remove-orphans 2>/dev/null) || true
|
||||||
|
docker rm -f "${ORACLE_CONTAINER}" 2>/dev/null || true
|
||||||
|
log "Oracle TROAD 컨테이너·볼륨 삭제 (${ORACLE_CONTAINER})"
|
||||||
|
else
|
||||||
|
(cd "${SERVER_DEV_DIR}" && docker compose -f docker-compose.oracle.yml stop 2>/dev/null) || true
|
||||||
|
docker stop "${ORACLE_CONTAINER}" 2>/dev/null || true
|
||||||
|
log "Oracle TROAD 중지 (${ORACLE_CONTAINER}, 데이터 볼륨 유지)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if $PURGE_MONGO; then
|
if $PURGE_MONGO; then
|
||||||
docker stop "${MONGO_CONTAINER}" 2>/dev/null || true
|
docker stop "${MONGO_CONTAINER}" 2>/dev/null || true
|
||||||
docker rm -f "${MONGO_CONTAINER}" 2>/dev/null || true
|
docker rm -f "${MONGO_CONTAINER}" 2>/dev/null || true
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ SUBMODULES=(
|
|||||||
chatbotApi-chatbot2.0-agent
|
chatbotApi-chatbot2.0-agent
|
||||||
exAiChatBot-chatbot2.0-agent
|
exAiChatBot-chatbot2.0-agent
|
||||||
kakaoChatbotSkill-chatbot2.0-agent
|
kakaoChatbotSkill-chatbot2.0-agent
|
||||||
|
chatbotDesktopApp-chatbot2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
log "원격 동기화: ${EXDEV_SSH}:${REMOTE_WT}"
|
log "원격 동기화: ${EXDEV_SSH}:${REMOTE_WT}"
|
||||||
@@ -22,22 +23,32 @@ for path in "${SUBMODULES[@]}"; do
|
|||||||
local_src="${ROOT_DIR}/${path}"
|
local_src="${ROOT_DIR}/${path}"
|
||||||
[[ -d "${local_src}" ]] || { echo "ERROR: ${local_src} 없음"; exit 1; }
|
[[ -d "${local_src}" ]] || { echo "ERROR: ${local_src} 없음"; exit 1; }
|
||||||
log ">>> rsync ${path}"
|
log ">>> rsync ${path}"
|
||||||
|
# build/dist/logs 는 자바 패키지명(예: kakao.response.build)과 충돌하므로
|
||||||
|
# 선행 슬래시로 프로젝트 최상위에만 적용한다.
|
||||||
rsync -az --delete \
|
rsync -az --delete \
|
||||||
--exclude 'node_modules/' \
|
--exclude 'node_modules/' \
|
||||||
--exclude 'build/' \
|
|
||||||
--exclude '.gradle/' \
|
--exclude '.gradle/' \
|
||||||
--exclude 'qdrant_data/' \
|
--exclude 'qdrant_data/' \
|
||||||
--exclude 'logs/' \
|
--exclude '.next/' \
|
||||||
|
--exclude '.git/' \
|
||||||
|
--exclude '/build/' \
|
||||||
|
--exclude '/dist/' \
|
||||||
|
--exclude '/logs/' \
|
||||||
|
--exclude '/web/out/' \
|
||||||
"${local_src}/" "${EXDEV_SSH}:${REMOTE_WT}/${path}/"
|
"${local_src}/" "${EXDEV_SSH}:${REMOTE_WT}/${path}/"
|
||||||
done
|
done
|
||||||
|
|
||||||
log "overlay 복사..."
|
log "overlay 복사..."
|
||||||
rsync -az "${ROOT_DIR}/server-dev/docker-compose.rag.server.yml" \
|
rsync -az "${ROOT_DIR}/server-dev/docker-compose.rag.server.yml" \
|
||||||
"${EXDEV_SSH}:${REMOTE_WT}/server-dev/docker-compose.rag.server.yml"
|
"${EXDEV_SSH}:${REMOTE_WT}/server-dev/docker-compose.rag.server.yml"
|
||||||
|
rsync -az "${ROOT_DIR}/server-dev/docker-compose.oracle.yml" \
|
||||||
|
"${EXDEV_SSH}:${REMOTE_WT}/server-dev/docker-compose.oracle.yml"
|
||||||
|
rsync -az "${ROOT_DIR}/server-dev/oracle/" \
|
||||||
|
"${EXDEV_SSH}:${REMOTE_WT}/server-dev/oracle/"
|
||||||
rsync -az "${ROOT_DIR}/local-dev/docker-compose.rag.local.yml" \
|
rsync -az "${ROOT_DIR}/local-dev/docker-compose.rag.local.yml" \
|
||||||
"${EXDEV_SSH}:${REMOTE_WT}/local-dev/docker-compose.rag.local.yml" 2>/dev/null || true
|
"${EXDEV_SSH}:${REMOTE_WT}/local-dev/docker-compose.rag.local.yml" 2>/dev/null || true
|
||||||
|
|
||||||
ssh -o BatchMode=yes "${EXDEV_SSH}" "mkdir -p '${REMOTE_WT}/exAiChatBot-chatbot2.0-agent' && \
|
ssh -o BatchMode=yes "${EXDEV_SSH}" "mkdir -p '${REMOTE_WT}/exAiChatBot-chatbot2.0-agent' '${REMOTE_WT}/server-dev/oracle/init' && \
|
||||||
cp '${REMOTE_WT}/server-dev/docker-compose.rag.server.yml' '${REMOTE_WT}/exAiChatBot-chatbot2.0-agent/docker-compose.server.yml' 2>/dev/null || true"
|
cp '${REMOTE_WT}/server-dev/docker-compose.rag.server.yml' '${REMOTE_WT}/exAiChatBot-chatbot2.0-agent/docker-compose.server.yml' 2>/dev/null || true"
|
||||||
|
|
||||||
if [[ -d "${ROOT_DIR}/chatbotApp-chatbot2.0-agent/public" ]]; then
|
if [[ -d "${ROOT_DIR}/chatbotApp-chatbot2.0-agent/public" ]]; then
|
||||||
@@ -46,4 +57,26 @@ if [[ -d "${ROOT_DIR}/chatbotApp-chatbot2.0-agent/public" ]]; then
|
|||||||
"${EXDEV_SSH}:${REMOTE_WT}/chatbotApp-chatbot2.0-agent/public/"
|
"${EXDEV_SSH}:${REMOTE_WT}/chatbotApp-chatbot2.0-agent/public/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -d "${ROOT_DIR}/chatbotApp-chatbot2.0-agent/public-ai" ]]; then
|
||||||
|
log ">>> rsync chatbotApp/public-ai (AI 모드 빌드 산출물)"
|
||||||
|
rsync -az "${ROOT_DIR}/chatbotApp-chatbot2.0-agent/public-ai/" \
|
||||||
|
"${EXDEV_SSH}:${REMOTE_WT}/chatbotApp-chatbot2.0-agent/public-ai/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Windows 체크아웃(core.autocrlf)에서 넘어온 CRLF 는 macOS 에서
|
||||||
|
# "/bin/sh^M: bad interpreter" 로 죽는다. 전송 후 실행 진입점만 LF 로 강제한다.
|
||||||
|
log "원격 실행 스크립트 LF 정규화..."
|
||||||
|
ssh -o BatchMode=yes "${EXDEV_SSH}" "bash -s" <<EOSSH
|
||||||
|
set -e
|
||||||
|
WT="${REMOTE_WT}"
|
||||||
|
for f in \$(find "\${WT}" -name gradlew -not -path '*/node_modules/*' 2>/dev/null) \
|
||||||
|
\$(find "\${WT}" -name '*.sh' -not -path '*/node_modules/*' 2>/dev/null); do
|
||||||
|
if head -c 4000 "\$f" | grep -q \$'\r'; then
|
||||||
|
tr -d '\r' < "\$f" > "\$f.lf" && mv "\$f.lf" "\$f"
|
||||||
|
echo " LF 변환: \$f"
|
||||||
|
fi
|
||||||
|
chmod +x "\$f" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
EOSSH
|
||||||
|
|
||||||
log "✅ submodule rsync 완료"
|
log "✅ submodule rsync 완료"
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Gitea push 후 chatbot.exdev.co.kr 배포 완료 대기
|
# Gitea push 후 chatbot.exdev.co.kr 배포 완료 대기
|
||||||
|
# - UI 응답 또는 배포 로그의 "배포 완료" 확인
|
||||||
|
# - "배포 실패"/컴파일 오류는 즉시 종료 (900s 무의미 대기 방지)
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
EXDEV_SSH="${EXDEV_SSH:-aidev@chatbot.exdev.co.kr}"
|
EXDEV_SSH="${EXDEV_SSH:-aidev@chatbot.exdev.co.kr}"
|
||||||
DEPLOY_LOG="${DEPLOY_LOG:-/Volumes/ADATA/logs/deploy/exAichatbot_agent.log}"
|
DEPLOY_LOG="${DEPLOY_LOG:-/Volumes/ADATA/logs/deploy/exAichatbot_agent.log}"
|
||||||
PUBLIC_URL="${PUBLIC_BASE_URL:-https://chatbot.exdev.co.kr}/chatbot/app/"
|
PUBLIC_URL="${PUBLIC_BASE_URL:-https://chatbot.exdev.co.kr}/chatbot/ai/"
|
||||||
MAX_WAIT="${DEPLOY_WAIT_SEC:-900}"
|
MAX_WAIT="${DEPLOY_WAIT_SEC:-900}"
|
||||||
|
|
||||||
log() { echo "[wait-deploy] $*"; }
|
log() { echo "[wait-deploy] $*"; }
|
||||||
@@ -18,26 +20,67 @@ if ! ssh_cmd "test -f '${DEPLOY_LOG}'" 2>/dev/null; then
|
|||||||
ssh_cmd "bash /Volumes/ADATA/git/deploy-exAichatbot_agent.sh" || true
|
ssh_cmd "bash /Volumes/ADATA/git/deploy-exAichatbot_agent.sh" || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 대기 시작 시점의 로그 길이 — 이후 새로 찍힌 줄만 성공/실패 판정에 사용
|
||||||
|
LOG_BASE_BYTES="$(ssh_cmd "wc -c < '${DEPLOY_LOG}' 2>/dev/null || echo 0" | tr -d '[:space:]')"
|
||||||
|
LOG_BASE_BYTES="${LOG_BASE_BYTES:-0}"
|
||||||
|
|
||||||
log "배포 완료 대기 (최대 ${MAX_WAIT}s) — ${EXDEV_SSH}"
|
log "배포 완료 대기 (최대 ${MAX_WAIT}s) — ${EXDEV_SSH}"
|
||||||
start_ts="$(date +%s)"
|
start_ts="$(date +%s)"
|
||||||
deadline=$((start_ts + MAX_WAIT))
|
deadline=$((start_ts + MAX_WAIT))
|
||||||
|
|
||||||
|
new_log_tail() {
|
||||||
|
ssh_cmd "tail -c +$((LOG_BASE_BYTES + 1)) '${DEPLOY_LOG}' 2>/dev/null | tail -80" || true
|
||||||
|
}
|
||||||
|
|
||||||
while (( $(date +%s) < deadline )); do
|
while (( $(date +%s) < deadline )); do
|
||||||
|
recent="$(new_log_tail)"
|
||||||
|
|
||||||
|
# 신규 로그에 실패 마커가 있으면 즉시 종료
|
||||||
|
if echo "${recent}" | grep -qE '\[ERROR\] 배포 실패|ERROR: chatbotApi 컴파일 실패|BUILD FAILED|\[ERROR\] 다른 배포 진행 중'; then
|
||||||
|
log "⚠️ 원격 배포 실패 감지 — 최근 로그:"
|
||||||
|
echo "${recent}" | tail -40
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if curl -sf --max-time 5 "${PUBLIC_URL}" 2>/dev/null | grep -q 'data-chatbot-app'; then
|
if curl -sf --max-time 5 "${PUBLIC_URL}" 2>/dev/null | grep -q 'data-chatbot-app'; then
|
||||||
|
# UI 살아있어도, 이번 배포가 아직 실패로 끝났으면 성공으로 치지 않음
|
||||||
|
if echo "${recent}" | grep -qE '\[ERROR\] 배포 실패|ERROR: chatbotApi 컴파일 실패|BUILD FAILED'; then
|
||||||
|
log "⚠️ UI는 응답하나 이번 배포 로그에 실패가 있습니다"
|
||||||
|
echo "${recent}" | tail -40
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if echo "${recent}" | grep -q '배포 완료'; then
|
||||||
|
log "✅ UI 응답 + 배포 완료 로그: ${PUBLIC_URL}"
|
||||||
|
ssh_cmd "tail -8 '${DEPLOY_LOG}'" 2>/dev/null || true
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
# start-only 직후 UI 가 이전 빌드로 살아 있을 수 있음 — 신규 성공 로그를 우선
|
||||||
|
if echo "${recent}" | grep -q '배포 시작'; then
|
||||||
|
:
|
||||||
|
else
|
||||||
log "✅ UI 응답: ${PUBLIC_URL}"
|
log "✅ UI 응답: ${PUBLIC_URL}"
|
||||||
ssh_cmd "tail -8 '${DEPLOY_LOG}'" 2>/dev/null || true
|
ssh_cmd "tail -8 '${DEPLOY_LOG}'" 2>/dev/null || true
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
if ssh_cmd "grep -q '배포 완료' '${DEPLOY_LOG}'" 2>/dev/null; then
|
fi
|
||||||
|
|
||||||
|
if echo "${recent}" | grep -q '배포 완료'; then
|
||||||
last_line="$(ssh_cmd "tail -1 '${DEPLOY_LOG}'" 2>/dev/null || true)"
|
last_line="$(ssh_cmd "tail -1 '${DEPLOY_LOG}'" 2>/dev/null || true)"
|
||||||
if [[ "${last_line}" == *"배포 완료"* ]]; then
|
if [[ "${last_line}" == *"배포 완료"* ]] || [[ "${last_line}" == *"락 해제"* ]]; then
|
||||||
|
# 성공 후 trap 이 락 해제를 찍을 수 있음
|
||||||
|
if echo "${recent}" | grep -qE '\[ERROR\] 배포 실패|BUILD FAILED'; then
|
||||||
|
log "⚠️ 배포 실패 로그 감지"
|
||||||
|
echo "${recent}" | tail -40
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
log "✅ 배포 로그 확인"
|
log "✅ 배포 로그 확인"
|
||||||
ssh_cmd "tail -8 '${DEPLOY_LOG}'" 2>/dev/null || true
|
ssh_cmd "tail -8 '${DEPLOY_LOG}'" 2>/dev/null || true
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
sleep 10
|
sleep 5
|
||||||
done
|
done
|
||||||
|
|
||||||
log "⚠️ 배포 대기 타임아웃 — 로그 확인: ssh ${EXDEV_SSH} tail -50 ${DEPLOY_LOG}"
|
log "⚠️ 배포 대기 타임아웃 — 로그 확인: ssh ${EXDEV_SSH} tail -50 ${DEPLOY_LOG}"
|
||||||
|
new_log_tail | tail -40
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
Reference in New Issue
Block a user