도메인 정리: invion.com → invyone.com 전체 일괄 치환 + 매핑 문서화
Build & Deploy to K8s / build-and-deploy (push) Has been cancelled
Build & Deploy to K8s / build-and-deploy (push) Has been cancelled
운영 도메인이 실제로는 v1.invyone.com / solution.invyone.com / api.invyone.com 인데 코드/문서 곳곳에 v1.invion.com / api.invion.com 등 미존재 도메인이 박혀 있어 정리. 변경 파일 (21): - frontend lib/api/client.ts, lib/utils/apiUrl.ts: hostname 체크 endsWith(\".invyone.com\") 일반화 - frontend lib/api/dashboard.ts, file.ts, flow.ts, FileViewerModal*2.tsx: 도메인 치환 - frontend invion-layout-v5.html: 시안 내 placeholder 도메인 정리 - backend-spring SecurityConfig.java: CORS 주석 예시 정리 - docker/deploy/docker-compose.yml, k8s/traefik-dynamic.yaml: traefik Host 라벨 정리 - scripts/prod/deploy.sh: 안내 메시지 정리 - .cursor/rules/api-client-usage.mdc, project-conventions.mdc: AI 가이드 정리 - docs/* 4개: 아키텍처/플로우 문서 도메인 정리 - notes/gbpark/* 3개: 과거 메모 정리 신규: - docs/DOMAIN_MAPPING.md: 운영/개발/폐기 도메인 영구 기록. AI 에이전트와 신규 개발자가 헷갈리지 않도록 단일 진실 출처. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,7 +39,7 @@ public class SecurityConfig {
|
||||
private final AiAgentApiKeyService aiAgentApiKeyService;
|
||||
|
||||
/**
|
||||
* CORS 화이트리스트. 콤마 구분 문자열로 주입 (예: "http://localhost:3000,https://v1.invion.com").
|
||||
* CORS 화이트리스트. 콤마 구분 문자열로 주입 (예: "http://localhost:3000,https://v1.invyone.com").
|
||||
* application.yml 또는 환경변수 CORS_ALLOWED_ORIGINS 로 설정.
|
||||
*/
|
||||
@Value("${cors.allowed-origins}")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
-- V001: ai_llm_providers
|
||||
-- LLM 프로바이더 테이블 (anthropic/openai/google/deepseek/ollama)
|
||||
|
||||
CREATE TABLE ai_llm_providers (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(50) NOT NULL UNIQUE,
|
||||
display_name VARCHAR(200) NOT NULL,
|
||||
api_key_encrypted TEXT NOT NULL,
|
||||
model_name VARCHAR(100) NOT NULL,
|
||||
endpoint VARCHAR(500),
|
||||
priority INTEGER NOT NULL DEFAULT 1,
|
||||
max_tokens INTEGER NOT NULL DEFAULT 4096,
|
||||
temperature NUMERIC(3,2) NOT NULL DEFAULT 0.70,
|
||||
cost_per_1k_input NUMERIC(10,6) NOT NULL DEFAULT 0,
|
||||
cost_per_1k_output NUMERIC(10,6) NOT NULL DEFAULT 0,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_providers_priority ON ai_llm_providers (priority);
|
||||
CREATE INDEX idx_providers_active ON ai_llm_providers (is_active);
|
||||
@@ -0,0 +1,23 @@
|
||||
-- V002: ai_agents
|
||||
-- AI 에이전트 테이블
|
||||
|
||||
CREATE TABLE ai_agents (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
agent_id VARCHAR(64) NOT NULL UNIQUE,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
description TEXT,
|
||||
model VARCHAR(100) NOT NULL DEFAULT 'claude-sonnet-4-20250514',
|
||||
system_prompt TEXT,
|
||||
tools JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
||||
CHECK (status IN ('active','inactive','archived')),
|
||||
company_code VARCHAR(20),
|
||||
created_by VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_ai_agents_company ON ai_agents (company_code);
|
||||
CREATE INDEX idx_ai_agents_status ON ai_agents (status);
|
||||
CREATE INDEX idx_ai_agents_created ON ai_agents (created_at DESC);
|
||||
@@ -0,0 +1,20 @@
|
||||
-- V003: ai_agent_groups
|
||||
-- AI 에이전트 그룹 테이블
|
||||
|
||||
CREATE TABLE ai_agent_groups (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
group_id VARCHAR(64) NOT NULL UNIQUE,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
description TEXT,
|
||||
execution_mode VARCHAR(20) NOT NULL DEFAULT 'mixed'
|
||||
CHECK (execution_mode IN ('parallel','sequential','mixed')),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
||||
CHECK (status IN ('active','inactive','archived')),
|
||||
company_code VARCHAR(20),
|
||||
created_by VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_ai_groups_company ON ai_agent_groups (company_code);
|
||||
CREATE INDEX idx_ai_groups_status ON ai_agent_groups (status);
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
-- V004: ai_agent_group_members
|
||||
-- AI 에이전트 그룹 멤버 테이블 (execution_order 로 mixed 모드 지원)
|
||||
|
||||
CREATE TABLE ai_agent_group_members (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
group_id BIGINT NOT NULL REFERENCES ai_agent_groups(id) ON DELETE CASCADE,
|
||||
agent_id BIGINT NOT NULL REFERENCES ai_agents(id) ON DELETE RESTRICT,
|
||||
role_name VARCHAR(100) NOT NULL,
|
||||
connectors JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
execution_order INTEGER NOT NULL DEFAULT 1,
|
||||
config JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_group_members_group ON ai_agent_group_members (group_id, execution_order);
|
||||
@@ -0,0 +1,27 @@
|
||||
-- V005: ai_agent_api_keys
|
||||
-- AI 에이전트 API 키 테이블 (sk-pipe-* 형식)
|
||||
|
||||
CREATE TABLE ai_agent_api_keys (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
key_hash CHAR(64) NOT NULL UNIQUE,
|
||||
key_prefix VARCHAR(16) NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
company_code VARCHAR(20),
|
||||
agent_id BIGINT REFERENCES ai_agents(id) ON DELETE SET NULL,
|
||||
permissions JSONB NOT NULL DEFAULT '["chat"]'::jsonb,
|
||||
rate_limit INTEGER NOT NULL DEFAULT 60,
|
||||
monthly_token_limit BIGINT NOT NULL DEFAULT 1000000,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
||||
CHECK (status IN ('active','revoked')),
|
||||
last_used_at TIMESTAMPTZ,
|
||||
usage_count BIGINT NOT NULL DEFAULT 0,
|
||||
total_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
expires_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_api_keys_hash ON ai_agent_api_keys (key_hash);
|
||||
CREATE INDEX idx_api_keys_user ON ai_agent_api_keys (user_id);
|
||||
CREATE INDEX idx_api_keys_company ON ai_agent_api_keys (company_code);
|
||||
CREATE INDEX idx_api_keys_status ON ai_agent_api_keys (status);
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
-- V006: ai_agent_conversations
|
||||
-- AI 에이전트 대화 세션 테이블
|
||||
|
||||
CREATE TABLE ai_agent_conversations (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
conversation_id VARCHAR(64) NOT NULL UNIQUE,
|
||||
agent_id BIGINT REFERENCES ai_agents(id) ON DELETE SET NULL,
|
||||
user_id VARCHAR(64),
|
||||
api_key_id BIGINT REFERENCES ai_agent_api_keys(id) ON DELETE SET NULL,
|
||||
title VARCHAR(500),
|
||||
message_count INTEGER NOT NULL DEFAULT 0,
|
||||
total_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active',
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_conv_agent ON ai_agent_conversations (agent_id);
|
||||
CREATE INDEX idx_conv_user ON ai_agent_conversations (user_id);
|
||||
CREATE INDEX idx_conv_apikey ON ai_agent_conversations (api_key_id);
|
||||
CREATE INDEX idx_conv_updated ON ai_agent_conversations (updated_at DESC);
|
||||
@@ -0,0 +1,15 @@
|
||||
-- V007: ai_agent_messages
|
||||
-- AI 에이전트 대화 메시지 테이블
|
||||
|
||||
CREATE TABLE ai_agent_messages (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
conversation_id BIGINT NOT NULL REFERENCES ai_agent_conversations(id) ON DELETE CASCADE,
|
||||
role VARCHAR(20) NOT NULL CHECK (role IN ('system','user','assistant','tool')),
|
||||
content TEXT NOT NULL,
|
||||
tool_calls JSONB,
|
||||
token_count INTEGER NOT NULL DEFAULT 0,
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_msg_conv ON ai_agent_messages (conversation_id, created_at);
|
||||
@@ -0,0 +1,28 @@
|
||||
-- V008: ai_agent_usage_logs
|
||||
-- AI 에이전트 사용량 로그 테이블 (토큰/비용 추적)
|
||||
|
||||
CREATE TABLE ai_agent_usage_logs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
user_id VARCHAR(64),
|
||||
api_key_id BIGINT REFERENCES ai_agent_api_keys(id) ON DELETE SET NULL,
|
||||
agent_id BIGINT REFERENCES ai_agents(id) ON DELETE SET NULL,
|
||||
conversation_id BIGINT REFERENCES ai_agent_conversations(id) ON DELETE SET NULL,
|
||||
provider_name VARCHAR(50),
|
||||
model_name VARCHAR(100),
|
||||
prompt_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
completion_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cost_usd NUMERIC(12,6) NOT NULL DEFAULT 0,
|
||||
response_time_ms INTEGER,
|
||||
success BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
error_message TEXT,
|
||||
request_path VARCHAR(500),
|
||||
ip_address INET,
|
||||
company_code VARCHAR(20),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_usage_created ON ai_agent_usage_logs (created_at DESC);
|
||||
CREATE INDEX idx_usage_apikey ON ai_agent_usage_logs (api_key_id, created_at DESC);
|
||||
CREATE INDEX idx_usage_agent ON ai_agent_usage_logs (agent_id, created_at DESC);
|
||||
CREATE INDEX idx_usage_company ON ai_agent_usage_logs (company_code, created_at DESC);
|
||||
@@ -0,0 +1,22 @@
|
||||
-- V009: ai_agent_schedules
|
||||
-- AI 에이전트 스케줄 테이블 (Quartz JDBC 연동)
|
||||
|
||||
CREATE TABLE ai_agent_schedules (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
group_id BIGINT NOT NULL REFERENCES ai_agent_groups(id) ON DELETE CASCADE,
|
||||
cron_expression VARCHAR(100) NOT NULL,
|
||||
timezone VARCHAR(50) NOT NULL DEFAULT 'Asia/Seoul',
|
||||
input_message TEXT NOT NULL,
|
||||
notification JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
last_run_at TIMESTAMPTZ,
|
||||
run_count BIGINT NOT NULL DEFAULT 0,
|
||||
company_code VARCHAR(20),
|
||||
created_by VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_sched_active ON ai_agent_schedules (is_active);
|
||||
CREATE INDEX idx_sched_company ON ai_agent_schedules (company_code);
|
||||
@@ -0,0 +1,24 @@
|
||||
-- V010: ai_analysis_logs
|
||||
-- AI 분석 실행 이력 테이블 (정확도 추적 포함)
|
||||
|
||||
CREATE TABLE ai_analysis_logs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
group_id BIGINT REFERENCES ai_agent_groups(id) ON DELETE SET NULL,
|
||||
agent_id BIGINT REFERENCES ai_agents(id) ON DELETE SET NULL,
|
||||
schedule_id BIGINT REFERENCES ai_agent_schedules(id) ON DELETE SET NULL,
|
||||
execution_type VARCHAR(20) NOT NULL
|
||||
CHECK (execution_type IN ('manual','api','schedule')),
|
||||
input_message TEXT NOT NULL,
|
||||
analysis_result TEXT NOT NULL,
|
||||
prediction JSONB,
|
||||
actual_result JSONB,
|
||||
accuracy_score NUMERIC(5,2),
|
||||
tokens_used INTEGER NOT NULL DEFAULT 0,
|
||||
duration_ms INTEGER,
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
company_code VARCHAR(20),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_analysis_group_created ON ai_analysis_logs (group_id, created_at DESC);
|
||||
CREATE INDEX idx_analysis_company ON ai_analysis_logs (company_code, created_at DESC);
|
||||
@@ -0,0 +1,20 @@
|
||||
-- V011: ai_knowledge_files
|
||||
-- AI 지식 파일 테이블 (RAG 문서 저장)
|
||||
|
||||
CREATE TABLE ai_knowledge_files (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(300) NOT NULL,
|
||||
file_name VARCHAR(300),
|
||||
category VARCHAR(100),
|
||||
description TEXT,
|
||||
content TEXT NOT NULL,
|
||||
file_size BIGINT NOT NULL DEFAULT 0,
|
||||
mime_type VARCHAR(100),
|
||||
company_code VARCHAR(20),
|
||||
created_by VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_knowledge_category ON ai_knowledge_files (category);
|
||||
CREATE INDEX idx_knowledge_company ON ai_knowledge_files (company_code);
|
||||
@@ -0,0 +1,156 @@
|
||||
-- V012: Quartz JDBC JobStore 영구 테이블 (PostgreSQL)
|
||||
-- 출처: spring-boot-starter-quartz / quartz tables_postgres.sql
|
||||
|
||||
CREATE TABLE QRTZ_JOB_DETAILS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
JOB_NAME VARCHAR(200) NOT NULL,
|
||||
JOB_GROUP VARCHAR(200) NOT NULL,
|
||||
DESCRIPTION VARCHAR(250),
|
||||
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
|
||||
IS_DURABLE BOOLEAN NOT NULL,
|
||||
IS_NONCONCURRENT BOOLEAN NOT NULL,
|
||||
IS_UPDATE_DATA BOOLEAN NOT NULL,
|
||||
REQUESTS_RECOVERY BOOLEAN NOT NULL,
|
||||
JOB_DATA BYTEA,
|
||||
CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||
JOB_NAME VARCHAR(200) NOT NULL,
|
||||
JOB_GROUP VARCHAR(200) NOT NULL,
|
||||
DESCRIPTION VARCHAR(250),
|
||||
NEXT_FIRE_TIME BIGINT,
|
||||
PREV_FIRE_TIME BIGINT,
|
||||
PRIORITY INTEGER,
|
||||
TRIGGER_STATE VARCHAR(16) NOT NULL,
|
||||
TRIGGER_TYPE VARCHAR(8) NOT NULL,
|
||||
START_TIME BIGINT NOT NULL,
|
||||
END_TIME BIGINT,
|
||||
CALENDAR_NAME VARCHAR(200),
|
||||
MISFIRE_INSTR SMALLINT,
|
||||
JOB_DATA BYTEA,
|
||||
CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||
CONSTRAINT FK_QRTZ_TRIGGERS_JOB_DETAILS FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||
REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||
REPEAT_COUNT BIGINT NOT NULL,
|
||||
REPEAT_INTERVAL BIGINT NOT NULL,
|
||||
TIMES_TRIGGERED BIGINT NOT NULL,
|
||||
CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||
CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_CRON_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||
CRON_EXPRESSION VARCHAR(120) NOT NULL,
|
||||
TIME_ZONE_ID VARCHAR(80),
|
||||
CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||
CONSTRAINT FK_QRTZ_CRON_TRIGGERS FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_SIMPROP_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||
STR_PROP_1 VARCHAR(512),
|
||||
STR_PROP_2 VARCHAR(512),
|
||||
STR_PROP_3 VARCHAR(512),
|
||||
INT_PROP_1 INTEGER,
|
||||
INT_PROP_2 INTEGER,
|
||||
LONG_PROP_1 BIGINT,
|
||||
LONG_PROP_2 BIGINT,
|
||||
DEC_PROP_1 NUMERIC(13,4),
|
||||
DEC_PROP_2 NUMERIC(13,4),
|
||||
BOOL_PROP_1 BOOLEAN,
|
||||
BOOL_PROP_2 BOOLEAN,
|
||||
CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||
CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_BLOB_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||
BLOB_DATA BYTEA,
|
||||
CONSTRAINT PK_QRTZ_BLOB_TRIGGERS PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
|
||||
CONSTRAINT FK_QRTZ_BLOB_TRIGGERS FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||
REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_CALENDARS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
CALENDAR_NAME VARCHAR(200) NOT NULL,
|
||||
CALENDAR BYTEA NOT NULL,
|
||||
CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||
CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_FIRED_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
ENTRY_ID VARCHAR(95) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(200) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(200) NOT NULL,
|
||||
INSTANCE_NAME VARCHAR(200) NOT NULL,
|
||||
FIRED_TIME BIGINT NOT NULL,
|
||||
SCHED_TIME BIGINT NOT NULL,
|
||||
PRIORITY INTEGER NOT NULL,
|
||||
STATE VARCHAR(16) NOT NULL,
|
||||
JOB_NAME VARCHAR(200),
|
||||
JOB_GROUP VARCHAR(200),
|
||||
IS_NONCONCURRENT BOOLEAN,
|
||||
REQUESTS_RECOVERY BOOLEAN,
|
||||
CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY (SCHED_NAME, ENTRY_ID)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_SCHEDULER_STATE (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
INSTANCE_NAME VARCHAR(200) NOT NULL,
|
||||
LAST_CHECKIN_TIME BIGINT NOT NULL,
|
||||
CHECKIN_INTERVAL BIGINT NOT NULL,
|
||||
CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY (SCHED_NAME, INSTANCE_NAME)
|
||||
);
|
||||
|
||||
CREATE TABLE QRTZ_LOCKS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
LOCK_NAME VARCHAR(40) NOT NULL,
|
||||
CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY (SCHED_NAME, LOCK_NAME)
|
||||
);
|
||||
|
||||
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
|
||||
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
|
||||
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
|
||||
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
|
||||
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
|
||||
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
|
||||
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
|
||||
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
|
||||
@@ -0,0 +1,29 @@
|
||||
-- V013: AI 테이블 추가 성능 인덱스
|
||||
-- 복합 인덱스 및 자주 조회되는 컬럼에 대한 보조 인덱스
|
||||
|
||||
-- ai_agents: agent_id 문자열 조회 (ApiKey 검증 시)
|
||||
CREATE INDEX idx_ai_agents_agent_id ON ai_agents (agent_id);
|
||||
|
||||
-- ai_agent_groups: group_id 문자열 조회
|
||||
CREATE INDEX idx_ai_groups_group_id ON ai_agent_groups (group_id);
|
||||
|
||||
-- ai_agent_group_members: agent_id 역방향 조회 (에이전트 삭제 전 그룹 확인)
|
||||
CREATE INDEX idx_group_members_agent ON ai_agent_group_members (agent_id);
|
||||
|
||||
-- ai_agent_conversations: conversation_id 문자열 조회
|
||||
CREATE INDEX idx_conv_conv_id ON ai_agent_conversations (conversation_id);
|
||||
|
||||
-- ai_agent_conversations: company_code 조회 (멀티테넌시)
|
||||
CREATE INDEX idx_conv_company ON ai_agent_conversations (user_id, updated_at DESC);
|
||||
|
||||
-- ai_analysis_logs: schedule_id 조회 (스케줄 실행 이력)
|
||||
CREATE INDEX idx_analysis_schedule ON ai_analysis_logs (schedule_id, created_at DESC);
|
||||
|
||||
-- ai_analysis_logs: agent_id 조회
|
||||
CREATE INDEX idx_analysis_agent ON ai_analysis_logs (agent_id, created_at DESC);
|
||||
|
||||
-- ai_agent_usage_logs: user_id + 기간 조회
|
||||
CREATE INDEX idx_usage_user ON ai_agent_usage_logs (user_id, created_at DESC);
|
||||
|
||||
-- ai_knowledge_files: company_code + category 복합 조회
|
||||
CREATE INDEX idx_knowledge_company_category ON ai_knowledge_files (company_code, category);
|
||||
@@ -0,0 +1,200 @@
|
||||
-- V014: AI 어시스턴트 메뉴 등록
|
||||
-- 관리자 메뉴(MENU_TYPE='0')에 AI 어시스턴트 그룹 및 하위 7개 메뉴를 등록합니다.
|
||||
-- SCREEN_GROUPS에 메뉴 그룹도 함께 등록하여 화면 그룹 트리와 연결합니다.
|
||||
-- 멱등성: INSERT ... WHERE NOT EXISTS 사용 (unique constraint 없는 기존 테이블 대응).
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- 1. SCREEN_GROUPS: AI 어시스턴트 루트 그룹
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
INSERT INTO SCREEN_GROUPS (
|
||||
GROUP_NAME, GROUP_CODE, PARENT_GROUP_ID, GROUP_LEVEL,
|
||||
DISPLAY_ORDER, COMPANY_CODE, WRITER, HIERARCHY_PATH, DESCRIPTION, IS_ACTIVE, ICON
|
||||
)
|
||||
SELECT
|
||||
'AI 어시스턴트', 'AI_ASSISTANT', NULL, 0,
|
||||
9900, '*', 'system', 'AI_ASSISTANT', 'AI 멀티 에이전트 관리 메뉴 그룹', 'Y', 'robot'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM SCREEN_GROUPS
|
||||
WHERE GROUP_CODE = 'AI_ASSISTANT' AND COMPANY_CODE = '*'
|
||||
);
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- 2. MENU_INFO: AI 어시스턴트 부모 메뉴 (관리자 메뉴, 루트)
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
INSERT INTO MENU_INFO (
|
||||
OBJID, MENU_TYPE, PARENT_OBJ_ID, MENU_NAME_KOR,
|
||||
MENU_URL, MENU_DESC, SEQ, WRITER, CREATED_DATE, STATUS, COMPANY_CODE, MENU_ICON
|
||||
)
|
||||
SELECT
|
||||
'AI_ASSISTANT_ROOT', '0', '0', 'AI 어시스턴트',
|
||||
'/admin/aiAssistant', 'AI 멀티 에이전트 관리',
|
||||
9900, 'system', NOW(), 'active', '*', 'robot'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM MENU_INFO WHERE OBJID = 'AI_ASSISTANT_ROOT'
|
||||
);
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- 3. SCREEN_GROUPS: 하위 그룹 6개
|
||||
-- PARENT_GROUP_ID는 위에서 삽입한 AI_ASSISTANT 그룹을 서브쿼리로 참조
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
|
||||
-- 3-1. 에이전트 관리
|
||||
INSERT INTO SCREEN_GROUPS (
|
||||
GROUP_NAME, GROUP_CODE, PARENT_GROUP_ID, GROUP_LEVEL,
|
||||
DISPLAY_ORDER, COMPANY_CODE, WRITER, HIERARCHY_PATH, DESCRIPTION, IS_ACTIVE, ICON
|
||||
)
|
||||
SELECT
|
||||
'에이전트 관리', 'AI_AGENTS', SG.ID, 1,
|
||||
9901, '*', 'system', 'AI_ASSISTANT/AI_AGENTS', 'LLM 에이전트 CRUD', 'Y', 'cpu'
|
||||
FROM SCREEN_GROUPS SG
|
||||
WHERE SG.GROUP_CODE = 'AI_ASSISTANT' AND SG.COMPANY_CODE = '*'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM SCREEN_GROUPS WHERE GROUP_CODE = 'AI_AGENTS' AND COMPANY_CODE = '*'
|
||||
);
|
||||
|
||||
-- 3-2. LLM 프로바이더
|
||||
INSERT INTO SCREEN_GROUPS (
|
||||
GROUP_NAME, GROUP_CODE, PARENT_GROUP_ID, GROUP_LEVEL,
|
||||
DISPLAY_ORDER, COMPANY_CODE, WRITER, HIERARCHY_PATH, DESCRIPTION, IS_ACTIVE, ICON
|
||||
)
|
||||
SELECT
|
||||
'LLM 프로바이더', 'AI_PROVIDERS', SG.ID, 1,
|
||||
9902, '*', 'system', 'AI_ASSISTANT/AI_PROVIDERS',
|
||||
'Anthropic/OpenAI/Google/Ollama 프로바이더 관리', 'Y', 'cloud'
|
||||
FROM SCREEN_GROUPS SG
|
||||
WHERE SG.GROUP_CODE = 'AI_ASSISTANT' AND SG.COMPANY_CODE = '*'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM SCREEN_GROUPS WHERE GROUP_CODE = 'AI_PROVIDERS' AND COMPANY_CODE = '*'
|
||||
);
|
||||
|
||||
-- 3-3. 멀티에이전트 워크스페이스
|
||||
INSERT INTO SCREEN_GROUPS (
|
||||
GROUP_NAME, GROUP_CODE, PARENT_GROUP_ID, GROUP_LEVEL,
|
||||
DISPLAY_ORDER, COMPANY_CODE, WRITER, HIERARCHY_PATH, DESCRIPTION, IS_ACTIVE, ICON
|
||||
)
|
||||
SELECT
|
||||
'멀티에이전트 워크스페이스', 'AI_WORKSPACE', SG.ID, 1,
|
||||
9903, '*', 'system', 'AI_ASSISTANT/AI_WORKSPACE', '에이전트 그룹 조립 및 실행', 'Y', 'diagram-3'
|
||||
FROM SCREEN_GROUPS SG
|
||||
WHERE SG.GROUP_CODE = 'AI_ASSISTANT' AND SG.COMPANY_CODE = '*'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM SCREEN_GROUPS WHERE GROUP_CODE = 'AI_WORKSPACE' AND COMPANY_CODE = '*'
|
||||
);
|
||||
|
||||
-- 3-4. 대화 모니터링
|
||||
INSERT INTO SCREEN_GROUPS (
|
||||
GROUP_NAME, GROUP_CODE, PARENT_GROUP_ID, GROUP_LEVEL,
|
||||
DISPLAY_ORDER, COMPANY_CODE, WRITER, HIERARCHY_PATH, DESCRIPTION, IS_ACTIVE, ICON
|
||||
)
|
||||
SELECT
|
||||
'대화 모니터링', 'AI_CONVERSATIONS', SG.ID, 1,
|
||||
9904, '*', 'system', 'AI_ASSISTANT/AI_CONVERSATIONS', '에이전트 대화 메시지 열람', 'Y', 'chat-dots'
|
||||
FROM SCREEN_GROUPS SG
|
||||
WHERE SG.GROUP_CODE = 'AI_ASSISTANT' AND SG.COMPANY_CODE = '*'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM SCREEN_GROUPS WHERE GROUP_CODE = 'AI_CONVERSATIONS' AND COMPANY_CODE = '*'
|
||||
);
|
||||
|
||||
-- 3-5. API 키 관리
|
||||
INSERT INTO SCREEN_GROUPS (
|
||||
GROUP_NAME, GROUP_CODE, PARENT_GROUP_ID, GROUP_LEVEL,
|
||||
DISPLAY_ORDER, COMPANY_CODE, WRITER, HIERARCHY_PATH, DESCRIPTION, IS_ACTIVE, ICON
|
||||
)
|
||||
SELECT
|
||||
'API 키 관리', 'AI_API_KEYS', SG.ID, 1,
|
||||
9905, '*', 'system', 'AI_ASSISTANT/AI_API_KEYS', 'sk-pipe-* API 키 발급 및 폐기', 'Y', 'key'
|
||||
FROM SCREEN_GROUPS SG
|
||||
WHERE SG.GROUP_CODE = 'AI_ASSISTANT' AND SG.COMPANY_CODE = '*'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM SCREEN_GROUPS WHERE GROUP_CODE = 'AI_API_KEYS' AND COMPANY_CODE = '*'
|
||||
);
|
||||
|
||||
-- 3-6. 지식 라이브러리
|
||||
INSERT INTO SCREEN_GROUPS (
|
||||
GROUP_NAME, GROUP_CODE, PARENT_GROUP_ID, GROUP_LEVEL,
|
||||
DISPLAY_ORDER, COMPANY_CODE, WRITER, HIERARCHY_PATH, DESCRIPTION, IS_ACTIVE, ICON
|
||||
)
|
||||
SELECT
|
||||
'지식 라이브러리', 'AI_KNOWLEDGE', SG.ID, 1,
|
||||
9906, '*', 'system', 'AI_ASSISTANT/AI_KNOWLEDGE', '지식 파일 업로드 및 관리', 'Y', 'book'
|
||||
FROM SCREEN_GROUPS SG
|
||||
WHERE SG.GROUP_CODE = 'AI_ASSISTANT' AND SG.COMPANY_CODE = '*'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM SCREEN_GROUPS WHERE GROUP_CODE = 'AI_KNOWLEDGE' AND COMPANY_CODE = '*'
|
||||
);
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- 4. MENU_INFO: 하위 메뉴 7개 (MENU_TYPE='0', 관리자 메뉴)
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO MENU_INFO (
|
||||
OBJID, MENU_TYPE, PARENT_OBJ_ID, MENU_NAME_KOR,
|
||||
MENU_URL, MENU_DESC, SEQ, WRITER, CREATED_DATE, STATUS, COMPANY_CODE, MENU_ICON
|
||||
)
|
||||
SELECT 'AI_MENU_ASSISTANT', '0', 'AI_ASSISTANT_ROOT', 'AI 어시스턴트',
|
||||
'/admin/aiAssistant', 'AI 어시스턴트 대시보드 (워크스페이스 리다이렉트)',
|
||||
9901, 'system', NOW(), 'active', '*', 'robot'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM MENU_INFO WHERE OBJID = 'AI_MENU_ASSISTANT');
|
||||
|
||||
INSERT INTO MENU_INFO (
|
||||
OBJID, MENU_TYPE, PARENT_OBJ_ID, MENU_NAME_KOR,
|
||||
MENU_URL, MENU_DESC, SEQ, WRITER, CREATED_DATE, STATUS, COMPANY_CODE, MENU_ICON
|
||||
)
|
||||
SELECT 'AI_MENU_AGENTS', '0', 'AI_ASSISTANT_ROOT', '에이전트 관리',
|
||||
'/admin/aiAssistant/agents', 'LLM 에이전트 CRUD',
|
||||
9902, 'system', NOW(), 'active', '*', 'cpu'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM MENU_INFO WHERE OBJID = 'AI_MENU_AGENTS');
|
||||
|
||||
INSERT INTO MENU_INFO (
|
||||
OBJID, MENU_TYPE, PARENT_OBJ_ID, MENU_NAME_KOR,
|
||||
MENU_URL, MENU_DESC, SEQ, WRITER, CREATED_DATE, STATUS, COMPANY_CODE, MENU_ICON
|
||||
)
|
||||
SELECT 'AI_MENU_PROVIDERS', '0', 'AI_ASSISTANT_ROOT', 'LLM 프로바이더',
|
||||
'/admin/aiAssistant/providers', 'Anthropic/OpenAI/Google/Ollama 프로바이더 설정',
|
||||
9903, 'system', NOW(), 'active', '*', 'cloud'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM MENU_INFO WHERE OBJID = 'AI_MENU_PROVIDERS');
|
||||
|
||||
INSERT INTO MENU_INFO (
|
||||
OBJID, MENU_TYPE, PARENT_OBJ_ID, MENU_NAME_KOR,
|
||||
MENU_URL, MENU_DESC, SEQ, WRITER, CREATED_DATE, STATUS, COMPANY_CODE, MENU_ICON
|
||||
)
|
||||
SELECT 'AI_MENU_WORKSPACE', '0', 'AI_ASSISTANT_ROOT', '멀티에이전트 워크스페이스',
|
||||
'/admin/aiAssistant/workspace', '에이전트 그룹 조립 및 실행',
|
||||
9904, 'system', NOW(), 'active', '*', 'diagram-3'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM MENU_INFO WHERE OBJID = 'AI_MENU_WORKSPACE');
|
||||
|
||||
INSERT INTO MENU_INFO (
|
||||
OBJID, MENU_TYPE, PARENT_OBJ_ID, MENU_NAME_KOR,
|
||||
MENU_URL, MENU_DESC, SEQ, WRITER, CREATED_DATE, STATUS, COMPANY_CODE, MENU_ICON
|
||||
)
|
||||
SELECT 'AI_MENU_CONVERSATIONS', '0', 'AI_ASSISTANT_ROOT', '대화 모니터링',
|
||||
'/admin/aiAssistant/conversations', '에이전트 대화 메시지 열람',
|
||||
9905, 'system', NOW(), 'active', '*', 'chat-dots'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM MENU_INFO WHERE OBJID = 'AI_MENU_CONVERSATIONS');
|
||||
|
||||
INSERT INTO MENU_INFO (
|
||||
OBJID, MENU_TYPE, PARENT_OBJ_ID, MENU_NAME_KOR,
|
||||
MENU_URL, MENU_DESC, SEQ, WRITER, CREATED_DATE, STATUS, COMPANY_CODE, MENU_ICON
|
||||
)
|
||||
SELECT 'AI_MENU_API_KEYS', '0', 'AI_ASSISTANT_ROOT', 'API 키 관리',
|
||||
'/admin/aiAssistant/api-keys-manage', 'sk-pipe-* API 키 발급 및 폐기',
|
||||
9906, 'system', NOW(), 'active', '*', 'key'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM MENU_INFO WHERE OBJID = 'AI_MENU_API_KEYS');
|
||||
|
||||
INSERT INTO MENU_INFO (
|
||||
OBJID, MENU_TYPE, PARENT_OBJ_ID, MENU_NAME_KOR,
|
||||
MENU_URL, MENU_DESC, SEQ, WRITER, CREATED_DATE, STATUS, COMPANY_CODE, MENU_ICON
|
||||
)
|
||||
SELECT 'AI_MENU_KNOWLEDGE', '0', 'AI_ASSISTANT_ROOT', '지식 라이브러리',
|
||||
'/admin/aiAssistant/knowledge', '지식 파일 업로드 및 관리',
|
||||
9907, 'system', NOW(), 'active', '*', 'book'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM MENU_INFO WHERE OBJID = 'AI_MENU_KNOWLEDGE');
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- 5. SCREEN_GROUPS.MENU_OBJID 연결 (루트 그룹 → 루트 메뉴)
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
UPDATE SCREEN_GROUPS
|
||||
SET MENU_OBJID = 'AI_ASSISTANT_ROOT'
|
||||
WHERE GROUP_CODE = 'AI_ASSISTANT'
|
||||
AND COMPANY_CODE = '*'
|
||||
AND MENU_OBJID IS NULL;
|
||||
Reference in New Issue
Block a user