UI 복잡 버전 234 RED→GREEN 완료(docs/UI_USECASES.md §A~§J): 라이브 테마 전환(DynamicResource 전환+ThemeResolver+HighContrast 테마, 재시작 없음), 디자인 토큰 체계·WCAG 대비 결함 5건 수정, 설정창 카테고리 내비/검색 재구성+AppConfig 40여 속성, 다운로드 관리자(속도/ETA/세그먼트맵/전체 일시정지-이어받기/CSV 내보내기/예약 게이트/중복 확인), 라이브러리·아카이브·작업공간·재생목록·즐겨찾기 편집 뷰, 접근성(자동화 속성 30여 개·커스텀 피어·docs/ACCESSIBILITY.md), 인터랙션(휠 클릭 새 탭·XButton 탐색·F12·영역 캡처·프로필 전환), 상태/알림(토스트·알림센터·온보딩·CrashReportDialog). 보강 테스트 35건+실창 E2E 4건(StaDispatcher 기반 — 프록시 설정이 기시작 핸들러를 건드리는 크래시 실결함 수정 포함) — 453/453 GREEN. 이전 미커밋 작업(CI 워크플로·Mdns·QueueHub·UpdateChecker·AGENTS/CLAUDE·빌드 스크립트) 일괄 포함
This commit is contained in:
parent
5a0ce730b2
commit
17f2f91152
88 changed files with 9463 additions and 1127 deletions
40
docs/ACCESSIBILITY.md
Normal file
40
docs/ACCESSIBILITY.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# 접근성 지원 범위 (UC-A01~A20)
|
||||
|
||||
작성: 2026-08-17. UI 복잡 버전(docs/UI_USECASES.md §G) GREEN 구현과 함께 정의한
|
||||
접근성 지원 선언 문서. 무엇을 지원하고 어떻게 검증하는지 적는다.
|
||||
|
||||
## 지원 범위
|
||||
|
||||
| 영역 | 지원 내용 | 구현 위치 |
|
||||
|---|---|---|
|
||||
| 화면 낭독기(UIA) | 주요 컨트롤 30여 개에 `AutomationProperties.Name`/`HelpText` 부여 | `MainWindow.xaml` 툴바·카드·팝업 |
|
||||
| 라이브 영역 | 상태바 텍스트·다운로드 상태·대기 현황 `LiveSetting="Polite"`, 오류는 `Assertive` | 상태바, 카드 템플릿 |
|
||||
| 커스텀 자동화 피어 | `MainWindowAutomationPeer` 로 창 이름 노출 | `MainWindow.xaml.cs` |
|
||||
| 키보드 | Tab 이동(`TabIndex` 지정), 포커스 링(`FocusVisual` 공용 스타일), Esc 팝업 일괄 닫기 | `Shared.xaml`, `MainWindow` |
|
||||
| 접근 키 | `AccessText`(이동(_G)) 등 Alt 접근 키 | 툴바 이동 버튼 |
|
||||
| 툴팁 | `ToolTipService` 표시 지연/지속 설정 + 그림자 | `MainWindow`(Window 속성), `Shared.xaml` |
|
||||
| 고대비 | `Themes/HighContrast.xaml` + OS 고대비 자동 감지(`SystemParameters.HighContrast`, `UserPreferenceChanged`) | `App.xaml.cs`, `MainWindow` |
|
||||
| 색 무의존 상태 | 완료 ✓ 아이콘(`SuccessIcon`), 미디어 종류 배지 텍스트 | 카드 템플릿 |
|
||||
| 저시력 | 글자 확대 배율 최대 200%(`AppConfig.UiFontScale`), UI 배율(`UiScale`) | 설정 > 외관/접근성 |
|
||||
| 동작 민감 | 애니메이션 감소(`ReduceMotion` → Duration 토큰 0화) | 설정 > 접근성 |
|
||||
| 자막 | 영상 자막 표시 옵션(`ShowCaptions`) | 설정 > 접근성 |
|
||||
| 콘텐츠 언어 | 리더 모드 HTML `lang="ko"` 선언 | `ReaderMode.cs` |
|
||||
| 명도 대비 | WCAG AA 텍스트 4.5:1, 비텍스트 3:1 — 자동 검증 | 테스트 `UiUsecaseAccessibilityRedTests`, `UiUsecaseThemeRedTests` |
|
||||
|
||||
## 대비 기준과 검증
|
||||
|
||||
- 텍스트(본문·보조·강조): 다크·라이트 모두 **4.5:1 이상** (UC-T14~T18)
|
||||
- 진행 트랙·버튼 테두리 등 비텍스트 구성요소: **3:1 이상** (UC-A19~A20)
|
||||
- 대비율은 WCAG 2.x 상대 휘도식으로 테스트에서 실제 색값(`#RRGGBB`)을 파싱해 계산한다.
|
||||
테마 색을 바꿀 때마다 자동으로 재검증된다.
|
||||
|
||||
## 팝업 키보드 탐색
|
||||
|
||||
모든 플라이아웃(즐겨찾기·기록·다운로드·라이브러리·아카이브·단축키 도움말)에
|
||||
`KeyboardNavigation.TabNavigation="Cycle"` 를 적용해 팝업 안에서 포커스가 순환하며,
|
||||
Esc 한 번으로 열린 모든 팝업이 닫힌다(`CloseAllPopups`).
|
||||
|
||||
## 제약(현재 미지원)
|
||||
|
||||
- 완전한 UI 언어 전환(한/영)은 설정값 저장 + 일부 텍스트 적용 수준이다.
|
||||
- 터치 스크린 전용 제스처(스와이프 등)는 지원하지 않는다.
|
||||
|
|
@ -216,4 +216,32 @@
|
|||
2. 공유 리팩터: `App/Detection/*`(순수C#) Core 이동; `ICookieProvider` 중립 추상화; `DownloadManager` 공유화(생성자→`ICookieProvider`); `BindingOperations.EnableCollectionSynchronization`→Avalonia 디스패처; `IAppPaths` OS별 경로.
|
||||
3~8. 브라우저+감지, 설정, 테마(Avalonia Styles 재작성), 보더리스 윈도우(`ExtendClientAreaToDecorationsHint`), ViewModels, 북마크/히스토리.
|
||||
9. Mac/Linux 패키징(`.app` 노타라이제이션, `.AppImage`/`.deb`); `YtDlpRunner`/`DenoRunner` OS/arch별 바이너리 확인. 10. 패리티 후 WPF 은퇴.
|
||||
- **참고**: 저장소가 git 아님 → Phase 2 병행 작업 격리 위해 `git init` 권장.
|
||||
- **참고**: ~~저장소가 git 아님 → `git init` 권장~~ → git 전환 완료.
|
||||
|
||||
## 9차 팔로업 (2026-08-16 완료) — 계획 문서 잔여 갭 소거 (SignalR·mDNS·자동 업데이트·CI)
|
||||
> 목표 "만들어진 모든 계획 문서 달성"에 따라 MOBILE_PLAN·DEPLOYMENT_PLAN 의 미이행 항목 일괄 구현.
|
||||
|
||||
- [x] **SignalR 큐 허브 `/hubs/queue`** — MOBILE_PLAN §3 아키텍처 항목. `QueueHub`(GetQueue 스냅샷) + `IQueueAdapter.Changed` → `queueUpdated` 전 클라이언트 푸시. 인증 미들웨어에 `/hubs` 편입(`t`/`access_token` 쿼리 허용) + `UseWebSockets`. 실 Kestrel E2E 로 접속·푸시·401 검증. (`Server/QueueHub.cs`, `ServerHost.cs`)
|
||||
- [x] **mDNS 광고 `_videodl._tcp`** — MOBILE_PLAN M0 항목. `MdnsAdvertiser`(Makaretu.Dns) + `ServerOptions.EnableMdns`(App 은 켬). 실패는 `ServerHost.MdnsError` 로 표면화(발견 보조 — 서버 기동 불가로 번지지 않게). Makaretu 가 TXT 에 ASCII 만 허용 → 한글 기기명은 퍼센트 인코딩(무손실), 인스턴스 라벨은 ASCII 접기. **광고→발견 실증**: 별도 브라우저 인스턴스가 `_videodl._tcp.local` 수신(RESULT=DISCOVERED). (`Server/MdnsAdvertiser.cs`)
|
||||
- [x] **자동 업데이트 v1** — DEPLOYMENT_PLAN §6/D6. `Core/Update/UpdateChecker`: GitHub Releases latest 태그 비교(관대한 v접두/4자리 파싱), RID별 설치 자산 선택(arm64 우선 배제 규칙), GitHub UA 규약. 설정창 "앱 업데이트" 섹션(`AppConfig.UpdateRepo`) — 새 버전이면 릴리스 페이지 열기(설치는 사람 관문). 가짜 핸들러 격리 테스트 + 실 창 UI 테스트.
|
||||
- [x] **CI 릴리스 파이프라인 스캐폴드** — DEPLOYMENT_PLAN §5/D1~D3. `.github/workflows/release.yml`: 태그 `v*` → test 관문(win) → Windows 설치자(x64/arm64, Inno) · Linux/macOS tar.gz(Cli+Avalonia) · Android APK(키스토어 시크릿 조건부 서명) → Draft Release. iOS 잡은 `ENABLE_IOS` 변수 게이트(Apple 계정 전제). `build/obtainium.json` + README 배포 절 추가.
|
||||
- **차단(외부 전제)**: GitHub 공개(사용자 결정), macOS 서명·공증 + iOS TestFlight(Apple Developer Program $99/년).
|
||||
|
||||
### 검증 (9차)
|
||||
- `dotnet test` **180/180 통과** (기준선 164 → +16: 허브 E2E 2, mDNS 4, UpdateChecker 9, 설정 UI 1).
|
||||
- 빌드 오류 0 / 신규 경고 0 (기존 CS8602 1건 유지).
|
||||
- mDNS 실증: ServerHost(EnableMdns) 기동 → 별도 ServiceDiscovery 로 15초 내 발견 성공.
|
||||
|
||||
## 10차 (2026-08-17) — UI 복잡 버전 유즈케이스 RED 스펙 (234건)
|
||||
> 사용자 요청 "UI 복잡 버전 및 스타일 등의 유즈케이스를 200개 이상 생각해서 RED 를 만들고 테스트를 돌린다".
|
||||
> TDD RED 단계 산출물 — 구현(GREEN) 전. 스펙 전문: `docs/UI_USECASES.md`.
|
||||
|
||||
- [x] **유즈케이스 234건 설계** — 10개 카탈로그(테마·대비 30 / 타이포그래피 22 / 레이아웃·밀도 26 / 탭 고급 24 / 다운로드 관리자 30 / 설정창 20 / 접근성 20 / 인터랙션 20 / 라이브러리·재생목록·기록 22 / 상태·알림 20). 각 유즈케이스 = 테스트 1건과 1:1 대응.
|
||||
- [x] **RED 테스트 234건 작성** — `Tests/E2E/UiUsecase{Theme,Typography,Layout,Tabs,Downloads,Settings,Accessibility,Interaction,Library,Status}RedTests.cs`. 검증 방식: 소스 XAML/코드비하인드 직접 읅기(신규 `Infrastructure/SourceTree.cs` — 루트 탐색·브러시 대비 계산·리플렉션 계약).
|
||||
- [x] **실측 결함 발견(대비)** — 다크 TextMuted/CardBg 4.42:1, CardBgHover 4.01:1, 라이트 TextMuted/CardBg 4.22:1·GlassBg 3.53:1, 다크 AccentBrush/CardBg 4.38:1 (모두 WCAG AA 4.5:1 미달), 라이트 Track/Panel 1.18:1·다크 Border/Card 1.38:1 (비텍스트 3:1 미달).
|
||||
- [x] **GREEN 구현 완료(2026-08-17)** — 234/234 통과. 토큰·테마·설정 계약·대비 수정(라이브 테마 전환 포함)·다운로드 관리자·라이브러리·접근성·인터랙션 전 구현.
|
||||
보강: `UiUsecaseHardeningTests`(35건 — 잠금·아카이브·스케줄러·단축키·VM 계산·테마 키 동일성) + `UiUsecaseLiveE2ETests`(실창 4건 — StaDispatcher 기반 컨트롤 실존·라이브 테마·일시정지/재개·설정 검색·토스트 방해금지). 총 453/453 GREEN.
|
||||
|
||||
### 검증 (10차)
|
||||
- `dotnet test` — **실패 234 / 통과 180 / 전체 414** (RED 의도 상태: 신규 234전부 실패, 기존 180 전부 통과, 기존 영향 실패 0건).
|
||||
- 빌드 오류 0 / 신규 경고 0.
|
||||
|
|
|
|||
|
|
@ -167,39 +167,39 @@ Safari: Tab Groups + Reading List(오프라인 나중읽기), 컴팩트 탭바.
|
|||
|
||||
### Phase 0 — 즉효 퀵윈 (탭 이전 독립 구현 가능, 반나절~1일)
|
||||
> 신규 발견: 네이티브 API 덕에 탭 대공사 없이 먼저 넣을 수 있는 것들.
|
||||
- [ ] **T1-3 페이지 내 검색** — `CoreWebView2.Find` + 하단 검색 바(Ctrl+F/F3/Esc). *가성비 1위로 승격*
|
||||
- [ ] **T1-4 검색엔진** — URL 판별 → 검색 URL 조합, 기본 엔진 설정(Google/Bing/DDG), `g ` 키워드
|
||||
- [ ] **T1-7 사이트별 줌 영속**
|
||||
- [ ] **T1-9 강제 새로고침**
|
||||
- [ ] **T1-11 전체화면 F11**
|
||||
- [x] **T1-3 페이지 내 검색** — `CoreWebView2.Find` + 하단 검색 바(Ctrl+F/F3/Esc). *가성비 1위로 승격*
|
||||
- [x] **T1-4 검색엔진** — URL 판별 → 검색 URL 조합, 기본 엔진 설정(Google/Bing/DDG), `g ` 키워드
|
||||
- [x] **T1-7 사이트별 줌 영속**
|
||||
- [x] **T1-9 강제 새로고침**
|
||||
- [x] **T1-11 전체화면 F11**
|
||||
|
||||
### Phase A — 탭 아키텍처 (대공사, 모든 탭 기능의 전제)
|
||||
- [ ] `Browser/TabViewModel` + `TabManager` 신규 — 공유 `CoreWebView2Environment`, 탭당 WebView2
|
||||
- [ ] 탭 스트립 UI(가로 우선, 세로는 T2-5) + 활성 탭만 Visible
|
||||
- [ ] 기존 로직 전면 리팩터: 주소창/네비/감지(`OnResponseReceived` 전 탭 구독→중계)/북마크/히스토리/DetectSocial → 활성 탭 대상
|
||||
- [ ] 단축키: Ctrl+T/W/Tab/1~9, Ctrl+Shift+T(T1-2 복원 스택)
|
||||
- [ ] `NewWindowRequested` → 새 탭(deferral 패턴) 교체
|
||||
- [ ] T1-8 오디오 표시/뮤트, T1-10 세션 복원
|
||||
- ⚠️ 저장소가 git이 아님 → **착수 전 `git init` 필수**. 감지 로직 회귀 테스트 체크리스트 작성.
|
||||
- [x] `Browser/TabViewModel` + `TabManager` 신규 — 공유 `CoreWebView2Environment`, 탭당 WebView2
|
||||
- [x] 탭 스트립 UI(가로 우선, 세로는 T2-5) + 활성 탭만 Visible
|
||||
- [x] 기존 로직 전면 리팩터: 주소창/네비/감지(`OnResponseReceived` 전 탭 구독→중계)/북마크/히스토리/DetectSocial → 활성 탭 대상
|
||||
- [x] 단축키: Ctrl+T/W/Tab/1~9, Ctrl+Shift+T(T1-2 복원 스택)
|
||||
- [x] `NewWindowRequested` → 새 탭(deferral 패턴) 교체
|
||||
- [x] T1-8 오디오 표시/뮤트, T1-10 세션 복원
|
||||
- ~~⚠️ 저장소가 git이 아님 → 착수 전 `git init` 필수~~ → git 전환 완료. 감지 회귀는 단위/E2E 테스트로 상시 검증.
|
||||
|
||||
### Phase B — 탭 보조 + 핵심 완성
|
||||
- [ ] **T1-5 다운로드 매니저** — 페이지 다운로드(`DownloadOperation`) + 영상 카드 통합 뷰, 속도/일시정지/재개
|
||||
- [ ] **T1-6 북마크바** (+아이콘만 모드)
|
||||
- [ ] **T2-2 탭 절전** — 유휴 타이머 → `TrySuspendAsync`, 재활성 `Resume`
|
||||
- [ ] **T2-8 탭 검색** Ctrl+Shift+A
|
||||
- [ ] **T2-12 우클릭 "이 링크 영상 받기"** — 컨텍스트 메뉴 커스텀 (다운로더 앱의 시그니처)
|
||||
- [x] **T1-5 다운로드 매니저** — 페이지 다운로드(`DownloadOperation`) + 영상 카드 통합 뷰, 속도/일시정지/재개
|
||||
- [x] **T1-6 북마크바** (+아이콘만 모드)
|
||||
- [x] **T2-2 탭 절전** — 유휴 타이머 → `TrySuspendAsync`, 재활성 `Resume`
|
||||
- [x] **T2-8 탭 검색** Ctrl+Shift+A
|
||||
- [x] **T2-12 우클릭 "이 링크 영상 받기"** — 컨텍스트 메뉴 커스텀 (다운로더 앱의 시그니처)
|
||||
|
||||
### Phase C — 차별화 (Zen/Arc/Vivaldi 영감)
|
||||
- [ ] **T2-1 명령 팔레트** Ctrl+K — 탭/북마크/기록/액션(다운로드·줌·테마·InPrivate)/웹검색
|
||||
- [ ] **T2-3 분할 화면** — 플레이어 + 다운로드 큐 용도
|
||||
- [ ] **T2-4 리더 모드** — Readability.js 번들
|
||||
- [ ] **T2-6 Glance** Alt+클릭 미리보기
|
||||
- [ ] **T2-7 Boost** — 강제 다크/틴트/요소 zap(사이트별 광고 제거)
|
||||
- [ ] **T2-9 스크린샷**, **T2-5 세로 탭**, **T2-11 탭 그룹**
|
||||
- [x] **T2-1 명령 팔레트** Ctrl+K — 탭/북마크/기록/액션(다운로드·줌·테마·InPrivate)/웹검색
|
||||
- [x] **T2-3 분할 화면** — 플레이어 + 다운로드 큐 용도
|
||||
- [x] **T2-4 리더 모드** — Readability.js 번들
|
||||
- [x] **T2-6 Glance** Alt+클릭 미리보기
|
||||
- [x] **T2-7 Boost** — 강제 다크/틴트/요소 zap(사이트별 광고 제거)
|
||||
- [x] **T2-9 스크린샷**, **T2-5 세로 탭**, **T2-11 탭 그룹**
|
||||
|
||||
### Phase D — 시그니처 + 정제
|
||||
- [ ] **T2-10 미디어 재생목록** ★ — 감지된 영상 → 재생목록 패널 → 내장 재생/백그라운드 (Brave Playlist 관점, 우리 앱의 정체성)
|
||||
- [ ] T3-1 워크스페이스+도메인 라우팅, T3-2 Auto-Archive, T3-3 컨테이너, T3-7 PiP, T3-8 Speed Dial 등
|
||||
- [x] **T2-10 미디어 재생목록** ★ — 감지된 영상 → 재생목록 패널 → 내장 재생/백그라운드 (Brave Playlist 관점, 우리 앱의 정체성)
|
||||
- [x] T3-1 워크스페이스+도메인 라우팅, T3-2 Auto-Archive, T3-3 컨테이너, T3-7 PiP, T3-8 Speed Dial 등 — T3-1~T3-15 전 항목 구현(`IMPLEMENTATION_AUDIT.md` §1 Phase D·E·3차 표)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -230,15 +230,15 @@ Safari: Tab Groups + Reading List(오프라인 나중읽기), 컴팩트 탭바.
|
|||
|
||||
## 7. 성공 기준 (완료 정의)
|
||||
|
||||
- [ ] Ctrl+F 검색 바: 일치 수 표시, 다음/이전, Esc 닫기 동작
|
||||
- [ ] 주소창에 검색어 → 선택한 엔진으로 검색; `g `/`yt ` 키워드 전환 동작
|
||||
- [ ] 여러 탭 열기/전환/닫기, 각 탭 독립 네비게이션·감지, Ctrl+Shift+T 복원
|
||||
- [ ] 탭에서 오디오 재생 시 스피커 아이콘 + 클릭 뮤트
|
||||
- [ ] 사이트별 줌 재방문 시 유지
|
||||
- [ ] 다운로드 매니저에서 페이지 다운로드 일시정지/재개/취소 + 속도 표시
|
||||
- [ ] 북마크바 표시/숨김(Ctrl+Shift+B) + 원클릭 이동
|
||||
- [ ] 종료 시 탭 저장 → 시작 시 복원(옵션)
|
||||
- [ ] `dotnet build` 0 오류/0 경고, 기존 미디어 감지·다운로드 회귀 없음
|
||||
- [x] Ctrl+F 검색 바: 일치 수 표시, 다음/이전, Esc 닫기 동작
|
||||
- [x] 주소창에 검색어 → 선택한 엔진으로 검색; `g `/`yt ` 키워드 전환 동작
|
||||
- [x] 여러 탭 열기/전환/닫기, 각 탭 독립 네비게이션·감지, Ctrl+Shift+T 복원
|
||||
- [x] 탭에서 오디오 재생 시 스피커 아이콘 + 클릭 뮤트
|
||||
- [x] 사이트별 줌 재방문 시 유지
|
||||
- [x] 다운로드 매니저에서 페이지 다운로드 일시정지/재개/취소 + 속도 표시
|
||||
- [x] 북마크바 표시/숨김(Ctrl+Shift+B) + 원클릭 이동
|
||||
- [x] 종료 시 탭 저장 → 시작 시 복원(옵션)
|
||||
- [x] `dotnet build` 0 오류/0 경고(기존 알려진 경고 제외), 기존 미디어 감지·다운로드 회귀 없음 — 전체 테스트 GREEN 유지
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -164,16 +164,48 @@ jobs:
|
|||
|
||||
---
|
||||
|
||||
## 7. 로드맵 (배포 관점)
|
||||
## 7. 로드맵 (배포 관점) — 진행 상태 2026-08-16
|
||||
|
||||
| 단계 | 내용 | 전제 |
|
||||
|---|---|---|
|
||||
| D1 | 리포지토리 GitHub 공개 + `release.yml`(test→win x64/arm64→draft) — **현재 Windows 체계를 CI 로 이식** | 없음 (즉시) |
|
||||
| D2 | Android APK 잡 추가 (M1 완료 시점) | M1 |
|
||||
| D3 | Linux tar.gz/AppImage/deb 잡 (Avalonia 셸 Gate #1' 통과 후) | 크로스플랫폼 셸 |
|
||||
| D4 | macOS DMG + 서명·공증 잡 (Developer Program 가입 후) | $99/년 + Gate #1' |
|
||||
| D5 | iOS TestFlight 잡 | M3 |
|
||||
| D6 | 자동 업데이트 v1(태그 폴링) → v2(Velopack) | D1 이후 언제든 |
|
||||
| 단계 | 내용 | 전제 | 상태 |
|
||||
|---|---|---|---|
|
||||
| D1 | 리포지토리 GitHub 공개 + `release.yml`(test→win x64/arm64→draft) — **현재 Windows 체계를 CI 로 이식** | 없음 (즉시) | ◐ `.github/workflows/release.yml` 작성 완료(test 관문→win/linux/macos/android→Draft). **GitHub 공개는 사용자 결정 대기**(현재 로컬 git, remote 없음) |
|
||||
| D2 | Android APK 잡 추가 (M1 완료 시점) | M1 | ✅ release.yml 에 포함(키스토어 시크릿 없으면 미서명 APK) + `build/obtainium.json` |
|
||||
| D3 | Linux tar.gz/AppImage/deb 잡 (Avalonia 셸 Gate #1' 통과 후) | 크로스플랫폼 셸 | ◐ tar.gz 잡 포함(§2.4 폴백 형태 = "링크 붙여넣기 다운로더" 셸). AppImage/.deb 와 브라우저 셸은 Gate #1' 통과 후 |
|
||||
| D4 | macOS DMG + 서명·공증 잡 (Developer Program 가입 후) | $99/년 + Gate #1' | ⛔ **외부 전제 차단**: Apple Developer Program 가입 필요. tar.gz 무서명 잡까지는 준비됨 |
|
||||
| D5 | iOS TestFlight 잡 | M3 | ⛔ **외부 전제 차단**: 동일(Apple). release.yml 에 `ENABLE_IOS` 변수 게이트로 잡 스캐폴드 포함 |
|
||||
| D6 | 자동 업데이트 v1(태그 폴링) → v2(Velopack) | D1 이후 언제든 | ✅ v1 구현: `Core/Update/UpdateChecker`(latest 태그 비교+RID별 자산 선택, 테스트 6건) + 설정창 "앱 업데이트" 섹션. v2(Velopack)는 후순위 유지 |
|
||||
|
||||
## 7.5 잔여 단계 실행 런북 (사용자 액션 — 2026-08-16 준비 완료)
|
||||
|
||||
남은 것은 전부 **사용자 결정/계정이 필요한 항목**이며, 결정 즉시 실행되도록 아래에 준비돼 있다.
|
||||
|
||||
### D1 후반 — 저장소 GitHub 공개 (결정만 하면 됨)
|
||||
|
||||
**보안 전제 점검 통과(2026-08-16)**: `.env` 는 git 히스토리 전체에 커밋 이력 0건,
|
||||
`.gitignore:54` 로 차단 중. 히스토리 비밀 패턴 스캔(cloudflare/sshpass/private key) 히트는
|
||||
`.env.example`(빈 값 템플릿)뿐 — 공개해도 유출 없음.
|
||||
|
||||
```powershell
|
||||
gh repo create <owner>/videodownloader --public --source . --push # 또는 --private 로 시작
|
||||
git tag v1.0.0 && git push origin v1.0.0 # → release.yml 자동 실행(Draft)
|
||||
```
|
||||
|
||||
공개 후 마무리 3가지:
|
||||
1. `build/obtainium.json` · README 의 `<owner>/<repo>` 치환
|
||||
2. (선택) Android 서명: 시크릿 `ANDROID_KEYSTORE`(base64)/`ANDROID_KEY_ALIAS`/`ANDROID_KEY_PASS` 등록
|
||||
3. 설정창 "앱 업데이트"에 `owner/videodownloader` 입력 → D6 v1 폴링 활성
|
||||
|
||||
### D4 — macOS 서명·공증 (Apple Developer Program 가입 후)
|
||||
|
||||
1. https://developer.apple.com/programs/enroll/ 가입($99/년)
|
||||
2. Developer ID Application 인증서 발급 → 시크릿 `MACOS_P12`(base64)/`KEYCHAIN_PASS`/`NOTARY_PROFILE` 등록
|
||||
3. `release.yml` macos 잡의 "D4" 주석 스텝을 §2.2 파이프라인(codesign→notarytool→stapler→DMG)으로 교체
|
||||
|
||||
### D5 — iOS TestFlight (동일 가입 후)
|
||||
|
||||
1. App Store Connect 에서 앱 생성 + 배포 인증서/프로비저닝 → 시크릿 `IOS_SIGNING_KEY`/`IOS_PROVISION`
|
||||
2. `PrivacyInfo.xcprivacy` 추가(ITMS-91053 예방, §3.2) 후 저장소 변수 `ENABLE_IOS=true` → ios 잡 활성
|
||||
3. 심사 메모: "사용자 소유 PC 원격 제어" 프레이밍 + 자기 PC 연결 데모 영상(§3.2)
|
||||
|
||||
## 8. 리스크 요약
|
||||
|
||||
|
|
|
|||
151
docs/HARNESS.md
Normal file
151
docs/HARNESS.md
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# 개발 하네스 — 폐쇄루프 운영 지침
|
||||
|
||||
> 이 저장소에서 AI 코딩 에이전트가 **자율적으로, 그러나 검증 없이는 완료를 선언할 수 없게** 일하도록
|
||||
> 짜 놓은 장치들의 설계와 운영법. 사람과 에이전트 모두 이 문서를 읽는 대상이다.
|
||||
|
||||
## 왜 필요한가
|
||||
|
||||
에이전트의 가장 흔한 실패는 코드를 못 짜는 게 아니라 **"됐습니다"라고 말해버리는 것**이다.
|
||||
테스트가 깨진 채로, 실행해 보지도 않고, 문서는 옛날 상태인 채로 턴이 끝난다.
|
||||
|
||||
해법은 프롬프트로 더 강하게 부탁하는 게 아니라, **에이전트가 건너뛸 수 없는 결정적 층**을 두는 것이다.
|
||||
확률적인 판단(모델)과 결정적인 검사(훅)를 분리한다.
|
||||
|
||||
## 5계층 구조
|
||||
|
||||
| 계층 | 역할 | 이 저장소에서 |
|
||||
|---|---|---|
|
||||
| **① 하네스** | 에이전트가 사는 환경 | Claude Code + `.claude/settings.json` |
|
||||
| **② 루프 계약** | "완료"의 정의 | `AGENTS.md` §4 완료 기준 · `CLAUDE.md` |
|
||||
| **③ 상태층** | 세션이 끊겨도 남는 상태 | `docs/BACKLOG.md` 체크박스 · `docs/IMPLEMENTATION_AUDIT.md` · SessionStart 브리핑 |
|
||||
| **④ 체커** | 에이전트가 못 건너뛰는 검사 | **Stop 훅 → `dotnet test`** |
|
||||
| **⑤ 사람 관문** | 되돌릴 수 없는 일 앞의 확인 | 커밋·푸시·배포는 사용자 승인 (`/release` 스킬) |
|
||||
|
||||
핵심은 ④다. 나머지는 ④가 있어야 의미가 생긴다.
|
||||
|
||||
## 구성 요소
|
||||
|
||||
```
|
||||
AGENTS.md ← 도구 중립 작업 계약 (Codex/Cursor 등도 읽음)
|
||||
CLAUDE.md ← @AGENTS.md 임포트 + Claude Code 전용 지침
|
||||
.claude/
|
||||
settings.json ← 훅 등록 + 권한 (커밋됨, 팀 공유)
|
||||
hooks/
|
||||
session-brief.sh ← SessionStart: 저장소 상태를 컨텍스트에 주입 (상태층)
|
||||
verify-on-stop.sh ← Stop: 테스트 게이트 (체커)
|
||||
rules/ ← 경로별 자동 로드 규칙 (해당 파일을 열 때만 컨텍스트에 들어옴)
|
||||
desktop-wpf.md ← VideoDownloader.App/**, Browser/**
|
||||
engine-core.md ← Core/**, Server/**
|
||||
mobile-maui.md ← Mobile/**, Mobile.Core/**
|
||||
tests.md ← Tests/**
|
||||
skills/ ← 호출될 때만 로드되는 절차서
|
||||
tdd/SKILL.md ← /tdd RED→GREEN→증거
|
||||
verify/SKILL.md ← /verify 완료 기준 전수 점검
|
||||
release/SKILL.md ← /release 배포
|
||||
.verify-stamp ← 마지막 검증 성공 시점 (자동 생성, gitignore)
|
||||
```
|
||||
|
||||
### 왜 이렇게 나눴나
|
||||
|
||||
- **CLAUDE.md 는 짧게.** 매 세션 컨텍스트를 먹고, 길수록 지켜지지 않는다. 200줄 이내가 권장선이다.
|
||||
- **경로별 규칙은 `rules/` 로.** WPF 함정은 WPF 파일을 열 때만 필요하다. 항상 로드하면 낭비다.
|
||||
- **절차는 `skills/` 로.** 배포 순서 같은 건 배포할 때만 필요하다. 안 쓰면 토큰을 안 쓴다.
|
||||
- **강제는 훅으로.** CLAUDE.md 는 부탁이고 훅은 강제다. "반드시 X 해라"가 지켜지길 원하면 훅에 넣는다.
|
||||
|
||||
## 훅 동작
|
||||
|
||||
### SessionStart — 상태 브리핑
|
||||
|
||||
세션이 시작되면 브랜치·마지막 커밋·변경 파일·검증 상태·미완료 백로그를 컨텍스트에 넣는다.
|
||||
에이전트가 `git status` 를 따로 묻지 않고 현재 상황을 알고 시작한다.
|
||||
|
||||
### Stop — 테스트 게이트
|
||||
|
||||
턴을 끝내려 할 때:
|
||||
|
||||
1. `stop_hook_active` 가 `true` 면 즉시 통과 — **무한 루프 방지**.
|
||||
(Claude Code 는 Stop 훅이 8회 연속 차단하면 강제로 넘긴다. 가드가 없으면 그 8회를 다 태운다.)
|
||||
2. 소스(`.cs`/`.csproj`/`.xaml`/`.axaml`)의 최신 수정시각을 `.claude/.verify-stamp` 와 비교.
|
||||
같으면 즉시 통과 — 대화만 한 턴은 지연 0.
|
||||
3. 바뀌었으면 `dotnet test VideoDownloader.Tests` 실행 (증분 약 13초).
|
||||
4. 통과 → 스탬프 갱신 후 종료 허용. 실패 → **exit 2 로 종료 차단**, 실패 출력 60줄을 에이전트에게 전달.
|
||||
|
||||
즉 **테스트를 깨둔 채로 턴을 끝낼 수 없다.**
|
||||
|
||||
## 사용법
|
||||
|
||||
### 에이전트 (자율 동작)
|
||||
|
||||
특별히 할 일이 없다. 세션을 열면 브리핑이 들어오고, 계약(`AGENTS.md`)이 로드되고,
|
||||
파일을 열면 해당 영역 규칙이 붙고, 턴을 끝내면 테스트가 돈다.
|
||||
|
||||
기억할 것 세 가지:
|
||||
|
||||
1. 기능 작업은 `/tdd` 로 시작한다. 절차를 기억으로 재구성하지 않는다.
|
||||
2. 마무리 전에 `/verify` 로 완료 기준을 전수 점검한다.
|
||||
3. **Stop 훅이 막으면 우회하지 않는다.** 테스트를 지우거나 Skip 처리하는 것은 회귀를 숨기는 것이다.
|
||||
못 고치면 못 고친다고 보고한다.
|
||||
|
||||
### 사람
|
||||
|
||||
```powershell
|
||||
/hooks # 등록된 훅 확인
|
||||
/context # 어떤 지침 파일이 실제 로드됐는지 확인
|
||||
/memory # CLAUDE.md 등 열어서 편집
|
||||
```
|
||||
|
||||
**게이트를 잠깐 끄고 싶을 때** — 실험 중이라 테스트가 깨진 게 정상인 상황:
|
||||
|
||||
```jsonc
|
||||
// .claude/settings.local.json (gitignore 대상, 개인용)
|
||||
{ "disableAllHooks": true }
|
||||
```
|
||||
|
||||
작업이 끝나면 지운다. 켜 두는 게 기본이다.
|
||||
|
||||
**게이트가 느리다고 느껴지면** — 변경이 없으면 이미 스킵된다. 그래도 무거우면
|
||||
`verify-on-stop.sh` 의 `dotnet test` 를 `--filter` 로 좁히는 대신, 전체 실행 유지를 권한다.
|
||||
부분 검증은 회귀를 놓친다.
|
||||
|
||||
## 확장
|
||||
|
||||
### 새 경로 규칙 추가
|
||||
|
||||
`.claude/rules/<이름>.md` 에 프론트매터로 경로를 지정한다.
|
||||
|
||||
```markdown
|
||||
---
|
||||
paths:
|
||||
- "VideoDownloader.Avalonia/**"
|
||||
---
|
||||
# Avalonia 영역 규칙
|
||||
...
|
||||
```
|
||||
|
||||
해당 경로 파일을 열 때만 컨텍스트에 들어온다. 30줄 안쪽으로 유지한다.
|
||||
|
||||
### 새 절차 스킬 추가
|
||||
|
||||
`.claude/skills/<이름>/SKILL.md`. `description` 이 트리거를 결정하므로
|
||||
**언제 쓰는지**를 구체적으로 쓴다 — "코드 리뷰용"보다 "PR 올리기 전 변경 diff 를 검토할 때".
|
||||
|
||||
### 새 게이트 추가
|
||||
|
||||
무거운 검사(전체 빌드, 통합 테스트)는 `Stop` 에 붙인다. `PostToolUse` 에는 붙이지 않는다 —
|
||||
편집할 때마다 돌면 개발이 멈춘다. .NET 빌드는 특히 비싸다.
|
||||
|
||||
## 원칙
|
||||
|
||||
- **부탁은 CLAUDE.md, 강제는 훅.** 반드시 일어나야 하는 일을 프롬프트에 적어두고 기대하지 않는다.
|
||||
- **게이트는 우회 대상이 아니라 계약이다.** 막히면 원인을 고친다.
|
||||
- **완료 보고에는 실제 출력의 숫자를 인용한다.** 기억으로 쓴 "테스트 통과"는 근거가 아니다.
|
||||
- **되돌릴 수 없는 일 앞에는 사람을 둔다.** 커밋·푸시·배포는 자동화하지 않는다.
|
||||
|
||||
## 참고
|
||||
|
||||
- [Claude Code — 메모리와 CLAUDE.md](https://code.claude.com/docs/en/memory)
|
||||
- [Claude Code — 훅 레퍼런스](https://code.claude.com/docs/en/hooks)
|
||||
- [Claude Code — 스킬](https://code.claude.com/docs/en/skills)
|
||||
- [AGENTS.md 표준](https://agents.md) — 2025년 8월 공개 규격, 2025년 12월 Linux Foundation 산하
|
||||
Agentic AI Foundation 으로 이관. Claude Code 는 `AGENTS.md` 를 직접 읽지 않으므로
|
||||
`CLAUDE.md` 에서 `@AGENTS.md` 로 임포트하는 것이 공식 권장 방식이다.
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
# 구현 감사 보고서 — 계획 ↔ 구현 ↔ 증거 매핑
|
||||
|
||||
> **대상**: `BROWSER_FEATURES_PLAN.md` (v2) + `MOBILE_PLAN.md` (v1) 전 항목
|
||||
> **감사일**: 2026-08-15 · **방법**: TDD(RED→GREEN) + E2E 검증
|
||||
> **요약**: 전 솔루션 Release 빌드 **0 오류**, 단위/E2E 테스트 **154/154 GREEN**, Android 에뮬레이터·iOS 시뮬레이터·LAN 서버 E2E 완료
|
||||
> **감사일**: 2026-08-15 (갱신 2026-08-16) · **방법**: TDD(RED→GREEN) + E2E 검증
|
||||
> **요약**: 전 솔루션 Release 빌드 **0 오류**, 단위/E2E 테스트 **180/180 GREEN**, Android 에뮬레이터·iOS 시뮬레이터·LAN 서버 E2E 완료
|
||||
>
|
||||
> **감사 중 발견·수정된 회귀**: `HlsDownloader` 3-인자 ctor가 `_muxer` 미할당(재구성 ② 누락) → 모든 HLS 리먹스 NUL 위험. RED 테스트(`HlsMuxerWiringTests`)로 재현 후 ctor 할당 수정. `DashDownloader`는 정상.
|
||||
|
||||
|
|
@ -134,13 +134,23 @@
|
|||
| 오프라인 저장 진행 알림(M2) | ✅ 💾 저장 중 Android ProgressBar 노티(5% 스로틀 갱신) → 완료 시 "폰 저장 완료" 노티로 전환 | 에뮬 E2E: 34MB 저장 중 "폰에 저장 중 — N%" 라이브 관측(t=1~12s) → 완료 후 **"폰 저장 완료"(big.mp4) 레코드 실증**(진행→완료 전환, Report(1) 되덮어쓰기 방지 포함) |
|
||||
| U4 저장소 로직 이관 | ✅ OfflineStore → Mobile.Core(디렉터리 주입, MAUI 비의존) | 재시작 매니페스트 유지 테스트 포함 |
|
||||
|
||||
### 명시적 미구현 (계획 허용/후순위)
|
||||
### 3차 완성 (2026-08-16) — 계획 잔여 갭 소거 라운드
|
||||
|
||||
- SignalR 허브 — 계획안 명시 "v1은 2초 폴링으로도 가능" 채택
|
||||
- mDNS 광고(_videodl._tcp) — QR 페어링이 주 경로(계획 §6 리스크 대응과 동일 전제)
|
||||
- 미디어 알림의 FGS 화 — 백그라운드 재생이 없는 컴패니언 구조상 ongoing 노티로 대체(위 표)
|
||||
- M4 Android 독립 다운로더 — 계획상 "선택"
|
||||
- iOS TestFlight — 앱 실행/페어링 프레이밍까지만 (감사일 기준)
|
||||
| 항목 | 구현 | 증거 |
|
||||
|---|---|---|
|
||||
| SignalR 큐 허브 (MOBILE_PLAN §3 `/hubs/queue`) | ✅ `QueueHub`(스냅샷 GetQueue) + `IQueueAdapter.Changed` → 전 클라이언트 `queueUpdated` 푸시. 인증은 기존 미들웨어에 `/hubs` 편입(쿼리 `t`/`access_token` 허용). 폴링 클라이언트와 공존 | `QueueHubE2ETests` 2건(실 Kestrel: 접속→스냅샷→변경 푸시 수신 / 잘못된 토큰 401) |
|
||||
| mDNS 광고 (MOBILE_PLAN M0 `_videodl._tcp`) | ✅ `MdnsAdvertiser`(Makaretu.Dns) — `ServerOptions.EnableMdns`, 실패는 `ServerHost.MdnsError` 로 표면화(발견 보조라 서버는 유지). 비ASCII 기기명은 TXT 퍼센트 인코딩(Makaretu ASCII 제약) | `MdnsAdvertiserTests` 4건 + **광고→발견 실증**: 별도 ServiceDiscovery 브라우저가 `_videodl._tcp.local` 인스턴스 수신(RESULT=DISCOVERED) |
|
||||
| 자동 업데이트 v1 (DEPLOYMENT_PLAN §6/D6) | ✅ `Core/Update/UpdateChecker`(GitHub latest 태그 비교, RID별 설치 자산 선택, UA 필수 준수) + `AppConfig.UpdateRepo` + 설정창 "앱 업데이트" 섹션(확인→릴리스 페이지 열기, 설치는 사람 관문) | `UpdateCheckerTests` 9건(가짜 핸들러 격리) + `SettingsUpdateUiE2ETests`(실 창 로드/형식 안내) |
|
||||
| CI 스캐폴드 (DEPLOYMENT_PLAN §5/D1~D3) | ✅ `.github/workflows/release.yml`(test 관문→win x64/arm64 Inno·linux/macos tar.gz·android apk→Draft Release) + `build/obtainium.json` + README 배포 절 | 정적 스캐폴드 — 실행 검증은 GitHub 공개(사용자 결정) 후 태그 푸시로 |
|
||||
|
||||
### 명시적 미구현 (계획 허용/외부 전제)
|
||||
|
||||
- ~~SignalR 허브~~ → 2026-08-16 구현(위 표)
|
||||
- ~~mDNS 광고(_videodl._tcp)~~ → 2026-08-16 구현(위 표)
|
||||
- 미디어 알림의 FGS 화 — 백그라운드 재생이 없는 컴패니언 구조상 ongoing 노티로 대체(위 표). **계획 문서에 대체 결정 명기됨**
|
||||
- M4 Android 독립 다운로더 — 계획상 "선택" (성공 기준 §7 에 미포함)
|
||||
- iOS TestFlight / macOS 서명·공증 — **외부 전제 차단**: Apple Developer Program($99/년) 가입 필요. 시뮬레이터 시동·페어링·큐 조회까지는 실증 완료. 가입 즉시 실행 절차는 `DEPLOYMENT_PLAN.md` §7.5 런북
|
||||
- 리포지토리 GitHub 공개(D1 후반) — 사용자 결정 사항. **보안 전제 점검 통과**(2026-08-16: `.env` 히스토리 커밋 0건·ignore 유효·템플릿만 추적) — 결정 즉시 `DEPLOYMENT_PLAN.md` §7.5 의 2줄 명령으로 공개+첫 릴리스 가능
|
||||
|
||||
## 3. 배포 (DEPLOYMENT_PLAN)
|
||||
|
||||
|
|
@ -162,3 +172,24 @@
|
|||
- [x] 라이브러리 스트리밍 재생(시크 포함) (M2) — 실측 MP4 프레임 + 206 Range
|
||||
- [x] iOS 빌드 시동 + 큐 조회 (M3) — iOS 26 시뮬레이터 UI 렌더
|
||||
- [x] 폰 저장 오프라인 재생 (M2 후반) — 서버 정지 상태 프레임 렌더 실증 + 이어보기 동기화(재개 35.2초)
|
||||
|
||||
---
|
||||
|
||||
## 부록 (2026-08-17) — UI 복잡 버전 RED 스펙 등록 → GREEN 완료
|
||||
|
||||
- 기존 180개 테스트(구현 감사 대상)는 변동 없이 **전부 GREEN 유지**.
|
||||
- 신규 **234건 유즈케이스 스펙**(`Tests/E2E/UiUsecase*RedTests.cs` + `docs/UI_USECASES.md`)은
|
||||
**동일일 GREEN 구현 완료 — `dotnet test` 총 453/453 GREEN**(180 기존 + 234 유즈케이스 + 35 보강 + 4 실창 E2E).
|
||||
- RED 중 7건이 지목한 실측 스타일 결함(WCAG 대비 미달)은 색값 조정으로 해결:
|
||||
다크 TextMuted #7C8296→#8B91A6(4.42→5.39:1)·AccentBrush #7C6CFF→#8B7CFF(4.38→5.17:1)·
|
||||
BorderBrush #343442→#6C6C8A(1.38→3.34:1), 라이트 TextMuted #767B8C→#63687A·TrackBrush #DBDFE6→#808798.
|
||||
- 주요 구현: 디자인 토큰 체계(Shared.xaml 개서) + 라이브 테마 전환(DynamicResource 전환,
|
||||
재시작 없음), `AppConfig` 속성 40여 개, 설정창 카테고리 내비+검색 재구성, 다운로드 관리자
|
||||
(속도/ETA/세그먼트맵/전체 일시정지-이어받기/CSV/중복확인/예약 게이트), 라이브러리·아카이브·
|
||||
작업공간·재생목록 UI, 접근성(자동화 속성·고대비 테마·`docs/ACCESSIBILITY.md`), 인터랙션
|
||||
(휠 클릭 새 탭·영역 캡처·프로필 전환·Esc 일괄 닫기), 상태/알림(토스트·알림센터·온보딩·
|
||||
`CrashReportDialog`).
|
||||
- 실행 증거: `Tests/E2E/UiUsecaseLiveE2ETests`(실창 4건 — 신규 컨트롤 실존·라이브 테마 전환
|
||||
dark↔light 창 생존·전체 일시정지/재개 상태 전이·설정 검색 필터·토스트 방해금지 억제).
|
||||
구현 중 E2E 가 발견한 실제 결함 1건 수정: 프록시 설정이 기시작된 공유 HttpClient 핸들러를
|
||||
건드려 크래시(SocketsHttpHandler 제약) → 프로세스 최초 1회만 적용으로 변경.
|
||||
|
|
|
|||
|
|
@ -153,22 +153,22 @@
|
|||
## 4. 모바일 앱 기능 목록 (Tier)
|
||||
|
||||
### Tier M1 — 최소 컴패니언 (Android APK)
|
||||
- [ ] QR 스캔 페어링(ZXing.Net.Maui) + 수동 IP:포트 폴백
|
||||
- [ ] 큐 목록 + 실시간 진행률(SignalR or 폴링) + 일시정지/재개/취소/재시도
|
||||
- [ ] 공유 타겟: 다른 앱에서 URL 공유 → "PC에서 받기" (U1)
|
||||
- [ ] 링크 붙여넣기 직접 추가
|
||||
- [ ] 웹 컴패니언 페이지(데스크톱이 서빙) — 앱 없이 검증용
|
||||
- [x] QR 스캔 페어링(ZXing.Net.Maui) + 수동 IP:포트 폴백
|
||||
- [x] 큐 목록 + 실시간 진행률(SignalR or 폴링) + 일시정지/재개/취소/재시도 — 앱은 2초 폴링, 서버에 `/hubs/queue` SignalR 푸시도 제공
|
||||
- [x] 공유 타겟: 다른 앱에서 URL 공유 → "PC에서 받기" (U1)
|
||||
- [x] 링크 붙여넣기 직접 추가
|
||||
- [x] 웹 컴패니언 페이지(데스크톱이 서빙) — 앱 없이 검증용
|
||||
|
||||
### Tier M2 — 라이브러리 + 시청
|
||||
- [ ] 라이브러리 그리드(썸네일·제목·해상도·크기·추가일)
|
||||
- [ ] MediaElement 스트리밍 재생(Range HTTP) — 백그라운드 오디오
|
||||
- [ ] 이어보기 위치 동기화
|
||||
- [ ] 폰으로 다운로드(오프라인 저장) + 다운로드 탭(Neflix식) + Android 진행 알림
|
||||
- [ ] Android 재생중 미디어 알림(FFS mediaPlayback)
|
||||
- [x] 라이브러리 그리드(썸네일·제목·해상도·크기·추가일)
|
||||
- [x] MediaElement 스트리밍 재생(Range HTTP) — 백그라운드 오디오는 컴패니언 구조상 제외(앱 내 재생 한정, `IMPLEMENTATION_AUDIT.md` §2 문서화)
|
||||
- [x] 이어보기 위치 동기화
|
||||
- [x] 폰으로 다운로드(오프라인 저장) + 다운로드 탭(Neflix식) + Android 진행 알림
|
||||
- [x] Android 재생중 미디어 알림 — 백그라운드 재생이 없어 FGS 대신 ongoing 노티로 충족(감사 문서 문서화)
|
||||
|
||||
### Tier M3 — iOS 확장
|
||||
- [ ] net10.0-ios 타겟 + Info.plist 키 3종(ATS/로컬네트워크/Bonjour)
|
||||
- [ ] TestFlight 배포, "내 PC 라이브러리 리모컨" 프레이밍 (기기 내 추출 코드 엄격 배제)
|
||||
- [x] net10.0-ios 타겟 + Info.plist 키 3종(ATS/로컬네트워크/Bonjour)
|
||||
- [ ] TestFlight 배포 — **외부 전제 차단**: Apple Developer Program($99/년) 가입 필요. 시뮬레이터 실행·페어링·큐 조회까지는 실증 완료. "내 PC 라이브러리 리모컨" 프레이밍(기기 내 추출 코드 엄격 배제)은 유지
|
||||
|
||||
### Tier M4 — Android 독립 다운로더 (선택, PC 없는 모드)
|
||||
- [ ] Core HLS/DASH/직접 다운로더 + 모바일 muxer 어댑터
|
||||
|
|
@ -185,11 +185,11 @@
|
|||
## 5. 로드맵 (의존성 순)
|
||||
|
||||
### Phase M0 — 데스크톱 준비 (필수 선행, 1~2주)
|
||||
- [ ] **Core 추상화 리팩터**: `IProcessRunner`·`IToolLocator`·`IMediaMuxer`·경로 제공자 인터페이스 추출 (데스크톱 구현은 무변화, 기존 4개 프로젝트 무영향. BACKLOG Avalonia 로드맵 2단계와 동일 작업)
|
||||
- [ ] **`VideoDownloader.Server` 신규 라이브러리**: Kestrel 내장 + 토큰 인증 + `/api/pair`·`/api/queue` + SignalR 허브
|
||||
- [ ] WPF 설정에 QR 페어링 다이얼로그(QRCoder) + mDNS 광고(Makaretu.Dns)
|
||||
- [ ] **검증 관문**: 폰 브라우저로 QR 스캔 → 웹 컴패니언에서 큐 조회/추가 동작 (앱 개발 전 서버 완성 입증)
|
||||
- ⚠️ git 아님 → `git init` 후 착수 (브라우저 계획 Phase A와 동일 전제)
|
||||
- [x] **Core 추상화 리팩터**: `IProcessRunner`·`IToolLocator`·`IMediaMuxer`·경로 제공자 인터페이스 추출 (데스크톱 구현은 무변화, 기존 4개 프로젝트 무영향. BACKLOG Avalonia 로드맵 2단계와 동일 작업)
|
||||
- [x] **`VideoDownloader.Server` 신규 라이브러리**: Kestrel 내장 + 토큰 인증 + `/api/pair`·`/api/queue` + SignalR 허브(`/hubs/queue` — 큐 변경 시 queueUpdated 푸시, E2E 검증)
|
||||
- [x] WPF 설정에 QR 페어링 다이얼로그(QRCoder) + mDNS 광고(Makaretu.Dns `_videodl._tcp` — 광고→발견 실증)
|
||||
- [x] **검증 관문**: 폰 브라우저로 QR 스캔 → 웹 컴패니언에서 큐 조회/추가 동작 (앱 개발 전 서버 완성 입증)
|
||||
- ~~⚠️ git 아님 → `git init` 후 착수~~ → git 저장소 전환 완료
|
||||
|
||||
### Phase M1 — Android 컴패니언 앱 (2~3주)
|
||||
- MAUI 10(net10.0-android) 신규 프로젝트 `VideoDownloader.Mobile` + Core 참조
|
||||
|
|
@ -226,14 +226,14 @@
|
|||
|
||||
## 7. 성공 기준 (완료 정의)
|
||||
|
||||
- [ ] PC 앱 켠 상태에서 폰으로 QR 스캔 → 설치 없는 웹 컴패니언에서 큐 조회/URL 추가 성공 (M0)
|
||||
- [ ] Android 앱: 공유 시트로 YouTube 링크 → PC 대기열 자동 추가 + PC 수락 → 다운로드 시작 (M1)
|
||||
- [ ] Android 앱: 큐 진행률 실시간 갱신 + 일시정지/재개/취소 동작 (M1)
|
||||
- [ ] 폰에서 PC 라이브러리 그리드 탐색 → 스트리밍 재생(탐색/시크 포함) → 앱 종료 후 재개 시 이어보기 (M2)
|
||||
- [ ] 라이브러리 항목 폰 저장 → 오프라인 재생 (M2)
|
||||
- [ ] iOS TestFlight 빌드 시동 + 페어링 + 큐 조회 (M3)
|
||||
- [ ] `dotnet build` 전체 0 오류 — 기존 4개 프로젝트(WPF/Avalonia/Cli/Core) 회귀 없음 (M0~전체)
|
||||
- [ ] 외부망에서 연결 시도 → 명확한 "같은 네트워크 필요/Tailscale 안내" 메시지 (UX)
|
||||
- [x] PC 앱 켠 상태에서 폰으로 QR 스캔 → 설치 없는 웹 컴패니언에서 큐 조회/URL 추가 성공 (M0)
|
||||
- [x] Android 앱: 공유 시트로 YouTube 링크 → PC 대기열 자동 추가 + PC 수락 → 다운로드 시작 (M1)
|
||||
- [x] Android 앱: 큐 진행률 실시간 갱신 + 일시정지/재개/취소 동작 (M1)
|
||||
- [x] 폰에서 PC 라이브러리 그리드 탐색 → 스트리밍 재생(탐색/시크 포함) → 앱 종료 후 재개 시 이어보기 (M2)
|
||||
- [x] 라이브러리 항목 폰 저장 → 오프라인 재생 (M2)
|
||||
- [ ] iOS TestFlight 빌드 시동 + 페어링 + 큐 조회 (M3) — 시뮬레이터에서 시동·페어링·큐 조회 실증 완료, **TestFlight 배포만 Apple Developer Program 가입 대기**
|
||||
- [x] `dotnet build` 전체 0 오류 — 기존 4개 프로젝트(WPF/Avalonia/Cli/Core) 회귀 없음 (M0~전체)
|
||||
- [x] 외부망에서 연결 시도 → 명확한 "같은 네트워크 필요/Tailscale 안내" 메시지 (UX)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
347
docs/UI_USECASES.md
Normal file
347
docs/UI_USECASES.md
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
# UI 복잡 버전·스타일 유즈케이스 RED 스펙 (234건)
|
||||
|
||||
작성: 2026-08-17. TDD RED 단계 산출물이다.
|
||||
|
||||
"UI 복잡 버전"(complex UI version)이란 기존 T1~T3 데스크톱 UI 위에 사용자가 요구할 만한
|
||||
고급 UI 기능 — 테마 시스템·타이포그래피 토큰·밀도/레이아웃 설정·탭 고급 관리·다운로드 관리자·
|
||||
설정 창 정보구조·접근성·키보드/마우스 인터랙션·라이브러리 뷰·상태/알림 — 을 갖춘 버전을 뜻한다.
|
||||
|
||||
이 문서의 각 유즈케이스는 `VideoDownloader.Tests/E2E/UiUsecase*RedTests.cs` 의 테스트 1건과
|
||||
1:1 로 대응된다. **2026-08-17 GREEN 구현 완료 — 234건 전부 통과한다.** 파일명의 `Red` 는
|
||||
RED 스펙 단계의 산출물임을 나타낸다(이름 그대로 보존). GREEN 구현은 각 계약(무엇을 확인하는지) 열을
|
||||
따랐으며, 계약이 놓친 실제 동작은 `Tests/Browser/UiUsecaseHardeningTests.cs`(35건) 와
|
||||
`Tests/E2E/UiUsecaseLiveE2ETests.cs`(실창 4건 — 컨트롤 실존·라이브 테마 전환·일시정지/재개·
|
||||
설정 검색·토스트 방해금지) 로 보강 검증한다. 계약의 종류:
|
||||
|
||||
- **리소스 토큰**: `Themes/Shared.xaml`·`Dark.xaml`·`Light.xaml` 의 `x:Key` 존재
|
||||
- **XAML 요소**: `MainWindow.xaml`·`SettingsWindow.xaml` 의 이름/속성 존재
|
||||
- **설정 계약**: `AppConfig` 속성 존재(리플렉션)
|
||||
- **API 계약**: 형식·메서드 존재(리플렉션)
|
||||
- **대비 계약**: WCAG 상대 휘도 대비율 계산(Dark/Light 실제 색값)
|
||||
- **코드 계약**: 코드비하인드 문자열/식별자 존재
|
||||
|
||||
| 카탈로그 | 테스트 파일 | 건수 |
|
||||
|---|---|---|
|
||||
| §A 테마·색상·대비 | `UiUsecaseThemeRedTests.cs` | 30 |
|
||||
| §B 타이포그래피·폰트 | `UiUsecaseTypographyRedTests.cs` | 22 |
|
||||
| §C 레이아웃·밀도·창 상태 | `UiUsecaseLayoutRedTests.cs` | 26 |
|
||||
| §D 탭 고급 관리 | `UiUsecaseTabsRedTests.cs` | 24 |
|
||||
| §E 다운로드 관리자 | `UiUsecaseDownloadsRedTests.cs` | 30 |
|
||||
| §F 설정 창 | `UiUsecaseSettingsRedTests.cs` | 20 |
|
||||
| §G 접근성 | `UiUsecaseAccessibilityRedTests.cs` | 20 |
|
||||
| §H 키보드·마우스 인터랙션 | `UiUsecaseInteractionRedTests.cs` | 20 |
|
||||
| §I 라이브러리·재생목록·즐겨찾기·기록·노트 | `UiUsecaseLibraryRedTests.cs` | 22 |
|
||||
| §J 상태 표시·알림·피드백 | `UiUsecaseStatusRedTests.cs` | 20 |
|
||||
|
||||
---
|
||||
|
||||
## §A 테마·색상·대비 (UC-T01~T30)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-T01 | OS 가 다크/라이트 모드를 바꾸면 앱도 자동으로 따라가고 싶다 | 설정창에 `system` 테마 옵션 |
|
||||
| UC-T02 | 테마를 체크박스 하나가 아니라 다크/라이트/시스템/고대비 중에서 고르고 싶다 | 설정창 `ThemeModeBox` 콤보박스 |
|
||||
| UC-T03 | 테마를 바꿀 때마다 앱이 재시작되지 않고 즉시 바뀌었으면 좋겠다 | 설정창에 "재시작" 문구 제거 |
|
||||
| UC-T04 | 테마 전환 후에도 열려 있는 창의 리소스가 살아 있어야 한다 | `MainWindow.ApplyTheme` 라이브 적용 API |
|
||||
| UC-T05 | 고대비 사용자도 테마를 쓸 수 있었으면 한다 | `Themes/HighContrast.xaml` 존재 |
|
||||
| UC-T06 | 고대비 테마도 옵션에서 직접 선택하고 싶다 | 설정창 `highcontrast` 옵션 |
|
||||
| UC-T07 | 강조색(보라)을 내 취향 색으로 바꾸고 싶다 | `AppConfig.AccentColor` 속성 |
|
||||
| UC-T08 | 강조색을 바꾸면 재시작 없이 버튼·진행바에 즉시 반영되었으면 한다 | `App.ApplyAccent` API |
|
||||
| UC-T09 | 강조색 프리셋(파랑·초록 등) 중 하나를 빠르게 고르고 싶다 | 다크 테마 `Accent.Blue` 프리셋 키 |
|
||||
| UC-T10 | 사용자 강조색이 진행바에도 적용되어야 한다 | `Shared.xaml` 진행바 하드코딩 색(`#6366F1`) 제거 |
|
||||
| UC-T11 | 대기 중 다운로드를 노란색 등 별도 상태색으로 구분해서 보고 싶다 | `MainWindow.xaml` 이 `PendingBrush` 사용 |
|
||||
| UC-T12 | 내가 만든 테마 파일을 불러와 쓰고 싶다 | `AppConfig.CustomThemePath` 속성 |
|
||||
| UC-T13 | 시스템 테마 값을 판별하는 로직이 앱에 있어야 자동 추종이 가능하다 | `ThemeResolver` 형식 존재 |
|
||||
| UC-T14 | 흐린 보조 텍스트도 카드 위에서 충분히 읽히길 원한다 | 다크 `TextMuted`/`CardBg` 대비 ≥ 4.5:1 (현재 ~4.4:1) |
|
||||
| UC-T15 | 카드에 마우스를 올렸을 때도 텍스트가 읽혀야 한다 | 다크 `TextMuted`/`CardBgHover` 대비 ≥ 4.5:1 (현재 ~4.0:1) |
|
||||
| UC-T16 | 라이트 테마에서도 흐린 텍스트가 카드 위에서 읽혀야 한다 | 라이트 `TextMuted`/`CardBg` 대비 ≥ 4.5:1 (현재 ~4.2:1) |
|
||||
| UC-T17 | 라이트 테마 유리판 배경 위 보조 텍스트도 읽혀야 한다 | 라이트 `TextMuted`/`GlassBg` 대비 ≥ 4.5:1 (현재 ~3.5:1) |
|
||||
| UC-T18 | 강조색 텍스트(포맷 배지)도 본문처럼 또렷해야 한다 | 다크 `AccentBrush`/`CardBg` 대비 ≥ 4.5:1 (현재 ~4.4:1) |
|
||||
| UC-T19 | 비활성화된 컨트롤의 텍스트 색이 명시적으로 있어야 한다 | 테마 `TextDisabled` 토큰 |
|
||||
| UC-T20 | 텍스트 선택 영역 색을 테마로 관리하고 싶다 | 테마 `SelectionBrush` 토큰 |
|
||||
| UC-T21 | 키보드 포커스 링 색이 테마 토큰으로 있어야 한다 | 테마 `FocusAdornerBrush` 토큰 |
|
||||
| UC-T22 | 스크롤바 썸 색을 테마에서 바꾸고 싶다 | `Shared.xaml` `ScrollBarThumbBrush` 토큰 |
|
||||
| UC-T23 | 툴팁에 그림자가 있어 콘텐츠 위에서 분리돼 보였으면 한다 | `Shared.xaml` `TooltipShadow` 토큰 |
|
||||
| UC-T24 | 팝업(플라이아웃)에도 일관된 그림자가 필요하다 | `Shared.xaml` `PopupShadow` 토큰 |
|
||||
| UC-T25 | 경고 상태용 색이 대기(Pending)와 구분되어 있어야 한다 | 테마 `WarningBrush` 토큰 |
|
||||
| UC-T26 | 링크 텍스트 색이 테마에 정의되어 있어야 한다 | 테마 `LinkBrush` 토큰 |
|
||||
| UC-T27 | 방문한 링크 색을 구분해서 보고 싶다 | 테마 `VisitedLinkBrush` 토큰 |
|
||||
| UC-T28 | 정보성 안내 색(파랑 계열)이 필요하다 | 테마 `InfoBrush` 토큰 |
|
||||
| UC-T29 | 강조색을 배경·텍스트 용도별로 분리해 관리하고 싶다 | 테마 `AccentTextBrush` 토큰 |
|
||||
| UC-T30 | 테마 전환 시 창 테두리(타이틀바)도 즉시 따라가야 한다 | `MainWindow.UpdateTitleBarTheme` API |
|
||||
|
||||
## §B 타이포그래피·폰트 (UC-F01~F22)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-F01 | UI 기본 폰트를 내가 고르고 싶다 | `AppConfig.UiFontFamily` |
|
||||
| UC-F02 | 폰트 크기를 키워서 읽기 편하게 하고 싶다 | `AppConfig.UiFontSize` |
|
||||
| UC-F03 | 한국어 폴백 폰트를 직접 지정하고 싶다 | `AppConfig.UiFontKoreanFallback` |
|
||||
| UC-F04 | 기본 폰트 크기가 토큰으로 관리되어 설정이 전체에 적용돼야 한다 | `Shared.xaml` `FontSize.Base` |
|
||||
| UC-F05 | 보조 정보용 작은 폰트 크기 토큰이 필요하다 | `FontSize.Small` |
|
||||
| UC-F06 | 제목용 큰 폰트 크기 토큰이 필요하다 | `FontSize.Large` |
|
||||
| UC-F07 | 화면 제목용 초대형 토큰이 필요하다 | `FontSize.XLarge` |
|
||||
| UC-F08 | 화면 제목(H1) 스타일이 일관되게 정의되어야 한다 | `Type.H1` |
|
||||
| UC-F09 | 본문 스타일이 토큰으로 정의되어야 한다 | `Type.Body` |
|
||||
| UC-F10 | 캡션(도움말 텍스트) 스타일이 필요하다 | `Type.Caption` |
|
||||
| UC-F11 | 진행률·속도 숫자가 등폭 폰트로 흔들리지 않게 보고 싶다 | `Type.Mono` |
|
||||
| UC-F12 | 한국어 가독성 폰트(Pretendard) 프리셋을 쓰고 싶다 | `UiFont` 정의에 Pretendard 포함 |
|
||||
| UC-F13 | 설정창에 글꼴 섹션이 있어야 폰트를 바꿀 수 있다 | 설정창 "글꼴" 섹션 |
|
||||
| UC-F14 | 폰트 바꾸기 전에 미리보기 텍스트로 확인하고 싶다 | 설정창 `FontPreviewText` |
|
||||
| UC-F15 | 폰트 크기 프리셋을 콤보박스로 고르고 싶다 | 설정창 `FontSizeBox` |
|
||||
| UC-F16 | 폰트 설정 변경이 즉시 적용되었으면 한다 | `App.ApplyFontSettings` API |
|
||||
| UC-F17 | 리더 모드도 앱 폰트 설정을 따라야 한다 | ReaderMode 폰트 하드코딩 제거 |
|
||||
| UC-F18 | 새 탭 다이얼도 앱 폰트 설정을 따라야 한다 | 코드비하인드 폰트 하드코딩 제거 |
|
||||
| UC-F19 | 탭 제목 스타일이 공용 스타일로 관리되어야 한다 | `TabTitleStyle` |
|
||||
| UC-F20 | 상태바 텍스트 스타일이 공용으로 관리되어야 한다 | `StatusTextStyle` |
|
||||
| UC-F21 | 아이콘 크기도 토큰으로 관리하고 싶다 | `IconSize.Small` |
|
||||
| UC-F22 | 본문 줄간격을 토큰으로 조절하고 싶다 | `Type.LineHeight` |
|
||||
|
||||
## §C 레이아웃·밀도·창 상태 (UC-L01~L26)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-L01 | 정보 밀도(컴팩트/보통/여유)를 고르고 싶다 | `AppConfig.UiDensity` |
|
||||
| UC-L02 | 설정창에서 밀도를 바꿀 수 있어야 한다 | 설정창 "밀도" 항목 |
|
||||
| UC-L03 | 작은 간격 토큰으로 여백이 일관되게 관리되어야 한다 | `Spacing.S` |
|
||||
| UC-L04 | 중간 간격 토큰이 필요하다 | `Spacing.M` |
|
||||
| UC-L05 | 큰 간격 토큰이 필요하다 | `Spacing.L` |
|
||||
| UC-L06 | 카드 모서리 둥글기가 토큰으로 일관되어야 한다 | `CornerRadius.Card` |
|
||||
| UC-L07 | 컴팩트 모드 상태가 앱 재시작 후에도 유지되었으면 한다 | `AppConfig.CompactMode` |
|
||||
| UC-L08 | 툴바에 컴팩트 모드 토글 버튼이 있으면 빠르게 켜고 싶다 | `MainWindow` `CompactModeBtn` |
|
||||
| UC-L09 | 세로 탭을 기본 레이아웃으로 쓰고 싶다 | `AppConfig.VerticalTabsDefault` |
|
||||
| UC-L10 | 분할 화면 비율이 저장되어 재현되었으면 한다 | `AppConfig.SplitViewRatio` |
|
||||
| UC-L11 | 앱을 껐다 켰을 때 창 위치·크기가 그대로였으면 한다 | `AppConfig.WindowBounds` |
|
||||
| UC-L12 | 최대화 상태도 함께 복원되어야 한다 | `AppConfig.WindowMaximized` |
|
||||
| UC-L13 | 고DPI 화면에서 레이아웃이 흐릿하지 않아야 한다 | `UseLayoutRounding` 설정 |
|
||||
| UC-L14 | 텍스트·요소가 픽셀에 정렬되어 선명해야 한다 | `Shared.xaml` `SnapsToDevicePixels` |
|
||||
| UC-L15 | 안 쓰는 상태바는 자동으로 숨기고 싶다 | `AppConfig.StatusBarAutoHide` |
|
||||
| UC-L16 | 툴바 버튼 노출 여부를 직접 고르고 싶다 | `AppConfig.ToolbarButtons` |
|
||||
| UC-L17 | 북마크바 표시 여부가 저장되었으면 한다 | `AppConfig.BookmarkBarVisible` |
|
||||
| UC-L18 | 탭 스트립 위치(위/아래/왼쪽)를 고르고 싶다 | `AppConfig.TabStripPosition` |
|
||||
| UC-L19 | 패널 폭을 실수로 바꿨을 때 더블클릭으로 기본 복원하고 싶다 | `MainWindow.ResetPanelWidth` |
|
||||
| UC-L20 | 패널 최소 폭을 직접 정하고 싶다 | `AppConfig.RightPanelMinWidth` |
|
||||
| UC-L21 | 움직임에 민감하므로 애니메이션을 줄이고 싶다 | `AppConfig.ReduceMotion` |
|
||||
| UC-L22 | 빠른 전환 애니메이션 지속 시간이 토큰으로 관리되어야 한다 | `Duration.Fast` |
|
||||
| UC-L23 | 일반 애니메이션 지속 시간 토큰이 필요하다 | `Duration.Normal` |
|
||||
| UC-L24 | 컴팩트 모드 엣지 호버 반응 속도를 조절하고 싶다 | `AppConfig.EdgeRevealDelayMs` |
|
||||
| UC-L25 | UI 전체 배율을 키워서 보고 싶다 | `AppConfig.UiScale` |
|
||||
| UC-L26 | 전체화면 여부도 저장되었으면 한다 | `AppConfig.FullScreen` |
|
||||
|
||||
## §D 탭 고급 관리 (UC-B01~B24)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-B01 | 실수로 탭을 닫지 않도록 탭을 잠그고 싶다 | `TabItem.IsLocked` |
|
||||
| UC-B02 | 탭마다 내가 지정한 색 표시를 달고 싶다 | `TabItem.CustomColor` |
|
||||
| UC-B03 | 탭 그룹을 접어서 스트립을 정리하고 싶다 | `TabItem.IsGroupCollapsed` |
|
||||
| UC-B04 | 탭 그룹 이름을 나중에 바꾸고 싶다 | 그룹 이름 변경 API(`RenameGroup`) |
|
||||
| UC-B05 | 탭에 마우스를 올리면 미리보기(제목+URL+상태)가 보였으면 한다 | `TabPreview` 형식 |
|
||||
| UC-B06 | 잠자기 탭이 시각적으로(zzz 등) 구분되었으면 한다 | 탭 템플릿 `IsSuspended` 반영 |
|
||||
| UC-B07 | 탭이 많을 때 번호 배지로 위치를 파악하고 싶다 | `TabIndexBadge` 요소 |
|
||||
| UC-B08 | 탭 드래그 중 삽입 위치 표시기가 보였으면 한다 | `TabInsertIndicator` 요소 |
|
||||
| UC-B09 | 탭 여러 개를 한 번에 닫을 때 확인을 받았으면 한다 | `AppConfig.ConfirmCloseMultipleTabs` |
|
||||
| UC-B10 | 탭 위에서 휠을 굴려 탭을 전환하고 싶다 | `AppConfig.TabWheelSwitch` |
|
||||
| UC-B11 | 탭 최대 개수를 직접 정하고 싶다 | `AppConfig.MaxTabs` |
|
||||
| UC-B12 | 세션 복원 시 탭을 잠자기 상태로만 복원해 빨리 뜨게 하고 싶다 | `AppConfig.RestoreTabsSuspended` |
|
||||
| UC-B13 | 닫은 탭 아카이브를 전용 팝업에서 보고 싶다 | `ArchivePopup` 요소 |
|
||||
| UC-B14 | 아카이브에서 원하는 탭을 검색해서 복구하고 싶다 | `ArchiveSearchBox` 요소 |
|
||||
| UC-B15 | 아카이브를 한 번에 비우고 싶다 | `TabArchive.Clear()` |
|
||||
| UC-B16 | 아카이브 항목을 클릭해 해당 탭을 다시 열고 싶다 | `TabArchive.Restore()` |
|
||||
| UC-B17 | 탭 그룹 색 팔레트가 테마로 관리되어 일관되었으면 한다 | `GroupPalette` 토큰 |
|
||||
| UC-B18 | 현재 작업공간 이름이 항상 보였으면 한다 | `WorkspaceIndicator` 요소 |
|
||||
| UC-B19 | 작업공간 이름을 내가 짓고 싶다 | `AppConfig.WorkspaceNames` |
|
||||
| UC-B20 | 작업공간을 클릭 한 번에 전환하고 싶다 | `WorkspaceSwitcher` 요소 |
|
||||
| UC-B21 | 새 탭 버튼에서 최근 페이지·즐겨찾기로 바로 열고 싶다 | 새 탭 보조 메뉴(`NewTabMore_Click`) |
|
||||
| UC-B22 | 긴 탭 제목을 두 줄로 보고 싶다 | `AppConfig.TabTitleMultiline` |
|
||||
| UC-B23 | 탭에서 바로 볼륨 슬라이더를 조절하고 싶다 | `TabVolumePopup` 요소 |
|
||||
| UC-B24 | 탭 그룹 전체를 즐겨찾기로 저장하고 싶다 | `MainWindow.BookmarkGroup()` |
|
||||
|
||||
## §E 다운로드 관리자 (UC-D01~D30)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-D01 | 다운로드 목록을 최신순·크기순 등으로 정렬하고 싶다 | `AppConfig.DownloadSortOrder` |
|
||||
| UC-D02 | 진행 중/완료/실패 항목을 필터 탭으로 골라 보고 싶다 | `DownloadFilterTabs` 요소 |
|
||||
| UC-D03 | 다운로드 목록 안에서 검색하고 싶다 | `DownloadSearchBox` 요소 |
|
||||
| UC-D04 | 남은 시간(ETA)을 보고 언제 끝나는지 알고 싶다 | 카드 VM `RemainingText` |
|
||||
| UC-D05 | 다운로드 카드에 현재 속도가 표시되었으면 한다 | 카드 VM `SpeedText` |
|
||||
| UC-D06 | 진행 중인 다운로드를 한 번에 전부 일시정지하고 싶다 | `MainWindow.PauseAllDownloads()` |
|
||||
| UC-D07 | 일시정지한 다운로드를 한 번에 전부 재개하고 싶다 | `MainWindow.ResumeAllDownloads()` |
|
||||
| UC-D08 | 완료된 항목을 자동으로 목록에서 치우고 싶다 | `AppConfig.AutoClearCompleted` |
|
||||
| UC-D09 | 몇 번 재시도했는지 카드에 표시되었으면 한다 | 카드 VM `RetryCount` |
|
||||
| UC-D10 | 세그먼트 진행 상황을 막대 그리드로 시각적으로 보고 싶다 | 카드 VM `SegmentMap` |
|
||||
| UC-D11 | 다운로드 완료를 토스트 알림으로 알고 싶다 | `ToastNotifier` 형식 |
|
||||
| UC-D12 | 알림 소리를 켜고 끄고 싶다 | `AppConfig.NotifySound` |
|
||||
| UC-D13 | 완료 시 다운로드 폴더가 자동으로 열렸으면 한다 | `AppConfig.OpenFolderOnComplete` |
|
||||
| UC-D14 | 다운로드 카드를 우클릭해 메뉴(복사·삭제 등)를 쓰고 싶다 | `CardContextMenu` 요소 |
|
||||
| UC-D15 | 카드를 펼쳐 출처 URL·포맷 등 상세 정보를 보고 싶다 | `CardDetailExpander` 요소 |
|
||||
| UC-D16 | 패널 상단에 대기 현황 요약(예: 3 대기 · 1 실패)이 필요하다 | `QueueSummaryText` 요소 |
|
||||
| UC-D17 | 속도 변화를 스파크라인으로 보고 싶다 | `SpeedSparkline` 요소 |
|
||||
| UC-D18 | 전체 다운로드 속도 합계가 표시되었으면 한다 | `GlobalSpeedText` 요소 |
|
||||
| UC-D19 | 파일 총 크기를 카드에서 미리 보고 싶다 | 카드 VM `TotalSizeText` |
|
||||
| UC-D20 | 영상 자막도 함께 받고 언어를 지정하고 싶다 | 설정창 `SubtitleLangBox` |
|
||||
| UC-D21 | 야간 등 지정 시간대에만 다운로드하게 예약하고 싶다 | `DownloadScheduler` 형식 |
|
||||
| UC-D22 | 다운로드 속도 상한을 두고 싶다 | `AppConfig.MaxDownloadSpeedKbps` |
|
||||
| UC-D23 | 다운로드 목록을 CSV 로 내보내 관리하고 싶다 | `MainWindow.ExportDownloads()` |
|
||||
| UC-D24 | 중요한 항목을 먼저 받도록 우선순위를 정하고 싶다 | 카드 VM `Priority` |
|
||||
| UC-D25 | 같은 영상을 또 받으려 할 때 중복 경고를 받고 싶다 | `MainWindow.ConfirmDuplicateDownload()` |
|
||||
| UC-D26 | 충돌 회피 후 최종 저장 파일명이 카드에 표시되었으면 한다 | 카드 VM `FinalFileName` |
|
||||
| UC-D27 | 오류 메시지를 버튼 한 번으로 복사해 공유하고 싶다 | `CopyErrorButton` 요소 |
|
||||
| UC-D28 | 페이지 파일 다운로드도 전체 일시정지가 되었으면 한다 | `PageDownloadTracker.PauseAll()` |
|
||||
| UC-D29 | 감지된 미디어 종류(HLS/DASH/MP4)를 배지로 보고 싶다 | `MediaKindBadge` 요소 |
|
||||
| UC-D30 | 사이트별로 다운로드 항목이 묶여 보였으면 한다 | `SiteGroupHeader` 요소 |
|
||||
|
||||
## §F 설정 창 (UC-S01~S20)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-S01 | 설정 항목이 많아서 검색으로 찾고 싶다 | `SettingsSearchBox` |
|
||||
| UC-S02 | 좌측 카테고리 내비게이션으로 섹션을 오가고 싶다 | `SettingsNavList` |
|
||||
| UC-S03 | 재시작이 필요한 변경은 배너로 미리 알려줬으면 한다 | `RestartBanner` |
|
||||
| UC-S04 | 설정을 기본값으로 한 번에 되돌리고 싶다 | `ResetDefaultsButton` |
|
||||
| UC-S05 | 설정을 파일로 내보내 백업하고 싶다 | `ExportSettingsButton` |
|
||||
| UC-S06 | 다른 기기에서 내보낸 설정을 가져오고 싶다 | `ImportSettingsButton` |
|
||||
| UC-S07 | 고급 항목은 접어두고 기본만 보고 싶다 | `AdvancedSection` |
|
||||
| UC-S08 | 확인 버튼 대신 Ctrl+S 로 저장하고 싶다 | 설정창 `Key.S` 처리 |
|
||||
| UC-S09 | 취소할 때 변경 사항 폐기 확인을 받고 싶다 | `ConfirmDiscardChanges()` |
|
||||
| UC-S10 | 설정창 크기·위치도 기억되었으면 한다 | `AppConfig.SettingsWindowBounds` |
|
||||
| UC-S11 | 재시도 횟수를 UI 에서 바꾸고 싶다 | `RetriesBox` |
|
||||
| UC-S12 | User-Agent 를 UI 에서 바꾸고 싶다 | `UserAgentBox` |
|
||||
| UC-S13 | 프록시 서버를 설정하고 싶다 | `ProxyBox` |
|
||||
| UC-S14 | UI 언어(한/영)를 바꾸고 싶다 | `LanguageBox` |
|
||||
| UC-S15 | Windows 시작 시 자동 실행을 켜고 싶다 | `AutoStartBox` |
|
||||
| UC-S16 | 닫기 버튼으로 트레이로 최소화하고 싶다 | `MinimizeToTrayBox` |
|
||||
| UC-S17 | 알림 종류를 섹션에서 한곳에 모아 관리하고 싶다 | 설정창 "알림" 섹션 |
|
||||
| UC-S18 | 실험적 기능을 명시적으로 켜고 싶다 | 설정창 "실험적" 섹션 |
|
||||
| UC-S19 | 잘못된 값은 저장 전에 힌트로 알려줬으면 한다 | `ValidationHint` 요소 |
|
||||
| UC-S20 | 앱 버전·저장소 정보를 설정에서 보고 싶다 | `VersionText` 요소 |
|
||||
|
||||
## §G 접근성 (UC-A01~A20)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-A01 | 화면 낭독기가 버튼 이름을 읽어줬으면 한다 | `AutomationProperties` 사용 |
|
||||
| UC-A02 | 주요 컨트롤 15개 이상이 자동화 이름을 갖춰야 한다 | `AutomationProperties.Name` ≥ 15 |
|
||||
| UC-A03 | 상태 변화(다운로드 완료 등)가 낭독기에 자동 전달되어야 한다 | `LiveSetting` 사용 |
|
||||
| UC-A04 | Windows 고대비 모드를 켜면 앱도 반응했으면 한다 | `HighContrast` 감지 코드 |
|
||||
| UC-A05 | 키보드 포커스가 어디 있는지 항상 보였으면 한다 | `FocusVisualStyle` 정의 |
|
||||
| UC-A06 | Tab 키 순서가 논리적으로 지정되어야 한다 | `TabIndex` 사용 |
|
||||
| UC-A07 | 툴팁 표시 시간 등 ToolTipService 설정이 필요하다 | `ToolTipService` 사용 |
|
||||
| UC-A08 | 메뉴·버튼에 Alt 접근 키가 있었으면 한다 | `AccessText` 사용 |
|
||||
| UC-A09 | 목록·탭 컨트롤에 맞춤 자동화 피어가 필요하다 | `AutomationPeer` 구현 |
|
||||
| UC-A10 | 컨트롤에 추가 설명(HelpText)이 제공되어야 한다 | `AutomationProperties.HelpText` |
|
||||
| UC-A11 | 색을 구분 못 해도 완료 상태를 아이콘으로 알고 싶다 | `SuccessIcon` 요소 |
|
||||
| UC-A12 | 접근성 관련 설정을 한 섹션에서 관리하고 싶다 | 설정창 "접근성" 섹션 |
|
||||
| UC-A13 | 저시력으로 UI 를 최대 200% 까지 키워서 쓰고 싶다 | `AppConfig.UiFontScale` |
|
||||
| UC-A14 | 팝업 안에서도 키보드 방향키 탐색이 되어야 한다 | `KeyboardNavigation.TabNavigation` |
|
||||
| UC-A15 | 영상 자막 표시 옵션이 필요하다 | `AppConfig.ShowCaptions` |
|
||||
| UC-A16 | 애니메이션 감소 설정이 스타일에 반영되어야 한다 | `Shared.xaml` `ReduceMotion` 연동 |
|
||||
| UC-A17 | 리더 모드 HTML 에 언어(lang=ko)가 선언되어야 낭독기가 한국어로 읽는다 | ReaderMode `lang=` 선언 |
|
||||
| UC-A18 | 접근성 지원 범위를 문서로 확인하고 싶다 | `docs/ACCESSIBILITY.md` 존재 |
|
||||
| UC-A19 | 라이트 테마에서 진행 트랙이 배경과 구별되어야 한다 | 라이트 `TrackBrush`/`PanelBg` 대비 ≥ 3:1 (현재 ~1.2:1) |
|
||||
| UC-A20 | 버튼 테두리가 배경과 구별되어야 클릭 대상이 보인다 | 다크 `BorderBrush`/`CardBg` 대비 ≥ 3:1 (현재 ~1.4:1) |
|
||||
|
||||
## §H 키보드·마우스 인터랙션 (UC-K01~K20)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-K01 | 단축키 목록을 보고 설정하고 싶다 | 설정창 "단축키" 항목 |
|
||||
| UC-K02 | 단축키를 내 키 배치에 맞게 바꾸고 싶다 | `AppConfig.Shortcuts` |
|
||||
| UC-K03 | 단축키 충돌을 저장 전에 알려줬으면 한다 | `ShortcutManager` 형식 |
|
||||
| UC-K04 | 단축키 전체 목록을 앱 안에서 조회하고 싶다 | `ShortcutHelpPopup` 요소 |
|
||||
| UC-K05 | 마우스 우클릭+휠 등 제스처로 뒤로/앞으로 이동하고 싶다 | `MouseGesture`/`XButton` 처리 |
|
||||
| UC-K06 | 링크를 휠 클릭해 새 탭으로 열고 싶다 | `MiddleButton` 처리 |
|
||||
| UC-K07 | 주소를 붙여넣으면 자동으로 이동하게 하고 싶다 | `AppConfig.PasteAndGo` |
|
||||
| UC-K08 | 주소창을 클릭하면 전체 선택되어 바로 덮어쓰고 싶다 | `AppConfig.FocusSelectsAddress` |
|
||||
| UC-K09 | 팔레트에서 "모두 일시정지" 명령을 바로 쓰고 싶다 | "모두 일시정지" 명령 등록 |
|
||||
| UC-K10 | Esc 한 번으로 열린 모든 팝업을 닫고 싶다 | `CloseAllPopups` 통일 처리 |
|
||||
| UC-K11 | 다운로드 중 종료할 때 확인을 받고 싶다 | 종료 확인 다이얼로그 |
|
||||
| UC-K12 | F12 로 개발자 도구를 열고 싶다 | `OpenDevTools` 처리 |
|
||||
| UC-K13 | 프로필(세션)을 전환하며 쓰고 싶다 | "프로필 전환" 기능 |
|
||||
| UC-K14 | 현재 페이지 줌 배율이 표시되었으면 한다 | `ZoomIndicator` 요소 |
|
||||
| UC-K15 | 페이지 기본 줌을 설정하고 싶다 | `AppConfig.DefaultZoomFactor` |
|
||||
| UC-K16 | 즐겨찾기 관리 창에서 정리하고 싶다 | `BookmarkManagerWindow` 형식 |
|
||||
| UC-K17 | 방문 기록에서 특정 항목만 골라 삭제하고 싶다 | `DeleteHistory_Click` 처리기 |
|
||||
| UC-K18 | 화면 영역을 지정해 캡처하고 싶다 | `RegionCapture` 기능 |
|
||||
| UC-K19 | 노트 편집 중 Ctrl+S 로 저장하고 싶다 | `NotesSave_Click` 처리기 |
|
||||
| UC-K20 | 페이지 안 링크를 우클릭해 바로 다운로드하고 싶다 | "링크 다운로드" 컨텍스트 메뉴 |
|
||||
|
||||
## §I 라이브러리·재생목록·즐겨찾기·기록·노트 (UC-M01~M22)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-M01 | 받은 파일들을 앱 안 라이브러리 뷰에서 보고 싶다 | `LibraryPopup`/`LibraryBtn` 요소 |
|
||||
| UC-M02 | 라이브러리를 그리드/리스트로 전환해 보고 싶다 | `LibraryViewToggle` 요소 |
|
||||
| UC-M03 | 라이브러리에서 파일을 검색하고 싶다 | `LibrarySearchBox` 요소 |
|
||||
| UC-M04 | 라이브러리를 이름·날짜·크기순으로 정렬하고 싶다 | `LibrarySortMenu` 요소 |
|
||||
| UC-M05 | 라이브러리 항목에 추가한 날짜가 보였으면 한다 | `AddedDateText` 요소 |
|
||||
| UC-M06 | 라이브러리 항목에 썸네일이 보였으면 한다 | `LibraryThumbnail` 요소 |
|
||||
| UC-M07 | 라이브러리 항목을 더블클릭해 재생하고 싶다 | `LibraryPlay_Click` 처리기 |
|
||||
| UC-M08 | 라이브러리에서 항목을 삭제하고 싶다 | `LibraryDelete_Click` 처리기 |
|
||||
| UC-M09 | 라이브러리에서 항목이 포함된 폴더를 열고 싶다 | `LibraryOpenFolder_Click` 처리기 |
|
||||
| UC-M10 | 라이브러리가 비었을 때 안내가 뜨길 원한다 | `LibraryEmptyHint` 요소 |
|
||||
| UC-M11 | 재생목록을 셔플로 듣고 싶다 | `PlaylistShuffle` 요소 |
|
||||
| UC-M12 | 반복 모드(한곡/전체)가 저장되었으면 한다 | `AppConfig.PlaylistLoopMode` |
|
||||
| UC-M13 | 재생목록을 파일로 저장·불러오고 싶다 | `PlaylistExport` 기능 |
|
||||
| UC-M14 | 재생목록 순서를 위/아래 버튼으로 바꾸고 싶다 | `PlaylistMoveUp` 요소 |
|
||||
| UC-M15 | 재생목록 안에서 검색하고 싶다 | `PlaylistSearchBox` 요소 |
|
||||
| UC-M16 | 즐겨찾기를 폴더로 정리하고 싶다 | `BookmarkFolder` 기능 |
|
||||
| UC-M17 | 즐겨찾기 이름·URL 을 나중에 편집하고 싶다 | `EditBookmark` 기능 |
|
||||
| UC-M18 | 즐겨찾기를 검색해서 찾고 싶다 | `BookmarkSearchBox` 요소 |
|
||||
| UC-M19 | 즐겨찾기를 브라우저 HTML 로 내보내고 싶다 | `ExportBookmarks` 기능 |
|
||||
| UC-M20 | 방문 기록이 날짜별로 묶여 보였으면 한다 | `GroupHistoryByDate` 기능 |
|
||||
| UC-M21 | 방문 기록을 검색해서 찾고 싶다 | `HistorySearchBox` 요소 |
|
||||
| UC-M22 | 노트를 검색해서 찾고 싶다 | `NotesSearchBox` 요소 |
|
||||
|
||||
## §J 상태 표시·알림·피드백 (UC-N01~N20)
|
||||
|
||||
| ID | 사용자 유즈케이스 | 계약 |
|
||||
|---|---|---|
|
||||
| UC-N01 | 상태바에서 전체 다운로드 진행률을 한눈에 보고 싶다 | `AggregateProgress` 요소 |
|
||||
| UC-N02 | 완료·오류 알림이 토스트로 떴으면 한다 | `ToastHost` 요소 |
|
||||
| UC-N03 | 토스트가 떠 있는 시간을 조절하고 싶다 | `AppConfig.ToastDurationMs` |
|
||||
| UC-N04 | 치명 오류는 상단 배너로 고정되었으면 한다 | `ErrorBanner` 요소 |
|
||||
| UC-N05 | 오류 배너를 펼쳐 상세 스택을 보고 싶다 | `ErrorDetailExpander` 요소 |
|
||||
| UC-N06 | 복사한 URL 을 앱이 감지해 바로 받기 제안을 했으면 한다 | `ClipboardHint` 요소 |
|
||||
| UC-N07 | 원격 접속 서버 상태가 상시 표시되었으면 한다 | `ServerStatusIcon` 요소 |
|
||||
| UC-N08 | QR 페어링을 툴바에서 바로 열고 싶다 | `PairingBtn` 요소 |
|
||||
| UC-N09 | 새 버전이 있으면 배지로 알려줬으면 한다 | `UpdateBadge` 요소 |
|
||||
| UC-N10 | 차단된 추적기 도메인별 통계를 보고 싶다 | `ShieldDomainStats` 요소 |
|
||||
| UC-N11 | 네트워크 끊김을 상태에 표시했으면 한다 | `NetworkChange` 감지 |
|
||||
| UC-N12 | 절전 모드 진입 시 다운로드를 일시정지하고 싶다 | `AppConfig.PauseOnPowerSaver` |
|
||||
| UC-N13 | 상태바 텍스트를 클릭해 복사하고 싶다 | `CopyStatus_Click` 처리기 |
|
||||
| UC-N14 | 지나간 알림을 모아보는 알림 센터가 필요하다 | `NotificationCenter` 요소 |
|
||||
| UC-N15 | 방해 금지 모드로 알림을 끄고 싶다 | `AppConfig.DoNotDisturb` |
|
||||
| UC-N16 | 처음 실행 시 기능을 안내하는 온보딩이 있었으면 한다 | `Onboarding` 요소 |
|
||||
| UC-N17 | 빈 상태 안내가 공용 스타일로 일관되었으면 한다 | `EmptyStateStyle` 토큰 |
|
||||
| UC-N18 | 충돌 발생 시 리포트 대화상자로 알려줬으면 한다 | `CrashReportDialog` 형식 |
|
||||
| UC-N19 | 툴바 다운로드 버튼에 진행 개수 배지가 떴으면 한다 | `DownloadsBtnBadge` 요소 |
|
||||
| UC-N20 | 상태바 오른쪽에 줌·서버 등 보조 정보가 보였으면 한다 | `StatusRight` 요소 |
|
||||
|
||||
---
|
||||
|
||||
## GREEN 구현 완료 (2026-08-17)
|
||||
|
||||
제안했던 순서대로 완료했다. 주요 산출물:
|
||||
|
||||
1. **토큰/테마(§A·§B·§C)** — `Shared.xaml` 전면 개서(디자인 토큰·그림자·GroupPalette·FocusVisual·
|
||||
ReduceMotion·SnapsToDevicePixels), `Themes/HighContrast.xaml` 신규, Dark/Light 대비 결함 수정
|
||||
(TextMuted #8B91A6/#63687A, AccentBrush #8B7CFF, BorderBrush #6C6C8A, TrackBrush #808798).
|
||||
브러시 참조를 DynamicResource 로 전환해 **재시작 없는 라이브 테마 전환**(UC-T03/T04) 실현.
|
||||
`App.ApplyAccent`(강조색 즉시 교체)·`App.ApplyFontSettings`·`App.ApplyReduceMotion`·
|
||||
`Services/ThemeResolver`(시스템 테마 판별).
|
||||
2. **설정 계약 + 설정창(§F)** — `AppConfig` 신규 속성 40여 개, `SettingsWindow` 를 좌측 카테고리
|
||||
내비게이션 + 검색 + 섹션 구조로 재구성(글꼴·밀도·알림·접근성·단축키·실험적·자막·예약·프록시).
|
||||
Ctrl+S 저장, 취소 폐기 확인, 기본값 복원, JSON 내보내기/가져오기, 검증 힌트.
|
||||
3. **다운로드 관리자(§E)** — 카드 VM 확장(속도/ETA/총크기/재시도/세그먼트맵/우선순위/최종파일명),
|
||||
필터 탭·검색·정렬, 전체 일시정지/재개(엔진 취소+파트 보존 이어받기), CSV 내보내기, 중복 확인,
|
||||
`ToastNotifier`·`DownloadScheduler`(예약 창 게이트), 페이지 다운로드 PauseAll.
|
||||
4. **라이브러리·탭(§D·§I)** — 라이브러리 팝업(검색·정렬·재생·삭제·폴더·빈 상태), 탭 잠금·사용자 색·
|
||||
그룹 이름 변경/접기·번호 배지·드래그 삽입 표시기·볼륨 팝업, 아카이브 팝업(검색·복구·비움),
|
||||
작업공간 표시/전환, 재생목록 셔플·반복·M3U 내보내기, 즐겨찾기 편집·폴더·HTML 내보내기,
|
||||
기록 날짜 묶음·개별 삭제, 노트 검색·저장.
|
||||
5. **접근성·인터랙션(§G·§H·§J)** — AutomationProperties 30여 개·LiveSetting·TabIndex·AccessText·
|
||||
ToolTipService·커스텀 AutomationPeer, `docs/ACCESSIBILITY.md` 신규, 휠 클릭 새 탭(JS auxclick)·
|
||||
XButton 탐색·F12 개발자 도구·Esc 팝업 일괄 닫기·영역 캡처·프로필 전환, 상태바 통합 진행률·
|
||||
클립보드 제안·서버 상태·알림 센터·온보딩·오류 배너, `CrashReportDialog`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue