VOC_Monitor/docs/project_spec.md

648 lines
22 KiB
Markdown

# 📋 Project Specification: VOC 모니터링 시스템
## 1. 프로젝트 비전
### 목표
부산교통공사 1호선 차량 관련 VOC(Voice of Customer)를 실시간으로 모니터링하고,
자동으로 보고서를 생성하여 업무 효율을 극대화합니다.
### 핵심 가치
- **자동화**: 수동으로 웹사이트를 확인하던 작업을 자동화
- **신속성**: 신규 VOC 발생 시 즉시 알림
- **정확성**: 열차 정보 자동 추출 및 시각표 기반 검증
- **편의성**: 한글(HWP) 보고서 자동 생성
### 핵심 페르소나
- **직무**: 부산교통공사 차량 부서 직원
- **환경**: Windows 10/11, 사내망
- **사용 패턴**: 백그라운드 상시 실행, 알림 기반 대응
---
## 2. 시스템 범위 (Scope)
### 포함 기능
- [x] **웹 크롤링**: 부산교통공사 VOC 게시판 자동 수집
- [x] **데이터베이스**: SQLite 기반 로컬 저장
- [x] **실시간 알림**: Windows 토스트 알림
- [x] **보고서 생성**: HWP/PDF 자동 작성
- [x] **열차 정보 분석**: 시각표 기반 열차번호, 입고지 자동 추출
- [x] **히스토리 관리**: 과거 VOC 조회 및 필터링
- [x] **설정 관리**: 크롤링 주기, 알림 키워드 등
### 제외 기능 (Out of Scope)
- ❌ 웹 기반 UI (데스크톱 전용)
- ❌ 다중 사용자 지원 (1인 사용 전제)
- ❌ 클라우드 동기화
- ❌ 모바일 앱
---
## 3. 핵심 비즈니스 로직 (Core Logic)
### 3.1 크롤링 사이클
```
1. 로그인 세션 확인 (만료 시 재로그인)
2. 목록 페이지 수집 (최대 N페이지)
3. 키워드/부서 필터링
4. DB 저장 (Upsert)
5. 상세 내용 수집 (조건부)
```
### 3.2 알림 사이클 (v2.1 개선)
#### 3.2.1 신규 알림 사이클 (기본 3분, 설정 가능)
```
1. 마지막 체크 이후 신규 데이터 조회 (get_new_posts_since)
- 설정 `noti.use_related_filter = true`: 관심글(is_related=1)만 조회
- 설정 `noti.use_related_filter = false`: 신규글 전체 조회
2. 중복 알림 필터링 (notified_post_ids 체크)
3. 모든 관심글(is_related=1)에 대해 알림 ⭐ 변경: 키워드 필터링 제거
4. 소리 재생 (설정 시)
5. 토스트 알림 및 팝업 표시
6. last_check_time 영속화 저장 ⭐ 신규
```
#### 3.2.2 미확인 알림 사이클 (기본 10분, 설정 가능) ⭐ 신규
```
1. 확인하지 않은 관심글 조회 (get_unchecked_related_posts)
- 설정 `noti.use_related_filter = true`: 관심글(is_related=1)의 미확인만 조회
- 설정 `noti.use_related_filter = false`: 전체 미확인글 조회
2. 30분 경과 조건 ON/OFF에 따라 필터링
- ON: 30분 이상 지난 글만 알림
- OFF: 미확인 글 전체 알림
3. 미확인 알림 발송 (⚠️ 표시)
4. 사용자가 확인할 때까지 반복 알림
```
#### 3.2.3 알림 개선 사항
- **키워드 필터링 제거**: 모든 관심글에 대해 알림 발송
- **중복 방지**: notified_post_ids 세트로 동일 글 중복 알림 방지
- **영속화**: last_check_time을 scheduler_state.json에 저장하여 프로그램 재시작 시에도 유지
- **미확인 체크**: 사용자가 확인하지 않은 글에 대해 주기적 재알림
- **주기 설정화**: 신규 알림 주기 및 미확인 알림 주기를 설정 UI에서 변경 가능
- **미확인 조건 토글**: "30분 경과 후 알림" 옵션 ON/OFF 지원
- **관심조건 토글**: "관심 조건(키워드/부서)만 알림" 옵션 ON/OFF 지원
### 3.3 보고서 생성 프로세스
```
1. VOC 데이터 수신
2. VOCParser로 기본 정보 추출 (호선, 편성, 호차, 열차번호)
3. DateScheduleUtils로 날짜 타입 판별 (평일/주말/휴일)
4. TrainAnalyzer로 열차 정보 분석 (종별, 방향, 입고지)
5. TimetableService로 시각표 조회 및 검증
6. HWP 템플릿에 데이터 입력
7. 파일 저장 (중복 체크)
```
### 3.4 통계 분석 프로세스 (신규)
```
1. 사용자 입력 수신 (기간, 분석 옵션)
2. 입력 검증 (날짜 형식, 기간 제한)
3. DB에서 데이터 집계
├── 기간별 통계 (일/주/월/년)
├── 부서별 분포
├── 상태별 현황
└── 키워드 빈도 분석
4. 차트 생성 (matplotlib/plotly)
├── 막대 그래프 (부서별, 상태별)
├── 선 그래프 (시계열 추이)
├── 파이 차트 (비율)
└── 워드 클라우드 (키워드)
5. 보고서 생성 (Excel/PDF)
6. 파일 저장 및 열기
```
#### 3.4.1 데이터 집계 로직
**기간별 통계**:
```python
SELECT
DATE(date) as day,
COUNT(*) as count
FROM voc_posts
WHERE date BETWEEN ? AND ?
GROUP BY DATE(date)
ORDER BY day
```
**부서별 분포**:
```python
SELECT
department,
COUNT(*) as count,
ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM voc_posts WHERE date BETWEEN ? AND ?), 2) as percentage
FROM voc_posts
WHERE date BETWEEN ? AND ?
GROUP BY department
ORDER BY count DESC
```
**키워드 빈도 분석**:
```python
# 1. 모든 제목 + 내용 추출
# 2. 형태소 분석 (선택, 한글 처리)
# 3. 불용어 제거 ("의", "를", "이" 등)
# 4. 빈도 계산
# 5. TOP 10 추출
```
#### 3.4.2 예외 케이스 처리
| 예외 상황 | 처리 방법 | 사용자 메시지 |
|-----------|-----------|---------------|
| 기간 내 데이터 없음 | 빈 보고서 생성 | "선택한 기간에 VOC 데이터가 없습니다." |
| 기간이 너무 긺 (1년 초과) | 기간 제한 | "최대 1년까지만 조회 가능합니다." |
| 차트 생성 실패 | 텍스트 표만 생성 | "차트 생성 실패. 표 형식으로 제공됩니다." |
| 메모리 부족 | 데이터 샘플링 | "데이터가 많아 일부만 표시됩니다." |
| Excel/PDF 생성 실패 | 에러 다이얼로그 | "보고서 생성 중 오류 발생: [상세 메시지]" |
#### 3.4.3 성능 최적화
**인덱스 추가**:
```sql
CREATE INDEX IF NOT EXISTS idx_date ON voc_posts(date);
CREATE INDEX IF NOT EXISTS idx_department ON voc_posts(department);
CREATE INDEX IF NOT EXISTS idx_status ON voc_posts(status);
CREATE INDEX IF NOT EXISTS idx_date_department ON voc_posts(date, department);
```
**쿼리 최적화**:
- 기간 제한: 최대 1년
- 페이징: 대량 데이터 시 배치 처리
- 캐싱: 동일 기간 재조회 시 캐시 사용 (선택)
**메모리 관리**:
- 차트 생성 후 즉시 파일 저장
- `plt.close()` 호출하여 메모리 해제
- 대용량 데이터 시 청크 단위 처리
---
## 4. 에러 처리 전략
### 4.1 부분 실패 허용 원칙
보고서 생성 시 일부 정보 조회 실패는 전체 작업을 중단하지 않습니다.
| 실패 유형 | 처리 방법 | 사용자 경험 |
|-----------|-----------|-------------|
| 열차번호 조회 실패 | 필드 비움 | 드롭박스 비활성화 |
| 시각표 조회 실패 | "정보 없음" 표시 | 경고 로그 |
| 템플릿 파일 없음 | 전체 중단 | 에러 다이얼로그 |
### 4.2 로그 레벨 구분
- `INFO`: 정상 동작 (크롤링 완료, 보고서 생성 등)
- `WARNING`: 부분 실패 (열차 정보 미조회 등)
- `ERROR`: 전체 실패 (로그인 실패, DB 오류 등)
### 4.3 사용자 친화적 메시지
모든 에러 메시지는 한국어로 작성하며, 기술적 용어를 최소화합니다.
**예시:**
- ❌ (Bad) `TimetableServiceError: train_number not found in dataframe`
- ✅ (Good) `열차 정보를 조회할 수 없습니다. 보고서는 생성되지만 열차번호 필드가 비어있습니다.`
---
## 5. 보고서 생성 규칙
### 5.1 필수 정보 vs 선택 정보
| 구분 | 필드 | 실패 시 처리 |
|------|------|--------------|
| **필수** | 제목, 내용, 날짜, 부서 | 전체 중단 |
| **선택** | 열차번호, 편성, 호차 | 필드 비움 |
| **선택** | 입고 정보, 비고 | "정보 없음" 표시 |
### 5.2 UI 동작 규칙
- **열차번호 조회 성공**: 드롭박스에 후보 목록 표시
- **열차번호 조회 실패**: 드롭박스 비활성화 + 수동 입력 허용
- **시각표 미로드**: 관련 기능 전체 비활성화
### 5.3 파일명 규칙
```
[날짜]_[부서]_[제목(정제)].hwp
예: 2026-02-17_차량_1호선_서면역_소음발생.hwp
```
---
## 6. 데이터 모델
### 6.1 VOCPost (Pydantic)
```python
class VOCPost(BaseModel):
id: str # 게시글 ID
title: str # 제목
writer: str # 작성자
department: str # 담당 부서
date: str # 작성일 (YYYY-MM-DD HH:MM:SS)
status: str # 처리 상태
channel: str # 접수 경로
is_public: int # 공개 여부 (0/1)
content: Optional[str] # 상세 내용
attachment: Optional[str] # 첨부파일명
is_related: int = 0 # 관심글 여부
```
### 6.2 데이터베이스 스키마
```sql
CREATE TABLE voc_posts (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
writer TEXT,
department TEXT,
date TEXT,
status TEXT,
channel TEXT,
is_public INTEGER DEFAULT 1,
content TEXT,
attachment TEXT,
is_related INTEGER DEFAULT 0,
checked_at TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
```
---
## 7. UI/UX 요구사항
### 7.1 메인 화면 (트레이 아이콘)
- 시스템 트레이에 상주
- 우클릭 메뉴: 수동 크롤링, 목록 보기, 설정, 종료
### 7.2 히스토리 다이얼로그
- 테이블 뷰: ID, 제목, 작성자, 부서, 날짜, 상태
- 필터: 부서별, 키워드, 날짜 범위
- 더블클릭: 상세 팝업
- 우클릭 메뉴: 보고서 생성, 인쇄, 첨부파일 보기
### 7.3 보고서 옵션 다이얼로그
- 사업소 선택 (신평/노포)
- 팀 선택 (검수1/검수2/...)
- 작성자 정보
- 열차번호 드롭박스 (자동 추출 시)
---
## 8. 제약 및 요구사항
### 8.1 기술 제약
- **Python**: 3.8 이상
- **OS**: Windows 10/11
- **필수 라이브러리**:
- `customtkinter`: UI
- `selenium`: 크롤링
- `pywin32`: HWP 자동화
- `pydantic`: 데이터 검증
- `pandas`: 시각표 처리
### 8.2 성능 목표
- 크롤링 주기: 10분 (설정 가능)
- 알림 지연: 5분 이내
- 보고서 생성: 3초 이내
- DB 조회: 1초 이내
### 8.3 보안 요구사항
- 로그인 정보: 로컬 JSON 파일 (평문 저장, 사내망 전제)
- HWP 보안 모듈: 레지스트리 자동 등록
---
## 9. 시스템 아키텍처
### 9.1 계층 구조 (v3.0 - Manager 패턴 적용)
```
┌─────────────────────────────────────────────────────┐
│ View (CustomTkinter) │
│ HistoryDialog, SettingsDialog, Notification │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Controller (MVC) - 위임 패턴 │
│ │
│ AppController (487줄) │
│ ├── SchedulerManager : 크롤링, DB 체크, 스케줄링│
│ ├── NotificationManager : 토스트/팝업 알림 │
│ ├── ReportManager : 보고서 생성/인쇄/PDF │
│ ├── FileManager : 첨부파일 다운로드/열기 │
│ └── UIManager : UI 창 관리 │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Services (Business Logic) │
│ ReportService, ScraperService, TimetableService │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Utils & Models (Data) │
│ VOCParser, TrainAnalyzer, VOCDatabase, ... │
└─────────────────────────────────────────────────────┘
```
### 9.2 주요 모듈 책임
| 모듈 | 책임 | 라인 수 |
|------|------|---------|
| `AppController` | 전체 흐름 제어, Manager 위임 | 487줄 |
| `SchedulerManager` | 크롤링 사이클, DB 체크, 스케줄링 | 399줄 |
| `NotificationManager` | Windows 토스트 알림, 팝업 다이얼로그 | 192줄 |
| `ReportManager` | 보고서 생성 요청, 인쇄, PDF 생성 위임 | 283줄 |
| `FileManager` | 첨부파일 다운로드 및 열기 | 151줄 |
| `UIManager` | UI 창 생성 및 포커스 관리 | 198줄 |
| `VOCScraper` | 웹 크롤링, 로그인 관리 | - |
| `ReportService` | HWP/PDF 생성, 인쇄 | 691줄 |
| `TimetableService` | 시각표 조회, 열차 검색 | - |
| `VOCParser` | VOC 텍스트 파싱 | - |
| `TrainAnalyzer` | 열차 정보 분석, 입고지 추적 | 355줄 |
| `DateScheduleUtils` | 날짜 처리, 공휴일 판별 | - |
---
## 10. 자동 업데이트 시스템 (Auto Update System) ⭐ 신규
### 10.1 개요
**목표**: 프로그램의 자동 업데이트 기능 구현
- Supabase 기반 원격 버전 관리
- 1시간마다 자동 업데이트 체크
- 사용자友好的 업데이트 알림 및 설치
- **멀티프로젝트 지원**: 다른 프로젝트에서도 재사용 가능한 모듈 설계
---
### 10.2 데이터베이스 테이블 정의 (Supabase)
**테이블명**: `program_version`
| 필드명 | 타입 | 설명 | 필수 |
|--------|------|------|------|
| `id` | SERIAL | Primary Key | ✅ |
| `program_id` | TEXT | 프로그램 식별자 (예: "voc_monitor") | ✅ |
| `version` | TEXT | 버전 번호 (예: "3.1.0") | ✅ |
| `is_stable` | BOOLEAN | 안정版 여부 | ✅ |
| `release_note` | TEXT | 배포 노트 | ❌ |
| `download_url` | TEXT | 다운로드 URL | ✅ |
| `min_required_version` | TEXT | 최소 요구 버전 (업그레이드 시) | ❌ |
| `created_at` | TIMESTAMP | 생성일시 | ✅ |
| `updated_at` | TIMESTAMP | 수정일시 | ✅ |
**예시 데이터**:
```json
{
"program_id": "voc_monitor",
"version": "3.1.0",
"is_stable": true,
"release_note": "- 크롤링 필터링 개선\n- Z-order 문제 해결\n- 자동 업데이트 기능 추가",
"download_url": "https://example.com/releases/voc_monitor_3.1.0.exe",
"min_required_version": "2.0.0",
"created_at": "2026-02-18T10:00:00Z"
}
```
---
### 10.3 로컬 버전 관리 파일
**1. `__version__.py`**
```python
"""
버전 정보
이 파일은 프로그램의 현재 버전을 정의합니다.
업데이트 시 이 파일의 VERSION과 비교하여进行检查합니다.
"""
VERSION = "3.0.0"
PROGRAM_ID = "voc_monitor"
APP_NAME = "VOC 모니터링"
```
**2. `updatelog.md`** (위치: `app/updater/updatelog.md`)
```markdown
# 업데이트 로그
## v3.1.0 (2026-02-18)
- 크롤링 필터링 개선 (AND/OR 모드 지원)
- Z-order 문제 해결
- 자동 업데이트 기능 추가
## v3.0.0 (2026-02-17)
- Controller 리팩토링
- Manager 패턴 적용
```
> **중요**: `updatelog.md`는 `app/updater/` 모듈 내에 위치하며, 개발 과정에서 발생한 변경사항을 기록하는 용도입니다. 모든 버전 업데이트 시 이 파일을 최신화해야 합니다.
---
### 10.4 모듈 설계 (utils/auto_updater.py)
```python
class AutoUpdater:
"""
자동 업데이트 관리자
Supabase에서 버전 정보를 조회하고 업데이트를 처리합니다.
Attributes:
program_id: 프로그램 식별자
current_version: 현재 버전
supabase_url: Supabase 프로젝트 URL
supabase_key: Supabase API 키
check_interval: 업데이트 체크 간격 (기본: 1시간)
주요 메서드:
check_for_updates: 업데이트 확인
download_update: 업데이트 파일 다운로드
install_update: 업데이트 설치
start_background_check: 백그라운드 업데이트 체크 시작
"""
```
---
### 10.5 업데이트 체크 주기
```
1시간마다 (기본값, 설정 가능)
├── Supabase에서 최신 버전 조회
├── 현재 버전과 비교
├── 업데이트 필요 시:
│ ├── 알림 다이얼로그 표시
│ ├── 사용자가 "지금 설치" 선택
│ │ ├── temp 폴더에 다운로드
│ │ ├── 현재 프로세스 종료
│ │ ├── 새 프로세스 실행 (업데이터)
│ │ └── 업데이터가 기존 파일 교체
│ └── "나중에" 선택 → 다음 주기까지 대기
└── 업데이트 없음 → 로그만 기록
```
**통합 동작 (v3.2.2 반영):**
- 앱 시작 시 `UpdateManager` 초기화 후 백그라운드 체크 시작
- 트레이 메뉴에 `업데이트 확인` 수동 항목 제공
- 업데이트 발견 시 사용자 확인 다이얼로그 표시
- 사용자 승인 시 `prepare_update()` -> `launch_updater()` -> 메인 앱 종료
**로그 명세 (필수 기록):**
- 초기화 성공/실패
- 백그라운드 체크 시작/오류
- 수동 확인 수행/결과(최신/업데이트 필요)
- 준비 실패/실행 실패 원인
---
### 10.6 아키텍처: updater.exe 분리 ⭐ 중요
**구조**:
```
메인 프로젝트 (cx_freeze 패킹)
├── updater.exe (별도 패킹, 최소 GUI 포함)
├── app/
│ └── updater/
│ ├── __init__.py
│ ├── __version__.py # 버전 정보
│ ├── update_manager.py # 메인 프로그램용 업데이트 관리자
│ ├── updater_gui.py # updater.exe용 GUI
│ └── updatelog.md # 업데이트 로그
└── ...
```
**실행 흐름**:
```
1. update_manager.py (메인 프로그램 내):
├── Supabase에서 새 버전 확인
├── 업데이트 config.json 생성 (%TEMP%/voc_updater_config.json)
│ {
│ "download_url": "https://supabase.../voc_noti_3.2.0.zip",
│ "target_path": "C:/Program Files/voc_noti",
│ "version": "3.2.0",
│ "restart_exe": "voc_noti.exe"
│ }
├── updater.exe를 %TEMP%로 복사
└── updater.exe 실행 후 메인 프로그램 종료
2. updater.exe (별도 프로세스):
├── config.json 읽기
├── zip 다운로드 (진행률 표시 - CustomTkinter GUI)
├── 압축 해제 → 파일 교체
└── 메인 프로그램 재실행
```
**updater.exe UI**:
- CustomTkinter 기반 최소 GUI 창
- 다운로드 진행률 표시 (Progress Bar)
- 상태 메시지 표시 (다운로드 중, 압축 해제 중, 완료)
- 성공/실패 결과 표시
**파일 교체 방식**:
- **전체 교체**: zip 다운로드 후 압축 해제
- 백업 폴더 생성 (이전 버전 보존)
- 실패 시 롤백 가능
**통신 방식**:
- 임시 JSON 파일 (`%TEMP%/voc_updater_config.json`)
- 메인 프로그램이 파일 생성 → updater.exe가 읽기
---
### 10.7 예외 케이스 처리
| 상황 | 처리 방법 |
|------|-----------|
| 네트워크 오류 | 업데이트 체크 건너뛰기, 로그 기록 |
| Supabase 연결 실패 | 재시도 (3회), 실패 시 다음 주기까지 대기 |
| 다운로드 실패 | 에러 메시지 표시, 재시도 옵션 제공 |
| 설치 중 오류 | 롤백 (백업 파일 활용), 에러 로그 기록 |
| 자기 자신 업데이트 | temp 폴더에 복사 후 별도 프로세스로 실행 |
| 버전 불일치 | min_required_version 기준 판단 |
**추가 안정화 반영 (통합 전 단독 검증 단계)**:
- Supabase URL/KEY 누락 시 사전 설정 오류 반환
- `voc_updater_config.json` 원자적 저장(`.tmp` -> 교체)
- updater.exe 누락 시 준비 단계에서 즉시 실패 반환
- 압축 해제 시 임시 폴더 사용 후 대상 경로에 단계적 복사
- 설치 실패 시 백업 롤백 + 임시 폴더 정리
---
### 10.8 멀티프로젝트 지원
**설계 원칙**:
- `program_id` 기반으로 동적 설정
- Supabase 테이블 구조的统一
- 설정 파일로 URL/Key 관리
**사용 예시**:
```python
# VOC 모니터링
updater = AutoUpdater(
program_id="voc_monitor",
current_version=VERSION,
settings=settings
)
# 다른 프로젝트
updater = AutoUpdater(
program_id="other_app",
current_version="1.0.0",
settings=settings
)
```
---
### 10.9 의존성
```json
{
"supabase": "^2.0.0",
"requests": "^2.31.0"
}
```
### 10.10 연결 설정 관리 (하드코딩 금지)
- Supabase 연결 정보는 `app/updater/config.json`에서 관리
- `config_url`: 원격 설정 URL
- `fallback.supabase_url`, `fallback.anon_key`: 원격 실패 시 대체값
- 런타임 동작 설정은 `settings.json``update` 섹션에서 관리
- `connection_config_path`, `environment`, `check_interval_hours`, `program_id`, `version_table`
- 버전 체크 시 테이블 자동 폴백 지원
- `program_version` 조회 실패(404) 시 `program_versions` 재시도
### 10.11 테스트 모드 검증 옵션
- `python app/main.py --test --test-update-now`
- 테스트 DB 모드로 앱을 실행하면서 updater 연결 확인을 시작 직후 1회 수행
- 네트워크/설정 오류 시 사용자 메시지 + 로그 기록
### 10.12 업데이터 빌드/통합 절차
1. 업데이터 단독 빌드
- `python app/update_build_setup.py`
- 결과: `app/updater_build/dist/updater.exe`
2. 메인 패키징
- `python app/setup.py build`
- 포함 항목:
- `updater.exe` (메인 exe와 동일 경로)
- `app/updater/config.json` (연결 설정)
3. 런타임
- `UpdateManager.prepare_update()`가 설치 경로의 `updater.exe``%TEMP%`로 복사 후 실행
---
## 11. 향후 개선 사항 (Roadmap 참조)
- [ ] 다중 호선 지원 (2호선, 3호선)
- [ ] 통계 대시보드
- [ ] 엑셀 내보내기
- [ ] 자동 응답 템플릿
---
작성자: KH.Choi
최종 수정: 2026-02-18
버전: 3.3