# 📋 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
