diff --git a/.env.example b/.env.example index f36b100..a97b948 100644 --- a/.env.example +++ b/.env.example @@ -62,6 +62,8 @@ export BACKOFFICE_SELECT_AI_PROFILE="" export BACKOFFICE_SELECT_AI_RUNTIME_DB_URL="${BACKOFFICE_DB_URL}" export BACKOFFICE_SELECT_AI_RUNTIME_DB_USERNAME="CB_ORDS" export BACKOFFICE_SELECT_AI_RUNTIME_DB_PASSWORD="" +# Optional deployment-specific JSON contract. Keep project rules out of Java. +export BACKOFFICE_SELECT_AI_QUERY_CONTRACT_FILE="" # --- (2c) 재사용 가능한 백오피스 카탈로그와 표시 설정 --- # 승인 객체는 key/tableName/objectType/businessName/description JSON 배열입니다. @@ -103,7 +105,7 @@ export BACKOFFICE_AI_OCI_COMPARTMENT_ID="" export VPDTEST1_API_KEY="" export VPDTEST2_API_KEY="" -# --- (3) 데모용 ADB 엔드유저 비밀번호 (sql/adb/07_end_users.sql 에서 사용) --- +# --- (3) 데모용 ADB 엔드유저 비밀번호 (database/adb/07_end_users.sql 에서 사용) --- # ADB 비번 정책: 12자 이상, 대/소/숫자/특수 조합. # 4명의 데모 유저: # vpduser_my → MySQL view 만 SELECT 가능 @@ -116,7 +118,7 @@ export VPDUSER_BOTH_PASSWORD="RowFilter#Both26" export VPDUSER_NONE_PASSWORD="RowFilter#None26" # --- (3b) OPTIONAL — DDS 변형 데모용 엔드유저 비밀번호 --- -# sql/adb/13_dds_variant.sql (Oracle 26ai Deep Data Security 재구현) 에서만 사용. +# database/adb/13_dds_variant.sql (Oracle 26ai Deep Data Security 재구현) 에서만 사용. # 동일한 4-user 매트릭스를 declarative Data Grants 로 재현. VPD 데모와 공존. export DDSUSER_MY_PASSWORD="DdsGrant#My2026" export DDSUSER_PG_PASSWORD="DdsGrant#Pg2026" @@ -137,7 +139,7 @@ export DDS_MCP_BASE_URL="http://127.0.0.1:8083" export DDS_MCP_TEST_BEARER="" # 발급한 활성 CB_APP_USER Bearer만 로컬 테스트에 사용 # --- (4) 원격 Postgres (AWS RDS, Cloud SQL, ...) --- -# sql/source/postgres_setup.sql 가 여기로 customers 테이블/seed 생성. +# database/source/postgres_setup.sql 가 여기로 customers 테이블/seed 생성. # ADB 의 RDS_POSTGRES_LINK 가 이 인스턴스를 가리킴. export PG_HOST="" # 예: vpd-poc.xxxxx.ap-northeast-2.rds.amazonaws.com export PG_PORT="5432" diff --git a/.gitignore b/.gitignore index 6631670..357e835 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,12 @@ logs/ # Java / Maven target/ +# Python +__pycache__/ +*.py[cod] +.venv/ +data/ + # Locally downloaded development tools (for example SQLcl) .tools/ diff --git a/README.md b/README.md index 9d9b1af..955555a 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ End-to-End 데모입니다. 행 자체는 보여주되 특정 컬럼만 가리는 통제입니다. 예: 영업팀은 고객 행은 다 보지만 `email` 컬럼은 항상 `NULL` 로 반환. -* VPD 경로: 별도의 `DBMS_REDACT` 정책 (`sql/adb/06a_redaction.sql`). +* VPD 경로: 별도의 `DBMS_REDACT` 정책 (`database/adb/06a_redaction.sql`). * DDS 경로: 데이터 그랜트 안에 `(ALL COLUMNS EXCEPT email)` 한 줄로 흡수. ### 3. 두 가지 구현 — VPD 와 DDS @@ -59,20 +59,21 @@ DDS 변형의 능력 (멀티테넌트, OAuth2 federated identity, MAC 모드, ## 소스 위치와 Git 저장 기준 -현재 이 저장소에는 **VPD 관리 백오피스**와 **PoC4 MCP AI Console 외피**가 함께 들어 있다. -두 소스는 별도 Git repository가 아니라 같은 repository의 서로 다른 경로로 관리한다. +현재 이 저장소에는 서로 독립적으로 빌드·실행되는 세 애플리케이션이 있다. 각 제품은 +최상위 폴더를 하나씩 사용하며 저장소 루트에 프레임워크 `src`를 두지 않는다. | 구분 | 저장 위치 | 역할 | |---|---|---| -| VPD/ASO/FGA 관리 백오피스 | `src/main/java/com/cloudhandson/vpdbackoffice/` | Spring Boot 기반 데이터 접근 제어 관리 콘솔 | -| VPD 백오피스 화면 | `src/main/resources/templates/` | Thymeleaf 서버 렌더링 화면 | -| VPD 백오피스 CSS/JS | `src/main/resources/static/` | 화면 동작과 스타일 | -| VPD/ASO/FGA/ORDS/Select AI SQL | `sql/adb/` | ADB 적용·검증 SQL 스크립트 | -| 원격 원장 seed/검증 SQL | `sql/source/` | PostgreSQL·MySQL 가상 원장과 HMM 선사 실적 데이터 | +| VPD/ASO/FGA 관리 백오피스 | `vpd-backoffice/` | Spring Boot 기반 데이터 접근 제어 관리 콘솔 | +| VPD 백오피스 화면 | `vpd-backoffice/src/main/resources/templates/` | Thymeleaf 서버 렌더링 화면 | +| VPD 백오피스 CSS/JS | `vpd-backoffice/src/main/resources/static/` | 화면 동작과 스타일 | +| VPD/ASO/FGA/ORDS/Select AI SQL | `database/adb/` | ADB 적용·검증 SQL 스크립트 | +| 원격 원장 seed/검증 SQL | `database/source/` | PostgreSQL·MySQL 가상 원장과 HMM 선사 실적 데이터 | | DDS 백오피스 | `dds-backoffice/` | VPD와 분리된 DDS 전용 Spring Boot 데모 | -| Streamlit 외피 / PoC4 MCP AI Console | `poc4_active_source_20260714/` | ReAct-style로 MCP tool을 호출하는 PoC4 데모 소스 snapshot | -| Streamlit 외피 메인 화면 | `poc4_active_source_20260714/apps/poc4/mcp_discovery_ui.py` | MCP discovery, tool routing, ReAct-style agent loop, FGA evidence 표시 | -| Streamlit 외피 MCP 설정 | `poc4_active_source_20260714/config/mcp_servers.json` | `kb_mcp`, `kb_vector_mcp` endpoint와 allowlist | +| AI Web Agent Console | `ai-web-agent-console/` | Streamlit 기반 MCP 업무 에이전트 콘솔 | +| AI Web Agent Console 진입점 | `ai-web-agent-console/app.py` | MCP discovery, 도구 호출, 답변 합성, 감사 증적 표시 | +| AI Web Agent Console 패키지 | `ai-web-agent-console/ai_web_agent_console/` | 인증, 화면, MCP, 모델과 질의 계약 모듈 | +| AI Web Agent Console 설정 | `ai-web-agent-console/config/` | 제품, MCP, 모델, 데모 사용자와 질문 JSON | Git 기준은 다음과 같다. @@ -81,14 +82,12 @@ Git 기준은 다음과 같다. | 로컬 작업 디렉터리 | `/home/opc/workspaces/vpd-permission-poc-20260628213409` | | 운영 기준 remote | `gitea` | | 운영 기준 repository | `https://gittea.cloud-handson.com/joungmin/vpd-permission-poc.git` | -| 기준 branch | `main` | -| 보조 remote | `origin` = `https://github.com/devmrko/vpd-permission-poc.git` | +| HMM 기준 branch | `hmm-backoffice` | 주의: -- 현재 운영·현행화 기준은 `gitea/main`이다. -- `origin/main`은 보조 remote이며, 이 작업공간의 `main`이 `origin/main`보다 앞서 있을 수 있다. -- `poc4_active_source_20260714/`는 배포 VM의 PoC4 활성 소스를 가져온 snapshot이다. 원본은 배포 VM의 `/home/opc/poc_4/` 계열 경로에서 운영되었고, 저장소에는 비밀정보 없이 소스와 설정 sample만 보관한다. +- HMM 운영·현행화 기준은 Gitea의 `hmm-backoffice` 브랜치다. +- 날짜 스냅샷과 PoC 번호는 현재 소스 경로로 사용하지 않는다. - 실제 DB password, wallet password, Bearer token, AI key, 대화 SQLite DB는 Git에 넣지 않는다. --- @@ -111,7 +110,7 @@ Git 기준은 다음과 같다. ## 빠른 시작 (One-Click) ```bash -git clone https://github.com//vpd-permission-poc.git +git clone --branch hmm-backoffice https://gittea.cloud-handson.com/joungmin/vpd-permission-poc.git cd vpd-permission-poc # 1) 환경값 채우기 @@ -169,7 +168,7 @@ $EDITOR .env ## 데모 시나리오 — 2×2 source access matrix -`sql/adb/03_seed.sql` 의 매핑 (4 유저, 4 케이스): +`database/adb/03_seed.sql` 의 매핑 (4 유저, 4 케이스): | DB 유저 | 그룹 | PG 뷰 | MySQL 뷰 | VPD 결과 | |---|---|---|---|---| @@ -187,7 +186,7 @@ $EDITOR .env (`1=0` predicate) — **deny by default**. * 누구든 원본 테이블 직접 접근 시도 (`@RDS_POSTGRES_LINK` 등) → 권한 없음. -`sql/adb/08_tests_user_my.sql` 가 우회 시도 5개 (원격 직접 SELECT, 컨텍스트 +`database/adb/08_tests_user_my.sql` 가 우회 시도 5개 (원격 직접 SELECT, 컨텍스트 스푸핑, DBMS_RLS 변경, 매핑 테이블 SELECT) 를 시도하고 모두 ORA-xxxxx 로 실패하는 것을 보여줍니다. 09/10/11 은 각 유저의 expected 행 수를 가볍게 확인합니다. @@ -199,7 +198,7 @@ $EDITOR .env ## DDS 설정 핵심 -DDS 변형을 직접 셋업할 때 알아야 하는 최소 단위. `sql/adb/13_dds_variant.sql` 가 이 +DDS 변형을 직접 셋업할 때 알아야 하는 최소 단위. `database/adb/13_dds_variant.sql` 가 이 순서로 돌아가며, 행/컬럼 통제가 모두 **선언형 DDL 한 줄** 로 끝납니다. ### 사전 조건 @@ -259,8 +258,19 @@ CREATE DATA GRANT admin.alice_apac_grant . ├── run.sh # 원클릭 엔트리포인트 ├── .env.example +├── vpd-backoffice/ # Spring Boot VPD 관리 백오피스 +│ ├── pom.xml +│ └── src/ +├── ai-web-agent-console/ # Streamlit MCP 업무 에이전트 +│ ├── app.py +│ ├── ai_web_agent_console/ +│ ├── config/ +│ └── tests/ +├── dds-backoffice/ # DDS 전용 Spring Boot 백오피스 +├── deploy/ # 애플리케이션별 배포 설정 +├── tests/ # 저장소 폴더 경계와 경로 규칙 검증 ├── scripts/lib/common.sh # log/ok/warn/die + env 검증 헬퍼 -├── sql/ +├── database/ │ ├── source/ │ │ ├── postgres_setup.sql # 원격 PG: customers + 12 rows │ │ ├── postgres_hmm_carrier_performance.sql # 원격 PG: HMM 가상 선사 8개 + 월간 KPI 144 rows diff --git a/ai-web-agent-console/.env.example b/ai-web-agent-console/.env.example new file mode 100644 index 0000000..e3d01e8 --- /dev/null +++ b/ai-web-agent-console/.env.example @@ -0,0 +1,48 @@ +# AI Web Agent Console local/VM configuration example. +# Copy to .env and keep real credentials out of Git. + +# MCP +HMM_MCP_BEARER_TOKEN= +AI_WEB_AGENT_CONSOLE_MCP_TIMEOUT_SECONDS=45 + +# OCI Generative AI SDK +OCI_AUTH_TYPE=config_file +OCI_CONFIG_FILE=~/.oci/config +OCI_PROFILE=DEFAULT +OCI_GENAI_COMPARTMENT_ID= +AI_WEB_AGENT_CONSOLE_MODEL_PROFILE=gpt54_mini_oci +AI_WEB_AGENT_CONSOLE_COMPLEX_REASONING_MODEL_PROFILE=gpt54_mini_oci + +# Optional model route overrides +# AI_WEB_AGENT_CONSOLE_LLM_GPT54_MINI_OCI_MODEL_ID=openai.gpt-5.4-mini +# AI_WEB_AGENT_CONSOLE_LLM_GPT54_MINI_OCI_REGION=us-chicago-1 +# AI_WEB_AGENT_CONSOLE_LLM_GPT54_MINI_OCI_ENDPOINT=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com + +# Login gateway. Generate PBKDF2 hash and random cookie secret outside Git. +AI_WEB_AGENT_CONSOLE_LOGIN_USER=demo-admin +AI_WEB_AGENT_CONSOLE_LOGIN_PASSWORD_PBKDF2= +AI_WEB_AGENT_CONSOLE_LOGIN_COOKIE_SECRET= +PORTAL_AUTH_BIND_ADDRESS=127.0.0.1 +PORTAL_AUTH_PORT=8621 +PORTAL_AUTH_SESSION_SECONDS=43200 +PORTAL_AUTH_REMEMBER_SECONDS=604800 + +# Product display +AGENT_CONSOLE_NAME=HMM AI 업무 에이전트 +AGENT_CONSOLE_SHORT_NAME=HMM +AGENT_CONSOLE_PAGE_TITLE=HMM AI 업무 에이전트 +AGENT_CONSOLE_PRIMARY_COLOR=#004b87 + +# Local conversation store +AI_WEB_AGENT_CONSOLE_CHAT_DB_PATH=data/ai_web_agent_console_chat.sqlite3 + +# Optional audit DB. Password and Wallet remain outside Git. +AI_WEB_AGENT_CONSOLE_AUDIT_DB_ENV_FILE=.env +AI_WEB_AGENT_CONSOLE_AUDIT_DB_USER=ADMIN +AI_WEB_AGENT_CONSOLE_AUDIT_DB_PASSWORD= +AI_WEB_AGENT_CONSOLE_AUDIT_DSN= +AI_WEB_AGENT_CONSOLE_AUDIT_WALLET_DIR= +AI_WEB_AGENT_CONSOLE_AUDIT_WALLET_PASSWORD= + +# Optional query contract override +AI_WEB_AGENT_CONSOLE_QUERY_CONTRACTS_PATH=config/hmm_hr_query_contracts.json diff --git a/ai-web-agent-console/README.md b/ai-web-agent-console/README.md new file mode 100644 index 0000000..799316d --- /dev/null +++ b/ai-web-agent-console/README.md @@ -0,0 +1,57 @@ +# AI Web Agent Console + +HMM 업무 데이터를 MCP 도구로 조회하고 OCI Generative AI로 답변을 구성하는 Streamlit +애플리케이션이다. 과거 PoC 번호나 소스 추출 날짜는 애플리케이션 이름과 패키지 경계로 +사용하지 않는다. + +## 구조 + +```text +ai-web-agent-console/ +├── app.py Streamlit 실행 진입점 +├── ai_web_agent_console/ 인증, 화면, MCP, 모델, 질의 계약 모듈 +├── config/ 제품·모델·MCP·시나리오 JSON +├── tests/ Python 회귀 테스트 +├── .env.example 환경변수 예시 +└── requirements.txt +``` + +## 실행 + +```bash +cd ai-web-agent-console +python3 -m venv .venv +.venv/bin/pip install -r requirements.txt +.venv/bin/streamlit run app.py --server.address 0.0.0.0 --server.port 8622 +``` + +인증 게이트웨이는 같은 디렉토리에서 다음과 같이 실행한다. + +```bash +.venv/bin/python -m ai_web_agent_console.auth_gateway +``` + +## 설정 + +- `config/app_profile.json`: 제품명, 설명, 아이콘, 색상 +- `config/mcp_servers.json`: MCP endpoint와 허용 도구 +- `config/model_profiles.json`: OCI Generative AI 모델 profile +- `config/vpd_token_presets.json`: 데모 사용자와 토큰 환경변수 매핑 +- `config/hmm_demo_scenarios.json`: 화면의 예제 질문 +- `config/hmm_hr_query_contracts.json`: 질의별 필수 근거와 계산·시간 규칙 + +실제 토큰, DB 비밀번호, Wallet, OCI private key는 Git에 넣지 않는다. 데모 사용자 JSON은 +`HMM_MCP_BEARER_TOKEN` 같은 환경변수 이름만 참조한다. + +## 검증 + +```bash +python3 -m compileall -q app.py ai_web_agent_console tests +python3 -m unittest discover -s tests -p 'test_*.py' +``` + +## 운영 호환성 + +운영 서버의 물리 경로 `/opt/hmm-poc4`와 기존 SQLite 테이블명은 대화 이력과 서비스 전환 +호환을 위해 유지할 수 있다. Git 폴더, Python 패키지와 실행 명령은 이 문서의 새 이름만 +사용한다. diff --git a/poc4_active_source_20260714/src/agent_console/__init__.py b/ai-web-agent-console/ai_web_agent_console/__init__.py similarity index 100% rename from poc4_active_source_20260714/src/agent_console/__init__.py rename to ai-web-agent-console/ai_web_agent_console/__init__.py diff --git a/poc4_active_source_20260714/src/agent_console/audit.py b/ai-web-agent-console/ai_web_agent_console/audit.py similarity index 100% rename from poc4_active_source_20260714/src/agent_console/audit.py rename to ai-web-agent-console/ai_web_agent_console/audit.py diff --git a/poc4_active_source_20260714/src/agent_console/auth_gateway.py b/ai-web-agent-console/ai_web_agent_console/auth_gateway.py similarity index 95% rename from poc4_active_source_20260714/src/agent_console/auth_gateway.py rename to ai-web-agent-console/ai_web_agent_console/auth_gateway.py index f9be767..03fd632 100644 --- a/poc4_active_source_20260714/src/agent_console/auth_gateway.py +++ b/ai-web-agent-console/ai_web_agent_console/auth_gateway.py @@ -28,6 +28,14 @@ from typing import Deque from urllib.parse import parse_qs, urlsplit +def _environment_value(*names: str, default: str = "") -> str: + for name in names: + value = os.environ.get(name) + if value is not None and value.strip(): + return value.strip() + return default + + LOG = logging.getLogger("hmm_portal_auth") SESSION_COOKIE_NAME = "__Host-HMM_PORTAL_SESSION" CSRF_COOKIE_NAME = "__Host-HMM_LOGIN_CSRF" @@ -54,13 +62,17 @@ class AuthConfig: @classmethod def from_environment(cls) -> "AuthConfig": config = cls( - username=os.environ.get("POC4_LOGIN_USER", "").strip(), - password_pbkdf2=os.environ.get( - "POC4_LOGIN_PASSWORD_PBKDF2", "" - ).strip(), - cookie_secret=os.environ.get( - "POC4_LOGIN_COOKIE_SECRET", "" - ).strip(), + username=_environment_value( + "AI_WEB_AGENT_CONSOLE_LOGIN_USER", "POC4_LOGIN_USER" + ), + password_pbkdf2=_environment_value( + "AI_WEB_AGENT_CONSOLE_LOGIN_PASSWORD_PBKDF2", + "POC4_LOGIN_PASSWORD_PBKDF2", + ), + cookie_secret=_environment_value( + "AI_WEB_AGENT_CONSOLE_LOGIN_COOKIE_SECRET", + "POC4_LOGIN_COOKIE_SECRET", + ), bind_address=os.environ.get( "PORTAL_AUTH_BIND_ADDRESS", "127.0.0.1" ).strip(), @@ -96,9 +108,11 @@ class AuthConfig: def validate(self) -> None: if not self.username or not self.password_pbkdf2: - raise ValueError("POC4 portal login credentials are not configured") + raise ValueError("AI web agent console login credentials are not configured") if len(self.cookie_secret.encode("utf-8")) < 32: - raise ValueError("POC4_LOGIN_COOKIE_SECRET must be at least 32 bytes") + raise ValueError( + "AI_WEB_AGENT_CONSOLE_LOGIN_COOKIE_SECRET must be at least 32 bytes" + ) if self.bind_address not in {"127.0.0.1", "::1"}: raise ValueError("Portal authentication service must bind to loopback") if not 1 <= self.port <= 65535: diff --git a/poc4_active_source_20260714/src/mcp_result.py b/ai-web-agent-console/ai_web_agent_console/mcp_result.py similarity index 100% rename from poc4_active_source_20260714/src/mcp_result.py rename to ai-web-agent-console/ai_web_agent_console/mcp_result.py diff --git a/poc4_active_source_20260714/src/mcp_tool_router.py b/ai-web-agent-console/ai_web_agent_console/mcp_tool_router.py similarity index 98% rename from poc4_active_source_20260714/src/mcp_tool_router.py rename to ai-web-agent-console/ai_web_agent_console/mcp_tool_router.py index 3dfae60..be0edae 100644 --- a/poc4_active_source_20260714/src/mcp_tool_router.py +++ b/ai-web-agent-console/ai_web_agent_console/mcp_tool_router.py @@ -10,11 +10,11 @@ from dataclasses import dataclass import json from typing import Any, Mapping -from src.oci_genai_sdk import ( +from ai_web_agent_console.oci_genai_sdk import ( build_oci_genai_completion_client, temperature_for_model_profile, ) -from src.poc3.model_registry import resolve_model_profile +from ai_web_agent_console.model_registry import resolve_model_profile @dataclass(frozen=True) diff --git a/poc4_active_source_20260714/src/poc3/model_registry.py b/ai-web-agent-console/ai_web_agent_console/model_registry.py similarity index 83% rename from poc4_active_source_20260714/src/poc3/model_registry.py rename to ai-web-agent-console/ai_web_agent_console/model_registry.py index ee9adf6..16ed237 100644 --- a/poc4_active_source_20260714/src/poc3/model_registry.py +++ b/ai-web-agent-console/ai_web_agent_console/model_registry.py @@ -1,7 +1,7 @@ -"""8512/8513 전용 PoC_3 model profile registry. +"""8512/8513 전용 AI Web Agent Console model profile registry. 이 registry는 모델 metadata만 관리한다. ``provider=oci``는 모델의 출처를 뜻하며 -``POC3_MCP_PROVIDER``와 독립적이다. 따라서 기본 model profile이 GPT-5.5여도 현재 +``AI_WEB_AGENT_CONSOLE_MCP_PROVIDER``와 독립적이다. 따라서 기본 model profile이 GPT-5.5여도 현재 MCP 실행 경로는 계속 ``mock``일 수 있다. """ @@ -15,11 +15,11 @@ import re from typing import Any, Mapping, Optional -ROOT = Path(__file__).resolve().parents[2] -REGISTRY_PATH = ROOT / "config" / "poc3_model_profiles.json" +ROOT = Path(__file__).resolve().parents[1] +REGISTRY_PATH = ROOT / "config" / "model_profiles.json" DEFAULT_MODEL_PROFILE_KEY = "gpt55_oci" -MODEL_PROFILE_ENV = "POC3_MODEL_PROFILE" -MODEL_PROFILE_DEFAULT_ENV = "POC3_MODEL_PROFILE_DEFAULT" +MODEL_PROFILE_ENV = "AI_WEB_AGENT_CONSOLE_MODEL_PROFILE" +MODEL_PROFILE_DEFAULT_ENV = "AI_WEB_AGENT_CONSOLE_MODEL_PROFILE_DEFAULT" EXISTING_MODEL_PROFILE_KEYS = ("grok43", "llama4_maverick", "llama33_70b") MODEL_PROFILE_ALIASES = { "gpt54_mini": "gpt54_mini_oci", @@ -84,36 +84,36 @@ _REQUIRED_PROFILE_FIELDS = ( "poc2_select_ai_profile", "poc2_native_agent_team", "verification_status", - "default_for_poc3", + "default_for_console", "source_tag", "notes", ) _PROFILE_ROUTE_ENV_KEYS = { "gpt55_oci": ( - "POC3_LLM_GPT55_OCI_MODEL_ID", - "POC3_LLM_GPT55_OCI_REGION", - "POC3_LLM_GPT55_OCI_ENDPOINT", + "AI_WEB_AGENT_CONSOLE_LLM_GPT55_OCI_MODEL_ID", + "AI_WEB_AGENT_CONSOLE_LLM_GPT55_OCI_REGION", + "AI_WEB_AGENT_CONSOLE_LLM_GPT55_OCI_ENDPOINT", ), "gpt54_mini_oci": ( - "POC3_LLM_GPT54_MINI_OCI_MODEL_ID", - "POC3_LLM_GPT54_MINI_OCI_REGION", - "POC3_LLM_GPT54_MINI_OCI_ENDPOINT", + "AI_WEB_AGENT_CONSOLE_LLM_GPT54_MINI_OCI_MODEL_ID", + "AI_WEB_AGENT_CONSOLE_LLM_GPT54_MINI_OCI_REGION", + "AI_WEB_AGENT_CONSOLE_LLM_GPT54_MINI_OCI_ENDPOINT", ), "grok43": ( - "POC3_LLM_GROK43_MODEL_ID", - "POC3_LLM_GROK43_REGION", - "POC3_LLM_GROK43_ENDPOINT", + "AI_WEB_AGENT_CONSOLE_LLM_GROK43_MODEL_ID", + "AI_WEB_AGENT_CONSOLE_LLM_GROK43_REGION", + "AI_WEB_AGENT_CONSOLE_LLM_GROK43_ENDPOINT", ), "llama4_maverick": ( - "POC3_LLM_LLAMA4_MAVERICK_MODEL_ID", - "POC3_LLM_LLAMA4_MAVERICK_REGION", - "POC3_LLM_LLAMA4_MAVERICK_ENDPOINT", + "AI_WEB_AGENT_CONSOLE_LLM_LLAMA4_MAVERICK_MODEL_ID", + "AI_WEB_AGENT_CONSOLE_LLM_LLAMA4_MAVERICK_REGION", + "AI_WEB_AGENT_CONSOLE_LLM_LLAMA4_MAVERICK_ENDPOINT", ), "llama33_70b": ( - "POC3_LLM_LLAMA33_70B_MODEL_ID", - "POC3_LLM_LLAMA33_70B_REGION", - "POC3_LLM_LLAMA33_70B_ENDPOINT", + "AI_WEB_AGENT_CONSOLE_LLM_LLAMA33_70B_MODEL_ID", + "AI_WEB_AGENT_CONSOLE_LLM_LLAMA33_70B_REGION", + "AI_WEB_AGENT_CONSOLE_LLM_LLAMA33_70B_ENDPOINT", ), } @@ -154,7 +154,7 @@ class ModelProfile: poc2_select_ai_profile: str poc2_native_agent_team: str verification_status: str - default_for_poc3: bool + default_for_console: bool source_tag: str notes: str display_order: int = 999 @@ -163,9 +163,9 @@ class ModelProfile: def from_mapping(cls, value: Mapping[str, Any]) -> "ModelProfile": missing = [name for name in _REQUIRED_PROFILE_FIELDS if name not in value] if missing: - raise ValueError("PoC_3 model profile fields are missing") - if not isinstance(value.get("default_for_poc3"), bool): - raise ValueError("default_for_poc3 must be boolean") + raise ValueError("AI Web Agent Console model profile fields are missing") + if not isinstance(value.get("default_for_console"), bool): + raise ValueError("default_for_console must be boolean") order = value.get("display_order", 999) if isinstance(order, bool) or not isinstance(order, int) or order < 0: raise ValueError("model profile display_order is invalid") @@ -191,7 +191,7 @@ class ModelProfile: .strip() .upper(), verification_status=str(value["verification_status"]).strip().upper(), - default_for_poc3=value["default_for_poc3"], + default_for_console=value["default_for_console"], source_tag=str(value["source_tag"]).strip(), notes=str(value["notes"]).strip(), display_order=order, @@ -276,7 +276,7 @@ class ModelProfile: "poc2_select_ai_profile": self.poc2_select_ai_profile, "poc2_native_agent_team": self.poc2_native_agent_team, "verification_status": self.verification_status, - "default_for_poc3": self.default_for_poc3, + "default_for_console": self.default_for_console, "source_tag": self.source_tag, "notes": self.notes, } @@ -284,7 +284,7 @@ class ModelProfile: @dataclass(frozen=True) class ModelProfileRegistry: - """검증된 PoC_3 model profile 집합.""" + """검증된 AI Web Agent Console model profile 집합.""" profiles: tuple[ModelProfile, ...] default_model_profile: str @@ -338,32 +338,32 @@ def load_model_registry(path: Path = REGISTRY_PATH) -> ModelProfileRegistry: try: payload = json.loads(path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError) as exc: - raise ValueError("PoC_3 model profile registry cannot be loaded") from exc + raise ValueError("AI Web Agent Console model profile registry cannot be loaded") from exc if not isinstance(payload, Mapping): - raise ValueError("PoC_3 model profile registry must be an object") + raise ValueError("AI Web Agent Console model profile registry must be an object") raw_profiles = payload.get("profiles") if not isinstance(raw_profiles, list) or not raw_profiles: - raise ValueError("PoC_3 model profile registry has no profiles") + raise ValueError("AI Web Agent Console model profile registry has no profiles") profiles = tuple( ModelProfile.from_mapping(item) for item in raw_profiles if isinstance(item, Mapping) ) if len(profiles) != len(raw_profiles): - raise ValueError("PoC_3 model profile registry contains an invalid profile") + raise ValueError("AI Web Agent Console model profile registry contains an invalid profile") keys = tuple(item.model_key for item in profiles) if len(set(keys)) != len(keys): - raise ValueError("PoC_3 model profile keys must be unique") + raise ValueError("AI Web Agent Console model profile keys must be unique") if len({item.display_name for item in profiles}) != len(profiles): - raise ValueError("PoC_3 model profile display names must be unique") - defaults = tuple(item.model_key for item in profiles if item.default_for_poc3) + raise ValueError("AI Web Agent Console model profile display names must be unique") + defaults = tuple(item.model_key for item in profiles if item.default_for_console) configured_default = str(payload.get("default_model_profile") or "").strip().lower() if defaults != (configured_default,): - raise ValueError("PoC_3 model profile default is inconsistent") + raise ValueError("AI Web Agent Console model profile default is inconsistent") if configured_default != DEFAULT_MODEL_PROFILE_KEY: - raise ValueError("PoC_3 GPT-5.5 default contract is not satisfied") + raise ValueError("AI Web Agent Console GPT-5.5 default contract is not satisfied") if not set(EXISTING_MODEL_PROFILE_KEYS).issubset(keys): - raise ValueError("existing PoC_3 selector models are missing") + raise ValueError("existing AI Web Agent Console selector models are missing") actual_answer_routes = { item.model_key: ( item.model_id, @@ -374,16 +374,16 @@ def load_model_registry(path: Path = REGISTRY_PATH) -> ModelProfileRegistry: for item in profiles } if actual_answer_routes != _EXPECTED_ANSWER_MODEL_ROUTES: - raise ValueError("PoC_3 answer model route mapping is inconsistent") + raise ValueError("AI Web Agent Console answer model route mapping is inconsistent") if str(payload.get("source_commit") or "").strip() != EXPECTED_SOURCE_COMMIT: raise ValueError("PoC_2 source commit is inconsistent") if any(item.source_tag != EXPECTED_SOURCE_TAG for item in profiles): raise ValueError("PoC_2 source tag is inconsistent") if payload.get("schema_version") != 1: - raise ValueError("unsupported PoC_3 model profile registry schema") + raise ValueError("unsupported AI Web Agent Console model profile registry schema") registry_name = str(payload.get("registry_name") or "").strip() if not registry_name: - raise ValueError("PoC_3 model profile registry name is missing") + raise ValueError("AI Web Agent Console model profile registry name is missing") return ModelProfileRegistry( profiles=profiles, default_model_profile=configured_default, diff --git a/poc4_active_source_20260714/src/oci_genai_sdk.py b/ai-web-agent-console/ai_web_agent_console/oci_genai_sdk.py similarity index 100% rename from poc4_active_source_20260714/src/oci_genai_sdk.py rename to ai-web-agent-console/ai_web_agent_console/oci_genai_sdk.py diff --git a/poc4_active_source_20260714/src/agent_console/presentation.py b/ai-web-agent-console/ai_web_agent_console/presentation.py similarity index 100% rename from poc4_active_source_20260714/src/agent_console/presentation.py rename to ai-web-agent-console/ai_web_agent_console/presentation.py diff --git a/poc4_active_source_20260714/src/agent_console/profile.py b/ai-web-agent-console/ai_web_agent_console/profile.py similarity index 100% rename from poc4_active_source_20260714/src/agent_console/profile.py rename to ai-web-agent-console/ai_web_agent_console/profile.py diff --git a/ai-web-agent-console/ai_web_agent_console/query_contracts.py b/ai-web-agent-console/ai_web_agent_console/query_contracts.py new file mode 100644 index 0000000..8427a73 --- /dev/null +++ b/ai-web-agent-console/ai_web_agent_console/query_contracts.py @@ -0,0 +1,407 @@ +"""Configuration-driven query and answer evidence contracts.""" + +from __future__ import annotations + +import ast +from decimal import Decimal, InvalidOperation +from functools import lru_cache +import json +import os +from pathlib import Path +import re +from typing import Any, Mapping + + +ROOT = Path(__file__).resolve().parents[1] +DEFAULT_CONTRACT_FILE = ROOT / "config" / "hmm_hr_query_contracts.json" + + +def _contract_file() -> Path: + configured = str( + os.getenv("AI_WEB_AGENT_CONSOLE_QUERY_CONTRACTS_PATH") + or os.getenv("POC4_QUERY_CONTRACTS_PATH") + or "" + ).strip() + if not configured: + return DEFAULT_CONTRACT_FILE + path = Path(configured).expanduser() + return path if path.is_absolute() else ROOT / path + + +@lru_cache(maxsize=4) +def _load_contract_file(path_text: str) -> tuple[Mapping[str, Any], ...]: + path = Path(path_text) + if not path.exists(): + return () + value = json.loads(path.read_text(encoding="utf-8")) + contracts = value.get("contracts") if isinstance(value, Mapping) else None + if not isinstance(contracts, list): + raise ValueError("query contracts must contain a contracts array") + return tuple(item for item in contracts if isinstance(item, Mapping)) + + +def load_query_contracts() -> tuple[Mapping[str, Any], ...]: + return _load_contract_file(str(_contract_file())) + + +def matching_query_contracts( + question: str, + tool_name: str, +) -> tuple[Mapping[str, Any], ...]: + normalized_question = " ".join(str(question or "").casefold().split()) + normalized_tool = str(tool_name or "").strip() + selected: list[Mapping[str, Any]] = [] + for contract in load_query_contracts(): + tools = contract.get("applies_to_tools") + if isinstance(tools, list) and normalized_tool not in { + str(item) for item in tools + }: + continue + intent = contract.get("intent_match") + if not isinstance(intent, Mapping): + continue + subject_terms = [ + str(item).casefold() + for item in intent.get("subject_terms_any", []) + if str(item).strip() + ] + action_terms = [ + str(item).casefold() + for item in intent.get("action_terms_any", []) + if str(item).strip() + ] + if subject_terms and not any( + term in normalized_question for term in subject_terms + ): + continue + if action_terms and not any( + term in normalized_question for term in action_terms + ): + continue + selected.append(contract) + return tuple(selected) + + +def query_contract_guidance(question: str, tool_name: str) -> str: + contracts = matching_query_contracts(question, tool_name) + if not contracts: + return "" + return json.dumps( + {"query_contracts": contracts}, + ensure_ascii=False, + separators=(",", ":"), + ) + + +def append_query_contract_guidance( + tool_query: str, + *, + original_question: str, + tool_name: str, +) -> str: + guidance = query_contract_guidance(original_question, tool_name) + normalized = str(tool_query or "").strip() + if not guidance: + return normalized + return ( + f"{normalized}\n" + "다음 질의 계약의 필드·계산·시간 기준을 반드시 지켜 결과를 반환하세요. " + f"계약: {guidance}" + ) + + +def _json_data_result(value: str) -> Any: + marker = "DATA_RESULT" + position = value.find(marker) + if position < 0: + return None + remainder = value[position + len(marker) :] + object_position = remainder.find("{") + array_position = remainder.find("[") + positions = [ + candidate + for candidate in (object_position, array_position) + if candidate >= 0 + ] + if not positions: + return None + candidate = remainder[min(positions) :] + try: + parsed, _ = json.JSONDecoder().raw_decode(candidate) + except (TypeError, ValueError, json.JSONDecodeError): + return None + return parsed + + +def _evidence_rows(value: Any) -> list[Mapping[str, Any]]: + rows: list[Mapping[str, Any]] = [] + if isinstance(value, Mapping): + rows.append(value) + for item in value.values(): + rows.extend(_evidence_rows(item)) + elif isinstance(value, list): + for item in value: + rows.extend(_evidence_rows(item)) + elif isinstance(value, str): + parsed = _json_data_result(value) + if parsed is not None: + rows.extend(_evidence_rows(parsed)) + return rows + + +def _decimal(value: Any) -> Decimal: + if isinstance(value, bool) or value is None: + raise InvalidOperation + return Decimal(str(value)) + + +def _evaluate_contract_expression( + expression: str, + row: Mapping[str, Any], +) -> Decimal: + tree = ast.parse(expression, mode="eval") + + def evaluate(node: ast.AST) -> Decimal: + if isinstance(node, ast.Expression): + return evaluate(node.body) + if isinstance(node, ast.Name): + key = node.id.casefold() + if key not in row: + raise InvalidOperation + return _decimal(row[key]) + if isinstance(node, ast.Constant): + return _decimal(node.value) + if isinstance(node, ast.UnaryOp) and isinstance( + node.op, (ast.UAdd, ast.USub) + ): + value = evaluate(node.operand) + return value if isinstance(node.op, ast.UAdd) else -value + if isinstance(node, ast.BinOp) and isinstance( + node.op, (ast.Add, ast.Sub, ast.Mult, ast.Div) + ): + left = evaluate(node.left) + right = evaluate(node.right) + if isinstance(node.op, ast.Add): + return left + right + if isinstance(node.op, ast.Sub): + return left - right + if isinstance(node.op, ast.Mult): + return left * right + return left / right + raise ValueError("unsupported contract expression") + + return evaluate(tree) + + +def evidence_contract_report( + contracts: tuple[Mapping[str, Any], ...], + evidence: Any, +) -> list[dict[str, Any]]: + rows = [ + {str(key).strip().casefold(): value for key, value in row.items()} + for row in _evidence_rows(evidence) + ] + reports: list[dict[str, Any]] = [] + for contract in contracts: + data_contract = contract.get("data_contract") + if not isinstance(data_contract, Mapping): + continue + required = [ + str(item).strip().casefold() + for item in data_contract.get("required_fields", []) + if str(item).strip() + ] + matching_row = next( + (row for row in rows if required and all(key in row for key in required)), + None, + ) + observed = sorted( + { + key + for row in rows + for key in row + if not required or key in required + } + ) + missing = [ + key.upper() + for key in required + if matching_row is None or key not in matching_row + ] + computed_checks: list[dict[str, Any]] = [] + computed_fields = data_contract.get("computed_fields") + if matching_row is not None and isinstance(computed_fields, Mapping): + for field, definition in computed_fields.items(): + normalized_field = str(field).strip().casefold() + expression = ( + str(definition.get("expression") or "").strip() + if isinstance(definition, Mapping) + else "" + ) + if not normalized_field or not expression: + continue + try: + actual = _decimal(matching_row.get(normalized_field)) + expected = _evaluate_contract_expression( + expression, + matching_row, + ) + matches = actual == expected + computed_checks.append( + { + "field": normalized_field.upper(), + "expression": expression, + "actual": str(actual), + "expected": str(expected), + "satisfied": matches, + } + ) + except (InvalidOperation, ValueError, ZeroDivisionError): + computed_checks.append( + { + "field": normalized_field.upper(), + "expression": expression, + "satisfied": False, + } + ) + calculations_satisfied = all( + bool(check.get("satisfied")) for check in computed_checks + ) + temporal_checks: list[dict[str, Any]] = [] + temporal_contract = contract.get("temporal_contract") + if matching_row is not None and isinstance(temporal_contract, Mapping): + status_fields = [ + str(item).strip().casefold() + for item in temporal_contract.get("period_status_fields", []) + if str(item).strip() + ] + past_status = str( + temporal_contract.get("past_period_status") or "" + ).strip() + observed_status = next( + ( + str(matching_row.get(field) or "").strip() + for field in status_fields + if str(matching_row.get(field) or "").strip() + ), + "", + ) + if observed_status == past_status and past_status: + decision_field = str( + temporal_contract.get("past_period_decision_field") or "" + ).strip().casefold() + decision_value = str( + temporal_contract.get("past_period_decision_value") or "" + ).strip() + actual_decision = str( + matching_row.get(decision_field) or "" + ).strip() + temporal_checks.append( + { + "check": "past_period_decision", + "field": decision_field.upper(), + "expected": decision_value, + "actual": actual_decision, + "satisfied": bool( + decision_field + and decision_value + and actual_decision == decision_value + ), + } + ) + forbidden_patterns = [ + str(item).strip() + for item in temporal_contract.get( + "forbidden_past_period_decision_field_patterns", [] + ) + if str(item).strip() + ] + forbidden_fields = sorted( + key.upper() + for key in matching_row + if any( + re.search(pattern, key, flags=re.IGNORECASE) + for pattern in forbidden_patterns + ) + ) + temporal_checks.append( + { + "check": "no_past_period_yes_no_decision", + "forbidden_fields": forbidden_fields, + "satisfied": not forbidden_fields, + } + ) + required_counts = [ + str(item).strip().casefold() + for item in temporal_contract.get( + "validate_stated_days_against", [] + ) + if str(item).strip() + ] + temporal_checks.append( + { + "check": "date_range_counts", + "required_fields": [ + field.upper() for field in required_counts + ], + "missing_fields": [ + field.upper() + for field in required_counts + if field not in matching_row + ], + "satisfied": all( + field in matching_row for field in required_counts + ), + } + ) + temporal_satisfied = all( + bool(check.get("satisfied")) for check in temporal_checks + ) + reports.append( + { + "contract_id": str(contract.get("id") or ""), + "satisfied": bool( + matching_row is not None + and not missing + and calculations_satisfied + and temporal_satisfied + ), + "required_fields": [key.upper() for key in required], + "observed_required_fields": [key.upper() for key in observed], + "missing_fields": missing, + "computed_field_checks": computed_checks, + "temporal_contract_checks": temporal_checks, + "validated_record": ( + { + key.upper(): matching_row.get(key) + for key in required + } + if matching_row is not None + else {} + ), + } + ) + return reports + + +def missing_evidence_message( + contracts: tuple[Mapping[str, Any], ...], +) -> str: + for contract in contracts: + answer_contract = contract.get("answer_contract") + if not isinstance(answer_contract, Mapping): + continue + message = str(answer_contract.get("missing_evidence_message") or "").strip() + if message: + return message + return "조회 결과가 답변 계약의 필수 근거를 충족하지 않아 결론을 제공할 수 없습니다." + + +__all__ = [ + "append_query_contract_guidance", + "evidence_contract_report", + "load_query_contracts", + "matching_query_contracts", + "missing_evidence_message", + "query_contract_guidance", +] diff --git a/poc4_active_source_20260714/src/poc3/questions.py b/ai-web-agent-console/ai_web_agent_console/questions.py similarity index 97% rename from poc4_active_source_20260714/src/poc3/questions.py rename to ai-web-agent-console/ai_web_agent_console/questions.py index da01a1e..ba6bd1b 100644 --- a/poc4_active_source_20260714/src/poc3/questions.py +++ b/ai-web-agent-console/ai_web_agent_console/questions.py @@ -1,4 +1,4 @@ -"""PoC_3 preset catalog와 현재 질문 기반의 결정적 intent router.""" +"""AI Web Agent Console preset catalog와 현재 질문 기반의 결정적 intent router.""" from __future__ import annotations @@ -90,7 +90,7 @@ COMMON_DEMO_QUESTIONS = ( _QUESTION_BY_ID = {item.question_id: item for item in COMMON_DEMO_QUESTIONS} if len(_QUESTION_BY_ID) != len(COMMON_DEMO_QUESTIONS): - raise RuntimeError("duplicate PoC_3 demo question id") + raise RuntimeError("duplicate AI Web Agent Console demo question id") def question_by_id(question_id: str) -> DemoQuestion: @@ -100,7 +100,7 @@ def question_by_id(question_id: str) -> DemoQuestion: try: return _QUESTION_BY_ID[normalized] except KeyError: - raise ValueError("unknown PoC_3 demo question id") from None + raise ValueError("unknown AI Web Agent Console demo question id") from None def normalize_scenario_id(value: object) -> str | None: diff --git a/poc4_active_source_20260714/src/poc4/scenarios.py b/ai-web-agent-console/ai_web_agent_console/scenarios.py similarity index 100% rename from poc4_active_source_20260714/src/poc4/scenarios.py rename to ai-web-agent-console/ai_web_agent_console/scenarios.py diff --git a/poc4_active_source_20260714/apps/poc4/mcp_discovery_ui.py b/ai-web-agent-console/app.py similarity index 87% rename from poc4_active_source_20260714/apps/poc4/mcp_discovery_ui.py rename to ai-web-agent-console/app.py index c1510ca..26d6e08 100644 --- a/poc4_active_source_20260714/apps/poc4/mcp_discovery_ui.py +++ b/ai-web-agent-console/app.py @@ -1,7 +1,7 @@ -"""Minimal MCP discovery UI for PoC4. +"""HMM AI Web Agent Console Streamlit entrypoint. Run: - streamlit run apps/poc4/mcp_discovery_ui.py --server.port 8622 + streamlit run app.py --server.port 8622 This screen intentionally does not use the existing LangGraph/actor-context pipeline. It discovers MCP tools, selects a query-capable tool, and calls it @@ -29,7 +29,7 @@ from urllib.error import HTTPError, URLError from urllib.parse import urlsplit from urllib.request import HTTPRedirectHandler, Request, build_opener -ROOT = Path(__file__).resolve().parents[2] +ROOT = Path(__file__).resolve().parent if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) @@ -37,32 +37,38 @@ import streamlit as st import streamlit.components.v1 as components import oracledb -from src.mcp_tool_router import ( +from ai_web_agent_console.mcp_tool_router import ( McpTool, McpToolRouterError, RoutedMcpTool, build_mcp_tool_arguments, route_mcp_tool_across_servers_with_llm, ) -from src.mcp_result import ( +from ai_web_agent_console.mcp_result import ( has_actionable_text_result, status_result_evidence, status_result_summary, text_result, ) -from src.oci_genai_sdk import ( +from ai_web_agent_console.oci_genai_sdk import ( build_oci_genai_completion_client, temperature_for_model_profile, ) -from src.poc3.model_registry import load_model_registry, resolve_model_profile -from src.agent_console.presentation import ( +from ai_web_agent_console.model_registry import load_model_registry, resolve_model_profile +from ai_web_agent_console.presentation import ( apply_console_theme, render_console_header, render_login_brand, ) -from src.agent_console.audit import render_hmm_audit_tab -from src.agent_console.profile import AppProfile, AppProfileError, load_app_profile -from src.poc4.scenarios import ScenarioConfigError, load_demo_scenarios +from ai_web_agent_console.audit import render_hmm_audit_tab +from ai_web_agent_console.profile import AppProfile, AppProfileError, load_app_profile +from ai_web_agent_console.scenarios import ScenarioConfigError, load_demo_scenarios +from ai_web_agent_console.query_contracts import ( + append_query_contract_guidance, + evidence_contract_report, + matching_query_contracts, + missing_evidence_message, +) LOG = logging.getLogger(__name__) @@ -75,7 +81,10 @@ CHAT_TURNS_PER_PAGE = 3 CHAT_CONTEXT_TURNS = 4 MAX_AGENT_TOOL_STEPS = 4 AGENT_FINAL_ROUTE = "__final__" -COMPLEX_REASONING_MODEL_PROFILE_ENV = "POC4_COMPLEX_REASONING_MODEL_PROFILE" +COMPLEX_REASONING_MODEL_PROFILE_ENV = ( + "AI_WEB_AGENT_CONSOLE_COMPLEX_REASONING_MODEL_PROFILE" +) +LEGACY_COMPLEX_REASONING_MODEL_PROFILE_ENV = "POC4_COMPLEX_REASONING_MODEL_PROFILE" DEFAULT_COMPLEX_REASONING_MODEL_PROFILE = "grok43" DEFAULT_SYNTHESIS_FALLBACK_MODEL_PROFILE = "gpt54_mini_oci" DEFAULT_QUERY_MODEL_PROFILE = "gpt54_mini_oci" @@ -92,7 +101,9 @@ PORTAL_AUTH_USER_KEY = "poc4_portal_auth_user" PORTAL_AUTH_PROXY_USER_HEADER = "X-HMM-Authenticated-User" PORTAL_AUTH_PROXY_EXPIRY_HEADER = "X-HMM-Auth-Expires" AUDIT_DB_ENV_FILE = Path( - os.environ.get("POC4_AUDIT_DB_ENV_FILE", str(ENV_FILE)) + os.environ.get("AI_WEB_AGENT_CONSOLE_AUDIT_DB_ENV_FILE") + or os.environ.get("POC4_AUDIT_DB_ENV_FILE") + or str(ENV_FILE) ).expanduser() DEFAULT_AUDIT_DB_DSN = ( "(description=(retry_count=3)(retry_delay=1)" @@ -102,1364 +113,6 @@ DEFAULT_AUDIT_DB_DSN = ( "(security=(ssl_server_dn_match=yes)))" ) _OPAQUE_BEARER = re.compile(r"^[\x21-\x7e]{1,4096}$") -KB_THEME_CSS = """ - -""" - -HMM_MINIMAL_THEME_CSS = """ - -""" - -HMM_CLEAN_THEME_CSS = """ - -""" - @dataclass(frozen=True) class McpServer: @@ -1549,7 +202,10 @@ def _utc_now() -> str: def _chat_db_path() -> Path: - configured = _runtime_env_value("POC4_CHAT_DB_PATH") + configured = _runtime_env_value( + "AI_WEB_AGENT_CONSOLE_CHAT_DB_PATH", + "POC4_CHAT_DB_PATH", + ) if not configured: return CHAT_DB_FILE path = Path(configured).expanduser() @@ -1907,8 +563,12 @@ def _apply_console_theme(profile: AppProfile) -> None: apply_console_theme(st, profile) -def _portal_auth_value(name: str) -> str: - return (os.environ.get(name) or _dotenv_value(name)).strip() +def _portal_auth_value(*names: str) -> str: + for name in names: + value = (os.environ.get(name) or _dotenv_value(name)).strip() + if value: + return value + return "" def _proxy_auth_headers() -> tuple[str, int]: @@ -1925,7 +585,10 @@ def _proxy_auth_headers() -> tuple[str, int]: def _restore_portal_proxy_session() -> None: username, expires_at = _proxy_auth_headers() - expected_username = _portal_auth_value("POC4_LOGIN_USER") + expected_username = _portal_auth_value( + "AI_WEB_AGENT_CONSOLE_LOGIN_USER", + "POC4_LOGIN_USER", + ) authenticated = bool( username and expected_username @@ -2040,25 +703,35 @@ class AuditLogError(RuntimeError): def _audit_db_env_value(name: str, default: str = "") -> str: - return ( - os.environ.get(name) - or _dotenv_value(name, AUDIT_DB_ENV_FILE) - or default - ).strip() + names = [name] + if name.startswith("AI_WEB_AGENT_CONSOLE_"): + names.append(name.replace("AI_WEB_AGENT_CONSOLE_", "POC4_", 1)) + for candidate in names: + value = ( + os.environ.get(candidate) + or _dotenv_value(candidate, AUDIT_DB_ENV_FILE) + ).strip() + if value: + return value + return default.strip() @st.cache_resource(show_spinner=False) def _audit_db_pool() -> Any: - password = _audit_db_env_value("POC4_AUDIT_DB_PASSWORD") + password = _audit_db_env_value("AI_WEB_AGENT_CONSOLE_AUDIT_DB_PASSWORD") if not password: raise AuditLogError("감사로그 DB 접속 설정을 확인해 주세요.") - dsn = _audit_db_env_value("POC4_AUDIT_DSN", DEFAULT_AUDIT_DB_DSN) - wallet_password = _audit_db_env_value("POC4_AUDIT_WALLET_PASSWORD") + dsn = _audit_db_env_value( + "AI_WEB_AGENT_CONSOLE_AUDIT_DSN", DEFAULT_AUDIT_DB_DSN + ) + wallet_password = _audit_db_env_value( + "AI_WEB_AGENT_CONSOLE_AUDIT_WALLET_PASSWORD" + ) pool_options: dict[str, Any] = {} if wallet_password: wallet_dir = Path( _audit_db_env_value( - "POC4_AUDIT_WALLET_DIR", + "AI_WEB_AGENT_CONSOLE_AUDIT_WALLET_DIR", "/home/opc/apps/vpd-backoffice/wallet", ) ).expanduser().resolve() @@ -2075,7 +748,9 @@ def _audit_db_pool() -> Any: ) try: return oracledb.create_pool( - user=_audit_db_env_value("POC4_AUDIT_DB_USER", "ADMIN"), + user=_audit_db_env_value( + "AI_WEB_AGENT_CONSOLE_AUDIT_DB_USER", "ADMIN" + ), password=password, dsn=dsn, min=1, @@ -3456,11 +2131,15 @@ def _enrich_answer_with_business_evidence( return f"{verified}\n\n{normalized}".strip() -def _runtime_env_value(name: object) -> str: - key = str(name or "").strip() - if not key: - return "" - return (os.environ.get(key) or _dotenv_value(key)).strip() +def _runtime_env_value(*names: object) -> str: + for name in names: + key = str(name or "").strip() + if not key: + continue + value = (os.environ.get(key) or _dotenv_value(key)).strip() + if value: + return value + return "" def _looks_like_http_url(value: str) -> bool: @@ -4022,6 +2701,8 @@ def _complex_reasoning_model_profile(default_model_profile: str) -> str: configured = ( os.environ.get(COMPLEX_REASONING_MODEL_PROFILE_ENV) or _dotenv_value(COMPLEX_REASONING_MODEL_PROFILE_ENV) + or os.environ.get(LEGACY_COMPLEX_REASONING_MODEL_PROFILE_ENV) + or _dotenv_value(LEGACY_COMPLEX_REASONING_MODEL_PROFILE_ENV) ).strip() return configured or DEFAULT_COMPLEX_REASONING_MODEL_PROFILE or default_model_profile @@ -4866,6 +3547,11 @@ def run_mcp_agent_loop( if route is None: route = next(iter(routes_by_key.values())) route_key = _route_key(route.server_id, route.tool.name) + tool_query = append_query_contract_guidance( + tool_query, + original_question=question, + tool_name=route.tool.name, + ) is_distinct_vector_query = ( _is_vector_route(route) and tool_query not in completed_vector_queries @@ -4890,6 +3576,11 @@ def run_mcp_agent_loop( route, observations, ) + tool_query = append_query_contract_guidance( + tool_query, + original_question=question, + tool_name=route.tool.name, + ) thought = ( f"{thought} / 중복 MCP route {repeated_route_key} 대신 " f"미호출 route {route_key}로 전환합니다." @@ -5340,8 +4031,15 @@ def _prepare_hmm_hr_tool_query( """Prepare an HMM HR query without inheriting retired KB/VPD prompt rules.""" fallback = str(question or "").strip() + def with_contract(value: str) -> str: + return append_query_contract_guidance( + value, + original_question=fallback, + tool_name=tool.name, + ) + if tool.name in {"resolve_hr_term", "search_hr_policy"}: - return fallback + return with_contract(fallback) contextual_question = _hmm_demo_user_context( fallback, user_id=selected_user_id.strip(), @@ -5350,7 +4048,7 @@ def _prepare_hmm_hr_tool_query( scope=selected_user_scope.strip(), ) if tool.name == "search_carrier_performance": - return contextual_question + return with_contract(contextual_question) try: profile = resolve_model_profile(model_profile_key) client = build_oci_genai_completion_client( @@ -5390,13 +4088,15 @@ def _prepare_hmm_hr_tool_query( parsed = json.loads(text) rewritten = _clean_agent_tool_query(parsed.get("tool_query"), fallback) except Exception: - return contextual_question - return _hmm_demo_user_context( - rewritten or fallback, - user_id=selected_user_id.strip(), - role=selected_user_role.strip(), - team=selected_user_team.strip(), - scope=selected_user_scope.strip(), + return with_contract(contextual_question) + return with_contract( + _hmm_demo_user_context( + rewritten or fallback, + user_id=selected_user_id.strip(), + role=selected_user_role.strip(), + team=selected_user_team.strip(), + scope=selected_user_scope.strip(), + ) ) @@ -5413,6 +4113,72 @@ def synthesize_answer( security_evidence: Mapping[str, Any] | None = None, business_evidence: Mapping[str, Any] | None = None, ) -> Mapping[str, Any]: + contract_tools = {tool.name} + contract_tools.update( + str(step.get("tool_name") or "") + for step in (agent_steps or []) + if isinstance(step, Mapping) + ) + active_contracts_by_id: dict[str, Mapping[str, Any]] = {} + for contract_tool in contract_tools: + for contract in matching_query_contracts(question, contract_tool): + contract_id = str(contract.get("id") or "") + active_contracts_by_id[contract_id] = contract + active_contracts = tuple(active_contracts_by_id.values()) + contract_evidence = { + "mcp_result": mcp_result, + "agent_steps": list(agent_steps or []), + } + contract_report = evidence_contract_report(active_contracts, contract_evidence) + + if contract_report and any( + not bool(report.get("satisfied")) for report in contract_report + ): + missing_fields = sorted( + { + str(field) + for report in contract_report + for field in report.get("missing_fields", []) + } + ) + failed_calculations = sorted( + { + str(check.get("field") or "") + for report in contract_report + for check in report.get("computed_field_checks", []) + if not bool(check.get("satisfied")) + } + ) + failed_temporal_checks = sorted( + { + str(check.get("check") or "") + for report in contract_report + for check in report.get("temporal_contract_checks", []) + if not bool(check.get("satisfied")) + } + ) + evidence_issues = [] + if missing_fields: + evidence_issues.append("필수 필드 누락: " + ", ".join(missing_fields)) + if failed_calculations: + evidence_issues.append( + "계산 결과 불일치: " + ", ".join(failed_calculations) + ) + if failed_temporal_checks: + evidence_issues.append( + "시간 기준 계약 불일치: " + ", ".join(failed_temporal_checks) + ) + return { + "answer": missing_evidence_message(active_contracts), + "basis": evidence_issues or ["질의 계약 검증 실패"], + "limitations": ( + "필수 원장 근거가 충족되지 않아 잔여일수나 승인 가능 여부를 " + "추정하지 않았습니다." + ), + "query_contracts": list(active_contracts), + "evidence_contract_report": contract_report, + } + def build_user_prompt(*, compact: bool) -> str: evidence_items = 10 if compact else 20 evidence_text = 260 if compact else 380 @@ -5421,6 +4187,8 @@ def synthesize_answer( prompt_payload = { "question": question, "required_answer_checks": _answer_requirements(question), + "query_contracts": list(active_contracts), + "evidence_contract_report": contract_report, "conversation": [] if compact else conversation[-4:], "selected_route": { "server_id": server.server_id, @@ -5536,6 +4304,10 @@ def synthesize_answer( "FC_ID scoping for customer data, plus active catalog document/chunk evidence. " "It takes precedence when Select AI returns an ambiguous or incorrect zero-row " "result. Never expose customer rows outside the business evidence scope. " + "The query_contracts and evidence_contract_report are authoritative. Follow " + "their required fields, calculations, temporal semantics, missing-record " + "semantics, forbidden fallbacks, and answer restrictions. Keep data facts " + "and policy requirements separate. " "Show audit_log_id when it is provided. Follow every required_answer_checks item in the user " "payload. When the user requests a result list, include every " "row provided in the MCP evidence, up to 20 rows, and state the total " @@ -5600,6 +4372,8 @@ def synthesize_answer( if evidence_verified: enriched["limitations"] = "" enriched["basis"] = basis[:5] + enriched["query_contracts"] = list(active_contracts) + enriched["evidence_contract_report"] = contract_report return enriched except Exception as exc: last_error = { @@ -6442,6 +5216,8 @@ def _process_submitted_question( ) assistant_message: dict[str, Any] synthesis_error_details: dict[str, Any] = {} + query_contract_details: list[Any] = [] + evidence_contract_details: list[Any] = [] answer_model_profile = reasoning_model_profile answer_synthesis_fallback_model = "" try: @@ -6473,6 +5249,10 @@ def _process_submitted_question( "basis": synthesized.get("basis", []), "limitations": str(synthesized.get("limitations") or ""), } + query_contract_details = list(synthesized.get("query_contracts") or []) + evidence_contract_details = list( + synthesized.get("evidence_contract_report") or [] + ) except AnswerSynthesisError as exc: synthesis_error_details = getattr(exc, "diagnostics", {}) or {} fallback_profile = DEFAULT_SYNTHESIS_FALLBACK_MODEL_PROFILE @@ -6512,6 +5292,12 @@ def _process_submitted_question( "basis": synthesized.get("basis", []), "limitations": str(synthesized.get("limitations") or ""), } + query_contract_details = list( + synthesized.get("query_contracts") or [] + ) + evidence_contract_details = list( + synthesized.get("evidence_contract_report") or [] + ) except AnswerSynthesisError as fallback_exc: synthesis_error_details = { "primary": synthesis_error_details, @@ -6586,6 +5372,8 @@ def _process_submitted_question( "agent_stop_reason": agent_stop_reason, "security_evidence": security_evidence, "business_evidence": business_evidence, + "query_contracts": query_contract_details, + "evidence_contract_report": evidence_contract_details, "execution_events": execution_events, "discovered_routes": [ { diff --git a/poc4_active_source_20260714/config/app_profile.json b/ai-web-agent-console/config/app_profile.json similarity index 100% rename from poc4_active_source_20260714/config/app_profile.json rename to ai-web-agent-console/config/app_profile.json diff --git a/poc4_active_source_20260714/config/hmm_demo_scenarios.json b/ai-web-agent-console/config/hmm_demo_scenarios.json similarity index 100% rename from poc4_active_source_20260714/config/hmm_demo_scenarios.json rename to ai-web-agent-console/config/hmm_demo_scenarios.json diff --git a/ai-web-agent-console/config/hmm_hr_query_contracts.json b/ai-web-agent-console/config/hmm_hr_query_contracts.json new file mode 100644 index 0000000..1014a9f --- /dev/null +++ b/ai-web-agent-console/config/hmm_hr_query_contracts.json @@ -0,0 +1,84 @@ +{ + "version": 1, + "contracts": [ + { + "id": "leave_balance_eligibility", + "description": "연차·휴가 잔여와 신청 가능 여부를 원장 연도 및 구성값으로 검증한다.", + "applies_to_tools": [ + "search_hr_data" + ], + "intent_match": { + "subject_terms_any": [ + "연차", + "휴가" + ], + "action_terms_any": [ + "잔여", + "가능", + "승인", + "신청", + "사용할 수" + ] + }, + "data_contract": { + "source_object": "HMM_LEAVE_BALANCES", + "identity_fields": [ + "EMPLOYEE_CODE" + ], + "required_fields": [ + "LEAVE_YEAR", + "ANNUAL_ENTITLEMENT", + "CARRYOVER_DAYS", + "USED_DAYS", + "PENDING_DAYS", + "AVAILABLE_REMAINING_DAYS" + ], + "computed_fields": { + "AVAILABLE_REMAINING_DAYS": { + "expression": "ANNUAL_ENTITLEMENT + CARRYOVER_DAYS - USED_DAYS - PENDING_DAYS", + "authoritative_source": "DATABASE_VIRTUAL_COLUMN" + } + }, + "missing_record_semantics": "NO_BALANCE_DATA_FOR_YEAR", + "forbidden_missing_record_fallbacks": [ + "ZERO", + "NVL", + "COALESCE", + "OUTER_JOIN_DEFAULT", + "LITERAL_VALUE" + ] + }, + "temporal_contract": { + "current_balance_year": "LATEST_AVAILABLE_LEAVE_YEAR", + "requested_period_and_current_balance_are_separate": true, + "period_status_fields": [ + "REQUEST_PERIOD_LABEL", + "PERIOD_STATUS" + ], + "past_period_status": "HISTORICAL_REQUEST_PERIOD", + "past_period_decision": "DO_NOT_DECIDE_NEW_APPLICATION_FROM_CURRENT_BALANCE", + "past_period_decision_field": "APPLICATION_DECISION_STATUS", + "past_period_decision_value": "NOT_APPLICABLE_FOR_HISTORICAL_PERIOD", + "forbidden_past_period_decision_field_patterns": [ + "^CAN_", + "^APPROVAL_(ALLOWED|DENIED)$" + ], + "validate_stated_days_against": [ + "INCLUSIVE_CALENDAR_DAYS", + "MONDAY_TO_FRIDAY_DAYS" + ], + "day_count_mismatch_status": "DATE_COUNT_REQUIRES_VALIDATION" + }, + "answer_contract": { + "separate_data_facts_and_policy_requirements": true, + "deny_conclusions_without_required_fields": [ + "ZERO_REMAINING_DAYS", + "LEAVE_APPROVAL_ALLOWED", + "LEAVE_APPROVAL_DENIED" + ], + "missing_evidence_response": "STATE_INSUFFICIENT_EVIDENCE_WITHOUT_INVENTING_VALUES", + "missing_evidence_message": "조회 결과가 필수 원장 근거나 시간 기준 계약을 충족하지 않아 휴가 가능 여부를 확정할 수 없습니다. 계약 필드가 충족된 원장 결과로 다시 조회해야 합니다." + } + } + ] +} diff --git a/poc4_active_source_20260714/config/mcp_servers.json b/ai-web-agent-console/config/mcp_servers.json similarity index 89% rename from poc4_active_source_20260714/config/mcp_servers.json rename to ai-web-agent-console/config/mcp_servers.json index 8a6242c..3da95f4 100644 --- a/poc4_active_source_20260714/config/mcp_servers.json +++ b/ai-web-agent-console/config/mcp_servers.json @@ -8,7 +8,7 @@ "transport": "http", "endpoint_url": "https://hmm-mcp.cloud-handson.com/mcp", "auth_token_env": "HMM_MCP_BEARER_TOKEN", - "timeout_seconds_env": "POC3_MCP_TIMEOUT_SECONDS", + "timeout_seconds_env": "AI_WEB_AGENT_CONSOLE_MCP_TIMEOUT_SECONDS", "default_tool": "search_hr_data", "router_model_profile": "gpt54_mini_oci", "tool_allowlist": [ diff --git a/poc4_active_source_20260714/config/poc3_model_profiles.json b/ai-web-agent-console/config/model_profiles.json similarity index 94% rename from poc4_active_source_20260714/config/poc3_model_profiles.json rename to ai-web-agent-console/config/model_profiles.json index 2883a08..f7c973f 100644 --- a/poc4_active_source_20260714/config/poc3_model_profiles.json +++ b/ai-web-agent-console/config/model_profiles.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "registry_name": "POC3_8512_8513_MODEL_PROFILES", + "registry_name": "AI_WEB_AGENT_CONSOLE_MODEL_PROFILES", "default_model_profile": "gpt55_oci", "source_commit": "7a3b37f175b65ed5eab1d8bf37c9bf6114e7558f", "profiles": [ @@ -15,7 +15,7 @@ "poc2_select_ai_profile": "KB_AIDP_SELECTAI_GPT55_OCI_PROFILE_V2", "poc2_native_agent_team": "KB_AIDP_AGENT_TEAM_GPT55_OCI_V2", "verification_status": "VERIFIED_WITH_WARNINGS", - "default_for_poc3": true, + "default_for_console": true, "source_tag": "poc_2-gpt55-oci-partial", "notes": "PoC_2 Select AI S1~S5와 승인된 read-only 실행은 5/5 PASS. 8503 Native Agent는 S1/S2/R1/H1 PASS이나 S3 safe-conversion marker 미확인 WARN으로 PARTIAL이다.", "display_order": 0 @@ -31,7 +31,7 @@ "poc2_select_ai_profile": "KB_AIDP_SELECTAI_GPT54_MINI_OCI_PROFILE_V1", "poc2_native_agent_team": "KB_AIDP_AGENT_TEAM_GPT54_MINI_OCI_V1", "verification_status": "PARTIAL_VERIFIED", - "default_for_poc3": false, + "default_for_console": false, "source_tag": "poc_2-gpt55-oci-partial", "notes": "PoC4 MCP 실행 방식(single/agent) 판단용 경량 planner profile. Select AI/Agent Team 본 처리 기본값은 gpt55_oci를 유지한다.", "display_order": 1 @@ -47,7 +47,7 @@ "poc2_select_ai_profile": "KB_AIDP_SELECTAI_GROK43_PROFILE_V2", "poc2_native_agent_team": "KB_AIDP_AGENT_TEAM_GROK43_V3", "verification_status": "VERIFIED", - "default_for_poc3": false, + "default_for_console": false, "source_tag": "poc_2-gpt55-oci-partial", "notes": "PoC_2 기존 모델 회귀에서 S1/S3 SHOWSQL, profile 확인 및 S3 safe conversion PASS.", "display_order": 2 @@ -63,7 +63,7 @@ "poc2_select_ai_profile": "KB_AIDP_SELECTAI_LLAMA4_MAVERICK_PROFILE_V2", "poc2_native_agent_team": "KB_AIDP_AGENT_TEAM_LLAMA4_MAVERICK_V3", "verification_status": "VERIFIED", - "default_for_poc3": false, + "default_for_console": false, "source_tag": "poc_2-gpt55-oci-partial", "notes": "PoC_2 기존 모델 회귀에서 S1/S3 SHOWSQL, profile 확인 및 S3 safe conversion PASS.", "display_order": 3 @@ -79,7 +79,7 @@ "poc2_select_ai_profile": "KB_AIDP_SELECTAI_LLAMA33_PROFILE_V2", "poc2_native_agent_team": "KB_AIDP_AGENT_TEAM_LLAMA33_V3", "verification_status": "VERIFIED", - "default_for_poc3": false, + "default_for_console": false, "source_tag": "poc_2-gpt55-oci-partial", "notes": "PoC_2 기존 모델 회귀에서 S1/S3 SHOWSQL, profile 확인 및 S3 safe conversion PASS.", "display_order": 4 diff --git a/poc4_active_source_20260714/config/vpd_token_presets.json b/ai-web-agent-console/config/vpd_token_presets.json similarity index 100% rename from poc4_active_source_20260714/config/vpd_token_presets.json rename to ai-web-agent-console/config/vpd_token_presets.json diff --git a/poc4_active_source_20260714/requirements-langgraph.txt b/ai-web-agent-console/requirements-langgraph.txt similarity index 100% rename from poc4_active_source_20260714/requirements-langgraph.txt rename to ai-web-agent-console/requirements-langgraph.txt diff --git a/poc4_active_source_20260714/requirements.txt b/ai-web-agent-console/requirements.txt similarity index 100% rename from poc4_active_source_20260714/requirements.txt rename to ai-web-agent-console/requirements.txt diff --git a/poc4_active_source_20260714/tests/test_auth_gateway.py b/ai-web-agent-console/tests/test_auth_gateway.py similarity index 99% rename from poc4_active_source_20260714/tests/test_auth_gateway.py rename to ai-web-agent-console/tests/test_auth_gateway.py index 689150a..d4a46d8 100644 --- a/poc4_active_source_20260714/tests/test_auth_gateway.py +++ b/ai-web-agent-console/tests/test_auth_gateway.py @@ -13,7 +13,7 @@ from urllib.parse import urlencode ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) -from src.agent_console.auth_gateway import ( # noqa: E402 +from ai_web_agent_console.auth_gateway import ( # noqa: E402 AuthConfig, LoginAttemptLimiter, SESSION_COOKIE_NAME, diff --git a/ai-web-agent-console/tests/test_query_contracts.py b/ai-web-agent-console/tests/test_query_contracts.py new file mode 100644 index 0000000..f25a707 --- /dev/null +++ b/ai-web-agent-console/tests/test_query_contracts.py @@ -0,0 +1,181 @@ +import unittest + +from ai_web_agent_console.query_contracts import ( + append_query_contract_guidance, + evidence_contract_report, + matching_query_contracts, +) + + +def test_leave_eligibility_question_selects_external_contract(): + contracts = matching_query_contracts( + "직원 E9999의 연차 잔여와 신청 가능 여부를 알려줘", + "search_hr_data", + ) + + assert [contract["id"] for contract in contracts] == [ + "leave_balance_eligibility" + ] + + +def test_unrelated_tool_does_not_receive_leave_contract(): + contracts = matching_query_contracts( + "직원 E9999의 연차 잔여를 알려줘", + "search_carrier_performance", + ) + + assert contracts == () + + +def test_incomplete_result_cannot_be_interpreted_as_zero_balance(): + contracts = matching_query_contracts( + "직원 E9999의 연차 사용 가능 여부를 알려줘", + "search_hr_data", + ) + evidence = { + "result": ( + 'DATA_RESULT: {"items":[{"EMPLOYEE_CODE":"E9999",' + '"REMAINING_DAYS":0}]}' + ) + } + + report = evidence_contract_report(contracts, evidence) + + assert report[0]["satisfied"] is False + assert "AVAILABLE_REMAINING_DAYS" in report[0]["missing_fields"] + assert "LEAVE_YEAR" in report[0]["missing_fields"] + + +def test_complete_database_row_satisfies_contract_without_fixture_values(): + contracts = matching_query_contracts( + "직원 E9999의 연차 신청 가능 여부를 알려줘", + "search_hr_data", + ) + evidence = { + "result": ( + 'DATA_RESULT\n{"items":[{"EMPLOYEE_CODE":"E9999",' + '"LEAVE_YEAR":2031,"ANNUAL_ENTITLEMENT":17,' + '"CARRYOVER_DAYS":2,"USED_DAYS":4,"PENDING_DAYS":1,' + '"AVAILABLE_REMAINING_DAYS":14}]}' + ) + } + + report = evidence_contract_report(contracts, evidence) + + assert report[0]["satisfied"] is True + assert report[0]["validated_record"]["LEAVE_YEAR"] == 2031 + assert report[0]["validated_record"]["AVAILABLE_REMAINING_DAYS"] == 14 + + +def test_conflicting_computed_value_fails_contract(): + contracts = matching_query_contracts( + "직원 E9999의 연차 신청 가능 여부를 알려줘", + "search_hr_data", + ) + evidence = { + "result": ( + 'DATA_RESULT\n{"items":[{"EMPLOYEE_CODE":"E9999",' + '"LEAVE_YEAR":2031,"ANNUAL_ENTITLEMENT":17,' + '"CARRYOVER_DAYS":2,"USED_DAYS":4,"PENDING_DAYS":1,' + '"AVAILABLE_REMAINING_DAYS":0}]}' + ) + } + + report = evidence_contract_report(contracts, evidence) + + assert report[0]["satisfied"] is False + assert report[0]["computed_field_checks"][0]["expected"] == "14" + assert report[0]["computed_field_checks"][0]["actual"] == "0" + + +def test_historical_period_rejects_yes_no_decision_and_missing_counts(): + contracts = matching_query_contracts( + "직원 E9999의 과거 연차 신청 가능 여부를 알려줘", + "search_hr_data", + ) + evidence = { + "result": ( + 'DATA_RESULT\n{"items":[{"EMPLOYEE_CODE":"E9999",' + '"LEAVE_YEAR":2031,"ANNUAL_ENTITLEMENT":17,' + '"CARRYOVER_DAYS":2,"USED_DAYS":4,"PENDING_DAYS":1,' + '"AVAILABLE_REMAINING_DAYS":14,' + '"REQUEST_PERIOD_LABEL":"HISTORICAL_REQUEST_PERIOD",' + '"CAN_APPLY":"YES","INCLUSIVE_CALENDAR_DAYS":11}]}' + ) + } + + report = evidence_contract_report(contracts, evidence) + + assert report[0]["satisfied"] is False + failed = { + check["check"] + for check in report[0]["temporal_contract_checks"] + if not check["satisfied"] + } + assert failed == { + "past_period_decision", + "no_past_period_yes_no_decision", + "date_range_counts", + } + + +def test_historical_period_contract_accepts_non_decision_status(): + contracts = matching_query_contracts( + "직원 E9999의 과거 연차 신청 가능 여부를 알려줘", + "search_hr_data", + ) + evidence = { + "result": ( + 'DATA_RESULT\n{"items":[{"EMPLOYEE_CODE":"E9999",' + '"LEAVE_YEAR":2031,"ANNUAL_ENTITLEMENT":17,' + '"CARRYOVER_DAYS":2,"USED_DAYS":4,"PENDING_DAYS":1,' + '"AVAILABLE_REMAINING_DAYS":14,' + '"REQUEST_PERIOD_LABEL":"HISTORICAL_REQUEST_PERIOD",' + '"APPLICATION_DECISION_STATUS":' + '"NOT_APPLICABLE_FOR_HISTORICAL_PERIOD",' + '"INCLUSIVE_CALENDAR_DAYS":11,' + '"MONDAY_TO_FRIDAY_DAYS":7}]}' + ) + } + + report = evidence_contract_report(contracts, evidence) + + assert report[0]["satisfied"] is True + + +def test_guidance_is_appended_from_json_contract(): + guided = append_query_contract_guidance( + "직원 E9999의 휴가 잔여를 조회해줘", + original_question="직원 E9999의 휴가 잔여를 조회해줘", + tool_name="search_hr_data", + ) + + assert '"id":"leave_balance_eligibility"' in guided + assert "AVAILABLE_REMAINING_DAYS" in guided + + +class QueryContractTest(unittest.TestCase): + test_leave_eligibility_question_selects_external_contract = staticmethod( + test_leave_eligibility_question_selects_external_contract + ) + test_unrelated_tool_does_not_receive_leave_contract = staticmethod( + test_unrelated_tool_does_not_receive_leave_contract + ) + test_incomplete_result_cannot_be_interpreted_as_zero_balance = staticmethod( + test_incomplete_result_cannot_be_interpreted_as_zero_balance + ) + test_complete_database_row_satisfies_contract_without_fixture_values = ( + staticmethod(test_complete_database_row_satisfies_contract_without_fixture_values) + ) + test_conflicting_computed_value_fails_contract = staticmethod( + test_conflicting_computed_value_fails_contract + ) + test_historical_period_rejects_yes_no_decision_and_missing_counts = ( + staticmethod(test_historical_period_rejects_yes_no_decision_and_missing_counts) + ) + test_historical_period_contract_accepts_non_decision_status = staticmethod( + test_historical_period_contract_accepts_non_decision_status + ) + test_guidance_is_appended_from_json_contract = staticmethod( + test_guidance_is_appended_from_json_contract + ) diff --git a/poc4_active_source_20260714/tests/test_scenarios.py b/ai-web-agent-console/tests/test_scenarios.py similarity index 86% rename from poc4_active_source_20260714/tests/test_scenarios.py rename to ai-web-agent-console/tests/test_scenarios.py index d819430..7c0b3e6 100644 --- a/poc4_active_source_20260714/tests/test_scenarios.py +++ b/ai-web-agent-console/tests/test_scenarios.py @@ -6,27 +6,37 @@ import tempfile import unittest from unittest.mock import patch -from src.poc4.scenarios import ScenarioConfigError, load_demo_scenarios -from src.agent_console.profile import load_app_profile -from src.mcp_tool_router import McpTool, build_mcp_tool_arguments -from src.mcp_result import ( +from ai_web_agent_console.scenarios import ScenarioConfigError, load_demo_scenarios +from ai_web_agent_console.profile import load_app_profile +from ai_web_agent_console.mcp_tool_router import McpTool, build_mcp_tool_arguments +from ai_web_agent_console.mcp_result import ( has_actionable_text_result, status_result_evidence, status_result_summary, ) +from ai_web_agent_console.model_registry import load_model_registry -def _load_poc4_query_helpers(): +def _load_console_query_helpers(): """Load the Streamlit entrypoint only when its optional runtime is installed.""" try: - from apps.poc4.mcp_discovery_ui import _prepare_hmm_hr_tool_query + from app import _prepare_hmm_hr_tool_query except ModuleNotFoundError: return None return _prepare_hmm_hr_tool_query class DemoScenarioConfigTest(unittest.TestCase): + def test_model_registry_uses_console_names(self) -> None: + registry = load_model_registry() + + self.assertEqual( + registry.registry_name, + "AI_WEB_AGENT_CONSOLE_MODEL_PROFILES", + ) + self.assertTrue(registry.default_profile.default_for_console) + def test_profile_environment_overrides_json_defaults(self) -> None: path = Path(__file__).parents[1] / "config" / "app_profile.json" with patch.dict( @@ -54,7 +64,7 @@ class DemoScenarioConfigTest(unittest.TestCase): self.assertEqual(profile.short_name, "HMM") def test_common_theme_covers_lists_expanders_and_secondary_buttons(self) -> None: - path = Path(__file__).parents[1] / "src" / "agent_console" / "presentation.py" + path = Path(__file__).parents[1] / "ai_web_agent_console" / "presentation.py" source = path.read_text(encoding="utf-8") self.assertIn('[data-testid="stAppViewContainer"] li', source) @@ -66,17 +76,20 @@ class DemoScenarioConfigTest(unittest.TestCase): def test_audit_tab_uses_hmm_access_audit_loaders(self) -> None: root = Path(__file__).parents[1] - entrypoint = (root / "apps" / "poc4" / "mcp_discovery_ui.py").read_text( + entrypoint = (root / "app.py").read_text( encoding="utf-8" ) - renderer = (root / "src" / "agent_console" / "audit.py").read_text( + renderer = (root / "ai_web_agent_console" / "audit.py").read_text( encoding="utf-8" ) self.assertIn("FROM ADMIN.HMM_ACCESS_AUDIT", entrypoint) self.assertIn("_load_hmm_audit_inventory", entrypoint) self.assertIn("(protocol=tcps)(port=1521)", entrypoint) - self.assertIn("POC4_AUDIT_WALLET_PASSWORD", entrypoint) + self.assertIn( + "AI_WEB_AGENT_CONSOLE_AUDIT_WALLET_PASSWORD", + entrypoint, + ) self.assertIn("HMM 접근 관리", renderer) self.assertNotIn('AUDIT_SCHEMA = "POC_2"', entrypoint) @@ -197,9 +210,9 @@ class DemoScenarioConfigTest(unittest.TestCase): has_actionable_text_result({"status": "success", "result": "No data found"}) ) - @unittest.skipIf(_load_poc4_query_helpers() is None, "Streamlit runtime is optional") + @unittest.skipIf(_load_console_query_helpers() is None, "Streamlit runtime is optional") def test_policy_query_does_not_include_demo_user_context(self) -> None: - prepare = _load_poc4_query_helpers() + prepare = _load_console_query_helpers() assert prepare is not None tool = McpTool( name="search_hr_policy", diff --git a/sql/adb/00_cleanup.sql b/database/adb/00_cleanup.sql similarity index 100% rename from sql/adb/00_cleanup.sql rename to database/adb/00_cleanup.sql diff --git a/sql/adb/01_dblinks.sql b/database/adb/01_dblinks.sql similarity index 100% rename from sql/adb/01_dblinks.sql rename to database/adb/01_dblinks.sql diff --git a/sql/adb/02_perm_tables.sql b/database/adb/02_perm_tables.sql similarity index 100% rename from sql/adb/02_perm_tables.sql rename to database/adb/02_perm_tables.sql diff --git a/sql/adb/03_seed.sql b/database/adb/03_seed.sql similarity index 98% rename from sql/adb/03_seed.sql rename to database/adb/03_seed.sql index 9223f3e..8205191 100644 --- a/sql/adb/03_seed.sql +++ b/database/adb/03_seed.sql @@ -80,7 +80,7 @@ COMMIT; -- COMMIT; -- -- The policy function vpd_region_filter handles CSV → IN-list --- conversion automatically. See sql/adb/06_policy.sql. +-- conversion automatically. See database/adb/06_policy.sql. -- ------------------------------------------------------------ PROMPT === Seed complete === diff --git a/sql/adb/04_secure_ctx.sql b/database/adb/04_secure_ctx.sql similarity index 100% rename from sql/adb/04_secure_ctx.sql rename to database/adb/04_secure_ctx.sql diff --git a/sql/adb/05_views.sql b/database/adb/05_views.sql similarity index 100% rename from sql/adb/05_views.sql rename to database/adb/05_views.sql diff --git a/sql/adb/06_policy.sql b/database/adb/06_policy.sql similarity index 100% rename from sql/adb/06_policy.sql rename to database/adb/06_policy.sql diff --git a/sql/adb/06a_redaction.sql b/database/adb/06a_redaction.sql similarity index 100% rename from sql/adb/06a_redaction.sql rename to database/adb/06a_redaction.sql diff --git a/sql/adb/07_end_users.sql b/database/adb/07_end_users.sql similarity index 100% rename from sql/adb/07_end_users.sql rename to database/adb/07_end_users.sql diff --git a/sql/adb/08_tests_user_my.sql b/database/adb/08_tests_user_my.sql similarity index 100% rename from sql/adb/08_tests_user_my.sql rename to database/adb/08_tests_user_my.sql diff --git a/sql/adb/09_tests_user_pg.sql b/database/adb/09_tests_user_pg.sql similarity index 100% rename from sql/adb/09_tests_user_pg.sql rename to database/adb/09_tests_user_pg.sql diff --git a/sql/adb/10_tests_user_both.sql b/database/adb/10_tests_user_both.sql similarity index 100% rename from sql/adb/10_tests_user_both.sql rename to database/adb/10_tests_user_both.sql diff --git a/sql/adb/11_tests_user_none.sql b/database/adb/11_tests_user_none.sql similarity index 100% rename from sql/adb/11_tests_user_none.sql rename to database/adb/11_tests_user_none.sql diff --git a/sql/adb/12_tests_admin_audit.sql b/database/adb/12_tests_admin_audit.sql similarity index 100% rename from sql/adb/12_tests_admin_audit.sql rename to database/adb/12_tests_admin_audit.sql diff --git a/sql/adb/13_dds_variant.sql b/database/adb/13_dds_variant.sql similarity index 100% rename from sql/adb/13_dds_variant.sql rename to database/adb/13_dds_variant.sql diff --git a/sql/adb/14_tests_dds_user.sql b/database/adb/14_tests_dds_user.sql similarity index 100% rename from sql/adb/14_tests_dds_user.sql rename to database/adb/14_tests_dds_user.sql diff --git a/sql/adb/15_dds_cleanup.sql b/database/adb/15_dds_cleanup.sql similarity index 100% rename from sql/adb/15_dds_cleanup.sql rename to database/adb/15_dds_cleanup.sql diff --git a/sql/adb/16_agent_ords_security_local_cleanup.sql b/database/adb/16_agent_ords_security_local_cleanup.sql similarity index 100% rename from sql/adb/16_agent_ords_security_local_cleanup.sql rename to database/adb/16_agent_ords_security_local_cleanup.sql diff --git a/sql/adb/17_agent_ords_security_local_vpd_setup.sql b/database/adb/17_agent_ords_security_local_vpd_setup.sql similarity index 100% rename from sql/adb/17_agent_ords_security_local_vpd_setup.sql rename to database/adb/17_agent_ords_security_local_vpd_setup.sql diff --git a/sql/adb/18_agent_ords_security_local_vpd_test.sql b/database/adb/18_agent_ords_security_local_vpd_test.sql similarity index 100% rename from sql/adb/18_agent_ords_security_local_vpd_test.sql rename to database/adb/18_agent_ords_security_local_vpd_test.sql diff --git a/sql/adb/19_agent_ords_security_local_dds_setup.sql b/database/adb/19_agent_ords_security_local_dds_setup.sql similarity index 100% rename from sql/adb/19_agent_ords_security_local_dds_setup.sql rename to database/adb/19_agent_ords_security_local_dds_setup.sql diff --git a/sql/adb/20_agent_ords_security_local_dds_test.sql b/database/adb/20_agent_ords_security_local_dds_test.sql similarity index 100% rename from sql/adb/20_agent_ords_security_local_dds_test.sql rename to database/adb/20_agent_ords_security_local_dds_test.sql diff --git a/sql/adb/21_agent_ords_security_ords_enable_schema.sql b/database/adb/21_agent_ords_security_ords_enable_schema.sql similarity index 100% rename from sql/adb/21_agent_ords_security_ords_enable_schema.sql rename to database/adb/21_agent_ords_security_ords_enable_schema.sql diff --git a/sql/adb/22_agent_ords_security_ords_handler_setup.sql b/database/adb/22_agent_ords_security_ords_handler_setup.sql similarity index 100% rename from sql/adb/22_agent_ords_security_ords_handler_setup.sql rename to database/adb/22_agent_ords_security_ords_handler_setup.sql diff --git a/sql/adb/23_agent_ords_security_ords_handler_test.sql b/database/adb/23_agent_ords_security_ords_handler_test.sql similarity index 100% rename from sql/adb/23_agent_ords_security_ords_handler_test.sql rename to database/adb/23_agent_ords_security_ords_handler_test.sql diff --git a/sql/adb/24_agent_ords_security_inventory.sql b/database/adb/24_agent_ords_security_inventory.sql similarity index 100% rename from sql/adb/24_agent_ords_security_inventory.sql rename to database/adb/24_agent_ords_security_inventory.sql diff --git a/sql/adb/25_agent_ords_security_backoffice_support.sql b/database/adb/25_agent_ords_security_backoffice_support.sql similarity index 100% rename from sql/adb/25_agent_ords_security_backoffice_support.sql rename to database/adb/25_agent_ords_security_backoffice_support.sql diff --git a/sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql b/database/adb/26_agent_ords_security_dynamic_vpd_filter.sql similarity index 100% rename from sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql rename to database/adb/26_agent_ords_security_dynamic_vpd_filter.sql diff --git a/sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql b/database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql similarity index 99% rename from sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql rename to database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql index 8b6b1e2..649c7e5 100644 --- a/sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql +++ b/database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql @@ -3,7 +3,7 @@ -- Unit-style checks for cb_agent_doc_vpd_filter. -- -- Run after: --- @sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql +-- @database/adb/26_agent_ords_security_dynamic_vpd_filter.sql -- ============================================================ WHENEVER SQLERROR EXIT SQL.SQLCODE SET ECHO OFF diff --git a/sql/adb/28_agent_ords_vector_tag_vpd_setup.sql b/database/adb/28_agent_ords_vector_tag_vpd_setup.sql similarity index 100% rename from sql/adb/28_agent_ords_vector_tag_vpd_setup.sql rename to database/adb/28_agent_ords_vector_tag_vpd_setup.sql diff --git a/sql/adb/29_agent_ords_vector_search_ords.sql b/database/adb/29_agent_ords_vector_search_ords.sql similarity index 100% rename from sql/adb/29_agent_ords_vector_search_ords.sql rename to database/adb/29_agent_ords_vector_search_ords.sql diff --git a/sql/adb/30_agent_ords_vector_tag_vpd_test.sql b/database/adb/30_agent_ords_vector_tag_vpd_test.sql similarity index 100% rename from sql/adb/30_agent_ords_vector_tag_vpd_test.sql rename to database/adb/30_agent_ords_vector_tag_vpd_test.sql diff --git a/sql/adb/31_agent_ords_backoffice_ux_metadata.sql b/database/adb/31_agent_ords_backoffice_ux_metadata.sql similarity index 100% rename from sql/adb/31_agent_ords_backoffice_ux_metadata.sql rename to database/adb/31_agent_ords_backoffice_ux_metadata.sql diff --git a/sql/adb/31_dds_standalone_demo_setup.sql b/database/adb/31_dds_standalone_demo_setup.sql similarity index 100% rename from sql/adb/31_dds_standalone_demo_setup.sql rename to database/adb/31_dds_standalone_demo_setup.sql diff --git a/sql/adb/32_dds_vector_tag_setup.sql b/database/adb/32_dds_vector_tag_setup.sql similarity index 100% rename from sql/adb/32_dds_vector_tag_setup.sql rename to database/adb/32_dds_vector_tag_setup.sql diff --git a/sql/adb/33_agent_ords_sql_trace_grant.sql b/database/adb/33_agent_ords_sql_trace_grant.sql similarity index 100% rename from sql/adb/33_agent_ords_sql_trace_grant.sql rename to database/adb/33_agent_ords_sql_trace_grant.sql diff --git a/sql/adb/34_agent_ords_execution_evidence_grant.sql b/database/adb/34_agent_ords_execution_evidence_grant.sql similarity index 100% rename from sql/adb/34_agent_ords_execution_evidence_grant.sql rename to database/adb/34_agent_ords_execution_evidence_grant.sql diff --git a/sql/adb/34_dds_token_data_grant_common_auth.sql b/database/adb/34_dds_token_data_grant_common_auth.sql similarity index 100% rename from sql/adb/34_dds_token_data_grant_common_auth.sql rename to database/adb/34_dds_token_data_grant_common_auth.sql diff --git a/sql/adb/35_dds_token_data_grant_cleanup.sql b/database/adb/35_dds_token_data_grant_cleanup.sql similarity index 100% rename from sql/adb/35_dds_token_data_grant_cleanup.sql rename to database/adb/35_dds_token_data_grant_cleanup.sql diff --git a/sql/adb/36_dds_sales_knowledge_scenario.sql b/database/adb/36_dds_sales_knowledge_scenario.sql similarity index 100% rename from sql/adb/36_dds_sales_knowledge_scenario.sql rename to database/adb/36_dds_sales_knowledge_scenario.sql diff --git a/sql/adb/37_dds_sales_knowledge_scenario_cleanup.sql b/database/adb/37_dds_sales_knowledge_scenario_cleanup.sql similarity index 100% rename from sql/adb/37_dds_sales_knowledge_scenario_cleanup.sql rename to database/adb/37_dds_sales_knowledge_scenario_cleanup.sql diff --git a/sql/adb/38_agent_ords_vector_all_permission_normalization.sql b/database/adb/38_agent_ords_vector_all_permission_normalization.sql similarity index 100% rename from sql/adb/38_agent_ords_vector_all_permission_normalization.sql rename to database/adb/38_agent_ords_vector_all_permission_normalization.sql diff --git a/sql/adb/39_agent_ords_default_user_display_name.sql b/database/adb/39_agent_ords_default_user_display_name.sql similarity index 100% rename from sql/adb/39_agent_ords_default_user_display_name.sql rename to database/adb/39_agent_ords_default_user_display_name.sql diff --git a/sql/adb/40_dds_protection_evidence.sql b/database/adb/40_dds_protection_evidence.sql similarity index 100% rename from sql/adb/40_dds_protection_evidence.sql rename to database/adb/40_dds_protection_evidence.sql diff --git a/sql/adb/41_dds_row_column_fixture.sql b/database/adb/41_dds_row_column_fixture.sql similarity index 100% rename from sql/adb/41_dds_row_column_fixture.sql rename to database/adb/41_dds_row_column_fixture.sql diff --git a/sql/adb/42_agent_ords_fga_execution_audit.sql b/database/adb/42_agent_ords_fga_execution_audit.sql similarity index 100% rename from sql/adb/42_agent_ords_fga_execution_audit.sql rename to database/adb/42_agent_ords_fga_execution_audit.sql diff --git a/sql/adb/42_dds_fga_execution_evidence.sql b/database/adb/42_dds_fga_execution_evidence.sql similarity index 100% rename from sql/adb/42_dds_fga_execution_evidence.sql rename to database/adb/42_dds_fga_execution_evidence.sql diff --git a/sql/adb/43_agent_ords_probe_id_handler_patch.sql b/database/adb/43_agent_ords_probe_id_handler_patch.sql similarity index 100% rename from sql/adb/43_agent_ords_probe_id_handler_patch.sql rename to database/adb/43_agent_ords_probe_id_handler_patch.sql diff --git a/sql/adb/44_dds_mcp_local_end_user_setup.sql b/database/adb/44_dds_mcp_local_end_user_setup.sql similarity index 100% rename from sql/adb/44_dds_mcp_local_end_user_setup.sql rename to database/adb/44_dds_mcp_local_end_user_setup.sql diff --git a/sql/adb/45_dds_mcp_local_end_user_test.sql b/database/adb/45_dds_mcp_local_end_user_test.sql similarity index 100% rename from sql/adb/45_dds_mcp_local_end_user_test.sql rename to database/adb/45_dds_mcp_local_end_user_test.sql diff --git a/sql/adb/46_kb_stakeholder_token_permission_example.sql b/database/adb/46_kb_stakeholder_token_permission_example.sql similarity index 100% rename from sql/adb/46_kb_stakeholder_token_permission_example.sql rename to database/adb/46_kb_stakeholder_token_permission_example.sql diff --git a/sql/adb/47_kb_stakeholder_permission_or_branches.sql b/database/adb/47_kb_stakeholder_permission_or_branches.sql similarity index 100% rename from sql/adb/47_kb_stakeholder_permission_or_branches.sql rename to database/adb/47_kb_stakeholder_permission_or_branches.sql diff --git a/sql/adb/48_kb_permission_condition_codes.sql b/database/adb/48_kb_permission_condition_codes.sql similarity index 100% rename from sql/adb/48_kb_permission_condition_codes.sql rename to database/adb/48_kb_permission_condition_codes.sql diff --git a/sql/adb/49_permission_static_sql_condition.sql b/database/adb/49_permission_static_sql_condition.sql similarity index 100% rename from sql/adb/49_permission_static_sql_condition.sql rename to database/adb/49_permission_static_sql_condition.sql diff --git a/sql/adb/51_kb_vpd_admin_token.sql b/database/adb/51_kb_vpd_admin_token.sql similarity index 100% rename from sql/adb/51_kb_vpd_admin_token.sql rename to database/adb/51_kb_vpd_admin_token.sql diff --git a/sql/adb/52_cleanup_to_kb_vpd_poc.sql b/database/adb/52_cleanup_to_kb_vpd_poc.sql similarity index 100% rename from sql/adb/52_cleanup_to_kb_vpd_poc.sql rename to database/adb/52_cleanup_to_kb_vpd_poc.sql diff --git a/sql/adb/53_drop_legacy_poc_objects.sql b/database/adb/53_drop_legacy_poc_objects.sql similarity index 100% rename from sql/adb/53_drop_legacy_poc_objects.sql rename to database/adb/53_drop_legacy_poc_objects.sql diff --git a/sql/adb/54_drop_legacy_dds_ords_examples.sql b/database/adb/54_drop_legacy_dds_ords_examples.sql similarity index 100% rename from sql/adb/54_drop_legacy_dds_ords_examples.sql rename to database/adb/54_drop_legacy_dds_ords_examples.sql diff --git a/sql/adb/55_reapply_kb_vpd_after_table_reload.sql b/database/adb/55_reapply_kb_vpd_after_table_reload.sql similarity index 100% rename from sql/adb/55_reapply_kb_vpd_after_table_reload.sql rename to database/adb/55_reapply_kb_vpd_after_table_reload.sql diff --git a/sql/adb/56_kb_select_ai_router_team.sql b/database/adb/56_kb_select_ai_router_team.sql similarity index 100% rename from sql/adb/56_kb_select_ai_router_team.sql rename to database/adb/56_kb_select_ai_router_team.sql diff --git a/sql/adb/57_kb_select_ai_router_team_test.sql b/database/adb/57_kb_select_ai_router_team_test.sql similarity index 100% rename from sql/adb/57_kb_select_ai_router_team_test.sql rename to database/adb/57_kb_select_ai_router_team_test.sql diff --git a/sql/adb/58_kb_select_ai_router_api.sql b/database/adb/58_kb_select_ai_router_api.sql similarity index 100% rename from sql/adb/58_kb_select_ai_router_api.sql rename to database/adb/58_kb_select_ai_router_api.sql diff --git a/sql/adb/59_kb_select_ai_router_ords.sql b/database/adb/59_kb_select_ai_router_ords.sql similarity index 100% rename from sql/adb/59_kb_select_ai_router_ords.sql rename to database/adb/59_kb_select_ai_router_ords.sql diff --git a/sql/adb/60_kb_vpd_admin_full_access_token.sql b/database/adb/60_kb_vpd_admin_full_access_token.sql similarity index 100% rename from sql/adb/60_kb_vpd_admin_full_access_token.sql rename to database/adb/60_kb_vpd_admin_full_access_token.sql diff --git a/sql/adb/62_kb_aso_masking_backoffice_metadata.sql b/database/adb/62_kb_aso_masking_backoffice_metadata.sql similarity index 100% rename from sql/adb/62_kb_aso_masking_backoffice_metadata.sql rename to database/adb/62_kb_aso_masking_backoffice_metadata.sql diff --git a/sql/adb/63_kb_aso_masking_rule_runtime.sql b/database/adb/63_kb_aso_masking_rule_runtime.sql similarity index 100% rename from sql/adb/63_kb_aso_masking_rule_runtime.sql rename to database/adb/63_kb_aso_masking_rule_runtime.sql diff --git a/sql/adb/64_kb_aso_masking_default_column_rules.sql b/database/adb/64_kb_aso_masking_default_column_rules.sql similarity index 100% rename from sql/adb/64_kb_aso_masking_default_column_rules.sql rename to database/adb/64_kb_aso_masking_default_column_rules.sql diff --git a/sql/adb/65_kb_select_ai_vpd_query_api.sql b/database/adb/65_kb_select_ai_vpd_query_api.sql similarity index 100% rename from sql/adb/65_kb_select_ai_vpd_query_api.sql rename to database/adb/65_kb_select_ai_vpd_query_api.sql diff --git a/sql/adb/66_kb_select_ai_vpd_query_ords.sql b/database/adb/66_kb_select_ai_vpd_query_ords.sql similarity index 100% rename from sql/adb/66_kb_select_ai_vpd_query_ords.sql rename to database/adb/66_kb_select_ai_vpd_query_ords.sql diff --git a/sql/adb/67_drop_legacy_kb_contracts_premium_vpd_cls_policy.sql b/database/adb/67_drop_legacy_kb_contracts_premium_vpd_cls_policy.sql similarity index 100% rename from sql/adb/67_drop_legacy_kb_contracts_premium_vpd_cls_policy.sql rename to database/adb/67_drop_legacy_kb_contracts_premium_vpd_cls_policy.sql diff --git a/sql/adb/70_sg_tool_user.sql b/database/adb/70_sg_tool_user.sql similarity index 100% rename from sql/adb/70_sg_tool_user.sql rename to database/adb/70_sg_tool_user.sql diff --git a/sql/adb/71_sg_identity_administration.sql b/database/adb/71_sg_identity_administration.sql similarity index 100% rename from sql/adb/71_sg_identity_administration.sql rename to database/adb/71_sg_identity_administration.sql diff --git a/sql/adb/72_hmm_leave_team_vpd.sql b/database/adb/72_hmm_leave_team_vpd.sql similarity index 100% rename from sql/adb/72_hmm_leave_team_vpd.sql rename to database/adb/72_hmm_leave_team_vpd.sql diff --git a/sql/adb/73_hmm_mcp_vpd_runtime.sql b/database/adb/73_hmm_mcp_vpd_runtime.sql similarity index 100% rename from sql/adb/73_hmm_mcp_vpd_runtime.sql rename to database/adb/73_hmm_mcp_vpd_runtime.sql diff --git a/sql/adb/73_hmm_rds_pg_00_precheck.sql b/database/adb/73_hmm_rds_pg_00_precheck.sql similarity index 100% rename from sql/adb/73_hmm_rds_pg_00_precheck.sql rename to database/adb/73_hmm_rds_pg_00_precheck.sql diff --git a/sql/adb/74_hmm_rds_pg_01_credential.sql b/database/adb/74_hmm_rds_pg_01_credential.sql similarity index 100% rename from sql/adb/74_hmm_rds_pg_01_credential.sql rename to database/adb/74_hmm_rds_pg_01_credential.sql diff --git a/sql/adb/75_hmm_rds_pg_02_acl.sql b/database/adb/75_hmm_rds_pg_02_acl.sql similarity index 100% rename from sql/adb/75_hmm_rds_pg_02_acl.sql rename to database/adb/75_hmm_rds_pg_02_acl.sql diff --git a/sql/adb/76_hmm_rds_pg_03_dblink.sql b/database/adb/76_hmm_rds_pg_03_dblink.sql similarity index 100% rename from sql/adb/76_hmm_rds_pg_03_dblink.sql rename to database/adb/76_hmm_rds_pg_03_dblink.sql diff --git a/sql/adb/77_hmm_rds_pg_04_remote_query.sql b/database/adb/77_hmm_rds_pg_04_remote_query.sql similarity index 100% rename from sql/adb/77_hmm_rds_pg_04_remote_query.sql rename to database/adb/77_hmm_rds_pg_04_remote_query.sql diff --git a/sql/adb/78_hmm_rds_pg_05_views.sql b/database/adb/78_hmm_rds_pg_05_views.sql similarity index 100% rename from sql/adb/78_hmm_rds_pg_05_views.sql rename to database/adb/78_hmm_rds_pg_05_views.sql diff --git a/sql/adb/79_hmm_rds_pg_06_verify.sql b/database/adb/79_hmm_rds_pg_06_verify.sql similarity index 100% rename from sql/adb/79_hmm_rds_pg_06_verify.sql rename to database/adb/79_hmm_rds_pg_06_verify.sql diff --git a/sql/adb/80_hmm_rds_pg_99_cleanup.sql b/database/adb/80_hmm_rds_pg_99_cleanup.sql similarity index 100% rename from sql/adb/80_hmm_rds_pg_99_cleanup.sql rename to database/adb/80_hmm_rds_pg_99_cleanup.sql diff --git a/sql/adb/81_hmm_carrier_access_groups.sql b/database/adb/81_hmm_carrier_access_groups.sql similarity index 100% rename from sql/adb/81_hmm_carrier_access_groups.sql rename to database/adb/81_hmm_carrier_access_groups.sql diff --git a/sql/adb/82_hmm_federation_relationship_comments.sql b/database/adb/82_hmm_federation_relationship_comments.sql similarity index 100% rename from sql/adb/82_hmm_federation_relationship_comments.sql rename to database/adb/82_hmm_federation_relationship_comments.sql diff --git a/sql/source/mysql_setup.sql b/database/source/mysql_setup.sql similarity index 96% rename from sql/source/mysql_setup.sql rename to database/source/mysql_setup.sql index 82530e6..5eb8e78 100644 --- a/sql/source/mysql_setup.sql +++ b/database/source/mysql_setup.sql @@ -1,5 +1,5 @@ -- ============================================================ --- sql/source/mysql_setup.sql +-- database/source/mysql_setup.sql -- Run on the REMOTE MySQL instance (mysql CLI). -- -- Creates the customers table in the `ecommerce_poc` schema with @@ -12,7 +12,7 @@ -- -- 호출 예시 (run.sh source 가 자동 실행): -- mysql -h $MY_HOST -P $MY_PORT -u $MY_USER -p"$MY_PASSWORD" \ --- $MY_DB < sql/source/mysql_setup.sql +-- $MY_DB < database/source/mysql_setup.sql -- ============================================================ SELECT '=== Creating ecommerce_poc.customers (idempotent) ===' AS status; diff --git a/sql/source/postgres_hmm_carrier_performance.sql b/database/source/postgres_hmm_carrier_performance.sql similarity index 98% rename from sql/source/postgres_hmm_carrier_performance.sql rename to database/source/postgres_hmm_carrier_performance.sql index 509895b..db766f6 100644 --- a/sql/source/postgres_hmm_carrier_performance.sql +++ b/database/source/postgres_hmm_carrier_performance.sql @@ -13,7 +13,7 @@ -- PGPASSWORD="$PG_PASSWORD" psql \ -- "host=$PG_HOST port=5432 dbname=postgres user=$PG_USER \ -- sslmode=verify-full sslrootcert=$PG_SSL_ROOT_CERT" \ --- -X -f sql/source/postgres_hmm_carrier_performance.sql +-- -X -f database/source/postgres_hmm_carrier_performance.sql -- ============================================================ \set ON_ERROR_STOP on @@ -297,4 +297,4 @@ ALTER DEFAULT PRIVILEGES IN SCHEMA hmm_demo COMMIT; \echo === HMM carrier performance demo: complete === -\echo Next: run sql/source/postgres_hmm_carrier_performance_verify.sql +\echo Next: run database/source/postgres_hmm_carrier_performance_verify.sql diff --git a/sql/source/postgres_hmm_carrier_performance_verify.sql b/database/source/postgres_hmm_carrier_performance_verify.sql similarity index 100% rename from sql/source/postgres_hmm_carrier_performance_verify.sql rename to database/source/postgres_hmm_carrier_performance_verify.sql diff --git a/sql/source/postgres_setup.sql b/database/source/postgres_setup.sql similarity index 96% rename from sql/source/postgres_setup.sql rename to database/source/postgres_setup.sql index 332b802..41cd911 100644 --- a/sql/source/postgres_setup.sql +++ b/database/source/postgres_setup.sql @@ -1,5 +1,5 @@ -- ============================================================ --- sql/source/postgres_setup.sql +-- database/source/postgres_setup.sql -- Run on the REMOTE PostgreSQL instance (psql). -- -- Creates the customers table in the `public` schema with sample @@ -10,7 +10,7 @@ -- -- 호출 예시 (run.sh source 가 자동 실행): -- PGPASSWORD=$PG_PASSWORD psql -h $PG_HOST -U $PG_USER -d $PG_DB \ --- -f sql/source/postgres_setup.sql +-- -f database/source/postgres_setup.sql -- ============================================================ \echo === Creating public.customers (idempotent) === diff --git a/dds-backoffice/README.md b/dds-backoffice/README.md index cd9d665..3c62f4c 100644 --- a/dds-backoffice/README.md +++ b/dds-backoffice/README.md @@ -56,10 +56,10 @@ ORDS Handler가 Bearer 값을 문자열로 바꾸는 것만으로 DDS Context가 먼저 DDS 데모 전용 로컬 데이터셋과 권한 객체를 적용합니다. 이 스크립트는 VPD VIEW나 외부 RDS DB Link를 사용하지 않습니다. ```bash -sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/31_dds_standalone_demo_setup.sql -sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/32_dds_vector_tag_setup.sql +sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @database/adb/31_dds_standalone_demo_setup.sql +sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @database/adb/32_dds_vector_tag_setup.sql bash scripts/setup-dds-token-data-grant.sh -sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/36_dds_sales_knowledge_scenario.sql +sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @database/adb/36_dds_sales_knowledge_scenario.sql ``` `32_dds_vector_tag_setup.sql`은 공통 청크·태그 저장소를 읽는 DDS 전용 VIEW를 만들고, 동일한 `CB_PERMISSION`/`CB_PERMISSION_RULE`에 역할별 TAG 규칙을 등록합니다. `SPRING_BOOT`, `ORDS`, `ORACLE_VPD`, `MCP`처럼 한 역할에 여러 TAG가 있으면 `/dds-provision`이 OR 조건으로 합쳐 DDS DATA GRANT를 다시 만듭니다. 벡터 검색에 필요한 `EMBEDDING`은 DDS 엔진이 거리 계산에 사용하므로 Grant에서 제외하지 않고, 검색 응답에서는 애플리케이션이 반환하지 않습니다. 그 외 민감 컬럼은 애플리케이션 권한의 원문 허용 목록에 없으면 `ALL COLUMNS EXCEPT`로 제외됩니다. 검색 화면에서는 같은 문서를 청킹·임베딩한 뒤 선택한 END USER로 직접 조회하므로, DDS Grant가 없는 주체는 보호 VIEW 자체를 볼 수 없습니다. @@ -68,7 +68,7 @@ sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/36_dds_sales_knowledge_scena `36_dds_sales_knowledge_scenario.sql`은 `agent_sales`와 `SALES_KNOWLEDGE_ROLE`을 만들고 `TECH_TAG=SALES`인 세일즈 청크(28004)를 추가합니다. 짧은 데모 토큰 `dds_sales_demo_token`을 사용하면 결과는 28004만 남아야 합니다. 운영에서는 이 토큰 대신 Bearer 관리 화면에서 발급한 임시 토큰을 사용합니다. -토큰 경로를 제거할 때는 사용 중인 애플리케이션이 없는지 확인한 뒤 `sql/adb/37_dds_sales_knowledge_scenario_cleanup.sql`과 `sql/adb/35_dds_token_data_grant_cleanup.sql`을 별도로 승인해 실행합니다. +토큰 경로를 제거할 때는 사용 중인 애플리케이션이 없는지 확인한 뒤 `database/adb/37_dds_sales_knowledge_scenario_cleanup.sql`과 `database/adb/35_dds_token_data_grant_cleanup.sql`을 별도로 승인해 실행합니다. 그 다음 DDS 인스턴스를 실행합니다. diff --git a/poc4_active_source_20260714/infra/nginx/hmm-portal-auth.locations.conf b/deploy/ai-web-agent-console/nginx/hmm-portal-auth.locations.conf similarity index 100% rename from poc4_active_source_20260714/infra/nginx/hmm-portal-auth.locations.conf rename to deploy/ai-web-agent-console/nginx/hmm-portal-auth.locations.conf diff --git a/poc4_active_source_20260714/deploy/systemd/poc4-streamlit-audit.conf b/deploy/ai-web-agent-console/systemd/ai-web-agent-console-audit.conf similarity index 100% rename from poc4_active_source_20260714/deploy/systemd/poc4-streamlit-audit.conf rename to deploy/ai-web-agent-console/systemd/ai-web-agent-console-audit.conf diff --git a/poc4_active_source_20260714/infra/systemd/hmm-portal-auth.service b/deploy/ai-web-agent-console/systemd/hmm-portal-auth.service similarity index 88% rename from poc4_active_source_20260714/infra/systemd/hmm-portal-auth.service rename to deploy/ai-web-agent-console/systemd/hmm-portal-auth.service index 80899ee..bc9e67f 100644 --- a/poc4_active_source_20260714/infra/systemd/hmm-portal-auth.service +++ b/deploy/ai-web-agent-console/systemd/hmm-portal-auth.service @@ -10,7 +10,7 @@ Group=opc WorkingDirectory=/opt/hmm-poc4 Environment=PYTHONUNBUFFERED=1 EnvironmentFile=/opt/hmm-poc4/.env -ExecStart=/opt/hmm-poc4/.venv/bin/python -m src.agent_console.auth_gateway +ExecStart=/opt/hmm-poc4/.venv/bin/python -m ai_web_agent_console.auth_gateway Restart=on-failure RestartSec=3 NoNewPrivileges=true diff --git a/deploy/hmm-backoffice.env.example b/deploy/vpd-backoffice/backoffice.env.example similarity index 100% rename from deploy/hmm-backoffice.env.example rename to deploy/vpd-backoffice/backoffice.env.example diff --git a/deploy/caddy/Caddyfile.template b/deploy/vpd-backoffice/caddy/Caddyfile.template similarity index 100% rename from deploy/caddy/Caddyfile.template rename to deploy/vpd-backoffice/caddy/Caddyfile.template diff --git a/deploy/caddy/install-caddy-config.sh b/deploy/vpd-backoffice/caddy/install-caddy-config.sh similarity index 100% rename from deploy/caddy/install-caddy-config.sh rename to deploy/vpd-backoffice/caddy/install-caddy-config.sh diff --git a/deploy/systemd/vpd-backoffice-structured-data.conf b/deploy/vpd-backoffice/vpd-backoffice-structured-data.conf similarity index 100% rename from deploy/systemd/vpd-backoffice-structured-data.conf rename to deploy/vpd-backoffice/vpd-backoffice-structured-data.conf diff --git a/docs/03-detailed-guide.md b/docs/03-detailed-guide.md index 5a0335f..806aecd 100644 --- a/docs/03-detailed-guide.md +++ b/docs/03-detailed-guide.md @@ -8,7 +8,7 @@ > 단위 매트릭스** 입니다 (README 참고). 본 상세 가이드는 그 위에 얹을 수 있는 **행 > 단위 region 필터링** 변형(`KR_ANALYSTS → APAC`, `GLOBAL_ADMINS → '*'`) 을 예시로 > 사용합니다 — VPD 메커니즘 자체는 동일하므로 개념 이해에는 차이가 없습니다. -> region 필터를 실제로 켜려면 `sql/adb/03_seed.sql` 하단의 주석을 해제하세요. +> region 필터를 실제로 켜려면 `database/adb/03_seed.sql` 하단의 주석을 해제하세요. --- @@ -543,7 +543,7 @@ SQL> SELECT COUNT(*) FROM admin.v_customers_pg; -- 0 SQL> SELECT COUNT(*) FROM admin.v_customers_my; -- 0 # region 필터 변형을 켰을 때 — vpduser_both 에게 APAC 만 허용한 경우 -# (sql/adb/03_seed.sql 하단 UPDATE 주석 해제 후) +# (database/adb/03_seed.sql 하단 UPDATE 주석 해제 후) sqlplus "vpduser_both/\"${VPDUSER_BOTH_PASSWORD}\"@$ADB_TNS" SQL> SELECT region, COUNT(*) FROM admin.v_customers_pg GROUP BY region; -- 결과: APAC 만 보임 diff --git a/docs/04-source-setup.md b/docs/04-source-setup.md index ffb49cb..d68e785 100644 --- a/docs/04-source-setup.md +++ b/docs/04-source-setup.md @@ -4,7 +4,7 @@ --- -## Postgres (`sql/source/postgres_setup.sql`) +## Postgres (`database/source/postgres_setup.sql`) ``` DB : 사용자가 .env 에서 지정 (PG_DB, 기본값 vpdpoc) @@ -22,12 +22,12 @@ seed rows : 12 (APAC 4 / EMEA 4 / AMER 4) ```bash PGPASSWORD=$PG_PASSWORD psql \ -h $PG_HOST -p $PG_PORT -U $PG_USER -d $PG_DB \ - -f sql/source/postgres_setup.sql + -f database/source/postgres_setup.sql ``` --- -## MySQL (`sql/source/mysql_setup.sql`) +## MySQL (`database/source/mysql_setup.sql`) ``` DB : MY_DB (기본 ecommerce_poc) @@ -47,12 +47,12 @@ PK 범위를 PG (1~12) 와 다르게 가져간 이유: ```bash mysql -h $MY_HOST -P $MY_PORT -u $MY_USER -p"$MY_PASSWORD" $MY_DB \ - < sql/source/mysql_setup.sql + < database/source/mysql_setup.sql ``` --- -## ADB → 원격 DB Link (`sql/adb/01_dblinks.sql`) +## ADB → 원격 DB Link (`database/adb/01_dblinks.sql`) `DBMS_CLOUD_ADMIN.CREATE_DATABASE_LINK` 가 ADB 안에서 직접 heterogeneous 연결을 처리합니다. 별도 Database Gateway 설치 불필요. diff --git a/docs/05-dds-variant.md b/docs/05-dds-variant.md index f6a35bf..8c835fc 100644 --- a/docs/05-dds-variant.md +++ b/docs/05-dds-variant.md @@ -2,7 +2,7 @@ > 본 문서는 **선택사항** 입니다. 메인 데모(`run.sh all`) 는 전통적 **VPD** 경로로 > 그대로 동작합니다. 이 문서는 동일한 4-user 매트릭스를 Oracle AI Database -> **26ai 신기능 Deep Data Security (DDS)** 로 재구현한 `sql/adb/13_dds_variant.sql` +> **26ai 신기능 Deep Data Security (DDS)** 로 재구현한 `database/adb/13_dds_variant.sql` > 의 사용법과, VPD ↔ DDS 1:1 매핑을 다룹니다. > > 본 변형은 **2026-05-26 실제 ADB (23.26.2.2.0) 에서 E2E 검증** 됨 (8장 결과). @@ -84,7 +84,7 @@ Oracle 이 **2026-04-09** 에 VPD/RAS 의 공식 후계자로 발표한 native a ```bash source .env # DDSUSER_*_PASSWORD 로드 -sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @sql/adb/13_dds_variant.sql +sqlplus "$ADB_USER/$ADB_PASSWORD@$ADB_TNS" @database/adb/13_dds_variant.sql ``` 스크립트가 만드는 객체: @@ -218,7 +218,7 @@ DROP VIEW v_dds_customers_my; ## 8. E2E 검증 결과 (2026-05-26, ADB 23.26.2.2.0) -`sql/adb/13_dds_variant.sql` 실행 후 4명의 ddsuser 로 `v_dds_customers_*` 조회: +`database/adb/13_dds_variant.sql` 실행 후 4명의 ddsuser 로 `v_dds_customers_*` 조회: | 사용자 | `v_dds_customers_pg` | `v_dds_customers_my` | 판정 | |---|---|---|---| diff --git a/docs/06-agent-ords-vpd-dds-security-brief.md b/docs/06-agent-ords-vpd-dds-security-brief.md index d98cf64..6d0003a 100644 --- a/docs/06-agent-ords-vpd-dds-security-brief.md +++ b/docs/06-agent-ords-vpd-dds-security-brief.md @@ -1165,15 +1165,15 @@ ORDER BY rg.grantee, dg.object_name, dg.grant_name; | 파일 | 역할 | |---|---| | `scripts/run_agent_ords_security_adb_local.sh` | 전체 실행 | -| `sql/adb/16_agent_ords_security_local_cleanup.sql` | `CB_*` 예제 객체 정리 | -| `sql/adb/17_agent_ords_security_local_vpd_setup.sql` | VPD용 로컬 테이블, 권한 테이블, context, redaction, 정책 생성 | -| `sql/adb/18_agent_ords_security_local_vpd_test.sql` | `CB_ORDS`로 Bearer Key 기반 VPD 테스트 | -| `sql/adb/19_agent_ords_security_local_dds_setup.sql` | DDS용 로컬 테이블, END USER, DATA ROLE, DATA GRANT 생성 | -| `sql/adb/20_agent_ords_security_local_dds_test.sql` | DDS end user별 조회 테스트 | -| `sql/adb/21_agent_ords_security_ords_enable_schema.sql` | `CB_ORDS` schema를 ORDS에 enable | -| `sql/adb/22_agent_ords_security_ords_handler_setup.sql` | ORDS Module/Handler와 Handler Package 생성 | -| `sql/adb/23_agent_ords_security_ords_handler_test.sql` | Handler Package 직접 실행으로 VPD/DDS Bearer 경로 검증 | -| `sql/adb/24_agent_ords_security_inventory.sql` | VPD/DDS 정책과 권한을 중앙 조회 | +| `database/adb/16_agent_ords_security_local_cleanup.sql` | `CB_*` 예제 객체 정리 | +| `database/adb/17_agent_ords_security_local_vpd_setup.sql` | VPD용 로컬 테이블, 권한 테이블, context, redaction, 정책 생성 | +| `database/adb/18_agent_ords_security_local_vpd_test.sql` | `CB_ORDS`로 Bearer Key 기반 VPD 테스트 | +| `database/adb/19_agent_ords_security_local_dds_setup.sql` | DDS용 로컬 테이블, END USER, DATA ROLE, DATA GRANT 생성 | +| `database/adb/20_agent_ords_security_local_dds_test.sql` | DDS end user별 조회 테스트 | +| `database/adb/21_agent_ords_security_ords_enable_schema.sql` | `CB_ORDS` schema를 ORDS에 enable | +| `database/adb/22_agent_ords_security_ords_handler_setup.sql` | ORDS Module/Handler와 Handler Package 생성 | +| `database/adb/23_agent_ords_security_ords_handler_test.sql` | Handler Package 직접 실행으로 VPD/DDS Bearer 경로 검증 | +| `database/adb/24_agent_ords_security_inventory.sql` | VPD/DDS 정책과 권한을 중앙 조회 | ### 7.1 VPD + Redaction 실행 검증 @@ -1634,7 +1634,7 @@ ORA-20101: Authorization header must be Bearer ### 7.4 중앙 권한 인벤토리 -VPD와 DDS 모두 적용 결과를 Dictionary View로 확인할 수 있다. 이 예제에서는 `sql/adb/24_agent_ords_security_inventory.sql`을 실행해 정책 연결과 DDS Grant Matrix를 확인한다. +VPD와 DDS 모두 적용 결과를 Dictionary View로 확인할 수 있다. 이 예제에서는 `database/adb/24_agent_ords_security_inventory.sql`을 실행해 정책 연결과 DDS Grant Matrix를 확인한다. VPD 정책 연결 확인: diff --git a/docs/design/424-spring-boot-vpd-backoffice/README.md b/docs/design/424-spring-boot-vpd-backoffice/README.md index 9440080..ee761f2 100644 --- a/docs/design/424-spring-boot-vpd-backoffice/README.md +++ b/docs/design/424-spring-boot-vpd-backoffice/README.md @@ -3,7 +3,7 @@ > **상태**: Draft > **작성**: [AI] Architect · **최종수정**: 2026-06-23 > **추적성** — Redmine: #424 · 관련 ADR: 없음 -> · 구현 파일: `pom.xml`, `src/main/**`, `src/test/**` · 테스트: `mvn test` +> · 구현 파일: `vpd-backoffice/pom.xml`, `vpd-backoffice/src/main/**`, `vpd-backoffice/src/test/**` · 테스트: `mvn test` ## 1. 목적 (Why) @@ -58,8 +58,8 @@ ### 모듈/파일 구조 ```text -pom.xml -src/main/java/com/cloudhandson/vpdbackoffice/ +vpd-backoffice/pom.xml +vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/ VpdBackofficeApplication.java config/ DataSourceConfig.java @@ -88,13 +88,13 @@ src/main/java/com/cloudhandson/vpdbackoffice/ TokenController.java ProbeController.java DashboardController.java -src/main/resources/ +vpd-backoffice/src/main/resources/ application.yml mapper/*.xml templates/**/*.html static/css/app.css static/js/app.js -src/test/java/com/cloudhandson/vpdbackoffice/ +vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/ ``` ### 데이터 흐름 @@ -251,7 +251,7 @@ MCP-style reasoning ## 12. 미해결 질문 (Open Questions) -- ORDS 검증 API는 기존 `sql/adb/22_agent_ords_security_ords_handler_setup.sql`의 Handler를 그대로 사용할지, 백오피스 전용 Handler를 추가할지 결정이 필요하다. +- ORDS 검증 API는 기존 `database/adb/22_agent_ords_security_ords_handler_setup.sql`의 Handler를 그대로 사용할지, 백오피스 전용 Handler를 추가할지 결정이 필요하다. - 백오피스 관리자 로그인은 초기에는 local user로 둘지, 사내 인증과 연결할지 후속 결정이 필요하다. - 컬럼 정책을 Redaction DDL까지 자동 생성할지, 관리 테이블 저장 후 DBA 적용으로 둘지 결정이 필요하다. - 실제 구현 issue를 별도 Redmine 하위 이슈로 나눌지, #424를 Developer 단계로 계속 이동할지 결정이 필요하다. diff --git a/docs/design/456-vpd-predicate-rule-tests/README.md b/docs/design/456-vpd-predicate-rule-tests/README.md index 1f5475d..e27797f 100644 --- a/docs/design/456-vpd-predicate-rule-tests/README.md +++ b/docs/design/456-vpd-predicate-rule-tests/README.md @@ -3,7 +3,7 @@ > **상태**: Approved > **작성**: [AI] Architect · **최종수정**: 2026-06-25 > **추적성** — Redmine: #456 · 관련 ADR: 없음 -> · 구현 파일: `sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql`, `sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` · 테스트: `sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql`, `mvn test` +> · 구현 파일: `database/adb/26_agent_ords_security_dynamic_vpd_filter.sql`, `database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` · 테스트: `database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql`, `mvn test` ## 1. 목적 (Why) @@ -78,8 +78,8 @@ I/O와 순수 로직 경계: ## 10. 테스트 계획 -- SQLcl: `@sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql` -- SQLcl: `@sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` +- SQLcl: `@database/adb/26_agent_ords_security_dynamic_vpd_filter.sql` +- SQLcl: `@database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` - Maven: `mvn test` - ORDS smoke: 기존 HR=3, SELF=1, ALL=6 결과 유지 확인. diff --git a/docs/design/456-vpd-predicate-rule-tests/fn-cb_agent_doc_vpd_filter.md b/docs/design/456-vpd-predicate-rule-tests/fn-cb_agent_doc_vpd_filter.md index 9db348a..4148a25 100644 --- a/docs/design/456-vpd-predicate-rule-tests/fn-cb_agent_doc_vpd_filter.md +++ b/docs/design/456-vpd-predicate-rule-tests/fn-cb_agent_doc_vpd_filter.md @@ -1,7 +1,7 @@ # 함수 설계서: `cb_agent_doc_vpd_filter` (#456) > **부모 설계서**: ./README.md · **상태**: Approved -> **작성**: [AI] Architect · **구현**: `sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql:cb_agent_doc_vpd_filter` · **테스트**: `sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` +> **작성**: [AI] Architect · **구현**: `database/adb/26_agent_ords_security_dynamic_vpd_filter.sql:cb_agent_doc_vpd_filter` · **테스트**: `database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` ## 1. 시그니처 diff --git a/docs/design/462-predicate-injection-defense/README.md b/docs/design/462-predicate-injection-defense/README.md index 2ffe20e..97cb16d 100644 --- a/docs/design/462-predicate-injection-defense/README.md +++ b/docs/design/462-predicate-injection-defense/README.md @@ -3,7 +3,7 @@ > **상태**: Approved > **작성**: [AI] Architect · **최종수정**: 2026-06-25 > **추적성** — Redmine: #462 · 관련 ADR: 없음 -> · 구현 파일: `sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` · 테스트: SQLcl `27`, `./run.sh backoffice-vpd-ords-test`, `mvn test` +> · 구현 파일: `database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` · 테스트: SQLcl `27`, `./run.sh backoffice-vpd-ords-test`, `mvn test` ## 1. 목적 (Why) @@ -67,8 +67,8 @@ malicious cb_permission_rule rows ## 10. 테스트 계획 -- `@sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql` -- `@sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` +- `@database/adb/26_agent_ords_security_dynamic_vpd_filter.sql` +- `@database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql` - `./run.sh backoffice-vpd-ords-test` - `mvn test` diff --git a/docs/design/547-vm-https-hardening/README.md b/docs/design/547-vm-https-hardening/README.md index 8a1fbc7..767b5f9 100644 --- a/docs/design/547-vm-https-hardening/README.md +++ b/docs/design/547-vm-https-hardening/README.md @@ -3,7 +3,7 @@ > **상태**: Approved > **작성**: [AI] Architect · **최종수정**: 2026-06-28 > **추적성** — Redmine: #547 · 관련 ADR: 없음 -> · 구현 파일: `src/main/resources/application.yml`, `SecurityConfig.java`, `scripts/deploy-backoffice-vm.sh`, `scripts/configure-backoffice-https-vm.sh`, `deploy/caddy/Caddyfile.template` +> · 구현 파일: `vpd-backoffice/src/main/resources/application.yml`, `SecurityConfig.java`, `scripts/deploy-backoffice-vm.sh`, `scripts/configure-backoffice-https-vm.sh`, `deploy/vpd-backoffice/caddy/Caddyfile.template` > · 테스트: `TransportSecurityTest.java`, `scripts/test-backoffice-https-config.sh` ## 1. 목적 (Why) @@ -49,7 +49,7 @@ Internet client Internet client ── HTTP :8082 ──X (loopback bind + firewalld/NSG deny) ``` -- `deploy/caddy/Caddyfile.template`: TLS/redirect/HSTS/reverse proxy의 선언적 설정. +- `deploy/vpd-backoffice/caddy/Caddyfile.template`: TLS/redirect/HSTS/reverse proxy의 선언적 설정. - `scripts/configure-backoffice-https-vm.sh`: 입력 검증, 원격 설정 검증·백업·적용·확인. - `scripts/deploy-backoffice-vm.sh`: 앱 배포 시 운영 보안 환경값을 강제하고 루프백 헬스체크. - Spring 설정: proxy가 전달한 HTTPS scheme을 인식하고 직접 HTTP 요청을 거부한다. diff --git a/docs/design/559-independent-vpd-dds-demos/README.md b/docs/design/559-independent-vpd-dds-demos/README.md index 7cb30bb..2d5775b 100644 --- a/docs/design/559-independent-vpd-dds-demos/README.md +++ b/docs/design/559-independent-vpd-dds-demos/README.md @@ -2,7 +2,7 @@ > **상태**: VPD·DDS 병행 검증 완료, 토큰 기반 객체별 Data Grant 적용 완료 > **추적성**: Redmine #565, #566 · DDS 구현 커밋 `1e48864`, `a5e70bc`, `04cca64`, `8978be4` -> **기준 구현**: `sql/adb/32_dds_vector_tag_setup.sql`, `sql/adb/34_dds_token_data_grant_common_auth.sql`, `sql/adb/36_dds_sales_knowledge_scenario.sql`, `dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsGrantPublisher.java`, `dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsVectorKnowledgeService.java` +> **기준 구현**: `database/adb/32_dds_vector_tag_setup.sql`, `database/adb/34_dds_token_data_grant_common_auth.sql`, `database/adb/36_dds_sales_knowledge_scenario.sql`, `dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsGrantPublisher.java`, `dds-backoffice/src/main/java/com/cloudhandson/ddsbackoffice/service/DdsVectorKnowledgeService.java` ## 목적 diff --git a/docs/design/567-ords-vpd-sql-trace/README.md b/docs/design/567-ords-vpd-sql-trace/README.md index af908b4..1ff3520 100644 --- a/docs/design/567-ords-vpd-sql-trace/README.md +++ b/docs/design/567-ords-vpd-sql-trace/README.md @@ -77,8 +77,8 @@ Authorization: Bearer ## 설치와 운영 절차 -1. `ADMIN`으로 [42_agent_ords_fga_execution_audit.sql](../../../sql/adb/42_agent_ords_fga_execution_audit.sql)을 실행해 활성 보호 객체마다 FGA `SELECT` 정책을 만든다. -2. `CB_ORDS`로 [22_agent_ords_security_ords_handler_setup.sql](../../../sql/adb/22_agent_ords_security_ords_handler_setup.sql), [29_agent_ords_vector_search_ords.sql](../../../sql/adb/29_agent_ords_vector_search_ords.sql), [43_agent_ords_probe_id_handler_patch.sql](../../../sql/adb/43_agent_ords_probe_id_handler_patch.sql)을 순서대로 실행한다. +1. `ADMIN`으로 [42_agent_ords_fga_execution_audit.sql](../../../database/adb/42_agent_ords_fga_execution_audit.sql)을 실행해 활성 보호 객체마다 FGA `SELECT` 정책을 만든다. +2. `CB_ORDS`로 [22_agent_ords_security_ords_handler_setup.sql](../../../database/adb/22_agent_ords_security_ords_handler_setup.sql), [29_agent_ords_vector_search_ords.sql](../../../database/adb/29_agent_ords_vector_search_ords.sql), [43_agent_ords_probe_id_handler_patch.sql](../../../database/adb/43_agent_ords_probe_id_handler_patch.sql)을 순서대로 실행한다. 3. 새 권한 결과 확인을 실행한다. 이전 요청에는 `CLIENT_ID`가 없으므로 소급해 매칭하지 않는다. 4. 백오피스 실행 계정이 Autonomous의 `UNIFIED_AUDIT_TRAIL`을 조회할 수 있어야 한다. 전통 FGA 환경은 `DBA_FGA_AUDIT_TRAIL`을 fallback으로 사용한다. 일반 계정이면 감사 조회 권한을 가진 전용 observer 계정을 사용한다. diff --git a/docs/design/567-ords-vpd-sql-trace/fn-addLocalSqlTrace.md b/docs/design/567-ords-vpd-sql-trace/fn-addLocalSqlTrace.md index 70f229e..a9e4007 100644 --- a/docs/design/567-ords-vpd-sql-trace/fn-addLocalSqlTrace.md +++ b/docs/design/567-ords-vpd-sql-trace/fn-addLocalSqlTrace.md @@ -1,7 +1,7 @@ # 함수 설계서: `addLocalSqlTrace` (#567) > **부모 설계서**: ./README.md · **상태**: Approved -> **작성**: [AI] Architect · **구현**: `src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeService.java:addLocalSqlTrace` · **테스트**: `ProbeResultTest`, `mvn test` +> **작성**: [AI] Architect · **구현**: `vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeService.java:addLocalSqlTrace` · **테스트**: `ProbeResultTest`, `mvn test` ## 1. 시그니처 diff --git a/docs/design/567-ords-vpd-sql-trace/fn-findVpdPredicate.md b/docs/design/567-ords-vpd-sql-trace/fn-findVpdPredicate.md index a175bfe..46936d4 100644 --- a/docs/design/567-ords-vpd-sql-trace/fn-findVpdPredicate.md +++ b/docs/design/567-ords-vpd-sql-trace/fn-findVpdPredicate.md @@ -1,7 +1,7 @@ # 함수 설계서: `findVpdPredicate` (#567) > **부모 설계서**: ./README.md · **상태**: Approved -> **작성**: [AI] Architect · **구현**: `src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeService.java:findVpdPredicate` · **테스트**: `mvn test`, 운영 smoke +> **작성**: [AI] Architect · **구현**: `vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeService.java:findVpdPredicate` · **테스트**: `mvn test`, 운영 smoke ## 1. 시그니처 diff --git a/docs/design/617-dds-mcp-end-user-context/README.md b/docs/design/617-dds-mcp-end-user-context/README.md index 135e862..7ddb6dc 100644 --- a/docs/design/617-dds-mcp-end-user-context/README.md +++ b/docs/design/617-dds-mcp-end-user-context/README.md @@ -4,8 +4,8 @@ > **최종수정**: 2026-07-19 > **추적성** — Redmine: #617 · 관련 ADR: [ADR-0001](../../adr/0001-dds-mcp-service-identity.md), [ADR-0002](../../adr/0002-dds-runtime-permission-source.md) > · 현재 구현: `DdsMcpBearerAuthenticator`, `DdsMcpEndUserResolver`, `DdsMcpContextExecutor`, `DdsMcpSseController` -> · 기존 PoC 게시: `sql/adb/44_dds_mcp_local_end_user_setup.sql` -> · 검증: `sql/adb/45_dds_mcp_local_end_user_test.sql`, SSE `tools/call` +> · 기존 PoC 게시: `database/adb/44_dds_mcp_local_end_user_setup.sql` +> · 검증: `database/adb/45_dds_mcp_local_end_user_test.sql`, SSE `tools/call` ## 1. 결정과 목적 diff --git a/docs/design/654-poc4-mcp-ai-console-vpd-audit/README.md b/docs/design/654-poc4-mcp-ai-console-vpd-audit/README.md index 2cb0ec7..a920a95 100644 --- a/docs/design/654-poc4-mcp-ai-console-vpd-audit/README.md +++ b/docs/design/654-poc4-mcp-ai-console-vpd-audit/README.md @@ -3,7 +3,9 @@ > **상태**: Implemented snapshot documented · follow-up contract pending > **작성**: [AI] Architect · **최종수정**: 2026-07-14 > **추적성** — Redmine: #654 · 관련 ADR: 없음 · 구현 커밋: `5bdd242`, `33399f9`, `1f6d974` -> · 스냅샷: `poc4_active_source_20260714/` · 원본 archive: `poc4_active_source_20260714/poc4_active_source_20260714.tar.gz` · 현행 구현 파일: `apps/poc4/mcp_discovery_ui.py`, `src/mcp_tool_router.py`, `src/oci_genai_sdk.py`, `src/poc3/model_registry.py`, `config/mcp_servers.json` · 테스트: Python 3.11 `py_compile`, 기존 백오피스 `mvn -q test` +> · 현재 소스: `ai-web-agent-console/` · 현행 구현 파일: `ai-web-agent-console/app.py`, `ai-web-agent-console/ai_web_agent_console/mcp_tool_router.py`, `ai-web-agent-console/ai_web_agent_console/oci_genai_sdk.py`, `ai-web-agent-console/ai_web_agent_console/model_registry.py`, `ai-web-agent-console/config/mcp_servers.json` · 테스트: Python 3.11 `compileall`/`unittest`, `mvn -f vpd-backoffice/pom.xml test` +> +> 이 문서의 PoC4 명칭과 원격 archive 경로는 2026-07-14 당시의 이력이다. 현재 저장소 구조는 #742 설계서를 기준으로 한다. ## 1. 목적 (Why) @@ -17,17 +19,17 @@ PoC4 MCP AI Console이 KB VPD MCP를 사용자별 Bearer 토큰으로 안전하 | 영역 | 현행 구현 | |---|---| -| 저장소 위치 | `poc4_active_source_20260714/` 단일 폴더에 격리 | -| 실행 진입점 | 직접 실행은 `streamlit run apps/poc4/mcp_discovery_ui.py --server.address 0.0.0.0 --server.port 8622` | +| 저장소 위치 | `ai-web-agent-console/` 단일 폴더에 격리 | +| 실행 진입점 | 직접 실행은 `streamlit run ai-web-agent-console/app.py --server.address 0.0.0.0 --server.port 8622` | | Python 런타임 | Python 3.11 이상. 배포 서버 검증 런타임은 `/home/opc/poc_4/.python-runtime/cpython-3.11.15+20260610/bin/python3.11` | -| Streamlit 화면 | `apps/poc4/mcp_discovery_ui.py` 단일 대형 UI. KB 테마, 포털 로그인, 대화 이력, MCP discovery/call, evidence 수집, 답변 합성을 포함 | -| MCP registry | `config/mcp_servers.json`. `kb_mcp`와 `kb_vector_mcp` 두 서버를 선언 | +| Streamlit 화면 | `ai-web-agent-console/app.py` 단일 대형 UI. KB 테마, 포털 로그인, 대화 이력, MCP discovery/call, evidence 수집, 답변 합성을 포함 | +| MCP registry | `ai-web-agent-console/config/mcp_servers.json` | | KB 정형 MCP | `https://kb.cloud-handson.com/mcp`, 기본 tool `ords.query.kb_select_ai_vpd` | | KB 벡터 MCP | `http://127.0.0.1:9978/mcp`, allowlist `hybrid_rerank_search` | -| 토큰 preset | `config/vpd_token_presets.json`. 실제 토큰 원문은 포함하지 않고 placeholder만 둠 | +| 토큰 preset | `ai-web-agent-console/config/vpd_token_presets.json`. 실제 토큰 원문은 포함하지 않고 placeholder만 둠 | | 대화 저장소 | 기본 `data/poc4_mcp_chat.sqlite3`, 환경변수 `POC4_CHAT_DB_PATH`로 변경 가능 | | DB evidence 연결 | 기본 env file `/home/opc/kbmcp/.env`, wallet fallback `/home/opc/wallet/kbaipoc` | -| OCI GenAI | `OCI_AUTH_TYPE=config_file`, `~/.oci/config`, `DEFAULT` profile 기반. model profile은 `config/poc3_model_profiles.json`에서 로드 | +| OCI GenAI | `OCI_AUTH_TYPE=config_file`, `~/.oci/config`, `DEFAULT` profile 기반. model profile은 `ai-web-agent-console/config/model_profiles.json`에서 로드 | | 보안 원칙 | wallet, DB password, wallet password, 실제 VPD token, 대화 DB는 저장소에 포함하지 않음 | 현행 데이터 흐름은 다음과 같다. @@ -60,25 +62,24 @@ SQLite 대화 이력 저장 | 파일 | 책임 | |---|---| -| `apps/poc4/mcp_discovery_ui.py` | Streamlit 화면, 포털 로그인, MCP discovery/call, agent loop, evidence 수집, 답변 합성, 대화 이력 저장 | -| `apps/poc4/ui_theme.py` | UI theme 보조 코드 | -| `src/mcp_tool_router.py` | 발견된 MCP tool descriptor를 기반으로 LLM router가 server/tool을 선택하고 tool arguments를 구성 | -| `src/oci_genai_sdk.py` | OCI Generative AI 호출 경계. MCP/VPD token을 알지 않는 최소 completion client | -| `src/poc3/model_registry.py` | 모델 profile registry 로드, region/endpoint 해석, 환경 override 처리 | -| `src/poc3/questions.py` | 데모 질문 목록 | -| `config/mcp_servers.json` | MCP 서버 registry. 현재는 `endpoint_url`이 있으면 이를 우선 사용 | -| `config/poc3_model_profiles.json` | `gpt55_oci`, `gpt54_mini_oci`, `grok43`, `llama4_maverick`, `llama33_70b` profile | -| `config/vpd_token_presets.json` | 데모 사용자 token preset 구조. 실제 토큰은 배포 환경에서 교체 | -| `scripts/poc4/start_8622_langgraph_tc_ui_nohup.sh` | 원본 PoC4 런처 wrapper. 현재 스냅샷의 직접 entrypoint와는 다르게 `/home/opc/poc_4/scripts/poc4/run_8622_langgraph_tc_ui.sh` 및 `apps/poc4/langgraph_tc_ui.py`를 참조 | +| `ai-web-agent-console/app.py` | Streamlit 화면, 포털 로그인, MCP discovery/call, agent loop, evidence 수집, 답변 합성, 대화 이력 저장 | +| `ai-web-agent-console/ai_web_agent_console/presentation.py` | 공통 UI theme와 화면 표현 보조 코드 | +| `ai-web-agent-console/ai_web_agent_console/mcp_tool_router.py` | 발견된 MCP tool descriptor를 기반으로 LLM router가 server/tool을 선택하고 tool arguments를 구성 | +| `ai-web-agent-console/ai_web_agent_console/oci_genai_sdk.py` | OCI Generative AI 호출 경계. MCP/VPD token을 알지 않는 최소 completion client | +| `ai-web-agent-console/ai_web_agent_console/model_registry.py` | 모델 profile registry 로드, region/endpoint 해석, 환경 override 처리 | +| `ai-web-agent-console/ai_web_agent_console/questions.py` | 데모 질문 목록 | +| `ai-web-agent-console/config/mcp_servers.json` | MCP 서버 registry | +| `ai-web-agent-console/config/model_profiles.json` | OCI GenAI model profile registry | +| `ai-web-agent-console/config/vpd_token_presets.json` | 데모 사용자 token preset 구조. 실제 토큰은 배포 환경에서 교체 | -런처 주의사항: 스냅샷에는 `mcp_discovery_ui.py` 직접 실행에 필요한 소스가 들어 있지만, 포함된 `start_8622...` script는 원본 서버의 공용 runtime wrapper에 의존한다. 이 저장소에서 독립 실행하려면 `SOURCE_README.md`의 직접 `streamlit run` 명령을 사용하거나, 별도 wrapper를 작성해야 한다. +현재 저장소에서는 `cd ai-web-agent-console && streamlit run app.py`를 독립 실행 진입점으로 사용한다. ## 1.3 현행 보안/비밀정보 경계 - `VpdTokenPreset.token`은 dataclass에서 `repr=False`이며, UI는 token을 정규화한 뒤 Authorization header에만 넣는다. - `_NoRedirectHandler`는 redirect 시 Authorization header가 다른 endpoint로 전달되는 것을 막는다. -- `src/mcp_tool_router.py`의 router는 질문과 tool descriptor만 받으며 bearer token 또는 provider credential을 받지 않는다. -- `src/oci_genai_sdk.py`는 `.env`에서 `OCI_AUTH_TYPE`, `OCI_CONFIG_FILE`, `OCI_GENAI_COMPARTMENT_ID`, `OCI_PROFILE`만 읽는다. +- `ai_web_agent_console.mcp_tool_router`의 router는 질문과 tool descriptor만 받으며 bearer token 또는 provider credential을 받지 않는다. +- `ai_web_agent_console.oci_genai_sdk`는 `.env`에서 `OCI_AUTH_TYPE`, `OCI_CONFIG_FILE`, `OCI_GENAI_COMPARTMENT_ID`, `OCI_PROFILE`만 읽는다. - Oracle audit/business evidence 조회는 `/home/opc/kbmcp/.env`에서 `ORACLE_DB_USER`, `ORACLE_DB_PASSWORD`, `ORACLE_DSN`, `ORACLE_WALLET_PASSWORD`, `ORACLE_WALLET_DIR`를 읽는다. - wallet 기본 fallback은 `/home/opc/wallet/kbaipoc`이다. - 저장소에는 실제 `.env`, wallet, SQLite 대화 DB, 실제 VPD bearer token 원문을 포함하지 않는다. @@ -97,7 +98,7 @@ SQLite 대화 이력 저장 ## 2. 범위 (Scope) - **포함**: - - `apps/poc4/mcp_discovery_ui.py`의 KB MCP endpoint, 인증 헤더, JSON-RPC, 오류 처리 정비 + - `ai-web-agent-console/app.py`의 KB MCP endpoint, 인증 헤더, JSON-RPC, 오류 처리 정비 - `config/mcp_servers.json` 및 sample의 KB MCP 선언 정비 - KB MCP의 단일 도구 `ords.query.kb_select_ai_vpd` 호출 계약 문서화 - VPD Backoffice `/mcp`과의 HTTP 상태·프로토콜 버전 호환성 점검 및 필요한 최소 보완 @@ -300,8 +301,8 @@ Authorization: Bearer 배포 서버의 PoC4 활성 화면 소스를 현재 저장소에 별도 폴더로 반입했다. - 원격 실제 위치: `/home/opc/poc_4/poc4_active_source_20260714.tar.gz` -- 사용자 제시 경로 `/home/opc/poc_4/poc4_active_source_20260714/poc4_active_source_20260714.tar.gz`에는 파일이 없었고, 실제 archive는 `/home/opc/poc_4/` 바로 아래에 있었다. -- 저장소 위치: `poc4_active_source_20260714/` +- 사용자 제시 경로 `/home/opc/poc_4/ai-web-agent-console/poc4_active_source_20260714.tar.gz`에는 파일이 없었고, 실제 archive는 `/home/opc/poc_4/` 바로 아래에 있었다. +- 저장소 위치: `ai-web-agent-console/` - 포함 파일: Streamlit UI, MCP router, OCI GenAI client, 모델 profile, token preset sample, 기동/status script, requirements - 보안 확인: 실제 `.env`, 실제 VPD token 원문, 대화 SQLite DB는 포함하지 않았다. `vpd_token_presets.json`에는 placeholder만 있다. - DB 참조 경로: VPD 개발본 배포 서버에서는 `/home/opc/kbmcp/.env`의 접속 정보를 사용하고, wallet directory는 `/home/opc/wallet/kbaipoc`를 사용한다. 두 경로의 파일 내용은 저장소에 포함하지 않는다. @@ -380,7 +381,7 @@ ENABLED_COUNT = 4 SELECT_POLICY_COUNT = 4 ``` -현재 DB의 정책명 계열은 모두 `KB_FGA_*`다. 저장소의 범용 적용 스크립트 `sql/adb/42_agent_ords_fga_execution_audit.sql`은 `CB_VPD_EXEC_AUDIT_` 형태의 정책을 만들도록 작성되어 있으나, 현행 ADB에는 이 계열이 아니라 `KB_FGA_*` 정책이 적용되어 있다. 따라서 운영 확인 시에는 “스크립트 파일명/예상명”보다 `DBA_AUDIT_POLICIES`의 실제 정책명을 기준으로 봐야 한다. +현재 DB의 정책명 계열은 모두 `KB_FGA_*`다. 저장소의 범용 적용 스크립트 `database/adb/42_agent_ords_fga_execution_audit.sql`은 `CB_VPD_EXEC_AUDIT_` 형태의 정책을 만들도록 작성되어 있으나, 현행 ADB에는 이 계열이 아니라 `KB_FGA_*` 정책이 적용되어 있다. 따라서 운영 확인 시에는 “스크립트 파일명/예상명”보다 `DBA_AUDIT_POLICIES`의 실제 정책명을 기준으로 봐야 한다. ### 15.4 감사 이벤트 저장 위치 @@ -437,7 +438,7 @@ DBA_FGA_AUDIT_TRAIL event_count_7d = 0 ### 15.6 소스 구현과 화면 연결 -PoC4 스냅샷의 `apps/poc4/mcp_discovery_ui.py`는 감사로그 탭에서 다음 두 쿼리를 사용한다. +PoC4 스냅샷의 `ai-web-agent-console/app.py`는 감사로그 탭에서 다음 두 쿼리를 사용한다. | 함수 | 조회 대상 | 역할 | |---|---|---| diff --git a/docs/design/701-hmm-ai-agent-modularization/README.md b/docs/design/701-hmm-ai-agent-modularization/README.md index 4bafd67..9726cf9 100644 --- a/docs/design/701-hmm-ai-agent-modularization/README.md +++ b/docs/design/701-hmm-ai-agent-modularization/README.md @@ -2,7 +2,9 @@ ## 프로젝트 개요 -`poc4_active_source_20260714`는 레거시 스냅샷 경로이며, 정식 서비스명은 HMM AI 업무 에이전트다. HMM MCP를 통해 HR 데이터, 표준 용어, 규정 문서를 조회하고 대화 이력과 보안 관리 화면을 제공한다. +정식 서비스명은 HMM AI 업무 에이전트이며 현재 소스 경계는 `ai-web-agent-console/`이다. +과거 `poc4_active_source_20260714` 스냅샷 경로는 #742에서 제거했다. HMM MCP를 통해 HR 데이터, +표준 용어, 규정 문서를 조회하고 대화 이력과 보안 관리 화면을 제공한다. ## 목표 @@ -10,7 +12,7 @@ ## 현재 문제 -- `apps/poc4/mcp_discovery_ui.py`가 화면, 설정, 인증, SQLite 대화 이력, MCP JSON-RPC, Agent 실행을 함께 관리한다. +- `ai-web-agent-console/app.py`가 화면, 설정, 인증, SQLite 대화 이력, MCP JSON-RPC, Agent 실행을 함께 관리한다. - MCP 설정과 인증 토큰 규칙을 수정할 때 화면 코드까지 함께 읽어야 한다. - MCP 프로토콜 처리의 단위 검증 지점이 없다. @@ -18,14 +20,15 @@ | 모듈 | 책임 | Streamlit 의존 | | --- | --- | --- | -| `src/poc4/runtime_config.py` | `.env`, MCP 서버 JSON, VPD preset 로드와 검증 | 없음 | -| `src/poc4/mcp_client.py` | endpoint 검증, JSON-RPC, 세션 fallback, tool discovery/call | 없음 | -| `src/poc4/chat_store.py` | SQLite 대화 이력 CRUD | 없음 | -| `apps/poc4/mcp_discovery_ui.py` | 사용자 입력, 상태, 화면 렌더링, 업무 Agent orchestration | 있음 | +| `ai-web-agent-console/ai_web_agent_console/profile.py` | 제품 프로필과 환경 override 로드 | 없음 | +| `ai-web-agent-console/ai_web_agent_console/mcp_tool_router.py` | MCP 도구 discovery 결과의 route와 arguments 구성 | 없음 | +| `ai-web-agent-console/ai_web_agent_console/auth_gateway.py` | 로그인·쿠키·세션 경계 | 없음 | +| `ai-web-agent-console/ai_web_agent_console/audit.py` | 감사·증적 조회 경계 | 없음 | +| `ai-web-agent-console/app.py` | 사용자 입력, 상태, 화면 렌더링, 업무 Agent orchestration | 있음 | ### 재사용 UI Shell과 제품 프로필 -공통 화면 shell은 `src/agent_console/`에서 제공하고, 특정 고객·PoC의 표현은 +공통 화면 shell은 `ai-web-agent-console/ai_web_agent_console/`에서 제공하고, 특정 고객·PoC의 표현은 `config/app_profile.json`에 둔다. 다른 프로젝트는 앱 코드를 복사·수정하지 않고 profile JSON을 교체할 수 있다. 실제 배포에서는 `AGENT_CONSOLE_NAME`, `AGENT_CONSOLE_HEADER_DESCRIPTION`, `AGENT_CONSOLE_PRIMARY_COLOR` 등 `AGENT_CONSOLE_*` 환경변수가 JSON 기본값보다 우선한다. @@ -48,7 +51,7 @@ 2. 변경은 Redmine 이슈에 설계·검증 결과와 Git commit SHA를 함께 기록한다. 3. Git commit message에는 Redmine 번호를 `refs #<번호>:` 형식으로 포함한다. 4. 환경별 값과 비밀값은 profile JSON에 넣지 않고 `.env` 또는 secret store에만 둔다. -5. UI CSS는 `src/agent_console/presentation.py` 한 곳에서 관리한다. 제품별 색상과 문구는 Python/CSS를 수정하지 않고 `app_profile.json`으로 조정한다. +5. UI CSS는 `ai-web-agent-console/ai_web_agent_console/presentation.py` 한 곳에서 관리한다. 제품별 색상과 문구는 Python/CSS를 수정하지 않고 `app_profile.json`으로 조정한다. 도메인 로직의 공개 오류는 `PublicMcpError`로 통일한다. UI는 이 오류를 사람이 이해할 수 있는 메시지로 표시하되 토큰과 HTTP 원문을 출력하지 않는다. diff --git a/docs/design/702-hmm-backoffice-identity/README.md b/docs/design/702-hmm-backoffice-identity/README.md index 0623966..7c53b84 100644 --- a/docs/design/702-hmm-backoffice-identity/README.md +++ b/docs/design/702-hmm-backoffice-identity/README.md @@ -60,7 +60,7 @@ HMM_KNOWLEDGE_DOCUMENTS ──< HMM_KNOWLEDGE_CHUNKS ──< HMM_KNOWLEDGE_TAGS - `/structured-data`와 `/schema-metadata`의 데이터 원본명, Oracle owner, 안내 문구, 최대 조회 건수, 허용 테이블 목록은 Java·HTML에 하드코딩하지 않는다. -- 기본 HMM 정의는 `src/main/resources/config/structured-data-catalog.json`에 둔다. 배포 환경에서는 +- 기본 HMM 정의는 `vpd-backoffice/src/main/resources/config/structured-data-catalog.json`에 둔다. 배포 환경에서는 `BACKOFFICE_STRUCTURED_DATA_CATALOG_LOCATION=file:/.../structured-data-catalog.json`으로 외부 JSON을 지정할 수 있어 다른 회사 PoC에서 애플리케이션 코드를 수정하지 않고 재사용할 수 있다. - 각 테이블 정의는 `key`, `tableName`, `businessName`, `description`을 기본으로 하고 필요하면 diff --git a/docs/design/707-hmm-leave-team-vpd/README.md b/docs/design/707-hmm-leave-team-vpd/README.md index 330611c..fc78203 100644 --- a/docs/design/707-hmm-leave-team-vpd/README.md +++ b/docs/design/707-hmm-leave-team-vpd/README.md @@ -73,7 +73,7 @@ E1001에는 `HMM_HR_MANAGER`, E1002~E1007에는 `HMM_HR_VIEWER`를 부여한다. ## 배포 순서 1. 애플리케이션 테스트와 SQL 구문 검사를 수행한다. -2. 멱등 SQL `sql/adb/72_hmm_leave_team_vpd.sql`을 `ADMIN`으로 실행한다. +2. 멱등 SQL `database/adb/72_hmm_leave_team_vpd.sql`을 `ADMIN`으로 실행한다. 3. VPD 정책·컴파일 상태·백오피스 화면을 확인한다. 4. 백오피스와 같은 SHA-256 저장 규칙으로 E1001과 E1002 임시 검증 토큰을 만든다. 5. 비면제 검증 사용자에서 토큰별 조회 결과를 확인하고 검증 토큰과 사용자를 제거한다. diff --git a/docs/design/723-hmm-configurable-backoffice/README.md b/docs/design/723-hmm-configurable-backoffice/README.md index 4f061b0..be3d389 100644 --- a/docs/design/723-hmm-configurable-backoffice/README.md +++ b/docs/design/723-hmm-configurable-backoffice/README.md @@ -182,7 +182,7 @@ HMM 운영 MCP는 현재 세 개의 Agent Tool을 사용하므로 Select AI 접 BACKOFFICE_SECURITY_SQL_SCRIPTS ``` -번들된 `sql/adb` 경로 안의 파일만 허용하며 요청값을 resource path로 사용하지 않는다. +번들된 `database/adb` 경로 안의 파일만 허용하며 요청값을 resource path로 사용하지 않는다. HMM 운영에서는 `72_hmm_leave_team_vpd.sql` 등 HMM 관련 SQL만 노출한다. ## 5. 코드 구조 diff --git a/docs/design/729-rds-carrier-performance-demo/README.md b/docs/design/729-rds-carrier-performance-demo/README.md index 897c6a2..c29c77c 100644 --- a/docs/design/729-rds-carrier-performance-demo/README.md +++ b/docs/design/729-rds-carrier-performance-demo/README.md @@ -110,8 +110,8 @@ CHECK 제약으로 보장한다. 월별 조회와 위험 선사 조회에 각각 ## 7. 적재 순서 1. RDS TLS와 현재 계정의 CREATE 권한을 확인한다. -2. `sql/source/postgres_hmm_carrier_performance.sql`을 실행한다. -3. `sql/source/postgres_hmm_carrier_performance_verify.sql`을 실행한다. +2. `database/source/postgres_hmm_carrier_performance.sql`을 실행한다. +3. `database/source/postgres_hmm_carrier_performance_verify.sql`을 실행한다. 4. 재실행 후에도 동일한 선사 8개와 실적 144행인지 확인한다. 5. 후속 작업에서 ADB credential과 PostgreSQL database link를 만든다. diff --git a/docs/design/742-application-oriented-repository-layout/README.md b/docs/design/742-application-oriented-repository-layout/README.md new file mode 100644 index 0000000..de90082 --- /dev/null +++ b/docs/design/742-application-oriented-repository-layout/README.md @@ -0,0 +1,112 @@ +# #742 애플리케이션 단위 저장소 구조 개편 + +## 문제 + +현재 저장소 루트의 `pom.xml`, `src/main`, `src/test`는 실제로 하나의 Spring Boot +백오피스지만 제품 폴더 없이 저장소 전체 애플리케이션처럼 보인다. Streamlit 앱은 +`poc4_active_source_20260714`라는 날짜 스냅샷 폴더에 있고 내부에서도 `poc3`, `poc4`, +`agent_console`, 단독 Python 모듈이 서로 참조한다. + +이 구조에서는 다음 내용을 파일 경로만 보고 알 수 없다. + +- 어떤 파일이 실제 배포 애플리케이션인지 +- Spring Boot와 Streamlit의 빌드·테스트 경계가 어디인지 +- `poc3`, `poc4`가 제품명인지 과거 실험 번호인지 +- DB 스크립트와 특정 애플리케이션의 관계가 무엇인지 + +## 목표 구조 + +```text +vpd-permission-poc/ +├── vpd-backoffice/ Spring Boot VPD·권한 관리 백오피스 +│ ├── pom.xml +│ ├── src/main/ +│ └── src/test/ +├── ai-web-agent-console/ Streamlit AI 업무 에이전트 +│ ├── app.py +│ ├── ai_web_agent_console/ 단일 Python 패키지 +│ ├── config/ +│ ├── tests/ +│ └── requirements.txt +├── dds-backoffice/ 별도 DDS 백오피스 +├── database/ +│ ├── adb/ +│ └── source/ +├── deploy/ 제품별 배포 설정 +├── docs/ 설계·운영·검증 문서 +├── scripts/ 저장소 공통 자동화 +└── README.md +``` + +## 이동 매핑 + +| 기존 | 변경 | 처리 | +|---|---|---| +| `pom.xml` | `vpd-backoffice/pom.xml` | Maven 프로젝트 경계 명시 | +| `src/main` | `vpd-backoffice/src/main` | Spring 애플리케이션 소스 | +| `src/test` | `vpd-backoffice/src/test` | Spring 단위·통합 테스트 | +| `sql/adb` | `database/adb` | Oracle/ADB 스크립트 | +| `sql/source` | `database/source` | 외부 원천 DB 스크립트 | +| `poc4_active_source_20260714` | `ai-web-agent-console` | 날짜·PoC 번호 제거 | +| `apps/poc4/mcp_discovery_ui.py` | `ai-web-agent-console/app.py` | 명확한 Streamlit 진입점 | +| `src/agent_console/*` | `ai-web-agent-console/ai_web_agent_console/*` | 단일 제품 패키지 | +| `src/poc3/model_registry.py` | `ai-web-agent-console/ai_web_agent_console/model_registry.py` | 실험 번호 제거 | +| `src/poc3/questions.py` | `ai-web-agent-console/ai_web_agent_console/questions.py` | 실험 번호 제거 | +| `src/poc4/scenarios.py` | `ai-web-agent-console/ai_web_agent_console/scenarios.py` | 실험 번호 제거 | +| `src/poc4/query_contracts.py` | `ai-web-agent-console/ai_web_agent_console/query_contracts.py` | 실험 번호 제거 | +| `src/mcp_*.py`, `src/oci_genai_sdk.py` | `ai-web-agent-console/ai_web_agent_console/` | 앱 전용 공용 모듈 통합 | +| `config/poc3_model_profiles.json` | `ai-web-agent-console/config/model_profiles.json` | 실험 번호 제거 | + +## 경로 규칙 + +1. 저장소 루트에는 애플리케이션 프레임워크의 `src`나 `pom.xml`을 두지 않는다. +2. 각 애플리케이션은 자신의 소스, 의존성 선언, 테스트 진입점을 가진다. +3. DB 스크립트는 `database`를 Git 원본으로 사용하고 Spring JAR는 해당 경로를 + 리소스로 포함한다. +4. 배포 설정은 `deploy/`에서 새 소스 경로를 참조한다. +5. 과거 경로를 유지하는 심볼릭 링크나 복제본은 만들지 않는다. 잘못된 경로가 다시 + 사용되면 테스트가 실패하도록 한다. +6. 운영 중인 환경변수와 SQLite 테이블명은 데이터 호환을 위해 이번 변경에서 유지한다. + 폴더·패키지·실행 경로에서만 PoC 명칭을 제거한다. + +## Maven 변경 + +`vpd-backoffice/pom.xml`의 SQL 리소스 경로는 `../database/adb`를 사용한다. 루트 자동화는 +`mvn -f vpd-backoffice/pom.xml`을 사용하며 앱 디렉토리 안에서는 기존처럼 `mvn test`가 +동작해야 한다. + +Java 테스트에서 파일을 직접 여는 경로는 앱 디렉토리를 기준으로 유지한다. 따라서 +`vpd-backoffice`에서 실행한 테스트와 루트에서 `-f`로 실행한 테스트를 모두 확인한다. + +## Python 변경 + +`ai-web-agent-console/app.py`는 자신의 부모 폴더를 애플리케이션 루트로 사용한다. +모든 import는 `ai_web_agent_console.` 형식으로 통일한다. 테스트도 같은 공개 +패키지 경로만 사용한다. + +`model_profiles.json` 안의 `default_for_poc3` 속성은 `default_for_console`로 바꾸고 +로더·검증 코드도 함께 변경한다. 배포된 비밀정보 파일과 대화 DB는 Git 이동 대상이 +아니다. + +## 배포 변경 + +- Spring 배포 빌드는 `vpd-backoffice/pom.xml`과 `vpd-backoffice/target`을 사용한다. +- Streamlit 실행은 `streamlit run app.py`를 사용한다. +- 인증 게이트웨이는 `python -m ai_web_agent_console.auth_gateway`를 사용한다. +- 기존 운영 디렉토리 `/opt/hmm-poc4`는 무중단 전환을 위해 물리 경로로 유지할 수 있지만, + 서비스의 Git 소스 경로와 Python 모듈명은 새 구조를 사용한다. + +## 검증 + +1. `git status --short`에서 기존 #741 변경이 새 경로에 남아 있는지 확인한다. +2. `mvn -f vpd-backoffice/pom.xml test`를 실행한다. +3. Python 전체 소스에 `compileall`을 실행한다. +4. `unittest discover -s ai-web-agent-console/tests`를 실행한다. +5. `rg`로 운영 코드의 `src.poc3`, `src.poc4`, `src.agent_console`, + `poc4_active_source_20260714`, `apps/poc4` 참조가 0건인지 확인한다. +6. 배포 스크립트의 dry-run 또는 정적 경로 검증을 수행한다. + +## 롤백 + +모든 이동은 한 Git 커밋으로 추적한다. 문제가 생기면 해당 커밋을 revert하여 이전 경로와 +import를 함께 복구한다. DB 스키마와 운영 데이터는 이 구조 변경에서 수정하지 않는다. diff --git a/docs/notes/2026-06-08-dds-qa-session.md b/docs/notes/2026-06-08-dds-qa-session.md index 34490d4..6ef6dc8 100644 --- a/docs/notes/2026-06-08-dds-qa-session.md +++ b/docs/notes/2026-06-08-dds-qa-session.md @@ -98,7 +98,7 @@ STEP 8 (선택) ALTER TABLE ... SET USE DATA GRANTS ONLY ENABLED -- MAC 모드 STEP 9 감사 (dba_data_grants 등) + 역순 정리 ``` -전체 스크립트는 세션 본문 참조. 이 POC 의 `sql/adb/13_dds_variant.sql` + `15_dds_cleanup.sql` 가 동일 패턴. +전체 스크립트는 세션 본문 참조. 이 POC 의 `database/adb/13_dds_variant.sql` + `15_dds_cleanup.sql` 가 동일 패턴. --- @@ -325,8 +325,8 @@ CREATE DATA GRANT admin.dg_scoped ### 이 POC 에서 보면 -- `sql/adb/06_policy.sql` + `permission` 테이블 = "앱/운영자가 행으로 권한 관리" → **VPD 답안** -- `sql/adb/13_dds_variant.sql` = "DBA 가 DDL 로 4 종 역할 정의" → **DDS 답안** +- `database/adb/06_policy.sql` + `permission` 테이블 = "앱/운영자가 행으로 권한 관리" → **VPD 답안** +- `database/adb/13_dds_variant.sql` = "DBA 가 DDL 로 4 종 역할 정의" → **DDS 답안** - 같은 결과를 두 다른 모델로 표현한 비교 데모 **권한 매핑 테이블 중심으로 가겠다면 VPD 그대로 두는 게 정답.** diff --git a/poc4_active_source_20260714/HMM_BRAND_REFRESH.md b/docs/notes/hmm-brand-refresh.md similarity index 92% rename from poc4_active_source_20260714/HMM_BRAND_REFRESH.md rename to docs/notes/hmm-brand-refresh.md index d98f22a..c945ae5 100644 --- a/poc4_active_source_20260714/HMM_BRAND_REFRESH.md +++ b/docs/notes/hmm-brand-refresh.md @@ -6,7 +6,8 @@ - 외부 KB 로고·전용 글꼴 의존성을 제거하고, 애플리케이션 내부 SVG 워드마크와 해양 청색 계열로 표시한다. - 기존 MCP, VPD, 데이터베이스 스키마 및 도구 계약은 변경하지 않는다. - 로그인 유지 기능은 서버 비밀키로 서명한 7일 만료 토큰을 사용하며, 로그아웃 시 즉시 폐기한다. -- 공통 화면 CSS와 로그인/헤더 renderer는 `src/agent_console/presentation.py`에서 관리한다. +- 공통 화면 CSS와 로그인/헤더 renderer는 + `ai-web-agent-console/ai_web_agent_console/presentation.py`에서 관리한다. HMM의 제품명·문구·색상은 `config/app_profile.json`에만 둔다. # HMM MCP runtime wiring diff --git a/docs/reference/ords-vpd-sql-trace.md b/docs/reference/ords-vpd-sql-trace.md index c78f478..f994562 100644 --- a/docs/reference/ords-vpd-sql-trace.md +++ b/docs/reference/ords-vpd-sql-trace.md @@ -12,10 +12,10 @@ 기존 Handler가 trace 필드를 반환하지 않으면 백오피스가 같은 DB 연결에서 `set_user_by_bearer` → `CB_AGENT_DOC_VPD_FILTER` → `clear_user` 순서로 기본 VPD predicate를 조회한다. 이 보조 조회가 실패해도 권한 결과 자체는 실패 처리하지 않는다. -기존 설치에 trace 권한을 추가하려면 ADMIN으로 `sql/adb/33_agent_ords_sql_trace_grant.sql`을 실행한 뒤 CB_ORDS로 `22_agent_ords_security_ords_handler_setup.sql`을 재실행하거나 `/ords-handlers`에서 trace가 포함된 Handler source를 저장한다. +기존 설치에 trace 권한을 추가하려면 ADMIN으로 `database/adb/33_agent_ords_sql_trace_grant.sql`을 실행한 뒤 CB_ORDS로 `22_agent_ords_security_ords_handler_setup.sql`을 재실행하거나 `/ords-handlers`에서 trace가 포함된 Handler source를 저장한다. 기본으로 표시되는 SQL은 해당 토큰 컨텍스트에서 VPD 정책 함수가 반환한 행 predicate를 기본 Handler SELECT에 결합한 확인용 SQL이다. Bearer 원문은 trace나 응답에 포함하지 않는다. 실행 DB가 `V$SQL`과 `DBMS_XPLAN` 조회를 허용하면 `/probe`는 최근 2분 내 같은 보호 객체의 SQL_ID, DB가 기록한 원문 SQL, cursor 누적 통계, Predicate Information도 함께 표시한다. `V$SQL` 원문은 VPD 주입 전 SQL이고, 실제 적용 조건은 `DBMS_XPLAN`의 Predicate Information에서 확인한다. 같은 객체에 동시 요청이 많은 경우에는 최근 cursor 매칭이므로 요청 ID 기반 상관 추적이 필요하다. -Autonomous DB에서 일반 `ADMIN` 계정은 `SYS.V_$SQL` 권한을 ORDS 계정에 위임하지 못할 수 있다. 이 경우에는 SYS/DBA가 [34_agent_ords_execution_evidence_grant.sql](../../sql/adb/34_agent_ords_execution_evidence_grant.sql)을 실행해 진단 권한을 준비해야 한다. 권한을 얻지 못해도 접근 검증 결과와 기존 권한 조건 재현 SQL은 그대로 제공된다. +Autonomous DB에서 일반 `ADMIN` 계정은 `SYS.V_$SQL` 권한을 ORDS 계정에 위임하지 못할 수 있다. 이 경우에는 SYS/DBA가 [34_agent_ords_execution_evidence_grant.sql](../../database/adb/34_agent_ords_execution_evidence_grant.sql)을 실행해 진단 권한을 준비해야 한다. 권한을 얻지 못해도 접근 검증 결과와 기존 권한 조건 재현 SQL은 그대로 제공된다. diff --git a/docs/reports/2026-07-10-existing-01-mcp-rag-diagnosis.md b/docs/reports/2026-07-10-existing-01-mcp-rag-diagnosis.md index f44bbe7..62009bb 100644 --- a/docs/reports/2026-07-10-existing-01-mcp-rag-diagnosis.md +++ b/docs/reports/2026-07-10-existing-01-mcp-rag-diagnosis.md @@ -54,7 +54,7 @@ EXTERNAL_CLAUSE_NAME=개인용애니카다이렉트자동차보험 변경 스크립트: -- `sql/adb/65_kb_select_ai_vpd_query_api.sql` +- `database/adb/65_kb_select_ai_vpd_query_api.sql` ## RAG 근거 검색 확인 결과 diff --git a/docs/reports/2026-07-10-select-ai-profile-performance-report.md b/docs/reports/2026-07-10-select-ai-profile-performance-report.md index ee3beb3..3856e52 100644 --- a/docs/reports/2026-07-10-select-ai-profile-performance-report.md +++ b/docs/reports/2026-07-10-select-ai-profile-performance-report.md @@ -202,7 +202,7 @@ c_profile_name CONSTANT VARCHAR2(128) := 'KB_AIDP_SELECTAI_GPT54_MINI_COMMENTS_P 대상 스크립트: ```text -sql/adb/65_kb_select_ai_vpd_query_api.sql +database/adb/65_kb_select_ai_vpd_query_api.sql ``` ### ORDS 응답 표시 @@ -216,7 +216,7 @@ profile=KB_AIDP_SELECTAI_GPT54_MINI_COMMENTS_PROFILE_V1 대상 스크립트: ```text -sql/adb/66_kb_select_ai_vpd_query_ords.sql +database/adb/66_kb_select_ai_vpd_query_ords.sql ``` ### MCP 응답 표시 @@ -226,8 +226,8 @@ MCP tool 응답 payload의 profile 표시와 화면 설명을 새 프로파일 대상 소스: ```text -src/main/java/com/cloudhandson/vpdbackoffice/service/McpSseService.java -src/main/resources/templates/mcp-sse.html +vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpSseService.java +vpd-backoffice/src/main/resources/templates/mcp-sse.html ``` ## 최종 속도 측정 diff --git a/docs/reports/2026-07-23-hmm-leave-team-vpd-verification.md b/docs/reports/2026-07-23-hmm-leave-team-vpd-verification.md index bba825a..d9573b3 100644 --- a/docs/reports/2026-07-23-hmm-leave-team-vpd-verification.md +++ b/docs/reports/2026-07-23-hmm-leave-team-vpd-verification.md @@ -8,7 +8,7 @@ ## 적용 결과 -`sql/adb/72_hmm_leave_team_vpd.sql`을 적용해 다음 구성을 활성화했다. +`database/adb/72_hmm_leave_team_vpd.sql`을 적용해 다음 구성을 활성화했다. | 구성 | 결과 | |---|---| diff --git a/docs/reports/2026-07-23-hmm-portal-full-browser-audit.md b/docs/reports/2026-07-23-hmm-portal-full-browser-audit.md index b499390..11d6312 100644 --- a/docs/reports/2026-07-23-hmm-portal-full-browser-audit.md +++ b/docs/reports/2026-07-23-hmm-portal-full-browser-audit.md @@ -32,7 +32,7 @@ ## 이번에 제거한 결함 1. 감사로그가 KB PoC의 `POC_2` FGA 메타데이터를 조회하던 경로를 제거했다. -2. 감사 원천을 `ADMIN.HMM_ACCESS_AUDIT`으로 교체하고 렌더러를 `src/agent_console/audit.py`로 +2. 감사 원천을 `ADMIN.HMM_ACCESS_AUDIT`으로 교체하고 렌더러를 `ai-web-agent-console/ai_web_agent_console/audit.py`로 분리했다. 3. Python Thin driver가 암호화 `ewallet.pem`의 암호를 대화형으로 기다리던 연결을 ADB TLS 1521 서버 인증 풀로 교체했다. diff --git a/docs/runbooks/460-sqlcl-vpd-deploy-runbook.md b/docs/runbooks/460-sqlcl-vpd-deploy-runbook.md index 9cea05f..65fb9fc 100644 --- a/docs/runbooks/460-sqlcl-vpd-deploy-runbook.md +++ b/docs/runbooks/460-sqlcl-vpd-deploy-runbook.md @@ -25,9 +25,9 @@ SQLCL_BIN=/path/to/sql SQLCL_JAVA_HOME=/path/to/jdk "$SQLCL_BIN" "USER/PASSWORD@ SQLcl 안에서 실행: ```sql -@sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql +@database/adb/26_agent_ords_security_dynamic_vpd_filter.sql SHOW ERRORS FUNCTION cb_agent_doc_vpd_filter -@sql/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql +@database/adb/27_agent_ords_security_dynamic_vpd_filter_test.sql ``` 기대 결과: @@ -64,7 +64,7 @@ SQLCL_JAVA_HOME=/path/to/jdk \ 가장 단순한 롤백은 직전 Git revision의 `26_agent_ords_security_dynamic_vpd_filter.sql`을 다시 적용하는 것이다. ```bash -git show HEAD~1:sql/adb/26_agent_ords_security_dynamic_vpd_filter.sql > /tmp/previous-vpd-filter.sql +git show HEAD~1:database/adb/26_agent_ords_security_dynamic_vpd_filter.sql > /tmp/previous-vpd-filter.sql SQLCL_BIN=/path/to/sql SQLCL_JAVA_HOME=/path/to/jdk "$SQLCL_BIN" "USER/PASSWORD@TNS" ``` diff --git a/docs/runbooks/hmm-mcp-token-configuration.md b/docs/runbooks/hmm-mcp-token-configuration.md index 83bffc1..86e423e 100644 --- a/docs/runbooks/hmm-mcp-token-configuration.md +++ b/docs/runbooks/hmm-mcp-token-configuration.md @@ -151,7 +151,7 @@ BACKOFFICE_SELECT_AI_RUNTIME_DB_USERNAME=CB_ORDS BACKOFFICE_SELECT_AI_RUNTIME_DB_PASSWORD=<운영 secret> ``` -DB 구성 스크립트는 `sql/adb/73_hmm_mcp_vpd_runtime.sql`이다. 이 스크립트는 승인된 HMM +DB 구성 스크립트는 `database/adb/73_hmm_mcp_vpd_runtime.sql`이다. 이 스크립트는 승인된 HMM HR 객체에 대한 개별 `SELECT`와 handler package 실행 권한만 부여하며 `EXEMPT ACCESS POLICY`는 부여하지 않는다. diff --git a/poc4_active_source_20260714/.env.sample b/poc4_active_source_20260714/.env.sample deleted file mode 100644 index c25caae..0000000 --- a/poc4_active_source_20260714/.env.sample +++ /dev/null @@ -1,131 +0,0 @@ -# PoC_4 runtime environment template -# -# 사용법: -# cp .env.sample .env -# chmod 600 .env -# 편집 후 scripts/poc4/start_*_nohup.sh 로 기동합니다. - -# 제품별 화면 값: 기본값은 config/app_profile.json, 아래 값이 있으면 환경변수가 우선합니다. -# AGENT_CONSOLE_NAME=HMM AI 업무 에이전트 -# AGENT_CONSOLE_SHORT_NAME=HMM -# AGENT_CONSOLE_PAGE_TITLE=HMM AI 업무 에이전트 -# AGENT_CONSOLE_PAGE_ICON=⛴️ -# AGENT_CONSOLE_HEADER_TITLE=AI 업무 에이전트 -# AGENT_CONSOLE_HEADER_DESCRIPTION=사용자 권한에 맞는 업무 질의와 보안 관리 기능을 제공합니다. -# AGENT_CONSOLE_LOGIN_KICKER=HMM SHIPPING & LOGISTICS DEMO -# AGENT_CONSOLE_LOGIN_TITLE=HMM AI 업무 에이전트 -# AGENT_CONSOLE_LOGIN_DESCRIPTION=사용자 인증 후 해운·물류 AI 질의와 보안 관리 기능을 이용할 수 있습니다. -# AGENT_CONSOLE_LOGIN_FOOTER=인증된 DEMO 사용자만 접근할 수 있습니다. -# AGENT_CONSOLE_PRIMARY_COLOR=#003b70 -# AGENT_CONSOLE_TEXT_COLOR=#172b3a -# AGENT_CONSOLE_MUTED_COLOR=#667785 -# AGENT_CONSOLE_BORDER_COLOR=#dfe7ed -# -# 실제 token, password, OCID, wallet 경로는 이 샘플에 기록하지 않습니다. -# 이 파일은 Bash에서 읽히므로 KEY=value 형식만 사용하고 명령 치환은 넣지 않습니다. - -# ----------------------------------------------------------------------------- -# MCP runtime (현재 PoC_4가 공유하는 PoC_3 호환 환경변수 계약) -# ----------------------------------------------------------------------------- -POC3_MCP_PROVIDER=custom_python -POC3_MCP_BASE_URL=http://127.0.0.1:8500 -POC3_MCP_AUTH_MODE=bearer -POC3_MCP_TOKEN= -# HMM MCP gateway token. 실제 값은 배포 서버 .env에만 둡니다. -HMM_MCP_BEARER_TOKEN= -POC3_MCP_TIMEOUT_SECONDS=30 -POC3_MCP_FALLBACK_TO_MOCK=false -POC3_MCP_LIVE_SMOKE=false - -# MCP server registry -# 실제 서버 URL/token 값은 JSON에 직접 넣지 않고 위 환경변수 이름을 참조합니다. -# 사용 전 config/mcp_servers.sample.json을 아래 파일명으로 복사해 조정합니다. -POC4_MCP_SERVERS_FILE=config/mcp_servers.json -POC4_MCP_DEFAULT_SERVER_ID=hmm_hr_mcp - -# MCP discovery UI conversation history store -# 기본값: /home/opc/poc_4/data/poc4_mcp_chat.sqlite3 -POC4_CHAT_DB_PATH=data/poc4_mcp_chat.sqlite3 - -# ----------------------------------------------------------------------------- -# Local trace / optional LangSmith metadata -# ----------------------------------------------------------------------------- -POC3_TRACE_MODE=local -POC3_TRACE_UI_ENABLED=true -LANGSMITH_TRACING=false -LANGSMITH_API_KEY= -LANGSMITH_PROJECT=kb-aidp-poc4 - -# ----------------------------------------------------------------------------- -# PoC_4 UI ports -# 현재 VM 기본 포트만 사용합니다. 공식 포트 전환은 .env만으로 허용되지 않으며 -# POC4_ALLOW_OFFICIAL_PORTS=1을 기동 명령의 환경에 별도로 지정해야 합니다. -# ----------------------------------------------------------------------------- -POC4_LANGGRAPH_UI_PORT=8612 -POC4_AGENT_TEAM_UI_PORT=8613 -POC4_LANGGRAPH_TC_UI_PORT=8622 -POC4_AGENT_TEAM_TC_UI_PORT=8623 - -# ----------------------------------------------------------------------------- -# OCI Generative AI -# compartment ID는 배포 환경의 값을 입력합니다. API key/private key 원문은 넣지 -# 않고 OCI config file 또는 instance/resource principal을 사용합니다. -# ----------------------------------------------------------------------------- -OCI_AUTH_TYPE=config_file -OCI_CONFIG_FILE=~/.oci/config -OCI_PROFILE=DEFAULT -OCI_GENAI_COMPARTMENT_ID= - -# 모델 route는 config/poc3_model_profiles.json의 검증된 기본값을 사용합니다. -# 배포 환경에서 route를 바꿔야 할 때만 아래 항목의 주석을 해제합니다. -# POC3_LLM_GPT55_OCI_MODEL_ID=openai.gpt-5.5 -# POC3_LLM_GPT55_OCI_REGION=us-chicago-1 -# POC3_LLM_GPT55_OCI_ENDPOINT=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com -# POC3_LLM_GPT54_MINI_OCI_MODEL_ID=openai.gpt-5.4-mini -# POC3_LLM_GPT54_MINI_OCI_REGION=us-chicago-1 -# POC3_LLM_GPT54_MINI_OCI_ENDPOINT=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com -# POC3_LLM_GROK43_MODEL_ID=xai.grok-4.3 -# POC3_LLM_GROK43_REGION=us-chicago-1 -# POC3_LLM_GROK43_ENDPOINT=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com -# 화면 LLM 모델 선택의 기본값입니다. -# 선택 모델은 후속 질문 정리, 실행 방식 판단, MCP tool 라우팅, -# Agent planning, 최종 답변 합성에 사용됩니다. -# 실패 시 애플리케이션 기본 fallback인 gpt54_mini_oci로 재시도합니다. -POC4_COMPLEX_REASONING_MODEL_PROFILE=grok43 - -# ----------------------------------------------------------------------------- -# Audit / security evidence DB connection -# ----------------------------------------------------------------------------- -# VPD 개발본 배포 서버 기준: -# - DB 접속 secret은 /home/opc/kbmcp/.env 에 둡니다. -# - DB wallet은 /home/opc/wallet/kbaipoc 를 사용합니다. -# 이 샘플에는 DB password, wallet password, token 원문을 넣지 않습니다. -POC4_AUDIT_DB_ENV_FILE=/home/opc/kbmcp/.env -ORACLE_WALLET_DIR=/home/opc/wallet/kbaipoc - -# ----------------------------------------------------------------------------- -# Direct Oracle DB administration tools (목표 계약) -# Streamlit/MCP-only 배포에서는 모두 비워 둡니다. 현재 launcher는 .env 전체를 UI -# process에 export하므로 역할별 설정 loader가 구현되기 전에는 이 파일에 DB secret을 -# 채우지 않습니다. DB migration/audit 전용 process environment에서만 주입합니다. -# ----------------------------------------------------------------------------- -POC4_DB_ADMIN_ENABLED=false -POC4_DB_USERNAME= -POC4_DB_PASSWORD= -POC4_DB_DSN= -POC4_DB_WALLET_DIR= -POC4_DB_WALLET_PASSWORD= -POC4_DB_EXPECTED_SCHEMA= -POC4_DB_CLIENT_LIB_DIR= -POC4_DB_MODE=thick -POC4_DB_CONNECT_TIMEOUT_SECONDS=60 -POC4_DB_CALL_TIMEOUT_MS=120000 - -# 신규 tenancy 이관 preflight에서만 사용하며 값 자체는 출력하지 않습니다. -POC4_EXPECTED_TENANCY_ID= - -# 다음 값은 복제된 .env가 보안/프로세스 제어를 바꾸지 못하도록 launcher 호출자만 -# 지정할 수 있습니다. 이 파일에 활성 값으로 추가하지 않습니다. -# POC4_BIND_ADDRESS=0.0.0.0 -# POC4_ALLOW_OFFICIAL_PORTS=1 -# POC4_MANAGED_FOREGROUND=1 diff --git a/poc4_active_source_20260714/SOURCE_README.md b/poc4_active_source_20260714/SOURCE_README.md deleted file mode 100644 index e86baa2..0000000 --- a/poc4_active_source_20260714/SOURCE_README.md +++ /dev/null @@ -1,65 +0,0 @@ -# HMM AI 업무 에이전트 소스 - -생성일: 2026-07-14 GMT - -이 폴더는 HMM AI 업무 에이전트 실행 소스다. `poc4`라는 디렉터리·환경변수 접두어는 -기존 배포 호환성을 위한 레거시 경로이며, 서비스의 정식 이름은 **HMM AI 업무 에이전트**다. - -## Entrypoint - -```bash -streamlit run apps/poc4/mcp_discovery_ui.py --server.address 0.0.0.0 --server.port 8622 -``` - -## Runtime - -- Python 3.11 이상을 사용합니다. -- 이 개발 서버의 기본 `python3`가 3.6 계열이면 문법 검증이 실패합니다. -- 배포 서버는 `/opt/hmm-poc4/.venv`와 Python 3.11을 사용합니다. -- OCI Generative AI SDK 인증은 배포 서버의 `/home/opc/.oci/config` `DEFAULT` profile을 사용합니다. - private key와 compartment OCID는 Git에 저장하지 않고 서버의 `~/.oci`와 `.env`에서만 관리합니다. - -## Deployment DB reference - -- VPD 개발본 배포 서버의 DB 접속 정보는 `/home/opc/kbmcp/.env`를 사용합니다. -- DB wallet directory는 `/home/opc/wallet/kbaipoc`를 사용합니다. -- 이 저장소에는 wallet 파일, DB password, wallet password, 실제 VPD token 원문을 넣지 않습니다. - -## Included - -- `apps/poc4/mcp_discovery_ui.py` -- `src/agent_console/presentation.py` -- `src/agent_console/profile.py` -- `src/mcp_tool_router.py` -- `src/oci_genai_sdk.py` -- `src/poc3/model_registry.py` -- `src/poc3/questions.py` -- `config/mcp_servers.json` -- `config/poc3_model_profiles.json` -- `config/vpd_token_presets.json` -- `config/hmm_demo_scenarios.json` — 화면에 표시할 데모 질문. 코드 수정 없이 이 파일만 변경한다. -- `config/app_profile.json` — 제품명, 문구, 아이콘, 색상을 지정하는 제품 profile -- `.env.sample` -- `requirements.txt` -- `requirements-langgraph.txt` -- `scripts/poc4/start_8622_langgraph_tc_ui_nohup.sh` -- `scripts/poc4/status_8622_langgraph_tc_ui_nohup.sh` - -## Security note - -- 실제 `.env`는 복사하지 않았습니다. `.env.sample`을 기준으로 새로 만드세요. -- `config/vpd_token_presets.json`은 파일명 호환성을 유지한 HMM **데모 사용자** 목록입니다. - 사용자별 `mcp_token_env`는 배포 환경의 `HMM_MCP_BEARER_TOKEN`만 참조하며, token 원문은 JSON·Git에 저장하지 않습니다. -- 대화 DB `data/poc4_mcp_chat.sqlite3`는 개인정보/대화 내용이 포함될 수 있어 복사하지 않았습니다. -- MCP 호출 상세의 JSON/code 영역은 공통 presentation CSS에서 밝은 배경과 어두운 글자를 함께 지정합니다. - -## 구성 원칙 - -- `config/`: 운영자가 바꿀 수 있는 MCP, 모델, HMM 데모 사용자 preset, 데모 질문 JSON -- `src/poc4/`: Streamlit과 분리 가능한 화면 보조 모듈 및 도메인 로직 -- `apps/poc4/`: 레거시 호환 entrypoint. 화면 조립과 사용자 상호작용만 담당하도록 점진적으로 축소 -- `tests/`: 설정 파일과 순수 Python 모듈의 회귀 검증 - -다른 프로젝트에 적용할 때는 scenario/MCP JSON만 교체하고, 제품명·설명·색상은 -`AGENT_CONSOLE_*` 환경변수로 지정합니다. 환경변수가 없을 때만 `config/app_profile.json`의 -중립 기본값을 사용합니다. diff --git a/poc4_active_source_20260714/poc4_active_source_20260714.tar.gz b/poc4_active_source_20260714/poc4_active_source_20260714.tar.gz deleted file mode 100644 index 9df851e..0000000 Binary files a/poc4_active_source_20260714/poc4_active_source_20260714.tar.gz and /dev/null differ diff --git a/poc4_active_source_20260714/scripts/poc4/start_8622_langgraph_tc_ui_nohup.sh b/poc4_active_source_20260714/scripts/poc4/start_8622_langgraph_tc_ui_nohup.sh deleted file mode 100755 index 58b03e4..0000000 --- a/poc4_active_source_20260714/scripts/poc4/start_8622_langgraph_tc_ui_nohup.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -source "/home/opc/poc_4/scripts/poc4/runtime_ui_lib.sh" -poc4_start_service "8622_langgraph_tc_ui" "/home/opc/poc_4/scripts/poc4/run_8622_langgraph_tc_ui.sh" "apps/poc4/langgraph_tc_ui.py" diff --git a/poc4_active_source_20260714/scripts/poc4/status_8622_langgraph_tc_ui_nohup.sh b/poc4_active_source_20260714/scripts/poc4/status_8622_langgraph_tc_ui_nohup.sh deleted file mode 100755 index 565daad..0000000 --- a/poc4_active_source_20260714/scripts/poc4/status_8622_langgraph_tc_ui_nohup.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -source "/home/opc/poc_4/scripts/poc4/runtime_ui_lib.sh" -poc4_status_service "8622_langgraph_tc_ui" "apps/poc4/langgraph_tc_ui.py" diff --git a/poc4_active_source_20260714/src/poc4/__init__.py b/poc4_active_source_20260714/src/poc4/__init__.py deleted file mode 100644 index ae16b2b..0000000 --- a/poc4_active_source_20260714/src/poc4/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""PoC4 UI support modules.""" diff --git a/run.sh b/run.sh index f7a3d2b..ea11a84 100755 --- a/run.sh +++ b/run.sh @@ -131,48 +131,48 @@ do_source() { PGPASSWORD="$PG_PASSWORD" psql \ -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" \ -v ON_ERROR_STOP=1 \ - -f "$ROOT/sql/source/postgres_setup.sql" + -f "$ROOT/database/source/postgres_setup.sql" ok "Postgres source 준비 완료" log "-- MySQL ($MY_HOST:$MY_PORT/$MY_DB) --" mysql \ -h "$MY_HOST" -P "$MY_PORT" -u "$MY_USER" "-p${MY_PASSWORD}" \ - "$MY_DB" < "$ROOT/sql/source/mysql_setup.sql" + "$MY_DB" < "$ROOT/database/source/mysql_setup.sql" ok "MySQL source 준비 완료" } do_adb() { log "=== adb: ADB 측 cleanup → dblinks → perm/ctx/view/policy → end_users ===" - run_sqlplus_file "$ROOT/sql/adb/00_cleanup.sql" - run_sqlplus_file "$ROOT/sql/adb/01_dblinks.sql" - run_sqlplus_file "$ROOT/sql/adb/02_perm_tables.sql" - run_sqlplus_file "$ROOT/sql/adb/03_seed.sql" - run_sqlplus_file "$ROOT/sql/adb/04_secure_ctx.sql" - run_sqlplus_file "$ROOT/sql/adb/05_views.sql" - run_sqlplus_file "$ROOT/sql/adb/06_policy.sql" - run_sqlplus_file "$ROOT/sql/adb/06a_redaction.sql" - run_sqlplus_file "$ROOT/sql/adb/07_end_users.sql" + run_sqlplus_file "$ROOT/database/adb/00_cleanup.sql" + run_sqlplus_file "$ROOT/database/adb/01_dblinks.sql" + run_sqlplus_file "$ROOT/database/adb/02_perm_tables.sql" + run_sqlplus_file "$ROOT/database/adb/03_seed.sql" + run_sqlplus_file "$ROOT/database/adb/04_secure_ctx.sql" + run_sqlplus_file "$ROOT/database/adb/05_views.sql" + run_sqlplus_file "$ROOT/database/adb/06_policy.sql" + run_sqlplus_file "$ROOT/database/adb/06a_redaction.sql" + run_sqlplus_file "$ROOT/database/adb/07_end_users.sql" ok "ADB setup 완료" } do_tests() { log "=== tests: 4-user access matrix 검증 ===" - run_sqlplus_as vpduser_my "$VPDUSER_MY_PASSWORD" "$ROOT/sql/adb/08_tests_user_my.sql" - run_sqlplus_as vpduser_pg "$VPDUSER_PG_PASSWORD" "$ROOT/sql/adb/09_tests_user_pg.sql" - run_sqlplus_as vpduser_both "$VPDUSER_BOTH_PASSWORD" "$ROOT/sql/adb/10_tests_user_both.sql" - run_sqlplus_as vpduser_none "$VPDUSER_NONE_PASSWORD" "$ROOT/sql/adb/11_tests_user_none.sql" + run_sqlplus_as vpduser_my "$VPDUSER_MY_PASSWORD" "$ROOT/database/adb/08_tests_user_my.sql" + run_sqlplus_as vpduser_pg "$VPDUSER_PG_PASSWORD" "$ROOT/database/adb/09_tests_user_pg.sql" + run_sqlplus_as vpduser_both "$VPDUSER_BOTH_PASSWORD" "$ROOT/database/adb/10_tests_user_both.sql" + run_sqlplus_as vpduser_none "$VPDUSER_NONE_PASSWORD" "$ROOT/database/adb/11_tests_user_none.sql" ok "4명 (MY / PG / BOTH / NONE) 테스트 실행 완료" } do_audit() { log "=== audit: admin 으로 정책 / 뷰 / 매트릭스 점검 ===" - run_sqlplus_file "$ROOT/sql/adb/12_tests_admin_audit.sql" + run_sqlplus_file "$ROOT/database/adb/12_tests_admin_audit.sql" ok "audit 완료" } do_backoffice_support() { log "=== backoffice-support: Spring Boot 백오피스 보조 객체 생성 ===" - run_sqlplus_file "$ROOT/sql/adb/25_agent_ords_security_backoffice_support.sql" + run_sqlplus_file "$ROOT/database/adb/25_agent_ords_security_backoffice_support.sql" ok "backoffice-support 완료" } @@ -191,7 +191,7 @@ do_backoffice_env_check() { do_teardown() { log "=== teardown: ADB 측 객체 + dblink/credential 정리 ===" warn "원격 PG/MySQL 의 customers 테이블은 건드리지 않습니다 (수동으로 DROP 하세요)" - run_sqlplus_file "$ROOT/sql/adb/00_cleanup.sql" + run_sqlplus_file "$ROOT/database/adb/00_cleanup.sql" ok "teardown 완료" } @@ -209,24 +209,24 @@ do_dds_prereq() { do_dds_setup() { log "=== dds-setup: 13_dds_variant.sql (END USER + DATA ROLE + DATA GRANT) ===" # 멱등성: 부분 적용 상태를 먼저 청소한 뒤 재생성 - run_sqlplus_file "$ROOT/sql/adb/15_dds_cleanup.sql" - run_sqlplus_file "$ROOT/sql/adb/13_dds_variant.sql" + run_sqlplus_file "$ROOT/database/adb/15_dds_cleanup.sql" + run_sqlplus_file "$ROOT/database/adb/13_dds_variant.sql" ok "DDS 셋업 완료" } do_dds_tests() { log "=== dds-tests: 4-user (ddsuser_*) 매트릭스 검증 ===" # END USER 이름이 lowercase 라 사용자명을 큰따옴표로 감싸서 전달. - run_sqlplus_as '"ddsuser_my"' "$DDSUSER_MY_PASSWORD" "$ROOT/sql/adb/14_tests_dds_user.sql" - run_sqlplus_as '"ddsuser_pg"' "$DDSUSER_PG_PASSWORD" "$ROOT/sql/adb/14_tests_dds_user.sql" - run_sqlplus_as '"ddsuser_both"' "$DDSUSER_BOTH_PASSWORD" "$ROOT/sql/adb/14_tests_dds_user.sql" - run_sqlplus_as '"ddsuser_none"' "$DDSUSER_NONE_PASSWORD" "$ROOT/sql/adb/14_tests_dds_user.sql" + run_sqlplus_as '"ddsuser_my"' "$DDSUSER_MY_PASSWORD" "$ROOT/database/adb/14_tests_dds_user.sql" + run_sqlplus_as '"ddsuser_pg"' "$DDSUSER_PG_PASSWORD" "$ROOT/database/adb/14_tests_dds_user.sql" + run_sqlplus_as '"ddsuser_both"' "$DDSUSER_BOTH_PASSWORD" "$ROOT/database/adb/14_tests_dds_user.sql" + run_sqlplus_as '"ddsuser_none"' "$DDSUSER_NONE_PASSWORD" "$ROOT/database/adb/14_tests_dds_user.sql" ok "DDS 4명 (MY / PG / BOTH / NONE) 테스트 실행 완료" } do_dds_teardown() { log "=== dds-teardown: DDS 객체만 정리 (VPD 데모는 보존) ===" - run_sqlplus_file "$ROOT/sql/adb/15_dds_cleanup.sql" + run_sqlplus_file "$ROOT/database/adb/15_dds_cleanup.sql" ok "DDS teardown 완료" } diff --git a/scripts/configure-backoffice-https-vm.sh b/scripts/configure-backoffice-https-vm.sh index 40a37bc..3eb7631 100755 --- a/scripts/configure-backoffice-https-vm.sh +++ b/scripts/configure-backoffice-https-vm.sh @@ -112,7 +112,7 @@ render_caddyfile() { gsub(/{{TLS_OPTIONS}}/, tls_options) print } - ' "$ROOT/deploy/caddy/Caddyfile.template" > "$output" + ' "$ROOT/deploy/vpd-backoffice/caddy/Caddyfile.template" > "$output" } build_ssh_args() { @@ -264,7 +264,7 @@ INSPECT log "Caddy candidate 업로드" ssh "${SSH_ARGS[@]}" "$HOST" "mkdir -p \"$remote_stage\"" - cp "$ROOT/deploy/caddy/install-caddy-config.sh" "$tmp_dir/install-caddy-config.sh" + cp "$ROOT/deploy/vpd-backoffice/caddy/install-caddy-config.sh" "$tmp_dir/install-caddy-config.sh" tar -C "$tmp_dir" -czf - Caddyfile install-caddy-config.sh \ | ssh "${SSH_ARGS[@]}" "$HOST" "tar -C \"$remote_stage\" -xzf - && chmod 700 \"$remote_stage/install-caddy-config.sh\"" diff --git a/scripts/deploy-backoffice-vm.sh b/scripts/deploy-backoffice-vm.sh index 5fc2451..393c242 100755 --- a/scripts/deploy-backoffice-vm.sh +++ b/scripts/deploy-backoffice-vm.sh @@ -32,7 +32,7 @@ Production transport defaults are always applied on the VM: HTTPS required, Secure/HttpOnly/SameSite session cookie. The script uploads: - - target/*.jar as app.jar + - vpd-backoffice/target/*.jar as app.jar - .env rewritten for the VM wallet path - TNS_ADMIN wallet directory - start.sh / stop.sh / status.sh @@ -127,11 +127,11 @@ ssh "${SSH_ARGS[@]}" "$HOST" 'printf "connected %s %s\n" "$(hostname)" "$(whoami if [[ "$SKIP_BUILD" != "Y" ]]; then log "jar 빌드" - mvn -DskipTests package + mvn -f "$ROOT/vpd-backoffice/pom.xml" -DskipTests package fi -JAR_PATH="$(find "$ROOT/target" -maxdepth 1 -type f -name '*.jar' ! -name '*sources.jar' ! -name '*javadoc.jar' | sort | tail -n 1)" -[[ -n "$JAR_PATH" && -f "$JAR_PATH" ]] || die "target jar를 찾을 수 없습니다. mvn package를 먼저 실행하세요." +JAR_PATH="$(find "$ROOT/vpd-backoffice/target" -maxdepth 1 -type f -name '*.jar' ! -name '*sources.jar' ! -name '*javadoc.jar' | sort | tail -n 1)" +[[ -n "$JAR_PATH" && -f "$JAR_PATH" ]] || die "vpd-backoffice target jar를 찾을 수 없습니다. 배포 빌드를 먼저 실행하세요." TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/vpd-backoffice-deploy.XXXXXX")" cleanup() { diff --git a/scripts/deploy-dds-backoffice-local.sh b/scripts/deploy-dds-backoffice-local.sh index b5bc50b..99bf0b0 100755 --- a/scripts/deploy-dds-backoffice-local.sh +++ b/scripts/deploy-dds-backoffice-local.sh @@ -13,10 +13,10 @@ if [[ -f /home/opc/apps/vpd-backoffice/.env ]]; then fi cd "$ROOT" -mvn -DskipTests package +mvn -f "$ROOT/vpd-backoffice/pom.xml" -DskipTests package mvn install:install-file \ - -Dfile="$ROOT/target/vpd-permission-backoffice-0.1.0-SNAPSHOT.jar.original" \ - -DpomFile="$ROOT/pom.xml" + -Dfile="$ROOT/vpd-backoffice/target/vpd-permission-backoffice-0.1.0-SNAPSHOT.jar.original" \ + -DpomFile="$ROOT/vpd-backoffice/pom.xml" cd "$ROOT/dds-backoffice" mvn -DskipTests package diff --git a/scripts/provision-dds-token-search.sh b/scripts/provision-dds-token-search.sh index 74c9f29..322902f 100644 --- a/scripts/provision-dds-token-search.sh +++ b/scripts/provision-dds-token-search.sh @@ -15,8 +15,8 @@ connect="${DDS_ADMIN_USERNAME}/${DDS_ADMIN_PASSWORD}@${DDS_ADMIN_DB_URL}" sqlplus -s "$connect" < None: + for relative in ( + "vpd-backoffice/pom.xml", + "vpd-backoffice/src/main", + "ai-web-agent-console/app.py", + "ai-web-agent-console/ai_web_agent_console", + "dds-backoffice/pom.xml", + "database/adb", + "deploy/vpd-backoffice", + "deploy/ai-web-agent-console", + ): + self.assertTrue((ROOT / relative).exists(), relative) + + def test_ambiguous_legacy_roots_are_absent(self) -> None: + for relative in ( + "pom.xml", + "src", + "sql", + "poc4_active_source_20260714", + ): + self.assertFalse((ROOT / relative).exists(), relative) + + def test_console_has_one_named_python_package(self) -> None: + console = ROOT / "ai-web-agent-console" + self.assertFalse((console / "src").exists()) + self.assertFalse((console / "apps").exists()) + self.assertTrue((console / "ai_web_agent_console" / "__init__.py").is_file()) + + source = "\n".join( + path.read_text(encoding="utf-8") + for path in (console / "ai_web_agent_console").glob("*.py") + ) + source += (console / "app.py").read_text(encoding="utf-8") + for forbidden in ( + "from src.", + "src.poc3", + "src.poc4", + "src.agent_console", + "apps/poc4", + ): + self.assertNotIn(forbidden, source) + + def test_vpd_backoffice_packages_database_sql(self) -> None: + pom = (ROOT / "vpd-backoffice" / "pom.xml").read_text(encoding="utf-8") + self.assertIn("../database/adb", pom) + self.assertNotIn("sql/adb", pom) + + +if __name__ == "__main__": + unittest.main() diff --git a/pom.xml b/vpd-backoffice/pom.xml similarity index 95% rename from pom.xml rename to vpd-backoffice/pom.xml index eefd731..d49518b 100644 --- a/pom.xml +++ b/vpd-backoffice/pom.xml @@ -92,11 +92,11 @@ src/main/resources - - sql/adb - sql/adb + ../database/adb + database/adb **/*.sql diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/VpdBackofficeApplication.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/VpdBackofficeApplication.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/VpdBackofficeApplication.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/VpdBackofficeApplication.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/AppConfig.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/AppConfig.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/AppConfig.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/AppConfig.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/BackofficeProperties.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/BackofficeProperties.java similarity index 97% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/BackofficeProperties.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/BackofficeProperties.java index e5edcd2..3b31783 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/config/BackofficeProperties.java +++ b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/BackofficeProperties.java @@ -82,7 +82,8 @@ public record BackofficeProperties( String profile, String runtimeDbUrl, String runtimeDbUsername, - String runtimeDbPassword + String runtimeDbPassword, + String queryContractFile ) { public boolean configured() { diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/CatalogProperties.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/CatalogProperties.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/CatalogProperties.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/CatalogProperties.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/DbPoolWarmup.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/DbPoolWarmup.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/DbPoolWarmup.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/DbPoolWarmup.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/MaskingProperties.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/MaskingProperties.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/MaskingProperties.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/MaskingProperties.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/McpProperties.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/McpProperties.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/McpProperties.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/McpProperties.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/OrdsClientConfig.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/OrdsClientConfig.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/OrdsClientConfig.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/OrdsClientConfig.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/ProductProperties.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/ProductProperties.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/ProductProperties.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/ProductProperties.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/SecurityConfig.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/SecurityConfig.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/SecurityConfig.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/SecurityConfig.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/config/SecuritySqlScriptProperties.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/SecuritySqlScriptProperties.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/config/SecuritySqlScriptProperties.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/config/SecuritySqlScriptProperties.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/audit/AuditEvent.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/audit/AuditEvent.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/audit/AuditEvent.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/audit/AuditEvent.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/EffectiveMatrixView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/EffectiveMatrixView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/EffectiveMatrixView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/EffectiveMatrixView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/GroupEffectiveAccessView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/GroupEffectiveAccessView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/GroupEffectiveAccessView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/GroupEffectiveAccessView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/RoleEffectiveImpactView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/RoleEffectiveImpactView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/RoleEffectiveImpactView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/RoleEffectiveImpactView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/UserEffectiveAccessView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/UserEffectiveAccessView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/UserEffectiveAccessView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/effective/UserEffectiveAccessView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/AppGroup.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/AppGroup.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/group/AppGroup.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/AppGroup.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupCreateCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupCreateCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupCreateCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupCreateCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupRoleView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupRoleView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupRoleView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupRoleView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupUserView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupUserView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupUserView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/group/GroupUserView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/ColumnMaskingRule.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/ColumnMaskingRule.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/ColumnMaskingRule.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/ColumnMaskingRule.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingPolicyStatus.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingPolicyStatus.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingPolicyStatus.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingPolicyStatus.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingRule.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingRule.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingRule.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingRule.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingRuleCreateCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingRuleCreateCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingRuleCreateCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingRuleCreateCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingTemplate.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingTemplate.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingTemplate.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingTemplate.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/UserMaskingRule.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/UserMaskingRule.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/UserMaskingRule.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/masking/UserMaskingRule.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpChatbotResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpChatbotResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpChatbotResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpChatbotResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpClientDemoResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpClientDemoResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpClientDemoResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpClientDemoResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpReasoningCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpReasoningCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpReasoningCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpReasoningCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpReasoningResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpReasoningResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpReasoningResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpReasoningResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpToolView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpToolView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpToolView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/mcp/McpToolView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/operation/OperationHealthSummary.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/operation/OperationHealthSummary.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/operation/OperationHealthSummary.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/operation/OperationHealthSummary.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/operation/OperationStatusRow.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/operation/OperationStatusRow.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/operation/OperationStatusRow.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/operation/OperationStatusRow.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsHandlerUpdateCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsHandlerUpdateCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsHandlerUpdateCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsHandlerUpdateCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsHandlerView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsHandlerView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsHandlerView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsHandlerView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsObjectHandlerResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsObjectHandlerResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsObjectHandlerResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/ords/OrdsObjectHandlerResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/AppRole.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/AppRole.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/AppRole.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/AppRole.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionRule.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionRule.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionRule.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionRule.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionSet.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionSet.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionSet.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionSet.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionSetCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionSetCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionSetCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionSetCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/RuleCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/RuleCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/RuleCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/permission/RuleCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/FgaExecutionEvidence.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/FgaExecutionEvidence.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/FgaExecutionEvidence.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/FgaExecutionEvidence.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeStatus.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeStatus.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeStatus.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeStatus.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/SqlExecutionCandidate.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/SqlExecutionCandidate.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/SqlExecutionCandidate.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/SqlExecutionCandidate.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/SqlExecutionEvidence.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/SqlExecutionEvidence.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/SqlExecutionEvidence.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/probe/SqlExecutionEvidence.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/DatabaseObjectOption.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/DatabaseObjectOption.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/DatabaseObjectOption.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/DatabaseObjectOption.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedColumn.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedColumn.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedColumn.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedColumn.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedObject.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedObject.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedObject.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedObject.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedObjectCreateCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedObjectCreateCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedObjectCreateCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedObjectCreateCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaActionResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaActionResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaActionResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaActionResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaPreflightCheck.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaPreflightCheck.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaPreflightCheck.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaPreflightCheck.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaPreflightView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaPreflightView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaPreflightView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schema/SchemaPreflightView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaAnnotation.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaAnnotation.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaAnnotation.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaAnnotation.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaMetadataColumn.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaMetadataColumn.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaMetadataColumn.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaMetadataColumn.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaMetadataView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaMetadataView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaMetadataView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/schemametadata/SchemaMetadataView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScript.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScript.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScript.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScript.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScriptExplanation.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScriptExplanation.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScriptExplanation.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScriptExplanation.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScriptSummary.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScriptSummary.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScriptSummary.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/securityscript/SecuritySqlScriptSummary.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/setting/BackofficeSetting.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/setting/BackofficeSetting.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/setting/BackofficeSetting.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/setting/BackofficeSetting.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/stakeholder/StakeholderTokenSubject.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/stakeholder/StakeholderTokenSubject.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/stakeholder/StakeholderTokenSubject.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/stakeholder/StakeholderTokenSubject.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/structured/StructuredDataPreview.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/structured/StructuredDataPreview.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/structured/StructuredDataPreview.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/structured/StructuredDataPreview.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/structured/StructuredDataTable.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/structured/StructuredDataTable.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/structured/StructuredDataTable.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/structured/StructuredDataTable.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/BearerTokenRecord.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/BearerTokenRecord.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/token/BearerTokenRecord.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/BearerTokenRecord.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/IssuedToken.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/IssuedToken.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/token/IssuedToken.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/IssuedToken.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/TokenContextView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/TokenContextView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/token/TokenContextView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/TokenContextView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/TokenIssueCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/TokenIssueCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/token/TokenIssueCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/token/TokenIssueCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/AppUser.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/AppUser.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/user/AppUser.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/AppUser.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/UserCreateCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/UserCreateCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/user/UserCreateCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/UserCreateCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/UserRoleView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/UserRoleView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/user/UserRoleView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/user/UserRoleView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorChunk.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorChunk.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorChunk.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorChunk.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorIngestCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorIngestCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorIngestCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorIngestCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorIngestResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorIngestResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorIngestResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorIngestResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorKnowledgeSummary.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorKnowledgeSummary.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorKnowledgeSummary.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorKnowledgeSummary.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorQueryEmbedding.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorQueryEmbedding.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorQueryEmbedding.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorQueryEmbedding.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorSearchResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorSearchResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorSearchResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vector/VectorSearchResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdBulkApplyResult.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdBulkApplyResult.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdBulkApplyResult.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdBulkApplyResult.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdDescriptionNote.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdDescriptionNote.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdDescriptionNote.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdDescriptionNote.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionOption.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionOption.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionOption.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionOption.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionSource.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionSource.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionSource.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdFunctionSource.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdObjectFilterDetail.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdObjectFilterDetail.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdObjectFilterDetail.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdObjectFilterDetail.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyCreateCommand.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyCreateCommand.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyCreateCommand.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyCreateCommand.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyDetail.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyDetail.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyDetail.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyDetail.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyExplanation.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyExplanation.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyExplanation.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyExplanation.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptions.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptions.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptions.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptions.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyTemplateOption.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyTemplateOption.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyTemplateOption.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyTemplateOption.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdSchemaObjectOption.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdSchemaObjectOption.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdSchemaObjectOption.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdSchemaObjectOption.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdTargetView.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdTargetView.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdTargetView.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdTargetView.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/AuditMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/AuditMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/AuditMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/AuditMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/BearerTokenMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/BearerTokenMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/BearerTokenMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/BearerTokenMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/GroupMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/GroupMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/GroupMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/GroupMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/MaskingRuleMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/MaskingRuleMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/MaskingRuleMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/MaskingRuleMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/OperationStatusMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/OperationStatusMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/OperationStatusMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/OperationStatusMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/OrdsMetadataMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/OrdsMetadataMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/OrdsMetadataMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/OrdsMetadataMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/PermissionMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/PermissionMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/PermissionMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/PermissionMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/ProtectedObjectMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/ProtectedObjectMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/ProtectedObjectMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/ProtectedObjectMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/SettingMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/SettingMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/SettingMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/SettingMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/StakeholderMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/StakeholderMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/StakeholderMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/StakeholderMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/UserMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/UserMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/UserMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/UserMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/mapper/VpdPolicyMapper.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/AppException.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/AppException.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/AppException.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/AppException.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/AuditService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/AuditService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/AuditService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/AuditService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/BackofficeSchemaService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/BackofficeSchemaService.java similarity index 99% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/BackofficeSchemaService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/BackofficeSchemaService.java index a3b6603..173901d 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/service/BackofficeSchemaService.java +++ b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/BackofficeSchemaService.java @@ -709,8 +709,8 @@ public class BackofficeSchemaService { return """ -- sqlcl에서 실행할 HMM VPD runtime 준비 순서 -- 1. ADMIN으로 접속 - @sql/adb/25_agent_ords_security_backoffice_support.sql - @sql/adb/72_hmm_leave_team_vpd.sql + @database/adb/25_agent_ords_security_backoffice_support.sql + @database/adb/72_hmm_leave_team_vpd.sql -- 2. 비면제 업무 runtime 사용자에 필요한 최소 권한 CONNECT %s/@ diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/BearerTokenService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/BearerTokenService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/BearerTokenService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/BearerTokenService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/DataCatalog.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/DataCatalog.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/DataCatalog.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/DataCatalog.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/EffectiveMatrixService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/EffectiveMatrixService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/EffectiveMatrixService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/EffectiveMatrixService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentDataCatalog.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentDataCatalog.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentDataCatalog.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentDataCatalog.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentMaskingPolicyCatalog.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentMaskingPolicyCatalog.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentMaskingPolicyCatalog.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentMaskingPolicyCatalog.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentMcpToolCatalog.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentMcpToolCatalog.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentMcpToolCatalog.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/EnvironmentMcpToolCatalog.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationChangeNotifier.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationChangeNotifier.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationChangeNotifier.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationChangeNotifier.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationSynchronizer.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationSynchronizer.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationSynchronizer.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationSynchronizer.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/GroupService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/GroupService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/GroupService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/GroupService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmAiAgentToolRunner.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmAiAgentToolRunner.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/HmmAiAgentToolRunner.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmAiAgentToolRunner.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmKnowledgeSchemaInitializer.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmKnowledgeSchemaInitializer.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/HmmKnowledgeSchemaInitializer.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmKnowledgeSchemaInitializer.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmMcpBearerAuthenticator.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmMcpBearerAuthenticator.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/HmmMcpBearerAuthenticator.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmMcpBearerAuthenticator.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmMcpPrincipal.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmMcpPrincipal.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/HmmMcpPrincipal.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmMcpPrincipal.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmRuntimeSettingsInitializer.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmRuntimeSettingsInitializer.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/HmmRuntimeSettingsInitializer.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/HmmRuntimeSettingsInitializer.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmAiAgentToolRunner.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmAiAgentToolRunner.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmAiAgentToolRunner.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmAiAgentToolRunner.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmMcpBearerAuthenticator.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmMcpBearerAuthenticator.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmMcpBearerAuthenticator.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmMcpBearerAuthenticator.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicyCatalog.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicyCatalog.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicyCatalog.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicyCatalog.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicySynchronizer.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicySynchronizer.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicySynchronizer.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicySynchronizer.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicyTarget.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicyTarget.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicyTarget.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicyTarget.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingRuleService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingRuleService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingRuleService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/MaskingRuleService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/McpChatbotService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpChatbotService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/McpChatbotService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpChatbotService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/McpClientDemoService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpClientDemoService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/McpClientDemoService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpClientDemoService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/McpReasoningService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpReasoningService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/McpReasoningService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpReasoningService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/McpSseService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpSseService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/McpSseService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpSseService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolCatalog.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolCatalog.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolCatalog.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolCatalog.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolDefinition.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolDefinition.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolDefinition.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolDefinition.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolRegistry.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolRegistry.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolRegistry.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpToolRegistry.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/McpUnauthorizedException.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpUnauthorizedException.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/McpUnauthorizedException.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/McpUnauthorizedException.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/OciGenerativeAiChatClient.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OciGenerativeAiChatClient.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/OciGenerativeAiChatClient.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OciGenerativeAiChatClient.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/OpenAiCompatibleClient.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OpenAiCompatibleClient.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/OpenAiCompatibleClient.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OpenAiCompatibleClient.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/OperationStatusService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OperationStatusService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/OperationStatusService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OperationStatusService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/PermissionService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/PermissionService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/PermissionService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/PermissionService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/ProbeErrorClassifier.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/ProbeErrorClassifier.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/ProbeErrorClassifier.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/ProbeErrorClassifier.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/ProtectedObjectService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/ProtectedObjectService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/ProtectedObjectService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/ProtectedObjectService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/SchemaMetadataService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SchemaMetadataService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/SchemaMetadataService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SchemaMetadataService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptExplanationService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptExplanationService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptExplanationService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptExplanationService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptService.java similarity index 96% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptService.java index 1550c72..61dabdb 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptService.java +++ b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptService.java @@ -17,7 +17,7 @@ import org.springframework.stereotype.Service; /** * Read-only catalogue of security deployment SQL bundled from the Git-tracked - * sql/adb directory. Script ids are an application whitelist: request input + * database/adb directory. Script ids are an application whitelist: request input * never becomes a filesystem or classpath path. */ @Service @@ -64,7 +64,7 @@ public class SecuritySqlScriptService { } private String readSource(String fileName) { - ClassPathResource resource = new ClassPathResource("sql/adb/" + fileName); + ClassPathResource resource = new ClassPathResource("database/adb/" + fileName); try (InputStream input = resource.getInputStream()) { return new String(input.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException exception) { diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiAgentOrdsService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiAgentOrdsService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiAgentOrdsService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiAgentOrdsService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java similarity index 88% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java index ef5c239..453bb4c 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java +++ b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java @@ -7,6 +7,9 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import java.math.BigDecimal; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; @@ -63,7 +66,13 @@ public class SelectAiService { } String generatedSql = generate( - selectAi, vpdAwarePrompt(normalizedPrompt, principal)); + selectAi, + vpdAwarePrompt( + normalizedPrompt, + principal, + loadQueryContract(selectAi.queryContractFile()) + ) + ); String normalizedSql = validateReadOnlySql(generatedSql); QueryExecution execution = executeReadOnly( selectAi, normalizedSql, bearerToken.trim(), principal); @@ -94,8 +103,12 @@ public class SelectAiService { return normalized; } - private String vpdAwarePrompt(String prompt, HmmMcpPrincipal principal) { - return """ + private String vpdAwarePrompt( + String prompt, + HmmMcpPrincipal principal, + String queryContract + ) { + String basePrompt = """ Oracle SQL 생성 규칙: - 프로필에 승인된 HMM HR 객체만 사용하세요. - 단일 읽기 전용 SELECT 또는 WITH 문을 생성하세요. @@ -104,6 +117,37 @@ public class SelectAiService { 사용자 질문: %s """.formatted(principal.employeeCode(), prompt); + if (queryContract == null || queryContract.isBlank()) { + return basePrompt; + } + return basePrompt + """ + + 배포별 질의 계약(JSON): + 아래 계약 중 사용자 질문에 해당하는 항목만 적용하세요. 필수 필드, 계산, + 시간 기준, 누락 레코드 의미와 금지 fallback을 그대로 지키세요. + """ + queryContract; + } + + private String loadQueryContract(String configuredPath) { + if (configuredPath == null || configuredPath.isBlank()) { + return ""; + } + try { + Path path = Path.of(configuredPath.trim()).toAbsolutePath().normalize(); + if (!Files.isRegularFile(path)) { + throw new AppException("Select AI 질의 계약 파일을 찾을 수 없습니다: " + path); + } + long size = Files.size(path); + if (size < 2 || size > 128_000) { + throw new AppException("Select AI 질의 계약 파일 크기가 허용 범위를 벗어났습니다."); + } + return Files.readString(path, StandardCharsets.UTF_8); + } catch (AppException exception) { + throw exception; + } catch (Exception exception) { + throw new AppException("Select AI 질의 계약 파일을 읽지 못했습니다: " + + safeMessage(exception)); + } } private String generate( diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/SettingService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SettingService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/SettingService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/SettingService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/StructuredDataService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/StructuredDataService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/StructuredDataService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/StructuredDataService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/TokenGenerator.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/TokenGenerator.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/TokenGenerator.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/TokenGenerator.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/TokenHasher.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/TokenHasher.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/TokenHasher.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/TokenHasher.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/UserService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/UserService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/UserService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/UserService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/VectorChunker.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/VectorChunker.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/VectorChunker.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/VectorChunker.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/VectorKnowledgeService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/VectorKnowledgeService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/VectorKnowledgeService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/VectorKnowledgeService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyService.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdTokenAccessDeniedException.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdTokenAccessDeniedException.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/service/VpdTokenAccessDeniedException.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/service/VpdTokenAccessDeniedException.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/AppExceptionHandler.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/AppExceptionHandler.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/AppExceptionHandler.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/AppExceptionHandler.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/DashboardController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/DashboardController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/DashboardController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/DashboardController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/EffectiveMatrixController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/EffectiveMatrixController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/EffectiveMatrixController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/EffectiveMatrixController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/GroupController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/GroupController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/GroupController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/GroupController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/LoginController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/LoginController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/LoginController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/LoginController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/MaskingRuleController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/MaskingRuleController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/MaskingRuleController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/MaskingRuleController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/McpChatbotController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/McpChatbotController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/McpChatbotController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/McpChatbotController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/McpClientDemoController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/McpClientDemoController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/McpClientDemoController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/McpClientDemoController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/McpReasoningController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/McpReasoningController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/McpReasoningController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/McpReasoningController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/McpSseController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/McpSseController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/McpSseController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/McpSseController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/OperationStatusController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/OperationStatusController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/OperationStatusController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/OperationStatusController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/OrdsHandlerController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/OrdsHandlerController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/OrdsHandlerController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/OrdsHandlerController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/PermissionController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/PermissionController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/PermissionController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/PermissionController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/ProbeController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/ProbeController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/ProbeController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/ProbeController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/ProductModelAdvice.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/ProductModelAdvice.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/ProductModelAdvice.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/ProductModelAdvice.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/ProtectedObjectController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/ProtectedObjectController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/ProtectedObjectController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/ProtectedObjectController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/RoleController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/RoleController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/RoleController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/RoleController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/RuntimeErrorMessage.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/RuntimeErrorMessage.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/RuntimeErrorMessage.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/RuntimeErrorMessage.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/RuntimeErrorMessages.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/RuntimeErrorMessages.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/RuntimeErrorMessages.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/RuntimeErrorMessages.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/SchemaMetadataController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/SchemaMetadataController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/SchemaMetadataController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/SchemaMetadataController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/SecurityModelAdvice.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/SecurityModelAdvice.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/SecurityModelAdvice.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/SecurityModelAdvice.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/SecuritySqlScriptController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/SecuritySqlScriptController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/SecuritySqlScriptController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/SecuritySqlScriptController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/SettingController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/SettingController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/SettingController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/SettingController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/StructuredDataController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/StructuredDataController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/StructuredDataController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/StructuredDataController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/TokenController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/TokenController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/TokenController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/TokenController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/UserController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/UserController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/UserController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/UserController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/UserMaskingRuleController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/UserMaskingRuleController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/UserMaskingRuleController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/UserMaskingRuleController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/VectorKnowledgeController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/VectorKnowledgeController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/VectorKnowledgeController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/VectorKnowledgeController.java diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java b/vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java similarity index 100% rename from src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java rename to vpd-backoffice/src/main/java/com/cloudhandson/vpdbackoffice/web/VpdPolicyController.java diff --git a/src/main/resources/application.yml b/vpd-backoffice/src/main/resources/application.yml similarity index 96% rename from src/main/resources/application.yml rename to vpd-backoffice/src/main/resources/application.yml index 16f5d20..6824731 100644 --- a/src/main/resources/application.yml +++ b/vpd-backoffice/src/main/resources/application.yml @@ -78,6 +78,8 @@ backoffice: runtime-db-url: ${BACKOFFICE_SELECT_AI_RUNTIME_DB_URL:} runtime-db-username: ${BACKOFFICE_SELECT_AI_RUNTIME_DB_USERNAME:} runtime-db-password: ${BACKOFFICE_SELECT_AI_RUNTIME_DB_PASSWORD:} + # Customer/project query semantics are external JSON, never Java constants. + query-contract-file: ${BACKOFFICE_SELECT_AI_QUERY_CONTRACT_FILE:} catalog: owner: ${BACKOFFICE_CATALOG_OWNER:} objects: ${BACKOFFICE_CATALOG_OBJECTS:} diff --git a/src/main/resources/mapper/AuditMapper.xml b/vpd-backoffice/src/main/resources/mapper/AuditMapper.xml similarity index 100% rename from src/main/resources/mapper/AuditMapper.xml rename to vpd-backoffice/src/main/resources/mapper/AuditMapper.xml diff --git a/src/main/resources/mapper/BearerTokenMapper.xml b/vpd-backoffice/src/main/resources/mapper/BearerTokenMapper.xml similarity index 100% rename from src/main/resources/mapper/BearerTokenMapper.xml rename to vpd-backoffice/src/main/resources/mapper/BearerTokenMapper.xml diff --git a/src/main/resources/mapper/GroupMapper.xml b/vpd-backoffice/src/main/resources/mapper/GroupMapper.xml similarity index 100% rename from src/main/resources/mapper/GroupMapper.xml rename to vpd-backoffice/src/main/resources/mapper/GroupMapper.xml diff --git a/src/main/resources/mapper/MaskingRuleMapper.xml b/vpd-backoffice/src/main/resources/mapper/MaskingRuleMapper.xml similarity index 100% rename from src/main/resources/mapper/MaskingRuleMapper.xml rename to vpd-backoffice/src/main/resources/mapper/MaskingRuleMapper.xml diff --git a/src/main/resources/mapper/OperationStatusMapper.xml b/vpd-backoffice/src/main/resources/mapper/OperationStatusMapper.xml similarity index 100% rename from src/main/resources/mapper/OperationStatusMapper.xml rename to vpd-backoffice/src/main/resources/mapper/OperationStatusMapper.xml diff --git a/src/main/resources/mapper/OrdsMetadataMapper.xml b/vpd-backoffice/src/main/resources/mapper/OrdsMetadataMapper.xml similarity index 100% rename from src/main/resources/mapper/OrdsMetadataMapper.xml rename to vpd-backoffice/src/main/resources/mapper/OrdsMetadataMapper.xml diff --git a/src/main/resources/mapper/PermissionMapper.xml b/vpd-backoffice/src/main/resources/mapper/PermissionMapper.xml similarity index 100% rename from src/main/resources/mapper/PermissionMapper.xml rename to vpd-backoffice/src/main/resources/mapper/PermissionMapper.xml diff --git a/src/main/resources/mapper/ProtectedObjectMapper.xml b/vpd-backoffice/src/main/resources/mapper/ProtectedObjectMapper.xml similarity index 100% rename from src/main/resources/mapper/ProtectedObjectMapper.xml rename to vpd-backoffice/src/main/resources/mapper/ProtectedObjectMapper.xml diff --git a/src/main/resources/mapper/SettingMapper.xml b/vpd-backoffice/src/main/resources/mapper/SettingMapper.xml similarity index 100% rename from src/main/resources/mapper/SettingMapper.xml rename to vpd-backoffice/src/main/resources/mapper/SettingMapper.xml diff --git a/src/main/resources/mapper/StakeholderMapper.xml b/vpd-backoffice/src/main/resources/mapper/StakeholderMapper.xml similarity index 100% rename from src/main/resources/mapper/StakeholderMapper.xml rename to vpd-backoffice/src/main/resources/mapper/StakeholderMapper.xml diff --git a/src/main/resources/mapper/UserMapper.xml b/vpd-backoffice/src/main/resources/mapper/UserMapper.xml similarity index 100% rename from src/main/resources/mapper/UserMapper.xml rename to vpd-backoffice/src/main/resources/mapper/UserMapper.xml diff --git a/src/main/resources/mapper/VpdPolicyMapper.xml b/vpd-backoffice/src/main/resources/mapper/VpdPolicyMapper.xml similarity index 100% rename from src/main/resources/mapper/VpdPolicyMapper.xml rename to vpd-backoffice/src/main/resources/mapper/VpdPolicyMapper.xml diff --git a/src/main/resources/static/css/app.css b/vpd-backoffice/src/main/resources/static/css/app.css similarity index 100% rename from src/main/resources/static/css/app.css rename to vpd-backoffice/src/main/resources/static/css/app.css diff --git a/src/main/resources/static/js/app.js b/vpd-backoffice/src/main/resources/static/js/app.js similarity index 100% rename from src/main/resources/static/js/app.js rename to vpd-backoffice/src/main/resources/static/js/app.js diff --git a/src/main/resources/templates/dashboard.html b/vpd-backoffice/src/main/resources/templates/dashboard.html similarity index 100% rename from src/main/resources/templates/dashboard.html rename to vpd-backoffice/src/main/resources/templates/dashboard.html diff --git a/src/main/resources/templates/effective-matrix.html b/vpd-backoffice/src/main/resources/templates/effective-matrix.html similarity index 100% rename from src/main/resources/templates/effective-matrix.html rename to vpd-backoffice/src/main/resources/templates/effective-matrix.html diff --git a/src/main/resources/templates/error.html b/vpd-backoffice/src/main/resources/templates/error.html similarity index 100% rename from src/main/resources/templates/error.html rename to vpd-backoffice/src/main/resources/templates/error.html diff --git a/src/main/resources/templates/fragments/layout.html b/vpd-backoffice/src/main/resources/templates/fragments/layout.html similarity index 100% rename from src/main/resources/templates/fragments/layout.html rename to vpd-backoffice/src/main/resources/templates/fragments/layout.html diff --git a/src/main/resources/templates/fragments/mcp-chatbot-result.html b/vpd-backoffice/src/main/resources/templates/fragments/mcp-chatbot-result.html similarity index 100% rename from src/main/resources/templates/fragments/mcp-chatbot-result.html rename to vpd-backoffice/src/main/resources/templates/fragments/mcp-chatbot-result.html diff --git a/src/main/resources/templates/fragments/mcp-client-demo-result.html b/vpd-backoffice/src/main/resources/templates/fragments/mcp-client-demo-result.html similarity index 100% rename from src/main/resources/templates/fragments/mcp-client-demo-result.html rename to vpd-backoffice/src/main/resources/templates/fragments/mcp-client-demo-result.html diff --git a/src/main/resources/templates/fragments/mcp-reasoning-result.html b/vpd-backoffice/src/main/resources/templates/fragments/mcp-reasoning-result.html similarity index 100% rename from src/main/resources/templates/fragments/mcp-reasoning-result.html rename to vpd-backoffice/src/main/resources/templates/fragments/mcp-reasoning-result.html diff --git a/src/main/resources/templates/fragments/ords-handler-source.html b/vpd-backoffice/src/main/resources/templates/fragments/ords-handler-source.html similarity index 100% rename from src/main/resources/templates/fragments/ords-handler-source.html rename to vpd-backoffice/src/main/resources/templates/fragments/ords-handler-source.html diff --git a/src/main/resources/templates/fragments/probe-result.html b/vpd-backoffice/src/main/resources/templates/fragments/probe-result.html similarity index 100% rename from src/main/resources/templates/fragments/probe-result.html rename to vpd-backoffice/src/main/resources/templates/fragments/probe-result.html diff --git a/src/main/resources/templates/fragments/security-sql-script-explanation.html b/vpd-backoffice/src/main/resources/templates/fragments/security-sql-script-explanation.html similarity index 100% rename from src/main/resources/templates/fragments/security-sql-script-explanation.html rename to vpd-backoffice/src/main/resources/templates/fragments/security-sql-script-explanation.html diff --git a/src/main/resources/templates/fragments/vector-search-result.html b/vpd-backoffice/src/main/resources/templates/fragments/vector-search-result.html similarity index 100% rename from src/main/resources/templates/fragments/vector-search-result.html rename to vpd-backoffice/src/main/resources/templates/fragments/vector-search-result.html diff --git a/src/main/resources/templates/fragments/vpd-function-source.html b/vpd-backoffice/src/main/resources/templates/fragments/vpd-function-source.html similarity index 100% rename from src/main/resources/templates/fragments/vpd-function-source.html rename to vpd-backoffice/src/main/resources/templates/fragments/vpd-function-source.html diff --git a/src/main/resources/templates/fragments/vpd-object-filter-detail.html b/vpd-backoffice/src/main/resources/templates/fragments/vpd-object-filter-detail.html similarity index 100% rename from src/main/resources/templates/fragments/vpd-object-filter-detail.html rename to vpd-backoffice/src/main/resources/templates/fragments/vpd-object-filter-detail.html diff --git a/src/main/resources/templates/fragments/vpd-policy-detail.html b/vpd-backoffice/src/main/resources/templates/fragments/vpd-policy-detail.html similarity index 100% rename from src/main/resources/templates/fragments/vpd-policy-detail.html rename to vpd-backoffice/src/main/resources/templates/fragments/vpd-policy-detail.html diff --git a/src/main/resources/templates/fragments/vpd-policy-explanation.html b/vpd-backoffice/src/main/resources/templates/fragments/vpd-policy-explanation.html similarity index 100% rename from src/main/resources/templates/fragments/vpd-policy-explanation.html rename to vpd-backoffice/src/main/resources/templates/fragments/vpd-policy-explanation.html diff --git a/src/main/resources/templates/groups.html b/vpd-backoffice/src/main/resources/templates/groups.html similarity index 100% rename from src/main/resources/templates/groups.html rename to vpd-backoffice/src/main/resources/templates/groups.html diff --git a/src/main/resources/templates/login.html b/vpd-backoffice/src/main/resources/templates/login.html similarity index 100% rename from src/main/resources/templates/login.html rename to vpd-backoffice/src/main/resources/templates/login.html diff --git a/src/main/resources/templates/masking-rules.html b/vpd-backoffice/src/main/resources/templates/masking-rules.html similarity index 100% rename from src/main/resources/templates/masking-rules.html rename to vpd-backoffice/src/main/resources/templates/masking-rules.html diff --git a/src/main/resources/templates/mcp-chatbot.html b/vpd-backoffice/src/main/resources/templates/mcp-chatbot.html similarity index 100% rename from src/main/resources/templates/mcp-chatbot.html rename to vpd-backoffice/src/main/resources/templates/mcp-chatbot.html diff --git a/src/main/resources/templates/mcp-client-demo.html b/vpd-backoffice/src/main/resources/templates/mcp-client-demo.html similarity index 100% rename from src/main/resources/templates/mcp-client-demo.html rename to vpd-backoffice/src/main/resources/templates/mcp-client-demo.html diff --git a/src/main/resources/templates/mcp-reasoning.html b/vpd-backoffice/src/main/resources/templates/mcp-reasoning.html similarity index 100% rename from src/main/resources/templates/mcp-reasoning.html rename to vpd-backoffice/src/main/resources/templates/mcp-reasoning.html diff --git a/src/main/resources/templates/mcp-sse.html b/vpd-backoffice/src/main/resources/templates/mcp-sse.html similarity index 100% rename from src/main/resources/templates/mcp-sse.html rename to vpd-backoffice/src/main/resources/templates/mcp-sse.html diff --git a/src/main/resources/templates/objects.html b/vpd-backoffice/src/main/resources/templates/objects.html similarity index 100% rename from src/main/resources/templates/objects.html rename to vpd-backoffice/src/main/resources/templates/objects.html diff --git a/src/main/resources/templates/operation-status.html b/vpd-backoffice/src/main/resources/templates/operation-status.html similarity index 100% rename from src/main/resources/templates/operation-status.html rename to vpd-backoffice/src/main/resources/templates/operation-status.html diff --git a/src/main/resources/templates/ords-handlers.html b/vpd-backoffice/src/main/resources/templates/ords-handlers.html similarity index 100% rename from src/main/resources/templates/ords-handlers.html rename to vpd-backoffice/src/main/resources/templates/ords-handlers.html diff --git a/src/main/resources/templates/permissions.html b/vpd-backoffice/src/main/resources/templates/permissions.html similarity index 100% rename from src/main/resources/templates/permissions.html rename to vpd-backoffice/src/main/resources/templates/permissions.html diff --git a/src/main/resources/templates/probe.html b/vpd-backoffice/src/main/resources/templates/probe.html similarity index 100% rename from src/main/resources/templates/probe.html rename to vpd-backoffice/src/main/resources/templates/probe.html diff --git a/src/main/resources/templates/roles.html b/vpd-backoffice/src/main/resources/templates/roles.html similarity index 100% rename from src/main/resources/templates/roles.html rename to vpd-backoffice/src/main/resources/templates/roles.html diff --git a/src/main/resources/templates/schema-metadata.html b/vpd-backoffice/src/main/resources/templates/schema-metadata.html similarity index 100% rename from src/main/resources/templates/schema-metadata.html rename to vpd-backoffice/src/main/resources/templates/schema-metadata.html diff --git a/src/main/resources/templates/security-sql-scripts.html b/vpd-backoffice/src/main/resources/templates/security-sql-scripts.html similarity index 92% rename from src/main/resources/templates/security-sql-scripts.html rename to vpd-backoffice/src/main/resources/templates/security-sql-scripts.html index 9524494..01157fa 100644 --- a/src/main/resources/templates/security-sql-scripts.html +++ b/vpd-backoffice/src/main/resources/templates/security-sql-scripts.html @@ -51,7 +51,7 @@ 62_kb_aso_masking_backoffice_metadata.sql -

Git source: sql/adb/62_kb_aso_masking_backoffice_metadata.sql. 실제 DB 배포본은 행 접근 필터 구조 및 DB 배포 이력과 함께 확인하세요.

+

Git source: database/adb/62_kb_aso_masking_backoffice_metadata.sql. 실제 DB 배포본은 행 접근 필터 구조 및 DB 배포 이력과 함께 확인하세요.

diff --git a/src/main/resources/templates/settings-database.html b/vpd-backoffice/src/main/resources/templates/settings-database.html similarity index 99% rename from src/main/resources/templates/settings-database.html rename to vpd-backoffice/src/main/resources/templates/settings-database.html index c36ab57..3ea34fe 100644 --- a/src/main/resources/templates/settings-database.html +++ b/vpd-backoffice/src/main/resources/templates/settings-database.html @@ -58,7 +58,7 @@

실행 전 SQL 확인

앱에서 실행하는 지원 DDL
CREATE TABLE ...
-
sqlcl로 실행할 VPD/ORDS runtime 순서
@sql/adb/...
+
sqlcl로 실행할 VPD/ORDS runtime 순서
@database/adb/...
diff --git a/src/main/resources/templates/settings.html b/vpd-backoffice/src/main/resources/templates/settings.html similarity index 100% rename from src/main/resources/templates/settings.html rename to vpd-backoffice/src/main/resources/templates/settings.html diff --git a/src/main/resources/templates/structured-data.html b/vpd-backoffice/src/main/resources/templates/structured-data.html similarity index 100% rename from src/main/resources/templates/structured-data.html rename to vpd-backoffice/src/main/resources/templates/structured-data.html diff --git a/src/main/resources/templates/tokens.html b/vpd-backoffice/src/main/resources/templates/tokens.html similarity index 100% rename from src/main/resources/templates/tokens.html rename to vpd-backoffice/src/main/resources/templates/tokens.html diff --git a/src/main/resources/templates/user-masking-rules.html b/vpd-backoffice/src/main/resources/templates/user-masking-rules.html similarity index 100% rename from src/main/resources/templates/user-masking-rules.html rename to vpd-backoffice/src/main/resources/templates/user-masking-rules.html diff --git a/src/main/resources/templates/users.html b/vpd-backoffice/src/main/resources/templates/users.html similarity index 100% rename from src/main/resources/templates/users.html rename to vpd-backoffice/src/main/resources/templates/users.html diff --git a/src/main/resources/templates/vector-knowledge.html b/vpd-backoffice/src/main/resources/templates/vector-knowledge.html similarity index 100% rename from src/main/resources/templates/vector-knowledge.html rename to vpd-backoffice/src/main/resources/templates/vector-knowledge.html diff --git a/src/main/resources/templates/vpd-filter-policies.html b/vpd-backoffice/src/main/resources/templates/vpd-filter-policies.html similarity index 100% rename from src/main/resources/templates/vpd-filter-policies.html rename to vpd-backoffice/src/main/resources/templates/vpd-filter-policies.html diff --git a/src/main/resources/templates/vpd-filter-runtime.html b/vpd-backoffice/src/main/resources/templates/vpd-filter-runtime.html similarity index 100% rename from src/main/resources/templates/vpd-filter-runtime.html rename to vpd-backoffice/src/main/resources/templates/vpd-filter-runtime.html diff --git a/src/main/resources/templates/vpd-policies.html b/vpd-backoffice/src/main/resources/templates/vpd-policies.html similarity index 100% rename from src/main/resources/templates/vpd-policies.html rename to vpd-backoffice/src/main/resources/templates/vpd-policies.html diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/config/TransportSecurityTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/config/TransportSecurityTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/config/TransportSecurityTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/config/TransportSecurityTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingTemplateTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingTemplateTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingTemplateTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/masking/MaskingTemplateTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionViewTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionViewTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionViewTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/permission/PermissionViewTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeResultTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeResultTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeResultTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/probe/ProbeResultTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedColumnTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedColumnTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedColumnTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/protectedobject/ProtectedColumnTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptionsTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptionsTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptionsTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/domain/vpd/VpdPolicyFormOptionsTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/EffectiveMatrixServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/EffectiveMatrixServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/EffectiveMatrixServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/EffectiveMatrixServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationChangeNotifierTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationChangeNotifierTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationChangeNotifierTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/ExternalAuthorizationChangeNotifierTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/HmmRuntimeSettingsInitializerTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/HmmRuntimeSettingsInitializerTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/HmmRuntimeSettingsInitializerTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/HmmRuntimeSettingsInitializerTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmAiAgentToolRunnerTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmAiAgentToolRunnerTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmAiAgentToolRunnerTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/JdbcHmmAiAgentToolRunnerTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicySynchronizerTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicySynchronizerTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicySynchronizerTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/MaskingPolicySynchronizerTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/McpSseServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/McpSseServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/McpSseServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/McpSseServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/OrdsMetadataServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/OrdsProbeServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/PermissionServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/PermissionServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/PermissionServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/PermissionServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/ProbeErrorClassifierTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/ProbeErrorClassifierTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/ProbeErrorClassifierTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/ProbeErrorClassifierTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/SchemaMetadataServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/SchemaMetadataServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/SchemaMetadataServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/SchemaMetadataServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/SecuritySqlScriptServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/SelectAiServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/SelectAiServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/SelectAiServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/SelectAiServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/StructuredDataServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/StructuredDataServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/StructuredDataServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/StructuredDataServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/TokenGeneratorTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/TokenGeneratorTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/TokenGeneratorTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/TokenGeneratorTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/TokenHasherTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/TokenHasherTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/TokenHasherTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/TokenHasherTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/VectorChunkerTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/VectorChunkerTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/VectorChunkerTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/VectorChunkerTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/VectorKnowledgeServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/VectorKnowledgeServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/VectorKnowledgeServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/VectorKnowledgeServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyServiceTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyServiceTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyServiceTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/service/VpdPolicyServiceTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/web/EffectiveMatrixTemplateRenderTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/EffectiveMatrixTemplateRenderTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/web/EffectiveMatrixTemplateRenderTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/EffectiveMatrixTemplateRenderTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java similarity index 96% rename from src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java index 303be54..df876dd 100644 --- a/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java +++ b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/GuidedFlowTemplateTest.java @@ -296,7 +296,7 @@ class GuidedFlowTemplateTest { @Test void probeResultSeparatesDbExecutionEvidenceFromReconstructedSql() throws IOException { String result = template("fragments/probe-result.html"); - String vectorSql = Files.readString(Path.of("sql/adb/29_agent_ords_vector_search_ords.sql")); + String vectorSql = Files.readString(Path.of("../database/adb/29_agent_ords_vector_search_ords.sql")); assertThat(result) .contains("DB 감사 실행 증적") @@ -317,7 +317,7 @@ class GuidedFlowTemplateTest { @Test void vectorDefaultRolesAreSeededAsWhitelistAllRules() throws IOException { - String setup = Files.readString(Path.of("sql/adb/32_dds_vector_tag_setup.sql")); + String setup = Files.readString(Path.of("../database/adb/32_dds_vector_tag_setup.sql")); assertThat(setup) .contains("ensure_vector_all_permission(10)") @@ -330,7 +330,7 @@ class GuidedFlowTemplateTest { @Test void defaultVerificationUsersUseHumanNamesInsteadOfRoleLikeAgentNames() throws IOException { - String seed = Files.readString(Path.of("sql/adb/17_agent_ords_security_local_vpd_setup.sql")); + String seed = Files.readString(Path.of("../database/adb/17_agent_ords_security_local_vpd_setup.sql")); String users = template("users.html"); String result = template("fragments/probe-result.html"); @@ -344,7 +344,7 @@ class GuidedFlowTemplateTest { @Test void vectorOrdsHandlerReadsBodyStreamOnlyOnce() throws IOException { - String sql = Files.readString(Path.of("sql/adb/29_agent_ords_vector_search_ords.sql")); + String sql = Files.readString(Path.of("../database/adb/29_agent_ords_vector_search_ords.sql")); assertThat(sql) .contains("v_body_text CLOB") @@ -358,8 +358,8 @@ class GuidedFlowTemplateTest { @Test void existingOrdsSetupCanReturnTheVpdPredicateTrace() throws IOException { - String setup = Files.readString(Path.of("sql/adb/22_agent_ords_security_ords_handler_setup.sql")); - String grant = Files.readString(Path.of("sql/adb/33_agent_ords_sql_trace_grant.sql")); + String setup = Files.readString(Path.of("../database/adb/22_agent_ords_security_ords_handler_setup.sql")); + String grant = Files.readString(Path.of("../database/adb/33_agent_ords_sql_trace_grant.sql")); assertThat(setup) .contains("admin.cb_agent_doc_vpd_filter('ADMIN', 'CB_V_SEARCH_DOCUMENTS')") diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/web/MaskingRuleTemplateRenderTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/MaskingRuleTemplateRenderTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/web/MaskingRuleTemplateRenderTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/MaskingRuleTemplateRenderTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/web/PermissionTemplateRenderTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/PermissionTemplateRenderTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/web/PermissionTemplateRenderTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/PermissionTemplateRenderTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/web/ProbeResultTemplateRenderTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/ProbeResultTemplateRenderTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/web/ProbeResultTemplateRenderTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/ProbeResultTemplateRenderTest.java diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/web/SettingsTemplateRenderTest.java b/vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/SettingsTemplateRenderTest.java similarity index 100% rename from src/test/java/com/cloudhandson/vpdbackoffice/web/SettingsTemplateRenderTest.java rename to vpd-backoffice/src/test/java/com/cloudhandson/vpdbackoffice/web/SettingsTemplateRenderTest.java diff --git a/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/vpd-backoffice/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker similarity index 100% rename from src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker rename to vpd-backoffice/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker