Files
vpd-permission-poc/docs/design/654-poc4-mcp-discovery-streamable-http/README.md
2026-07-14 14:19:10 +09:00

23 KiB

설계서: PoC_4 MCP AI Console 소스 스냅샷 역설계 및 KB VPD MCP 연동 정비 (#654)

상태: Implemented snapshot documented · follow-up contract pending 작성: [AI] Architect · 최종수정: 2026-07-14 추적성 — Redmine: #654 · 관련 ADR: 없음 · 구현 커밋: 5bdd242, 33399f9 · 스냅샷: 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

1. 목적 (Why)

PoC_4의 MCP Discovery UI가 KB VPD MCP를 사용자별 Bearer 토큰으로 안전하게 호출하면서도, 환경별 URL·전송 방식·오류 처리를 하나의 명확한 계약으로 관리한다.

현재 UI의 기본 호출 흐름은 동작한다. 다만 kb_mcp 설정에는 endpoint_urlbase_url_env가 함께 있고, UI는 endpoint_url을 우선 사용한다. 따라서 KB_MCP_BASE_URL을 바꿔도 실제 호출 대상이 바뀌지 않는다. 또한 custom_python은 로컬 8500 MCP용 이름이므로 외부 KB VPD MCP의 통신 계약을 설명하지 못한다.

1.1 현행 구현 역설계 요약

이번 문서는 목표 설계를 먼저 정한 것이 아니라, 배포 서버에서 이미 동작하던 PoC4 MCP AI Console 스냅샷을 저장소로 가져온 뒤 구현을 역으로 읽어 작성했다. 따라서 아래 표가 현재 동작의 기준이다.

영역 현행 구현
저장소 위치 poc4_active_source_20260714/ 단일 폴더에 격리
실행 진입점 직접 실행은 streamlit run apps/poc4/mcp_discovery_ui.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_mcpkb_vector_mcp 두 서버를 선언
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만 둠
대화 저장소 기본 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에서 로드
보안 원칙 wallet, DB password, wallet password, 실제 VPD token, 대화 DB는 저장소에 포함하지 않음

현행 데이터 흐름은 다음과 같다.

Streamlit 사용자 로그인
  ↓
VPD 사용자 preset 또는 직접 Bearer token 선택
  ↓
config/mcp_servers.json 로드
  ↓
각 MCP 서버에 initialize → initialized notification → tools/list
  ↓
질문 유형에 따라 single 또는 agent 실행 계획 선택
  ↓
tools/call 호출
  - Authorization: Bearer <현재 VPD token>
  - JSON-RPC body에는 tool name과 arguments만 포함
  ↓
정형 MCP / 벡터 MCP 결과 수집
  ↓
필요 시 /home/opc/kbmcp/.env + /home/opc/wallet/kbaipoc 로 Oracle evidence 조회
  ↓
OCI GenAI로 최종 답변 합성
  ↓
SQLite 대화 이력 저장

1.2 현행 구현 컴포넌트

파일 책임
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.shapps/poc4/langgraph_tc_ui.py를 참조

런처 주의사항: 스냅샷에는 mcp_discovery_ui.py 직접 실행에 필요한 소스가 들어 있지만, 포함된 start_8622... script는 원본 서버의 공용 runtime wrapper에 의존한다. 이 저장소에서 독립 실행하려면 SOURCE_README.md의 직접 streamlit run 명령을 사용하거나, 별도 wrapper를 작성해야 한다.

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만 읽는다.
  • 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 원문을 포함하지 않는다.

1.4 현행 구현과 후속 목표의 차이

항목 현행 구현 후속 목표
KB MCP provider/transport 명칭 provider=custom_python, transport=http kb_vpd_streamable_http, streamable_http처럼 외부 KB VPD MCP 계약을 명확히 표현
endpoint 해석 endpoint_url이 있으면 이를 우선 사용하고, 없으면 env 값을 사용 KB MCP는 KB_MCP_BASE_URL + /mcp 단일 계약으로 해석
tool routing route가 여러 개면 LLM router/agent mode를 사용할 수 있음 KB 단일 tool 호출에서는 router 없이 direct 선택
401/403 표시 현재 둘 다 “MCP 인증에 실패” 계열 안전 메시지로 축약 토큰 없음/만료/권한 부족을 UI에서 명확히 분리
start script 원본 /home/opc/poc_4 runtime wrapper 의존 스냅샷 폴더 안에서 독립 실행 가능한 wrapper 추가
회귀 테스트 원본 서버 Python 3.11 py_compile, Java mvn -q test PoC4 전용 단위 테스트와 실제 MCP HTTP smoke test 추가

2. 범위 (Scope)

  • 포함:
    • apps/poc4/mcp_discovery_ui.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 상태·프로토콜 버전 호환성 점검 및 필요한 최소 보완
  • 제외 (out of scope):
    • 기존 kb_vector_mcpcustom_python 8500 RAG MCP의 변경
    • VPD 권한 규칙, Select AI SQL 생성 규칙, ORDS 비즈니스 로직 변경
    • OAuth Authorization Server, 사용자 로그인/토큰 발급 UI 재설계
    • VPD 토큰 원문을 환경변수·레지스트리에 저장하는 방식

3. 인수조건 (Acceptance Criteria)

아래 체크박스는 최종 목표 기준이다. 2026-07-14 스냅샷 반입 상태에서는 일부만 충족한다.

  • KB MCP URL은 KB_MCP_BASE_URL 하나에서만 해석되고 /mcp path가 안전하게 결합된다.
  • initialize, notifications/initialized, tools/list, tools/call의 모든 HTTP 요청에 현재 선택된 사용자의 Authorization: Bearer <VPD token>만 전송된다.
  • Bearer 토큰은 JSON-RPC arguments, SQLite 대화 이력, UI 결과, 애플리케이션 로그에 저장·출력되지 않는다.
  • 호출 가능한 도구는 ords.query.kb_select_ai_vpd 하나이며, 인자는 promptlimit만 허용된다.
  • 단일 도구 구성에서는 LLM router를 호출하지 않고 허용 도구를 직접 선택한다.
  • 토큰 없음/위조/만료는 HTTP 401, 유효 토큰의 권한 부족은 HTTP 403으로 UI에 구분 표시된다.
  • 잘못된 Origin의 브라우저 요청은 MCP 서버에서 거부되며, 허용 Origin 및 Origin 없는 네이티브 MCP client 정책이 문서화된다.
  • 기존 kb_vector_mcp 및 로컬 8500 MCP 회귀 테스트가 통과한다.
조건 현행 판단 근거/메모
URL 단일 해석 부분 충족 _mcp_endpoint()/mcp 결합과 URL 검증은 수행하지만 config/mcp_servers.jsonendpoint_url이 env보다 우선한다.
요청별 Authorization header 충족 _jsonrpc_exchange()_jsonrpc_notification()Authorization: Bearer <token>을 header에 설정한다.
JSON-RPC arguments token 미포함 충족 build_mcp_tool_arguments()prompt, limit, query, question 계열만 구성한다.
SQLite token 원문 미저장 부분 충족 chat turn에는 선택 사용자/label, question/answer/details를 저장한다. token 원문 필드는 없지만 details_json의 evidence payload는 후속 보안 점검 필요.
단일 도구 direct routing 부분 충족 route가 1개면 single로 처리하지만, 복수 route에서는 LLM router/agent mode를 사용할 수 있다.
401/403 구분 미충족 현재 401, 403 모두 안전한 인증 실패 메시지로 축약한다.
Origin 검증 서버 범위 UI client는 redirect 차단을 수행한다. Origin 정책은 VPD Backoffice MCP 서버 설정에서 확인해야 한다.
벡터 MCP 회귀 미검증 소스 반입 시 Java 테스트와 Python 문법 검증만 수행했다. 실제 kb_vector_mcp smoke test는 후속이다.

4. 컨텍스트 & 제약

  • KB VPD MCP endpoint: https://kb.cloud-handson.com/mcp
  • 보호 대상: ords.query.kb_select_ai_vpd는 ORDS를 거쳐 VPD 컨텍스트가 적용된 Select AI 조회를 실행한다.
  • 토큰 주체: VPD 권한은 정적 서비스 계정이 아니라 현재 선택된 KB_STAKEHOLDERS 사용자 토큰에 의해 결정된다.
  • UI의 VPD token preset 파일은 데모 편의 기능일 뿐이다. 운영에서는 OS 소유자 전용 권한(0600)으로 관리하고 형상관리·로그·SQLite에서 제외한다.
  • UI가 현재 사용하는 2025-11-25 MCP protocol version과 서버의 지원 버전은 handshake에서 협상해야 한다. 지원하지 않는 버전을 무조건 강제하지 않는다.
  • 현재 서버는 stateless JSON-RPC POST 호출로도 동작한다. 서버가 Mcp-Session-Id를 발급하면 client는 이후 요청에만 그 값을 포함한다.

5. 아키텍처 개요

I/O는 Discovery UI의 HTTP transport와 VPD Backoffice /mcp에 한정한다. URL 결합, 허용 도구 검증, 요청·응답 검증, 안전한 오류 변환은 순수 함수로 분리해 네트워크 없이 테스트한다.

VPD 사용자 선택 / 토큰 입력
        │  (원문은 요청 메모리에만 존재)
        ▼
PoC_4 MCP Discovery UI
  ├─ KB_MCP_BASE_URL + "/mcp"
  ├─ tool allowlist 검증
  └─ Authorization: Bearer <current VPD token>
        │
        ▼ HTTPS JSON-RPC / Streamable HTTP
VPD Backoffice MCP (/mcp)
  ├─ Origin·토큰 검증
  ├─ tools/list: metadata only
  └─ tools/call: ords.query.kb_select_ai_vpd
        │
        ▼
ORDS Select AI API → VPD context → Oracle ADB

6. 데이터 모델

6.1 KB MCP registry 선언

config/mcp_servers.json의 KB 선언은 다음 계약을 따른다. 값은 예시이며, 토큰 값은 넣지 않는다.

{
  "id": "kb_mcp",
  "enabled": true,
  "provider": "kb_vpd_streamable_http",
  "transport": "streamable_http",
  "base_url_env": "KB_MCP_BASE_URL",
  "endpoint_path": "/mcp",
  "auth_delivery": "per_request_vpd_bearer",
  "timeout_seconds_env": "POC3_MCP_TIMEOUT_SECONDS",
  "default_tool": "ords.query.kb_select_ai_vpd",
  "tool_allowlist": ["ords.query.kb_select_ai_vpd"],
  "router_mode": "direct",
  "description": "KB VPD Select AI MCP; the current user's VPD bearer is sent only in the Authorization header."
}

환경 변수는 아래 두 값만 필요하다.

KB_MCP_BASE_URL=https://kb.cloud-handson.com
POC3_MCP_TIMEOUT_SECONDS=90

endpoint_url, token_env, POC3_MCP_TOKEN, BACKOFFICE_MCP_ACCESS_TOKEN은 KB MCP 선언에 두지 않는다. URL은 registry에 하드코딩하지 않고, VPD 토큰은 사용자별 요청에서만 받는다.

6.2 MCP 요청

모든 요청은 다음 헤더를 사용한다.

Accept: application/json, text/event-stream
Content-Type: application/json
MCP-Protocol-Version: <negotiated version>
Authorization: Bearer <current-user-vpd-token>

tools/call body의 arguments는 아래와 같이 제한한다.

{
  "name": "ords.query.kb_select_ai_vpd",
  "arguments": {
    "prompt": "담당 고객의 보험료 상세를 보여줘",
    "limit": 50
  }
}

경계 검증 규칙:

  • tool name은 정확히 allowlist 값 하나와 일치해야 한다.
  • prompt는 문자열이며 서버와 동일한 최대 길이를 적용한다.
  • limit은 정수 1..100으로 clamp한다.
  • 토큰은 공백·Bearer prefix를 정규화한 뒤 헤더에만 넣는다.
  • redirect는 허용하지 않는다. 다른 origin으로 Authorization이 전달되어서는 안 된다.

7. 함수 명세 (Function Specs)

함수 책임(1줄) 시그니처(잠정) 입력 출력 에러/실패 복잡?
resolve_kb_mcp_endpoint base URL과 고정 path를 안전하게 결합 (server, environ) -> str registry, env HTTPS MCP URL 누락/비정상 URL 단순
validate_kb_mcp_server KB 선언의 provider·transport·allowlist를 검증 (mapping) -> McpServer registry row typed server 계약 위반 단순
mcp_headers 요청별 VPD bearer 헤더 생성 (token, version, session_id) -> dict 사용자 토큰 안전한 headers 토큰 형식 오류 단순
discover_kb_tools initialize 및 tools/list 후 단일 도구를 검증 (server, token) -> McpDiscoveryResult endpoint, token tool descriptor auth/protocol 오류 복잡
call_kb_select_ai 고정 도구에 prompt·limit을 전달 (server, token, prompt, limit) -> result 사용자 요청 tool result auth/timeout/JSON-RPC 오류 복잡
to_public_mcp_error HTTP/JSON-RPC 오류를 안전한 UI 메시지로 변환 (exception) -> PublicMcpError 내부 오류 사용자 메시지 원문 노출 금지 단순

8. 흐름 / 알고리즘

  1. UI는 KB_MCP_BASE_URL을 읽고 /mcp만 결합한다. registry의 임의 endpoint_url은 KB 서버에 허용하지 않는다.
  2. 사용자가 VPD token preset 또는 일회성 Bearer를 선택한다. 토큰은 현재 실행 변수에만 유지한다.
  3. client는 initialize를 보내고 서버가 반환한 protocol version과 선택 가능한 session ID를 검증한다.
  4. notifications/initialized를 보낸 뒤 tools/list를 실행한다.
  5. 응답 목록이 정확히 허용 도구를 포함하는지, 해당 input schema가 prompt, limit 계약에 맞는지 확인한다.
  6. KB 서버는 단일 도구이므로 router model을 호출하지 않고 ords.query.kb_select_ai_vpd를 직접 선택한다.
  7. tools/call은 prompt·clamp된 limit만 body에 넣고 VPD Bearer는 Authorization에만 넣는다.
  8. 결과는 화면용 안전 projection만 SQLite에 저장한다. Authorization 헤더와 원문 token은 저장하지 않으며, 진단이 필요하면 단방향 token fingerprint만 별도 보존할 수 있다.

9. 엣지케이스 & 에러 처리

상황 client 처리 서버 기대 동작
토큰 없음 호출 전 안내, 네트워크 요청 없음 해당 없음
토큰 위조·만료 401 → “토큰이 유효하지 않거나 만료됨” WWW-Authenticate 포함 가능
유효하지만 권한 없음 403 → “이 사용자에게 조회 권한 없음” VPD fail-closed 유지
allowlist 밖 도구 호출 전 차단 tools/call에서도 차단
429 안전하게 재시도하지 않고 잠시 후 재시도 안내 rate limit 정책 적용
timeout tools/call 자동 재시도 금지 request ID 기반 감사 추적
session ID 미발급 stateless POST로 진행 session을 요구하지 않음
session ID 발급 이후 요청에 Mcp-Session-Id 포함 세션 소유·만료 검증
redirect 즉시 실패 Authorization 전달 금지
Origin 불일치 브라우저 UI에 일반 오류 표시 403으로 거부

10. 테스트 계획

  • registry 단위 테스트
    • KB_MCP_BASE_URL만으로 endpoint가 https://kb.cloud-handson.com/mcp가 되는지 검증
    • KB registry에 endpoint_url, token_env, custom_python이 있으면 fail-closed 되는지 검증
    • vector MCP 설정은 기존 형식으로 계속 로드되는지 검증
  • HTTP transport 단위 테스트
    • initialize/tools/list/tools/call 모두 Authorization header가 있고 JSON body에는 token key가 없는지 검증
    • 401, 403, 429, timeout, redirect, malformed JSON-RPC 응답을 안전한 메시지로 변환하는지 검증
    • session header 반환/재전송 및 stateless fallback을 검증
  • 통합 smoke test
    • 허용된 VPD 사용자 토큰으로 tools/listtools/call 성공
    • 잘못된 토큰은 401, 타 사용자 권한은 403
    • 설계사와 지점장 토큰으로 동일 질문을 실행해 VPD 행/컬럼 결과가 서로 다른지 확인
  • 비밀정보 점검
    • chat SQLite, Streamlit log, 예외 메시지에서 토큰 원문 검색 결과 0건

11. 리스크 & 대안 검토

  • 선택: KB MCP 전용 kb_vpd_streamable_http 선언을 도입하고, 로컬 8500용 custom_python과 분리한다. 외부 HTTPS/VPD Bearer 계약을 코드와 운영 화면에서 명확히 할 수 있다.
  • 대안 1 — 기존 custom_python 재사용: 동작은 시킬 수 있으나 provider 이름과 endpoint 제약이 실제 KB 서버와 맞지 않아 로컬 MCP와 외부 VPD MCP가 섞인다.
  • 대안 2 — 고정 MCP access token 사용: 구현은 간단하지만 모든 사용자가 동일 VPD 주체가 되어 데이터 권한 분리가 무너진다. 채택하지 않는다.
  • 대안 3 — 즉시 OAuth 2.1 전환: 표준 상호운용성에는 유리하지만 현재 데모의 VPD token 발급·검증 체계를 대체하므로 별도 인증 서버 설계가 필요하다.
  • 롤백: 새 registry 선언을 비활성화하고 기존 KB 선언을 복원한다. DB VPD 정책·ORDS endpoint·토큰 데이터는 변경하지 않는다.

12. 미해결 질문 (Open Questions)

  • VPD Backoffice MCP endpoint가 현재 지원할 MCP protocol version을 어떤 값으로 공식 고정할지 결정이 필요하다.
  • Streamable HTTP의 GET/SSE 및 Mcp-Session-Id를 완전 지원할지, stateless POST profile로 운영할지 결정이 필요하다.
  • 데모 이후 사용자 VPD bearer를 OAuth 2.1 access token으로 전환할지, 현 토큰을 resource-server token으로 계속 운영할지 결정이 필요하다.
  • chat 대화 이력의 basis_json/details_json에 민감 데이터 보존 기간과 삭제 정책을 별도로 정해야 한다.

13. 2026-07-14 소스 스냅샷 반입

배포 서버의 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/
  • 포함 파일: 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를 사용한다. 두 경로의 파일 내용은 저장소에 포함하지 않는다.
  • 런타임 전제: Python 3.11 이상. 현재 개발 서버 기본 python3는 3.6.8이므로 이 소스의 문법 검증에는 맞지 않는다.
  • 검증: 배포 서버 원본 경로에서 PoC4 전용 Python 3.11.15py_compile 통과. 기존 Java 백오피스 mvn -q test 통과.

주의: 이 반입은 소스 스냅샷 보관이다. 아직 본 설계서의 목표 계약인 kb_vpd_streamable_http, KB_MCP_BASE_URL 단일 endpoint 해석, 단일 도구 direct routing을 구현 완료했다는 의미는 아니다.

14. 2026-07-14 역설계 현행화

사용자 요청에 따라 “설계가 먼저 있고 구현을 맞추는 방식”이 아니라, 이미 배포 서버에서 구현·운영 중인 PoC4 MCP AI Console 소스를 기준으로 역설계했다.

현행화한 내용:

  • mcp_discovery_ui.py의 실제 책임 범위를 Streamlit UI, MCP JSON-RPC client, agent loop, evidence collector, answer synthesis, chat store로 분리해 기록했다.
  • mcp_servers.json의 현재 계약이 목표 계약과 다르다는 점을 명시했다. 특히 현행은 endpoint_url 우선이며, provider=custom_python, transport=http이다.
  • /home/opc/kbmcp/.env/home/opc/wallet/kbaipoc를 배포 서버 DB evidence 조회 기준으로 확정했다.
  • 포함된 start/status script가 스냅샷 단독 실행용이 아니라 원본 /home/opc/poc_4 runtime wrapper에 의존한다는 점을 기록했다.
  • 인수조건을 최종 목표와 현행 충족 상태로 분리했다.

검증:

  • 배포 서버 원본 소스 기준 Python 3.11.15 py_compile 통과
  • 백오피스 기존 회귀 mvn -q test 통과
  • 저장소 문서/스냅샷 커밋 및 gitea/main push 완료