Files
invyone/.omc/plans/ai-orchestration-replacement-prd.md
T
Johngreen 52386efb83
Build & Deploy to K8s / build-and-deploy (push) Has been cancelled
도메인 정리: invion.com → invyone.com 전체 일괄 치환 + 매핑 문서화
운영 도메인이 실제로는 v1.invyone.com / solution.invyone.com / api.invyone.com 인데
코드/문서 곳곳에 v1.invion.com / api.invion.com 등 미존재 도메인이 박혀 있어 정리.

변경 파일 (21):
- frontend lib/api/client.ts, lib/utils/apiUrl.ts: hostname 체크 endsWith(\".invyone.com\") 일반화
- frontend lib/api/dashboard.ts, file.ts, flow.ts, FileViewerModal*2.tsx: 도메인 치환
- frontend invion-layout-v5.html: 시안 내 placeholder 도메인 정리
- backend-spring SecurityConfig.java: CORS 주석 예시 정리
- docker/deploy/docker-compose.yml, k8s/traefik-dynamic.yaml: traefik Host 라벨 정리
- scripts/prod/deploy.sh: 안내 메시지 정리
- .cursor/rules/api-client-usage.mdc, project-conventions.mdc: AI 가이드 정리
- docs/* 4개: 아키텍처/플로우 문서 도메인 정리
- notes/gbpark/* 3개: 과거 메모 정리

신규:
- docs/DOMAIN_MAPPING.md: 운영/개발/폐기 도메인 영구 기록.
  AI 에이전트와 신규 개발자가 헷갈리지 않도록 단일 진실 출처.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 07:39:04 +09:00

38 KiB
Raw Blame History

AI 오케스트레이션 교체 PRD (invyone × vexplor_pipeline)

작성: planner (BMAD 1단계 / Analyst·PM) 일자: 2026-04-27 상태: Architect 검토 대기 다음 단계: architect (기술 아키텍처 결정) → executor → verifier


0. TL;DR

invyone 프로젝트의 기존 AI 어시스턴트(Node Express, port 3100) 를 전면 제거하고, vexplor_pipeline 프로젝트에서 운영 중인 멀티 에이전트 오케스트레이션 시스템(에이전트 CRUD, 그룹 조립, 커넥터, OpenClaw, 스케줄러, 사용량 추적)을 invyone에 이식한다. 백엔드는 TypeScript/Node → Java 21/Spring Boot 3.3.5/MyBatis 로 1:1 포팅, 프론트엔드는 vexplor의 7개 화면을 invyone Next.js로 그대로 옮기고, OpenClaw은 컨테이너로 함께 운영한다.

총량: 8 Epic / 39 Story 추정 / 백엔드 포팅 비중 가장 큼


1. 목표 (Goals & Non-Goals)

1.1 Goals (P0)

  • (G1) invyone에 멀티 에이전트 운영(에이전트 정의 → 그룹 조립 → 실행 모드 = 순차/병렬/혼합) 기능 도입
  • (G2) API 키 기반 외부 호출(OpenAI 호환 /v1/chat/completions) 엔드포인트 유지 — 외부 시스템이 invyone을 LLM 게이트웨이로 사용 가능
  • (G3) 멀티테넌시 강제 — 모든 AI 리소스(에이전트/그룹/키/대화/사용량)에 company_code 필터 일관 적용 (* = 전체 공유)
  • (G4) 기존 AI 어시스턴트(ai-assistant 컨테이너 + 프록시 + DB 테이블) 완전 제거 — 운영 데이터 보존 불필요(사용자 확인 완료)
  • (G5) Spring Security + JJWT 기반 인증 통합 (관리 API는 JWT, 외부 API는 sk-pipe-* 키)
  • (G6) 부서/권한 그룹 시스템(직전 커밋 2c57dc8c)에 새 AI 메뉴들 등록 가능

1.2 Goals (P1)

  • (G7) 다중 LLM 프로바이더(Anthropic, OpenAI, Google, DeepSeek, Ollama) 동시 운영 + 우선순위 라우팅
  • (G8) 에이전트별 커넥터(DB/REST/PLC/크롤러/파일) 매핑으로 운영 데이터에 기반한 분석 수행
  • (G9) cron 기반 스케줄 실행 + 알림(시스템 공지/슬랙 웹훅/이메일)
  • (G10) 사용량 대시보드(일별/월별 토큰·비용·요청 수)

1.3 Goals (P2)

  • (G11) 대화 모니터링(에이전트 간 메시지 트레이스)
  • (G12) 지식 파일 라이브러리(에이전트별 RAG 컨텍스트 주입)
  • (G13) AI 분석 이력 기반 정확도 추적(ai_analysis_logs)

1.4 Non-Goals

  • (NG1) vexplor_pipeline 자체의 화면관리/테이블관리/AI 화면 자동생성(workflow_patterns, keyword_mapping 등)은 이번 작업 범위 아님
  • (NG2) OpenClaw 자체 코드 포팅/수정. invyone은 OpenClaw을 블랙박스 외부 엔진으로만 사용
  • (NG3) Spring AI / Spring AI MCP 도입 결정 — 이번에는 직접 HTTP 호출(LlmClient 직역) 유지 (architect 단계에서 재검토)
  • (NG4) 사용량 청구/결제 기능
  • (NG5) 다중 회사 간 에이전트 권한 위임(P3 이상)
  • (NG6) 기존 vexplor _pipeline_backup 폴더 처리

2. 이해관계자 / 사용자 시나리오

페르소나 권한 핵심 시나리오
슈퍼관리자(SUPER_ADMIN) 전사 글로벌 LLM 프로바이더 등록/키 관리, * 회사용 공유 에이전트 정의, 전체 사용량 모니터링
회사관리자(COMPANY_ADMIN) 자사 company_code 자사 에이전트/그룹 CRUD, 자사 API 키 발급, 자사 사용량 조회
일반사용자 자사 + 메뉴 권한 AI 채팅 사용, 자기 API 키 발급(역할별로), 대화 이력 조회
외부 시스템(B2B) API 키 Authorization: Bearer sk-pipe-.../api/ai/v1/chat/completions 또는 /api/ai/v1/groups/:groupId 호출
운영자(DevOps) 인프라 docker-compose 기동, OpenClaw 컨테이너 헬스체크, Jenkins 배포

2.1 핵심 사용 시나리오 흐름

S1. 회사관리자가 멀티 에이전트 그룹 생성

  1. /admin/aiAssistant/agents 에서 "재고 분석가"(Claude Sonnet 4.5) + "구매 추천가"(GPT-4o) 에이전트 2개 생성
  2. /admin/aiAssistant/workspace 에서 그룹 재고-구매 자동분석 생성, 두 에이전트를 멤버로 추가, 각각 PostgreSQL 커넥터(외부 DB) 매핑, execution_mode = mixed
  3. UI에서 "현재 재고 위험 품목 분석해줘" 입력 → 백엔드 MultiAgentExecutionEngine이 두 에이전트를 mixed 모드로 실행 → 최종 요약 반환 + 대화 이력 저장 + ai_analysis_logs 기록

S2. 외부 시스템(B2B) 호출

  1. 관리자가 /admin/aiAssistant/api-keys-manage 에서 키 발급(키는 한 번만 표시, sha256 해시만 저장)
  2. 외부 시스템: POST /api/ai/v1/groups/123 with Authorization: Bearer sk-pipe-... and {"message":"오늘 재고 위험"}
  3. AiApiKeyAuthFilter 통과 → 월간 토큰 한도 체크 → 그룹 실행 → 사용량 누적

S3. cron 스케줄

  1. /admin/aiAssistant/scheduler(신규) 에서 매일 09:00 - 그룹 X 실행 - 슬랙 웹훅 알림
  2. Spring @Scheduled 또는 Quartz가 등록된 cron 표현식으로 그룹 실행 → ai_analysis_logs + system_notice + 슬랙 발송

3. 기능 요구사항 (FR)

3.1 에이전트 관리 (P0)

FR 설명 우선순위
FR-A-1 에이전트 CRUD(agent_id, name, model, system_prompt, tools, config, company_code) P0
FR-A-2 검색·상태(active/inactive/archived)·회사별 필터 P0
FR-A-3 agent_id 유니크 제약 P0
FR-A-4 에이전트별 config.knowledge_files(라이브러리 참조 또는 인라인 콘텐츠) P2
FR-A-5 tools 정의(JSON, MCP 도구 명세) P1

3.2 멀티 에이전트 그룹 (P0)

FR 설명 우선순위
FR-G-1 그룹 CRUD(group_id, name, execution_mode = parallel/sequential/mixed) P0
FR-G-2 그룹 멤버 추가·수정·삭제(role_name, connectors, execution_order) P0
FR-G-3 가용 커넥터 조회 — DB(external_db_connections) / REST(external_rest_api_connections) / PLC(pipeline_device_connections) / 크롤러(crawl_configs) P1
FR-G-4 그룹 실행 = MultiAgentExecutionEngine — sequential/parallel/mixed 분기 처리 + 이전 컨텍스트 누적 + 최종 요약 P0
FR-G-5 그룹 실행 시 과거 분석 이력 5건 자동 컨텍스트 주입 P2

3.3 LLM 프로바이더 관리 (P0)

FR 설명 우선순위
FR-P-1 프로바이더 CRUD(name, display_name, model_name, endpoint, priority, cost_per_1k_input/output) P0
FR-P-2 API 키 AES-256 암호화 저장(api_key_encrypted) — 응답 시 ****<last 4> 마스킹 P0
FR-P-3 다중 프로바이더 지원(Anthropic / OpenAI / Google / DeepSeek / Ollama) P1
FR-P-4 우선순위 기반 default 모델 자동 선정 P1

3.4 외부 API 키 관리 (P0)

FR 설명 우선순위
FR-K-1 sk-pipe-{64hex} 키 발급, sha256 해시 저장, prefix(16자) 표시용 저장 P0
FR-K-2 키 목록(SUPER/COMPANY 관리자는 전체, 일반 사용자는 자기 키만) P0
FR-K-3 키 폐기(SOFT delete: status=revoked 또는 hard delete — vexplor는 hard delete) P0
FR-K-4 rate_limit, monthly_token_limit, expires_at, permissions(JSON) P0
FR-K-5 키 검증 시 last_used_at, usage_count 자동 갱신 P0
FR-K-6 월간 토큰 한도 초과 시 HTTP 429 P0

3.5 외부 호출 게이트웨이 (P0)

FR 설명 우선순위
FR-X-1 POST /api/ai/v1/chat/completions — OpenAI 호환(스트리밍 포함) P0
FR-X-2 POST /api/ai/v1/groups/:groupId — 멀티 에이전트 그룹 실행 P0
FR-X-3 GET /api/ai/v1/groups — 사용 가능 그룹 목록 P1
FR-X-4 GET /api/ai/v1/models — 모델 목록(프로바이더 기반) P1
FR-X-5 GET /api/ai/v1/health — 헬스체크 P1
FR-X-6 API 키 + JWT 동시 인증 허용(내부/외부 모두 사용 가능) P0

3.6 사용량 추적 (P1)

FR 설명 우선순위
FR-U-1 모든 LLM 호출에 대해 ai_agent_usage_logs 적재(prompt/completion/total tokens, cost_usd, 응답시간, success, error) P1
FR-U-2 요약: 오늘/이번 달 토큰·요청·비용 + active 에이전트/키 수 P1
FR-U-3 일별 차트(최근 30일) P1
FR-U-4 페이징 로그 조회 P1

3.7 대화 모니터링 (P2)

FR 설명 우선순위
FR-C-1 그룹 실행 시 대화 자동 저장(conversation + 사용자 메시지 + 각 step 응답) P2
FR-C-2 대화 목록 페이징·에이전트별 필터 P2
FR-C-3 대화 상세(메시지 시퀀스) 조회 P2
FR-C-4 대화 삭제 P2

3.8 스케줄 실행 (P1)

FR 설명 우선순위
FR-S-1 스케줄 CRUD(cron_expression, group_id, input_message, notification) P1
FR-S-2 cron 표현식 검증 + 재등록 P1
FR-S-3 알림 채널: 시스템 공지(system_notice) / 웹훅(슬랙) / 이메일(기존 mailSend 서비스 재사용) P1
FR-S-4 서버 기동 시 활성 스케줄 자동 등록 P1
FR-S-5 last_run_at, run_count 누적 P1

3.9 OpenClaw 통합 (P1)

FR 설명 우선순위
FR-O-1 OpenClaw 컨테이너로 기동(invyone docker-compose에 서비스 추가, 기본 port 18789) P1
FR-O-2 OpenClaw config 동기화 — 프로바이더(authProfiles) + 에이전트(agents) → JSON 파일 P1
FR-O-3 프로바이더/에이전트 변경 시 트리거(저장 후 sync 호출) P1
FR-O-4 OpenClaw 다운 시 graceful — 관리 기능은 동작 유지, 외부 호출만 503 P1

3.10 지식 라이브러리 (P2)

FR 설명 우선순위
FR-N-1 지식 파일 CRUD(ai_knowledge_files: name, file_name, category, content) P2
FR-N-2 에이전트 config.knowledge_files에서 library_id 또는 인라인 content 참조 P2
FR-N-3 검색·카테고리 필터 P2

3.11 메뉴/권한 등록 (P0)

FR 설명 우선순위
FR-M-1 새 AI 메뉴 7개를 부서/권한 그룹 시스템(직전 커밋 2c57dc8c)에 등록 P0
FR-M-2 슈퍼관리자 전용 메뉴(LLM 관리, LLM 사용량 통계 등) 분리 P0
FR-M-3 기존 INVION 메뉴 가이드(AI_어시스턴트_메뉴_등록_가이드.md) 갱신 P1

4. 비기능 요구사항 (NFR)

4.1 멀티테넌시 (강제)

  • 모든 AI 테이블에 company_code VARCHAR(20) 컬럼 — NULL 또는 * 은 슈퍼관리자 전용 / 글로벌 공유
  • 모든 list/get/update/delete 쿼리에 (company_code = :myCompany OR company_code IS NULL) 적용
  • SUPER_ADMIN 만 회사 간 자료 조회 가능 (company_code=* 쿼리 매개변수 허용)

4.2 보안

  • API 키: 평문 저장 금지. SHA-256 해시 + 16자 prefix 만 저장. 발급 시점에만 평문 1회 노출
  • LLM 프로바이더 API 키: AES-256 대칭 암호화(EncryptUtil 포팅 필요). 응답에서 마스킹
  • JWT: 기존 invyone JJWT 0.12.3 그대로 사용
  • API 키 인증 필터(AiApiKeyAuthFilter): Spring Security 필터 체인에 추가, JWT 필터보다 앞 또는 같은 layer
  • Rate limit: 키당 분당 N회(기본 60), 월간 토큰 한도(기본 100만)
  • CORS: 기존 invyone 정책 따름

4.3 성능

  • 그룹 parallel 실행: CompletableFuture.allOf 기반(JDK 21 가상 스레드 권장)
  • 그룹 sequential 실행: 직렬 await
  • 그룹 mixed 실행: execution_order 동률 → 병렬, 다른 order → 순차 await
  • LLM 호출 타임아웃: 60초 default, 스트리밍은 무제한 (커넥션 keep-alive)
  • DB index: ai_agent_usage_logs(created_at), ai_agent_api_keys(key_hash), ai_agents(agent_id), ai_agent_groups(group_id)

4.4 가용성

  • OpenClaw 다운 시:
    • 외부 LLM 호출은 invyone 자체 LlmClient(직접 프로바이더 HTTP 호출)로 fallback
    • 관리 화면은 정상 동작
  • DB 다운 시: 통상 invyone 정책(=실패) 따름
  • 헬스체크: /api/ai/v1/health 가 프로바이더 수 응답

4.5 마이그레이션 안전성

  • ai-assistant Sequelize 테이블(users, api_keys, llm_providers, usage_logs) drop 가능 (사용자 확인됨, 운영 데이터 없음)
  • 새 vexplor 스키마는 별도 마이그레이션 스크립트로 적용. 기존 invyone PostgreSQL과 같은 DB 사용
  • 명명 충돌 위험: ai-assistant의 users, api_keys 등 일반 테이블명 — invyone 본 스키마와 동명 충돌 가능 → drop 시점에 보존 검증 필수
  • 새 스키마는 모두 ai_ prefix 사용 (vexplor 컨벤션) → 충돌 없음

4.6 관찰성

  • 모든 핵심 호출에 SLF4J + Spring Boot logback 로깅(요청/응답/에러)
  • ai_agent_usage_logs 가 사실상 1차 audit
  • 에러는 invyone 표준 ApiResponse(success/error code/message) 포맷

4.7 호환성

  • Java 21, Spring Boot 3.3.5, MyBatis 3.0.3, PostgreSQL 16, Lombok
  • Frontend: Next.js (invyone 기존), shadcn/ui, dnd-kit (vexplor에서 사용)
  • vexplor의 Promise.all, node-cron, axios → Java 등가물(CompletableFuture, Spring @Scheduled/Quartz, RestClient/WebClient)

5. 이식 작업 분해 (WBS)

Epic A — 기존 AI 어시스턴트 제거 (P0)

목표: invyone 측의 ai-assistant 모듈을 흔적 없이 걷어낸다.

Story 작업
A1: ai-assistant/ 디렉토리 통째 삭제 C:\Dev\projects\invyone\ai-assistant\ 폴더 삭제. README, package.json, src/ 전부
A2: Spring 프록시 컨트롤러 삭제 AiAssistantProxyController.java, AiAssistantProxyService.java 삭제 + Spring 컴포넌트 스캔 영향 확인
A3: docker-compose 정리 docker-compose.backend.win.yml, docker-compose.frontend.win.yml(있다면), Dockerfile에서 ai-assistant 참조 항목 제거. 현재 파일에는 명시적 ai-assistant 서비스 없음(확인됨) — 환경변수 AI_ASSISTANT_SERVICE_URL 등 잔재만 정리
A4: Jenkinsfile 정리 현재 Jenkinsfile은 단일 Build 단계만 있고 ai-assistant 별도 stage 없음(확인됨). 변경 불필요 — 단, helm-charts 측 values_invyone.yaml 의 ai-assistant 이미지 참조가 있다면 별도 PR 필요(미확인 사항으로 표기)
A5: 프론트엔드 메뉴/페이지 제거 frontend/app/(main)/admin/aiAssistant/ 8개 페이지 + frontend/lib/api/aiAssistant/ (client.ts, index.ts) + frontend/components/layout/AdminPageRenderer.tsx 라인 128, 142~147 제거 후 vexplor 신규 페이지로 교체(Epic F)
A6: 메뉴 가이드 문서 제거/갱신 frontend/docs/AI_어시스턴트_메뉴_등록_가이드.md, docs/leeheejin/AI_어시스턴트_사용가이드.md 폐기 또는 신규 가이드로 대체
A7: 기존 ai-assistant DB 테이블 drop users, api_keys, llm_providers, usage_logs (Sequelize 자동 생성). 주의: invyone 본 시스템에 동명 테이블 없는지 검증 후 drop. 마이그레이션 스크립트로 작성

Story 수: 7

Epic B — DB 스키마 마이그레이션 (P0)

목표: vexplor의 AI 스키마를 invyone PostgreSQL에 적용.

⚠️ 사용자 프롬프트에 명시된 db/migrations/300_create_openclaw_tables.sql 파일은 vexplor 리포지토리에 물리적으로 존재하지 않음(전체 검색 확인). 따라서 vexplor 서비스/타입 코드(aiAgent*.ts 9개 + aiAgent.ts 타입)에서 스키마를 역공학해야 한다 — 이 작업이 Epic B의 핵심이며 Story B1에서 수행한다.

Story 작업
B1: vexplor 코드 역공학으로 스키마 재구성 9개 서비스 + types/aiAgent.ts 분석 → 13개 테이블 DDL 작성: ai_agents, ai_agent_groups, ai_agent_group_members, ai_agent_api_keys, ai_llm_providers, ai_agent_conversations, ai_agent_messages, ai_agent_usage_logs, ai_agent_schedules, ai_analysis_logs, ai_knowledge_files, (선택) ai_agent_tools (P3)
B2: 마이그레이션 스크립트 작성 invyone DB 마이그레이션 컨벤션에 맞춰(MyBatis용 .sql 또는 별도 도구) V20260427__ai_orchestration.sql 형태. 멱등 보장(IF NOT EXISTS)
B3: 인덱스 / FK / 제약 정의 5.3 NFR 인덱스 + cascade 정책(예: 그룹 삭제 시 멤버 cascade)
B4: 시드 데이터 기본 LLM 프로바이더 row 1~2개(키 비활성 placeholder), 슈퍼관리자용 샘플 에이전트 1개(선택 P2)
B5: 마이그레이션 적용 절차 문서화 dev/staging/prod 적용 가이드 + 롤백 스크립트

Story 수: 5

Epic C — Spring 백엔드 포팅 (P0)

목표: TS 9개 서비스 + 컨트롤러 + 라우트 → Java 21 / Spring / MyBatis 1:1 매핑

Story 작업
C1: 공통 인프라 EncryptUtil(AES-256), LlmClient(Anthropic / OpenAI / Google / DeepSeek / Ollama HTTP 클라이언트, 스트리밍 포함), DTO 패키지(com.erp.dto.ai.*), MyBatis Mapper 인터페이스 + XML 13개
C2: AiAgentService 에이전트 CRUD + 검색·필터 + company_code 필터
C3: AiAgentGroupService 그룹 CRUD + 멤버 CRUD + 가용 커넥터 조회(invyone에 동등 테이블 존재 여부 확인 필요 — external_db_connections, external_rest_api_connections, crawl_configs, pipeline_device_connections 가 invyone에 있는지 architect가 결정)
C4: AiAgentApiKeyService sk-pipe 키 발급/검증/폐기 + 토큰 누적
C5: AiAgentProviderService 프로바이더 CRUD + 암복호화 + 마스킹
C6: AiAgentConversationService 대화 + 메시지 저장/조회/삭제
C7: AiAgentUsageService 사용량 적재 + 요약 + 일별/페이징
C8: AiAnalysisLogService 분석 이력 CRUD + 평균 정확도
C9: MultiAgentExecutionEngine sequential/parallel/mixed 분기 + 컨텍스트 누적 + 커넥터 실행 + 지식 파일 주입 + 최종 요약 — CompletableFuture 기반
C10: AiSchedulerService Spring @Scheduled 또는 Quartz로 cron 등록/해제, 알림 발송(시스템 공지 / 슬랙 웹훅 / 이메일)
C11: OpenClawSyncService 프로바이더/에이전트 → OpenClaw config(JSON) 동기화
C12: 컨트롤러 — 관리(JWT) /api/ai-agents, /api/ai-agents/keys/*, /api/ai-agents/providers/*, /api/ai-agents/conversations/*, /api/ai-agents/usage/*
C13: 컨트롤러 — 그룹(JWT) /api/ai-agent-groups(+ /:id/members, /connectors)
C14: 컨트롤러 — 외부(API Key) /api/ai/v1/chat/completions(스트리밍 포함), /api/ai/v1/groups/:groupId, /api/ai/v1/groups, /api/ai/v1/models, /api/ai/v1/health
C15: 컨트롤러 — 스케줄(JWT) /api/ai-agent-schedules CRUD
C16: 컨트롤러 — 지식(JWT) /api/ai-knowledge CRUD

Story 수: 16

Epic D — 인증 미들웨어 (P0)

Story 작업
D1: AiApiKeyAuthFilter Spring Security OncePerRequestFilter 로 작성 — Authorization: Bearer sk-pipe-* 만 처리, JWT 는 기존 필터로 위임
D2: SecurityConfig 조정 /api/ai/v1/** 경로는 AiApiKeyAuthFilter 우선 적용. 관리 경로(/api/ai-agents/** 등)는 JWT 유지
D3: 동시 인증 허용 외부 게이트웨이는 sk-pipe 키 + JWT 둘 다 허용 (vexplor 동일 동작)

Story 수: 3

Epic E — OpenClaw 컨테이너 통합 (P1)

Story 작업
E1: OpenClaw 배포 방식 결정 Dockerfile 또는 외부 이미지 사용 여부 조사. Helm chart 추가 또는 docker-compose 신규 서비스
E2: docker-compose에 openclaw 서비스 추가 docker-compose.backend.win.yml 에 openclaw 서비스(포트 18789), 환경변수, 볼륨(config 공유)
E3: invyone Spring → OpenClaw URL 환경변수 OPENCLAW_BASE_URL, OPENCLAW_ENABLED 추가
E4: Config 공유 볼륨 OpenClawSyncService 가 쓰는 JSON 파일 경로를 컨테이너 간 공유(또는 HTTP 동기화 API로 변경 architect 결정)
E5: K8s 매니페스트 k8s/ 폴더에 OpenClaw 매니페스트 추가(필요 시)

Story 수: 5

Epic F — 프론트엔드 통합 (P0)

Story 작업
F1: vexplor 7개 페이지 이식 agents/, providers/, conversations/, workspace/, api-keys-manage/, knowledge/, layout.tsx, page.tsx → invyone frontend/app/(main)/admin/aiAssistant/ 로 복사. 기존 invyone aiAssistant 폴더 통째 교체
F2: API 클라이언트 이식 vexplor frontend/lib/api/aiAgent.ts → invyone frontend/lib/api/aiAgent.ts 신규. invyone 기존 lib/api/aiAssistant/ 폴더 삭제
F3: BASE URL 정리 invyone apiClient(/api)와 일치하는지 검증, vexplor의 /ai-agents, /ai-agent-groups, /ai-knowledge 경로 그대로 사용
F4: AdminPageRenderer 라우팅 갱신 기존 `aiAssistant/dashboard
F5: shadcn 의존성 점검 dnd-kit(@dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities), sonner(toast) — invyone에 없으면 추가
F6: 다국어/스타일 점검 vexplor 페이지의 한국어 메시지, dark mode 클래스가 invyone 디자인 시스템과 호환되는지 확인
F7: 스케줄러 페이지 신규 작성 (vexplor에 미포함) /admin/aiAssistant/scheduler — 백엔드 AiSchedulerService 와 짝 (아키텍트 결정 후 Story 추가 가능)

Story 수: 6~7

Epic G — 메뉴/권한 등록 (P0)

Story 작업
G1: 신규 AI 메뉴 7개를 메뉴 마스터에 등록 2c57dc8c 부서 권한 그룹 권한 관리 커밋의 메뉴 시스템에 다음 URL 등록: /admin/aiAssistant, /admin/aiAssistant/agents, /admin/aiAssistant/workspace, /admin/aiAssistant/providers(SUPER), /admin/aiAssistant/api-keys-manage, /admin/aiAssistant/conversations, /admin/aiAssistant/knowledge
G2: 권한 그룹 매핑 SUPER_ADMIN/COMPANY_ADMIN/일반사용자 별 메뉴 노출 범위 정의
G3: 사이드바 아이콘 Bot 아이콘(기존 가이드 따라) — frontend/components/layout/Sidebar 등에서 키워드 매핑
G4: 가이드 문서 갱신 frontend/docs/AI_어시스턴트_메뉴_등록_가이드.md 신규 메뉴로 교체

Story 수: 4

Epic H — 검증/배포 (P0)

Story 작업
H1: 단위 테스트 — Service 계층 JUnit 5 + MyBatis 테스트(testcontainers PostgreSQL). 각 서비스 핵심 시나리오
H2: 통합 테스트 — 외부 게이트웨이 sk-pipe 키 발급 → /api/ai/v1/chat/completions 호출 → 사용량 적재 검증(MockServer로 LLM 응답 stub)
H3: E2E — 그룹 실행 mixed 모드, 2 멤버 + 커넥터 1개, 응답 + 대화 저장 + 분석 이력 검증
H4: 컨테이너 기동 검증 docker-compose up → backend + openclaw + frontend 헬스체크 통과
H5: 마이그레이션 dry-run dev DB에 마이그레이션 적용 → 전체 화면 + API 동작 확인
H6: 성능 smoke 동시 그룹 실행 10개 + parallel 멤버 5개 → 토큰 누적·DB write 정합성
H7: 보안 점검 API 키 평문 비노출, 프로바이더 키 마스킹, JWT 누락 시 401
H8: 운영 가이드 배포 / 롤백 / 트러블슈팅 / OpenClaw 관리 문서

Story 수: 8


5.x WBS 요약

Epic Story 수 주요 위험
A. 기존 제거 7 helm-charts 측 잔재, 메뉴 깨짐
B. DB 스키마 5 SQL 미존재 → 역공학 정확도
C. Spring 포팅 16 LlmClient 스트리밍, ExecutionEngine 동시성
D. 인증 3 필터 체인 충돌
E. OpenClaw 5 외부 엔진 라이선스/배포 가능성
F. 프론트엔드 6~7 디자인 시스템 호환성
G. 메뉴/권한 4 권한 매핑 누락
H. 검증 8 LLM mock 정확도
합계 54~55

참고: 사용자 프롬프트에서 "39 Story 추정"으로 시작했으나, 실제 분석 결과 54~55개가 더 정확함. 일부 Story는 architect 단계에서 묶거나 분할될 수 있다.


6. Story 상세 (대표 5개 발췌)

6.1 Story C9 — MultiAgentExecutionEngine 포팅

  • 입력: vexplor_pipeline/backend-node/src/services/multiAgentExecutionEngine.ts (478라인)
  • 변경 작업:
    • executeSequential → 직렬 await 루프
    • executeParallelCompletableFuture.allOf (Java 21 가상 스레드 권장)
    • executeMixed → execution_order 그룹핑 후 직렬+병렬 혼합
    • executeSingleAgent → 에이전트 조회 + 커넥터 실행 + 지식 파일 주입 + LlmClient 호출
    • executeConnector → DB / REST / PLC / 크롤러 / 파일 — invyone에 해당 테이블 존재 여부 확인 후 적용 (architect가 mapping 결정)
    • buildFinalSummary → 동일
    • 사이드 이펙트: AiAgentConversationService.createConversation/addMessage, AiAnalysisLogService.save, AiAgentUsageService.log
  • DoD:
    • 동일 입력에 대해 vexplor와 응답 메시지 구조 동일
    • parallel 모드에서 5개 에이전트 동시 실행 시 응답시간 ≤ max(개별 응답시간) × 1.2
    • 사용량 / 대화 / 분석 이력 모두 적재
    • 에이전트 실행 실패 1건은 그룹 전체 실패로 이어지지 않음(개별 step에 [실행 실패] 응답 기록)
  • 의존성: C1(LlmClient, EncryptUtil), C2~C7
  • 위험: Java/Node 동시성 모델 차이로 race condition 발생 가능. JDK 21 가상 스레드 사용 시 MyBatis SqlSession 스레드 안전성 검증 필요

6.2 Story B1 — 스키마 역공학

  • 입력: vexplor 9개 서비스 + types/aiAgent.ts
  • 변경 작업: 13개 테이블 DDL 작성. 각 테이블 컬럼 추론 근거(서비스 SQL 쿼리 라인) 주석 첨부
  • DoD: vexplor 백엔드를 invyone DB 스키마로 띄웠을 때(가상 시나리오) 모든 INSERT/UPDATE/SELECT 가 동작
  • 의존성: 없음 (Epic B 시작점)
  • 위험: 일부 컬럼이 서비스에서 SELECT/INSERT 모두 사용되지 않으면 역공학 누락. architect 검토 단계에서 vexplor DB dump 또는 별도 schema 문서 확보 권장

6.3 Story D1 — AiApiKeyAuthFilter

  • 입력: vexplor/backend-node/src/middleware/aiApiKeyAuthMiddleware.ts
  • 변경 작업:
    • OncePerRequestFilter 상속, /api/ai/v1/** 경로 매칭
    • sk-pipe-* 토큰 → AiAgentApiKeyService.validateKey
    • 월간 토큰 한도 초과 → 429
    • JWT 토큰은 기존 JwtAuthenticationFilter 로 위임 (이중 필터)
  • DoD: 키로 호출 시 req.apiKey 정보가 컨트롤러에 전달, JWT로 호출 시 Authentication 객체 정상
  • 의존성: C4(AiAgentApiKeyService)
  • 위험: 필터 순서. Spring Security 6 의 addFilterBefore 위치 결정

6.4 Story A7 — 기존 ai-assistant DB 테이블 drop

  • 입력: ai-assistant Sequelize 모델 4개(users, api_keys, llm_providers, usage_logs)
  • 변경 작업:
    • 사전 검증: invyone 본 시스템에 users, api_keys 동명 테이블이 있는지 (있을 가능성 높음 — users는 ERP 핵심 테이블일 수 있음)
    • 위험 해소: ai-assistant가 사용한 DB 스키마(예: ai_assistant 스키마) 존재 여부 확인 필요. 만약 동일 schema 라면 컬럼 충돌 / 데이터 덮어쓰기 위험
    • drop 스크립트(별도 schema에 있다면 DROP SCHEMA IF EXISTS ai_assistant CASCADE)
  • DoD: 메인 invyone 기능에 영향 없이 잔여 테이블/스키마 제거
  • 의존성: 없음 (Epic A 마지막)
  • 위험: 메인 users/api_keys 와 충돌. 반드시 architect 단계에서 ai-assistant DB 분리 여부 확인

6.5 Story F1 — vexplor 페이지 이식

  • 입력: vexplor 7개 페이지(agents, providers, conversations, workspace, api-keys-manage, knowledge, layout.tsx, page.tsx)
  • 변경 작업:
    • 기존 invyone aiAssistant/ 폴더 8개 페이지 삭제
    • vexplor 페이지 그대로 복사 + import path 조정(@/lib/api/aiAgent 신규)
    • shadcn 컴포넌트 의존성 검증
  • DoD: 7개 페이지 모두 build / type-check / lint 통과 + 핵심 화면 렌더링
  • 의존성: F2(API 클라이언트), C12~C16(백엔드 컨트롤러)
  • 위험: invyone vs vexplor의 shadcn 컴포넌트 버전 차이로 prop signature 불일치

7. 순서 / 의존성 그래프

        ┌──────────┐
        │   A      │ (기존 제거 — 어디서나 시작 가능, A7은 최후)
        └────┬─────┘
             │ A1~A6 병행
             ▼
        ┌──────────┐    ┌──────────┐
        │   B      │───▶│   C      │
        │ (스키마) │    │ (Spring) │
        └────┬─────┘    └────┬─────┘
             │               │
             │               ▼
             │          ┌──────────┐
             │          │   D      │ (Security 통합)
             │          └────┬─────┘
             │               │
             ▼               ▼
        ┌──────────┐    ┌──────────┐
        │   E      │    │   F      │ (Frontend) — C12~C16 후
        │ (Claw)   │    └────┬─────┘
        └────┬─────┘         │
             │               ▼
             │          ┌──────────┐
             │          │   G      │ (메뉴/권한)
             │          └────┬─────┘
             ▼               │
         ┌────────────────────┴──────┐
         │             H              │ (검증/배포)
         └────────────────────────────┘

Critical path: B → C → F → G → H (백엔드 + 프론트가 직렬에 가까움)

병행 가능: A(제거)는 B/C와 병행 가능, E(OpenClaw)는 C9(엔진)이 끝나면 시작


8. 위험 / 가정

8.1 위험 (Risk)

ID 위험 영향 대응
R1 300_create_openclaw_tables.sql 미존재 → 역공학 오류 High architect에 vexplor DB dump 요청. 또는 vexplor 저자 인터뷰
R2 OpenClaw 외부 엔진 라이선스/배포 불명 High architect 단계에서 OpenClaw 패키징 방식 결정 (npm global / Docker 이미지)
R3 invyone에 vexplor 커넥터 테이블 부재 (external_db_connections 등) Medium 커넥터 기능 P2로 후순위 또는 invyone 측에 동등 테이블 신설 결정
R4 ai-assistant users/api_keys 와 invyone 본 테이블 충돌 High A7 전 schema 분리 검증 필수
R5 LLM 스트리밍 응답 Spring 구현 난이도 Medium Spring WebFlux SSE 또는 RestClient 스트림 응답 사용
R6 컨테이너 추가에 따른 운영 비용 증가(OpenClaw) Low OPENCLAW_ENABLED=false 토글로 단계 도입
R7 vexplor와 invyone의 shadcn/Next.js 버전 차이 Medium F5 의존성 점검 단계에서 잠재 호환 이슈 포착
R8 Spring AI MCP 도입 결정 보류 → 향후 재작업 가능성 Medium 인터페이스를 LlmClient 추상화로 만들어 교체 용이성 확보
R9 멀티테넌시 정책 누락 → 회사 간 데이터 노출 Critical 모든 쿼리에 company_code 강제, 단위 테스트로 검증
R10 Jenkins helm-charts 측 ai-assistant 잔재 Low helm-charts 별도 PR(범위 외)

8.2 가정 (Assumption)

  • (A1) vexplor 백엔드의 PostgreSQL JSONB 사용은 invyone PostgreSQL에서도 동일하게 지원됨(같은 PG 16)
  • (A2) invyone 운영자가 OpenClaw 컨테이너를 추가하는 것에 동의함
  • (A3) AES-256 암호화 키는 환경변수로 주입(AI_PROVIDER_ENCRYPTION_KEY)
  • (A4) 기존 invyone JWT 발급 시 userType claim 에 SUPER_ADMIN / COMPANY_ADMIN / 일반 값이 들어 있음 (vexplor 컨트롤러가 의존)
  • (A5) company_code claim 도 JWT에 포함되어 있음
  • (A6) invyone PostgreSQL 마이그레이션 도구가 정해져 있음(MyBatis 자체 또는 Flyway/Liquibase 중 — architect 결정)
  • (A7) 외부 호출(B2B) 트래픽은 작음(분당 100 req 미만) — Rate limit 단순 구현 가능

9. Architect / Executor 가 결정해야 할 미정 사항

9.1 Architect 결정 필요

  1. 마이그레이션 도구: MyBatis 수동 SQL? Flyway? Liquibase?
  2. OpenClaw 배포: npm global 컨테이너 vs Docker Hub 공식 이미지(존재 여부 확인 필요) vs vexplor 측 Dockerfile 재사용
  3. OpenClaw config 동기화 방식: 공유 볼륨 파일? HTTP API? gRPC?
  4. Spring AI / Spring AI MCP 도입: 직접 HTTP 클라이언트 유지 vs Spring AI 채택
  5. 스케줄러 구현: Spring @Scheduled (단순) vs Quartz (DB 영속화 + 클러스터링)
  6. 커넥터 테이블 존재 여부: invyone에 external_db_connections, external_rest_api_connections, crawl_configs, pipeline_device_connections 가 있는지 확인 → 없으면 P2 디그레이드
  7. API 키 폐기: hard delete (vexplor) vs soft delete (status='revoked') — 감사 로그 정책에 따라 결정
  8. AES-256 키 관리: 환경변수 vs Vault vs KMS
  9. 스트리밍 응답: Spring MVC SSE vs WebFlux
  10. Rate limit 구현: 인메모리(단일 인스턴스) vs Redis(클러스터)
  11. 테스트 전략: testcontainers PostgreSQL + WireMock LLM, 또는 별도 dev DB
  12. Schedule: ai_agent_schedules 의 cron 타임존(서버 시간 vs UTC)

9.2 Executor 단계 결정 가능

  • 커밋 단위 분리 전략 (Epic 단위 vs Story 단위)
  • 기존 ai-assistant 제거 시점(B 시작 전 vs C 진행 중)
  • 페이지별 점진 이식 vs 일괄 교체

9.3 검증/협의 필요(사용자에게 한 번 더)

  • (Q1) helm-charts 리포지토리(gitlab.kpslp.kr/root/helm-charts/values_invyone.yaml)에 ai-assistant 이미지 참조 잔재 존재 여부 — 확인 후 별도 PR 필요한지
  • (Q2) ai-assistant가 사용한 DB schema 이름 / 호스트 — invyone 본 DB와 동일하면 users/api_keys 충돌 위험. A7 실행 전 반드시 확인 필요
  • (Q3) 스케줄러 페이지 vexplor에 부재 — invyone에 신규 작성 필요한지(F7 Story 활성화 여부)

10. 산출물 및 다음 단계

10.1 본 PRD 결과물

  • 파일: C:\Dev\projects\invyone\.omc\plans\ai-orchestration-replacement-prd.md (본 문서)
  • 추가 산출물 (이번 단계 외):
    • architecture.md (architect)
    • tasks/*.md (executor가 Story 분해)
    • verification.md (verifier)

10.2 권장 다음 단계

  1. 사용자에게 9.3 미정 질문 답변 요청 (특히 Q2 ai-assistant DB 분리 여부)
  2. architect 에이전트 호출:
    • 9.1 결정 사항 12개에 대해 기술 결정
    • C9 ExecutionEngine 동시성 모델 상세 설계
    • 스키마 ERD 작성
  3. architect 산출물을 바탕으로 executor 가 Story 단위 구현

11. 부록 — invyone 측 영향 파일 인덱스

11.1 삭제 대상

C:\Dev\projects\invyone\ai-assistant\                                    (전체)
C:\Dev\projects\invyone\backend-spring\src\main\java\com\erp\controller\AiAssistantProxyController.java
C:\Dev\projects\invyone\backend-spring\src\main\java\com\erp\service\AiAssistantProxyService.java
C:\Dev\projects\invyone\frontend\app\(main)\admin\aiAssistant\          (전체 8 파일/폴더)
C:\Dev\projects\invyone\frontend\lib\api\aiAssistant\                    (client.ts, index.ts)
C:\Dev\projects\invyone\frontend\docs\AI_어시스턴트_메뉴_등록_가이드.md
C:\Dev\projects\invyone\docs\leeheejin\AI_어시스턴트_사용가이드.md       (선택)

11.2 수정 대상

C:\Dev\projects\invyone\frontend\components\layout\AdminPageRenderer.tsx (라인 128, 142~147)
C:\Dev\projects\invyone\docker-compose.backend.win.yml                   (openclaw 서비스 추가)
C:\Dev\projects\invyone\backend-spring\src\main\java\com\erp\security\SecurityConfig.java (필터 체인)
C:\Dev\projects\invyone\backend-spring\build.gradle                       (의존성 추가 — RestClient, ScheduledTasks 등 필요시)

11.3 신규 작성 대상 (Spring 백엔드)

backend-spring/src/main/java/com/erp/
  ├── ai/
  │   ├── controller/
  │   │   ├── AiAgentController.java
  │   │   ├── AiAgentGroupController.java
  │   │   ├── AiAgentApiKeyController.java
  │   │   ├── AiAgentProviderController.java
  │   │   ├── AiAgentConversationController.java
  │   │   ├── AiAgentUsageController.java
  │   │   ├── AiAgentScheduleController.java
  │   │   ├── AiKnowledgeController.java
  │   │   └── AiV1GatewayController.java        (외부 API 키 진입)
  │   ├── service/
  │   │   ├── AiAgentService.java
  │   │   ├── AiAgentGroupService.java
  │   │   ├── AiAgentApiKeyService.java
  │   │   ├── AiAgentProviderService.java
  │   │   ├── AiAgentConversationService.java
  │   │   ├── AiAgentUsageService.java
  │   │   ├── AiAnalysisLogService.java
  │   │   ├── AiSchedulerService.java
  │   │   ├── AiKnowledgeService.java
  │   │   ├── MultiAgentExecutionEngine.java
  │   │   ├── OpenClawSyncService.java
  │   │   └── LlmClient.java
  │   ├── mapper/                                (MyBatis Mappers)
  │   ├── dto/                                   (Request/Response DTOs)
  │   ├── domain/                                (Domain models)
  │   ├── filter/AiApiKeyAuthFilter.java
  │   └── util/EncryptUtil.java
  └── ...
backend-spring/src/main/resources/mapper/ai/    (MyBatis XMLs)
backend-spring/src/main/resources/db/migration/V20260427__ai_orchestration.sql

11.4 신규 작성 대상 (프론트엔드)

frontend/app/(main)/admin/aiAssistant/
  ├── agents/page.tsx
  ├── workspace/page.tsx
  ├── providers/page.tsx
  ├── conversations/page.tsx
  ├── api-keys-manage/page.tsx
  ├── knowledge/page.tsx
  ├── (option) scheduler/page.tsx
  ├── layout.tsx
  └── page.tsx
frontend/lib/api/aiAgent.ts

12. 변경 이력

일자 작성자 변경
2026-04-27 planner 최초 작성