03. 보유 기술 아키텍처 상세 — PPS 모노레포
본 과제의 기반 자산인 PPS(Public Procurement System) 플랫폼의 아키텍처와 컴포넌트별 기술을 정리한다. 사업계획서 「수행실적 / 시스템 구성도」 작성 근거.
1. 플랫폼 개요
PPS는 AI 기반 공공조달 통합 플랫폼으로, 제안요청서(RFP) 자동 생성·기술평가 보조·조달사 챗봇을 제공하는 모노레포다. 본 정책자금 신청서 과제와 동일한 기술 도메인(한글 행정문서 + LLM + RAG + 서식 출력)에서 운영된다.
┌──────────────────────────────────────┐
사용자(웹/SSO) ───► │ portal-nginx (5-scope auth_request) │
└───────────────┬──────────────────────┘
┌─────────────────┼──────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌────────────────┐
│ 앱(Frontend) │ │ 앱(Backend) │ │ ai_dashboard │
│ rfp-gen │ │ FastAPI/SB │ │ 작업·비용모니터 │
│ eval-system │ └──────┬────────┘ └────────────────┘
└───────────────┘ │
┌──────────────┬────────────────┼─────────────────┬───────────────┐
▼ ▼ ▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌──────────────┐ ┌────────────┐ ┌────────────┐
│ ai_engine │ │knowledge_ │ │data_pipeline │ │analysis_ │ │ core_utils │
│ LLM 오케 │◄─┤ hub (RAG) │ │수집·파싱·벡터화│ │pipeline │ │ HWP 파서 │
│ 모델팩토리 │ │ Qdrant │ │ G2B/Upstage │ │교차문서분석 │ │ Upstage │
└─────┬─────┘ └─────┬─────┘ └──────────────┘ └────────────┘ └────────────┘
│ │
Celery+Redis Qdrant / PostgreSQL / MinIO
(분산 비동기 큐) (벡터·RDB·오브젝트 스토리지)
2. 기술 스택
| 영역 | 기술 |
|---|---|
| 백엔드 | Python 3.11 · FastAPI 0.124 · Pydantic v2 · SQLAlchemy 2.0 · Alembic / (eval-system) Java 17 · Spring Boot 3.4.6 |
| 비동기/큐 | Celery 5.4 · Redis 7 |
| 프론트엔드 | Next.js 15~16 · React 19 · TypeScript 5 · Tailwind CSS |
| AI/LLM | Gemini · OpenRouter · Qwen(vLLM) · HyperCLOVA X / 임베딩 KURE-v1(1024d 한국어) |
| 벡터/저장 | Qdrant(벡터) · PostgreSQL 16 · MinIO(S3 호환) |
| 문서 | 자체 HWP/HWPX 파서(olefile·lxml) · python-hwpx 생성 · Upstage 문서 디지털화 |
| 인프라 | Docker Compose(cloud/onprem/onprem-mock 3모드) · nginx · Infisical · K8s(템플릿) |
| 수집 | 나라장터(G2B) OpenAPI |
규모: Python 약 538개 · TS/TSX 약 309개 · Java 약 55개 소스 파일.
3. 코어 서비스 상세
3.1 ai_engine — LLM 오케스트레이션 (포트 8200)
- 모델 팩토리 (
core/engines/factory.py,base.py): provider별 엔진을 공통 인터페이스로 추상화. 민간 API와 로컬 vLLM을 동일 코드로 운용. - 동적 모델 설정 (
core/model_config.py):ModelConfigdataclass + 환경변수 로드 → 코드 수정 없이 모델 교체. - 모델 선택/Fallback (
core/model_selector.py):select_model(purpose, kind)— 목적별 라우팅 + 미일치 시 동종 fallback. - 프롬프트 레지스트리 (
core/prompts/registry.py):.md/.yamlfrontmatter 로드, 도메인별 디렉토리, 메타데이터(temperature·token 추정). - 비동기 작업 (
tasks/rfp_tasks.py,core/celery_app.py): Celery로 항목별 생성 분해, prerun/postrun 시그널로 상태 추적. - 사용량 추적 (
core/engines/mixins/llm_mixin.py,logging_mixin.py): 토큰·latency·비용 추정 누적.
3.2 knowledge_hub — RAG·벡터검색·인증 (포트 8100)
- 벡터 DB (
core/storage/vector_db/vector_db.py):VectorDBClient— Qdrant 래퍼. - 3-tier 인덱싱 (
core/rfp/rfp_indexer.py): documents/sections/requirements 컬렉션, 청킹(5000자/overlap 300). - 하이브리드 검색 (
core/rfp/rfp_query_service.py): RRF(40%) + cosine(60%). - 임베딩: KURE-v1 1024차원 한국어 모델(
docs/development/embedding_strategy.md), ai_engine/embed위임. - 포털 인증 (
app/api/portal_auth.py,core/storage/rdb/portal_db/jwt.py): 5-scope JWT·쿠키 분리, nginx auth_request 검증 엔드포인트.
3.3 data_pipeline — 수집·파싱·벡터화 (포트 8101)
- G2B 수집 (
rfp2/ingest.py,keyword_search.py): 나라장터 입찰공고·사전규격 API. - 파싱/추출 (
rfp2/parse.py,extract.py,requirement_extractor.py): 필드 추출·TOC 평탄화·요구사항 추출. - 검색 API (
app/api/rfp_search.py): bids/prespecs/integrated 엔드포인트.
3.4 analysis_pipeline — 교차 문서 분석 (포트 8102)
- 다중 문서 비교·분석 오케스트레이션.
3.5 ai_dashboard — 작업·비용 모니터링 (FE 8889 / BE 8890)
- 워커/작업 모니터링 (
backend/app/api/workers.py,tasks.py): 상태 집계·페이징·상세. - 토큰 집계: 작업별 input/output/total 토큰 노출. (예산 임계 차단은 미구현 → 04 참조)
3.6 core_utils — 공용 문서 라이브러리
- HWP/HWPX 파서 (
hwp_parser/parser/parse.py,services/hwpx_service.py): olefile(바이너리)·lxml(XML), 자동 포맷 감지. - Upstage 디지털화 (
upstage/document_digitizer.py): PDF·HWP→HTML 보조 경로.
4. 애플리케이션 — rfp-gen (본 과제 직접 원형)
정책자금 신청서 과제와 가장 직접적으로 대응하는 앱. RFP(제안요청서) 초안을 키워드/소스 기반으로 생성·편집·서식 출력하는 전체 흐름을 이미 구현.
| 계층 | 구현 |
|---|---|
| 백엔드(FastAPI) | apps/rfp-gen/backend/app/main.py — export/document/chatbot/search/section/session/template 라우터 |
| 생성 흐름 | services/ai_engine_client.py(generate_requirement·adapt_sections·edit_section), section_seeder.py(deterministic+AI 배치) |
| RAG 연동 | services/knowledge_hub_client.py — 유사 RFP·요구사항·TOC 조회 |
| 프론트(Next.js) | frontend/app/workspace/[id]/document/[docId]/layout.tsx — 7단계 진행, 목차/사이드바 |
| 인라인 편집/재생성 | frontend/components/document/DocumentWriteStep.tsx — 문단 클릭 직접수정·챗봇편집, openEditSegment·applyChatSuggestion, 목차 변경 시 증분 시딩(기존 보존) |
| A4 미리보기 | HWPX 렌더러 기반 HTML 렌더(render_hwpx_preview), A4 210×297mm |
| HWP 출력 | services/document_builder/hwpx_generator.py(python-hwpx) |
| DB | knowledge_hub/.../rfp_db/models.py — RFPSourceFile·RFPSection·RFPRequirement·RFPAIExecution 등 / Alembic asyncpg |
RFP 요구의 "키워드 입력 → 항목별 초안 생성 → 웹 에디터 인라인 편집·항목별 재생성 → HWP/PDF 출력" 흐름이 rfp-gen에 사실상 그대로 존재. 정책자금 도메인(서식·프롬프트·분류 라벨)만 교체하면 PoC 골격 완성.
5. 배포 아키텍처 (3-모드)
| 모드 | 파일 | 특성 |
|---|---|---|
| Cloud | docker-compose.cloud.yml |
인터넷/공공 모드, 민간 LLM, Cloudflare Origin Cert, self-hosted Infisical, HTTPS 쿠키 |
| OnPrem(폐쇄망) | docker-compose.onprem.yml |
pull_policy: never + 외부 레지스트리 차단, docker load < pps-images.tar 오프라인 반입 |
| OnPrem-Mock | docker-compose.onprem-mock.yml |
내부 vLLM(pps-kanana-2-30b·pps-qwen3-vl-8b) overlay, GPU 없는 검증용 |
- 모드 전환 스크립트:
scripts/start.sh(pps_resolve_mode, 네트워크 브리지). - RFP의 CSAP 인증 외부망 독립(CPU 기반) 요구는 OnPrem 모드로 직접 충족 — 통상 가장 까다로운 인프라 요건을 기보유 자산으로 해결.
6. 네트워크 격리
| 네트워크 | 범위 |
|---|---|
pps-network |
portal-nginx 허브 + 코어 서비스 |
pps_rfp-net |
rfp-gen 백엔드/프론트 격리 |
pps_eval-net |
eval-system 격리(전용 PostgreSQL 5433) |
jodal-pps-net |
eval-system-premium 격리 |
DB·캐시는 앱 내부망에만 노출, portal-nginx가 프록시 — RFP의 "보안·외부망 독립" 요구에 부합하는 격리 설계.