68893236+KINDNICK@users.noreply.github.com c5df37ca57 v2.8.0: 도전과제 시스템 + 다크 디자인 리뉴얼 + 안정성 강화
Added — 도전과제 시스템 (153개 자동 평가)
- core/achievements.py: 16개 카테고리, 5단계 등급, 시크릿 9개, 메타 도전과제
- ui/achievements_view.py: 4탭 다이얼로그 (전체/진행중/완료/시크릿)
- 5분 throttle 자동 평가 + 시스템 알림 + Discord embed push
- achievements 테이블 확장 (code/category/tier/is_secret/progress/target)
- hire_date 자동 추적, 뷰 진입 카운터 8개 settings 키

Changed — 다크 테마 디자인 리뉴얼
- ui/dark_components.py: 재사용 가능한 다크 컴포넌트 (header/card/button/progress)
- 통계/도움말/도전과제 다이얼로그 일관 다크 톤
- matplotlib 차트 다크 테마 적용 (figure/axes/grid/legend)
- 등급별 카드 그라디언트 (브론즈/실버/골드/플래티넘/레전드)

Fixed — 안정성·일관성
- 타임존 자정 경계 버그 (has_notification_today UTC vs localtime mismatch)
- DB 연결 누수: _conn() 컨텍스트 매니저 도입, 40+ 메서드 변환
- DB 이중 부트스트랩 제거 (MainWindow(db=None) 옵션 인자)
- crash_handler 다단계 폴백 (DB → 파일 → stderr)
- updater PID race: 지수 backoff 재시도 (총 ~9초)
- Discord URL 형식 검증 (snowflake regex)
- 일일 보고서 저녁 섹션, MealTimeDialog 출/퇴근 범위 검증
- check_dinner_reminder 신규, 알림 임계값 5개 설정화
- closeEvent timer/notifier 정리 (aboutToQuit hook)
- 마이그레이션 12개 모두 _conn() + try/finally
- DB 인덱스 5개 추가 (break/overtime/leave date)

Tests
- pytest 116/116 PASS, 통합 시나리오 48/48 PASS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 01:11:13 +09:00

316 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [2.8.0] — 2026-05-01
### Added — 도전과제 시스템 + 디자인 리뉴얼
- **🏆 도전과제 시스템** (153개 자동 평가) — 출근·퇴근·연장·연차·식사·외출·계절·시간대·시크릿 등 16개 카테고리.
- `core/achievements.py`: `Achievement` dataclass + `evaluate_all(db)` + `sync_definitions_to_db(db)`.
- 5분 throttle로 자동 평가, 신규 잠금 해제 시 시스템 알림 + Discord embed push.
- `achievements` 테이블 확장: `code`(UNIQUE), `category`, `tier`, `is_secret`, `progress`, `target`, `created_at` 컬럼 추가 (idempotent 마이그레이션).
- 5단계 등급: 🥉 브론즈 / 🥈 실버 / 🥇 골드 / 💎 플래티넘 / 🌟 레전드.
- 시크릿 9개 (회문, 잭팟 시각, 13일의 금요일, 7-7-7, 정확 8시간, π day, 피보나치 등).
- 메타 도전과제 (도전과제 자체 달성 카운트).
- **`ui/achievements_view.py`** — 4탭 다이얼로그 (전체 / 진행 중 / 완료 / 시크릿).
- 등급별 그라디언트 카드, 진행 게이지, 카테고리 태그, 시크릿 ❓ 처리.
- **자동 hire_date 추적** — 첫 `add_work_record` 호출 시 settings에 자동 기록 (1주년, 365일 후 출근 등 도전과제 활성화).
- **뷰 진입 카운터** — `stat_*_view_count`, `calendar_view_count`, `daily_report_count` 등 8개 settings 키. 도전과제 + 사용 통계용.
### Changed — 다크 테마 디자인 리뉴얼
- **`ui/dark_components.py`** 신설 — 재사용 가능한 다크 디자인 컴포넌트:
- `dialog_qss()`, `tabs_qss()`, `scroll_qss()`, `button_qss(variant)`.
- `build_gradient_header()`, `build_stat_card()`, `build_section_card()`.
- `style_progressbar()`, `transparent_label()` — 글로벌 QSS 충돌 회피.
- 카드 테마 7종: blue / cyan / green / gold / pink / red / gray.
- **`ui/stats_view.py`** — 4분할 카드 + 차트 섹션 카드. 골드 강조 탭. ghost 닫기 버튼.
- **`ui/help_view.py`** — 다크 톤 + HelpHTML 내부에 다크 CSS 주입 (h1/h2/h3, code, blockquote, table 컬러).
- **`ui/chart_widget.py`** — 모든 matplotlib 차트 다크 테마 적용 (figure/axes facecolor, grid, ticks, legend).
- **온보딩 위저드** — 저녁 분(minutes) 입력 옵션 + i18n화 (Korean/English 프리셋 라벨).
### Fixed — 안정성·일관성
- **타임존 자정 경계 버그**: `has_notification_today``CURRENT_TIMESTAMP`(UTC) vs `DATE('now', 'localtime')` mismatch로 KST 0~9시 사이 알림 중복 발송 가능 — `DATE(sent_at, 'localtime')` 양쪽 적용.
- **DB 연결 누수 가드** — `_conn()` 컨텍스트 매니저 도입, 40+ 메서드 변환 (직접 `get_connection()` 호출 0건).
- **DB 이중 부트스트랩 제거** — `MainWindow(db=None)` 옵션 인자 추가, main.py가 만든 db를 재사용.
- **crash_handler 폴백** — DB 로깅/다이얼로그 단계 분리, 모두 실패해도 `~/.clockout_logs/crashes.log`에 기록.
- **updater PID race window** — 지수 backoff 재시도 (0.3→4.8s, 총 ~9초). Windows Defender 락 해제 대기 충분.
- **Discord URL 형식 검증** — Snowflake ID 17~20자리 + 50+자 토큰 정규식.
- **MealTimeDialog** — 출근 시각 범위 검증 + 야간 출근자 자정 경계 자동 처리.
- **CSV importer/exporter** — `dinner_minutes` 컬럼 round-trip 지원.
- **일일 보고서** — 저녁 섹션 추가 (이전엔 점심만 표시), `break_type` 분리, 자정 경계 처리.
- **저녁 알림** — `check_dinner_reminder()` 신규 (점심 알림과 대칭).
- **알림 임계값 설정화** — 5개 하드코딩 값(점심/저녁 알림 시간, 연장 누적, 주간 한도, 연속 야근)을 settings로 노출.
- **closeEvent 정리** — `aboutToQuit` 시그널로 timer/notifier/tray 정리.
- **마이그레이션 일관성** — 12개 마이그레이션 모두 `_conn()` + try/finally 보장.
### DB 인덱스 (성능)
- `idx_break_records_date_type`, `idx_break_records_date`.
- `idx_overtime_bank_date`, `idx_overtime_usage_date`, `idx_leave_records_date`.
### Tests
- pytest 116개 PASS, 통합 시나리오 44/48 PASS (PyQt 환경 4개 제외).
- 도전과제 한 사이클 시나리오 검증 (30일 시뮬레이션 → 19개 자동 잠금 해제).
## [2.7.0] — 2026-04-30
### Added — 폴리싱 릴리스 (사용자 가시 변화는 작지만 i18n + 테스트 + 구조 개선)
- **i18n 사전 100% 커버리지** — `break_view`, `overtime_view`, `leave_view`,
`clock_in_dialog` 의 내부 라벨/메시지/플레이스홀더까지 전부 ko/en 키화.
새 키 50+개 추가 (`view.break.*`, `view.overtime.*`, `view.leave.*`, `dlg.*`).
- **i18n 런타임 재번역** — 재시작 없이 메인 화면 즉시 언어 전환.
- `ui/i18n_runtime.py`: `register(widget, key)` + `set_language_and_retranslate(lang)`
- 위젯은 weakref로 보관되어 삭제 시 자동 정리
- 메인 윈도우 타이틀/하단 메뉴 5개 버튼 등록 완료 (점진 확대)
- 일부 다이얼로그는 여전히 재시작 필요 (다음 릴리스에서 점진 등록)
- **MealController 분리** — `main_window.py` 에서 점심/저녁 토글·라벨 갱신 로직을
`ui/controllers/meal_controller.py` 로 추출. 기존 `LockMonitor`/`AutoLunch`/
`NotificationOrchestrator` 패턴 준수.
### Tests
- 통합 테스트 +15 시나리오 (S36S52): 온보딩 신규/기존, salary 추정, CSV 가져오기
(skip/overwrite/overtime 적립까지), notification_log dedupe, meal_record,
crash_log, updater semver 비교, Discord 입력 검증, goal/accessibility 키 등.
- 신규 pytest 모듈 4종 — `test_salary.py`, `test_csv_importer.py`,
`test_discord_webhook.py`(network mocked), `test_crash_handler.py`.
- `test_i18n_runtime.py` — register/retranslate/post-callback/dead-widget 정리 검증.
- 총 pytest 케이스: 90 → **122**, 통합 시나리오: 33 → **48**.
### Docs
- `README.md` v2.4v2.6 신기능 섹션 정리, 재번호.
- `CLAUDE.md` v2.6+ 아키텍처 — 컨트롤러 모듈, 35+ 설정 키, 릴리스 플로우 반영.
- `INSTALL.md` 최신 단일파일 배포 + 온보딩 + 디스코드 + 환경변수 정리.
- `AGENTS.md` 10+ DB 테이블, 컨트롤러 맵, Past Incidents 갱신.
## [2.6.0] — 2026-04-30
### Added — Phase 4 (3종)
- **글꼴 크기 조절** (100% / 125% / 150%) — 설정에서 즉시 반영
- **고대비 모드** — 검정 배경 + 노란 텍스트 (시각약자/야간)
- **코드 서명 인프라** — `release.ps1`에 Authenticode 서명 단계 추가 (옵션)
- `$env:CODE_SIGN_CERT` (`.pfx` 경로) + `$env:CODE_SIGN_PASS` 환경변수 설정 시 자동 서명
- signtool.exe 없거나 cert 미설정 시 자동 스킵
- 코드 서명 인증서 확보 후 활성화하면 SmartScreen 경고 제거 가능
### Settings (신규)
- `font_scale`, `high_contrast`
## [2.5.0] — 2026-04-30
### Added — Phase 3 (4종)
- **주간 자동 리포트** — 월요일 첫 출근 시 (또는 첫 5분 tick) 지난주 요약 발송
- 시스템 알림 + Discord push (옵션) 동시
- `notification_log`로 중복 발송 방지
- 항목: 총 근무·일평균·연장근무·가장 긴 날
- **matplotlib 차트 호버 디테일** — 막대 위에 마우스 올리면 정확한 수치 툴팁
- 일별 근무 시간 차트(주간 탭)에 적용
- **출근 시각 분포 차트** — 패턴 분석 탭에 30분 단위 히스토그램
- 평균 출근 시각 빨간 점선으로 표시
- **휴가 캘린더 시각화** — 연차 관리 → "📅 캘린더 보기"
- 사용 일자에 종일/반차/반반차별 색상 표시
- 날짜 클릭 → 사용 내역 표시
### Fixed
- `leave_view.py` setLayout 들여쓰기 회귀 수정
## [2.4.0] — 2026-04-30
### Added — Phase 2 (5종)
- **점심/저녁 실제 시간 입력** — 점심/저녁 버튼 우클릭 → 시작·종료 시각 입력 다이얼로그
- 자동 60분 대신 정확한 분 단위 기록 (`break_records.break_type='lunch'/'dinner'`)
- **캘린더 우클릭 → 과거 일자 추가/편집/삭제**
- 비어있는 날짜 우클릭: "기록 추가" — 출/퇴근/점심/메모 입력
- 기록 있는 날짜 우클릭: "편집"/"삭제"
- **월간 목표 설정 + 진행률**
- 설정 → 월 연장근무 상한 (시간/분) + 일 평균 근무 목표 (시간)
- 통계 → 월간 탭에 진행률 게이지 (60%/100% 임계 시 색상 변경)
- 0=비활성 (비활성 시 위젯 자체 숨김)
- **CSV 가져오기** — 표준 포맷 `date,clock_in,clock_out,lunch_minutes,memo`
- 충돌 정책: 덮어쓰기/건너뛰기/취소
- **자동 Crash Report (Gitea Issues)**
- 전역 예외 후킹 → crash_log 저장 + 사용자에게 다이얼로그
- "복사" / "Gitea에 보고" (PAT 옵션) — issue 자동 생성
### Settings (신규 4개)
- `goal_overtime_max_monthly`, `goal_avg_hours_daily`
- `gitea_feedback_token`, `gitea_feedback_enabled`
## [2.3.3] — 2026-04-30
### Fixed
- **Discord 웹훅 항상 실패하던 문제** (Cloudflare error 1010 / 403 Forbidden)
- 원인: Python 기본 User-Agent(`Python-urllib/3.x`)를 Discord/Cloudflare가
봇으로 인식해 차단
- 수정: `utils/discord_webhook.py`에 브라우저 UA 헤더 추가
(`Mozilla/5.0 (Windows NT 10.0; Win64; x64) ClockOutCalculator/2.3`)
- 이제 온보딩 위저드의 "테스트 메시지 보내기" + 출퇴근/휴식 push 모두 정상 동작
## [2.3.2] — 2026-04-30
### Fixed
- **도움말 다이얼로그가 빈 창으로 표시되던 치명적 버그**
- v2.3.1에서 "온보딩 다시 보기" 버튼 추가 시 `self.setLayout(main_layout)` 라인이
실수로 `_reopen_onboarding` 메서드 안으로 들여쓰기되어 init_ui가 setLayout 없이 종료
- F1 누르면 빈 화면만 나옴 (탭 6개 모두 미렌더링)
- setLayout 호출 위치 복원 → 정상 표시
## [2.3.1] — 2026-04-30
### Fixed
- **도움말 다이얼로그에 "온보딩 다시 보기" 버튼 추가**
- v2.3.0에서 `show_onboarding()` 메서드는 만들었지만 UI 진입점 누락
- 이제 도움말 (F1) → 좌측 하단 "🚀 온보딩 다시 보기" 버튼으로 위저드 재실행 가능
- 본인 검증/설정 변경 시 유용
## [2.3.0] — 2026-04-30
### Added — Phase 1 + E1 (소비자 친화 6종)
- **첫 실행 온보딩 위저드** (강제) — 5단계: 환영 → 근무패턴 → 출근 감지 방식 → 연차/시급(옵션) → Discord(옵션) → 완료
- 신규 사용자: 자동 표시 / 기존 사용자(work_records 있음): 자동 완료 처리
- "도움말 → 온보딩 다시 보기" 메뉴로 언제든 재실행 가능
- **시급 → 추정 급여** (옵션) — 포괄임금이 아닐 때만 활성화
- 통계 화면 월간 탭에 "이번 달 추정 급여" 카드
- 퇴근 후 "오늘 요약" 카드에도 추정 급여 표시
- 연장수당 가산률 1.0 / 1.5 / 2.0 선택
- **출퇴근 시각 인라인 편집** — 메인 화면 출근/퇴근 라벨 클릭 → 즉시 수정 다이얼로그
- **퇴근 후 "오늘 요약" 카드** — 메인 화면 상단에 총 근무/점심/외출/연장/추정급여 표시
- 다음 출근 시 자동 숨김 / X 버튼으로 수동 닫기
- **장시간 근무 휴식 권고 알림** — 연속 N시간(기본 4시간) 자리 비움 없으면 "🌿 잠시 일어나세요" 토스트
- 5분 throttle + 일 1회 가드 (notification_log 테이블)
- **Discord 웹훅 알림** (옵션) — 출퇴근/휴식권고 모바일 push
- 봇 등록·서버 운영 0. 채널 웹훅 URL만 입력
- 출근(녹색) / 퇴근 정시(파랑) / 퇴근 연장(주황) / 건강경고(분홍) embed
- 온보딩에서 즉시 활성화 + "테스트 메시지" 버튼
### Database
- `break_records.break_type` 컬럼 추가 ('break' / 'lunch' / 'dinner' 구분)
- `notification_log` 테이블 신규 (channel, event_type, sent_at, success — 중복 발송 가드 + 통계용)
- 기존 사용자 `onboarding_completed` 자동 true 처리 마이그레이션
### Settings (신규 11개)
- `onboarding_completed`, `salary_enabled`, `hourly_wage`, `overtime_rate`
- `health_break_enabled`, `health_break_hours`
- `discord_webhook_url`, `discord_notif_clock_in`, `discord_notif_clock_out`, `discord_notif_health`
## [2.2.4] — 2026-04-30
### Added
- **`auto_overtime` 옵션 실제 동작** — 기존엔 UI만 있고 동작 안 했음
- **OFF**: 퇴근 시 적립 가능한 분이 있으면 "적립할까요?" 다이얼로그 표시 (Y/N)
- **ON** (기본): 자동 적립 (이전과 동일)
- **`overtime_unit` 실제 동작** — 30/15/60분 단위 적립 선택 반영
- 기존엔 무조건 30분 절삭. 이제 설정값 사용 (`time_calculator.calculate_overtime` `unit_minutes` 파라미터)
- **퇴근 알림 시점 사용자 설정** (`notification_before_minutes`)
- 기존 30분 하드코드 → 1~120분 SpinBox로 사용자 지정
- 설정 → 알림 그룹에 "퇴근 알림 시점" SpinBox
### Removed (죽은 옵션 정리)
- `auto_detect_boot` — 부팅 감지 비활성화 모드. 어디서도 안 쓰임
- `notification_enabled` — 마스터 스위치. 4개 개별 NOTIF_* 키로 충분
- `annual_leave_used``leave_balance`로 대체된 레거시 카운터
### Fixed
- 죽은 옵션이 사용자에게 "동작하는 것처럼" 보이던 신뢰성 문제 일괄 해소
## [2.2.3] — 2026-04-30
### Fixed
- **`updater.exe` 임베딩 빌드 안정화**
- v2.2.2에서 `main.spec --clean`이 빌드 시작 시 `dist/updater.exe`를 지우면서
임베딩이 누락되던 문제 수정
- `release.ps1``dist/updater.exe``build/staging/`로 복사 후 main.spec이 그걸 참조
- main.exe 사이즈가 다시 ~78MB (updater 내장) 로 정상화
## [2.2.2] — 2026-04-30
### Added
- 윈도우 제목에 현재 버전 표시 — 자동 업데이트 후 신/구 버전 시각적 구분
- 예: `⏰ 퇴근시간 계산기 v2.2.2`
### Test
- 자동 업데이트 더미 릴리스 — 단독 main.exe 배포 + 자가 업데이트 흐름 검증용
## [2.2.1] — 2026-04-30
### Added
- **`updater.exe` 내장 (Single-file 배포)**
- `main.exe` 안에 `updater.exe`를 PyInstaller `datas`로 임베드
- 시작 시 `main.exe`가 같은 폴더에 `updater.exe`를 자동 추출 (없거나 사이즈 다르면 갱신)
- 사용자는 이제 **`main.exe` 하나만 받아도** 자동 업데이트 동작
- 업데이트로 `main.exe`가 교체되면 새 main 실행 시 새 updater.exe도 자동 갱신
- `utils/updater_client.py`: `_MEIPASS` fallback — 권한 부족 등으로 추출 실패 시 TEMP에서 동작
### Changed
- `release.ps1` 빌드 순서: updater 먼저 → main 나중 (datas 의존성)
- `main.spec`: `dist/updater.exe` 존재 시 자동 임베드 (조건부 datas)
### Fixed
- 한국어 릴리스 노트 인코딩 (`Get-Content` ANSI → `[System.IO.File]::ReadAllText` UTF-8)
## [2.2.0] — 2026-04-30
### Added
- **자동 업데이트** — Gitea Releases 기반
- 시작 5초 후 백그라운드 버전 체크 (silent)
- F5 또는 설정 → 데이터 관리 → "업데이트 확인" 버튼으로 수동 트리거
- 새 버전 발견 시 다운로드 → `updater.exe`가 메인 종료 대기 → 파일 교체 → 재시작
- 실패 시 .bak 자동 롤백
- **`core/version.py`** — `__version__` 상수
- **`updater.py` + `updater.spec`** — 독립 자가 업데이터 (Python 표준 라이브러리만, 6MB)
- **`utils/updater_client.py`** — Gitea/GitHub 호환 Releases API 클라이언트
- **`release.ps1`** — 로컬 원클릭 릴리스 스크립트 (Runner 불필요)
- 빌드 + 태그 push + Gitea Release 생성 + 자산 업로드 자동화
- CHANGELOG에서 릴리스 노트 자동 추출
- `--DryRun` / `--SkipTests` 옵션
### Changed
- `Settings → 데이터 관리`에 "버전 표시 + 업데이트 확인" 추가
- `main.spec` datas에 안내 주석 (updater.exe는 별도 배포)
## [2.1.0] — 2026-04-29
### Removed
- **Claude AI 분석 기능** 제거 — 외부 API 의존성 정리
- **로컬 HTTP API** 제거 — 외부 위젯 연동 기능 미사용으로 정리
- **pandas 의존성** 제거 — 코드에서 미사용 (PyInstaller 빌드 사이즈 감소)
### Added
- **첫 잠금 해제 = 출근 옵션** (`clock_in_on_unlock`) — PC를 안 끄는 사용자 케이스 해결
- **WAL 모드 + busy timeout** — 클라우드 동기화 환경에서 다중 PC 동시 접근 안전성↑
- **`MainWindow` 컨트롤러 분리** — `LockMonitor` / `AutoLunchManager` / `NotificationOrchestrator`
- **`update_display` 변화 감지** — 직전 값과 동일 시 `setText` 스킵 (1Hz hot-path 부하↓)
- **언어 변경 시 자동 재시작 제안** — 사용자 동의 후 `os.execv`로 재시작
- **`CHANGELOG.md`** + **GitHub Actions CI** 추가
### Changed
- 5분 throttle 알림 (건강/주간/누적) `_last_5min_bucket` 명시 가드
- `PyInstaller` `excludes``pandas`, `numpy.testing`, `PyQt5.QtWebEngineWidgets` 추가
## [2.0.0] — 2026-04-29
### Added
- **단축근무 지원**: `work_minutes`(분 단위) + 5종 프리셋 (8h / 7h30m / 7h / 6h / 4h)
- **자동 점심시간** 적용 (출근 4h 경과)
- **DB 자동 백업** (`~/.clockout_backups/`, 7일 회전, SQLite backup API)
- **화면 잠금 자동 외출/복귀**
- **공휴일 자동 등록** (`holidays` 패키지, 음력 명절 포함)
- **시스템 트레이 완전 통합** (점심/외출/통계/캘린더/도움말)
- **미니 위젯** (Always-on-top, 드래그 가능)
- **matplotlib 차트** (일별/요일별 근무시간)
- **건강·주간·누적 알림** (3종 추가)
- **i18n 인프라** (한국어/English, 28 카테고리, HelpView ko/en HTML)
- **설정 키 상수 모듈** (`core/settings_keys.py`)
- **DB 경로 override** (클라우드 동기화 폴더 지정 가능)
- **앱 단축키 7종** (Ctrl+O/L/D/B, F1, Ctrl+R, Ctrl+,)
- **사용 설명 가이드** (HelpView, 6 탭)
- **48 통합 시나리오** + 5 i18n GUI + 8 widget smoke 테스트
### Fixed
- **+29h remaining time bug** — `break_minutes`에서 overtime 차감하던 로직 수정
- **annual_leave_total / annual_leave_days 키 불일치** — 양방향 자동 동기화
## [1.0.0] — 2026-01-09
- 최초 릴리스: 자동 출퇴근 / 점심 관리 / 30분 단위 연장근무 적립 / 캘린더 / 통계