From 511c87b2903628f26b581abdb0cae6ee3e69fcbc Mon Sep 17 00:00:00 2001 From: sal Date: Mon, 1 Jun 2026 17:46:53 +0900 Subject: [PATCH] docs: update ROADMAP to reflect P0/P1 completion and services/ package structure Co-Authored-By: Claude Sonnet 4.6 --- ROADMAP.md | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index e1e564a..725c16a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,16 +4,16 @@ | 항목 | 현재 상태 | 심각도 | |------|---------|--------| -| 아키텍처 모듈화 | UI·비즈니스 로직 혼재 (2파일) | 🔴 높음 | +| 아키텍처 모듈화 | ~~2파일 혼재~~ → config / api_client / services/ / container / app 5모듈 분리 | ✅ 완료 | | Windows 호환성 | ~~TTS `say` 명령어 — macOS 전용~~ → 크로스플랫폼 구현 완료 | ✅ 완료 | | Gradio Chatbot 타입 | ~~`type="messages"` 누락~~ → Gradio 6.x 기본 포맷 사용 | ✅ 완료 | | JSON yield 타입 불일치 | ~~`JSONDecodeError` 시 타입 혼용~~ → `str()` 변환 적용 | ✅ 완료 | | run_id 인덱싱 버그 | ~~`history` / `run_ids` 동기화 취약~~ → 방어 로직 추가 | ✅ 완료 | | RAG 출처 표시 | ~~thinking 박스에 혼재~~ → 답변 하단 `📄 출처` 전용 박스로 분리 | ✅ 완료 | -| async/sync 혼용 | 동기 콜백에서 `asyncio.run()` 사용 (5곳) | 🟡 중간 | -| 코드 중복 | `asyncio.run()` 패턴 5회 반복 | 🟡 중간 | -| 결합도 | `api_client` 직접 임포트·전역 상태 | 🔴 높음 | -| 테스트 가능성 | ~20% (모킹 불가능) | 🔴 낮음 | +| async/sync 혼용 | ~~`asyncio.run()` 5곳~~ → 모든 콜백 async 전환 완료 | ✅ 완료 | +| 코드 중복 | ~~`asyncio.run()` 5회 반복~~ → container 위임으로 제거 | ✅ 완료 | +| 결합도 | ~~`api_client` 직접 임포트~~ → DI container + Protocol 추상화 | ✅ 완료 | +| 테스트 가능성 | Protocol 도입으로 모킹 가능 — 테스트 미작성 | 🟡 중간 | | 로깅 | `print()` 만 사용 | 🟢 낮음 | --- @@ -43,8 +43,8 @@ └──────────────┬───────────────────────────┘ │ 생성 ┌──────────────▼───────────────────────────┐ -│ services.py │ -│ ChatService / DocumentService / TTSService │ +│ services/ │ +│ chat.py / document.py / tts.py │ └──────────────┬───────────────────────────┘ │ 사용 ┌──────────────▼───────────────────────────┐ @@ -194,13 +194,14 @@ class HTTPAPIClient: # 기존 함수들을 메서드로 이전 ``` -### 3. 서비스 레이어 분리 → `services.py` 신규 생성 +### 3. 서비스 레이어 분리 → `services/` 패키지 신규 생성 ``` -services.py -├── ChatService(api_client) — chat, reset, save_feedback -├── DocumentService(api_client) — ingest, list_documents, delete_document -└── TTSService() — tts_speak (플랫폼 분기) +services/ +├── __init__.py — ChatService, DocumentService, TTSService 재익스포트 +├── chat.py — ChatService: chat, reset, save_feedback +├── document.py — DocumentService: ingest, list_documents, delete_document +└── tts.py — TTSService: speak (플랫폼 분기) ``` ### 4. 수동 DI 컨테이너 → `container.py` 신규 생성 @@ -259,10 +260,14 @@ class Container: ``` youlbot-webui/ ├── app.py # Gradio UI 전용 — 콜백만 존재, 비즈니스 로직 없음 -├── container.py # 수동 DI 컨테이너 (신규) -├── services.py # ChatService, DocumentService, TTSService (신규) -├── api_client.py # APIClientProtocol + HTTPAPIClient (리팩터링) -├── config.py # AppConfig, APIConfig dataclass (신규) +├── container.py # 수동 DI 컨테이너 +├── services/ +│ ├── __init__.py # 재익스포트 +│ ├── chat.py # ChatService +│ ├── document.py # DocumentService +│ └── tts.py # TTSService +├── api_client.py # APIClientProtocol + HTTPAPIClient +├── config.py # AppConfig, APIConfig dataclass ├── tests/ │ ├── test_chat_service.py │ └── test_document_service.py @@ -287,7 +292,7 @@ youlbot-webui/ ### P1 - [x] `config.py` 작성 (APIConfig, AppConfig) - [x] `api_client.py` — `APIClientProtocol` + `HTTPAPIClient` 분리 -- [x] `services.py` 작성 (ChatService, DocumentService, TTSService) +- [x] `services/` 패키지 작성 (chat.py, document.py, tts.py + __init__.py 재익스포트) - [x] `container.py` 작성 (lazy singleton 프로퍼티) - [x] `app.py` — 모든 콜백 async 전환 및 container 사용 (`asyncio.run()` 완전 제거)