releases/docs/DEPLOYMENT_PLAN.md

274 lines
21 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.

# Video Downloader — 멀티플랫폼 배포 체계 계획서 (v1)
> **범위**: Windows · macOS · Linux 데스크톱 + Android · iOS 모바일의 **빌드→서명→패키징→배포→업데이트** 전 체계.
> GitHub Releases 를 단일 배포 소스로, GitHub Actions 로 전 아티팩트 자동 빌드.
> **현행 운영(2026-08-17~)**: 자체 Forgejo + 자체 러너 3대가 주 채널 — §5-bis. GitHub 는 공개 시 백업 채널.
>
> **작성일**: 2026-08-15 · **관련 문서**: `BROWSER_FEATURES_PLAN.md`(v2) · `MOBILE_PLAN.md`(v1)
> **조사 근거**: 전문 조사팀 20회 검색 + GitHub Releases API 로 툴체인 바이너리 실물 검증 (2026-08 기준)
---
## 0. 핵심 결론
1. **배포 소스는 GitHub Releases 단일 채널** — 계정/서버 인프라 없음(제품 철학과 일치). 태그(`v*`) 푸시 → CI 매트릭스 빌드 → Draft Release → QA → Publish.
2. **⚠️ 중대 발견: CefGlue.Avalonia 는 Linux 미지원** (공식 문서 명시, 이슈 #189). MOBILE_PLAN/BACKLOG 의 "크로스플랫폼 브라우저 = CEF" 가정 수정 필요 → **플랫폼별 네이티브 WebView 계층**(Windows=WebView2, macOS=WKWebView, Linux=WebKitGTK)을 기본으로 하고 CEF는 Windows/macOS 보조 후보로 강등. 단, 네이티브 WebView 는 응답 가로채기(미디어 스니핑)가 CEF 보다 약함 → **크로스플랫폼 감지 품질 게이트를 별도로 통과해야 이관** (기존 Gate #1 정신 유지).
3. **macOS 는 Apple Developer Program($99/년) 없이는 실효 배포 불가** (공증 필수). 첫 macOS 릴리스 전 가입 예산 수립.
4. **데스크톱 자동 업데이트**: v1 = GitHub latest 태그 폴링 + 설치 열기(무의존·전 OS 공통), v2 = Velopack(델타 업데이트, Windows 우선 도입).
5. **툴체인(yt-dlp/ffmpeg/deno)은 전 플랫폼 자동 다운로드 가능** — 단 ffmpeg macOS arm64 는 BtbN 빌드가 없어 **ffmpeg-static 릴리스** 사용 (§4 검증표).
---
## 0.5 자체 빌드머신 (운영 중 — 2026-08-15 구축 완료)
GitHub Actions 대신(또는 보완으로) **사용자 소유 빌드머신 2대**로 리눅스/macOS 산출물을 생산한다:
| 별칭 | 머신 | 사양 | SDK | 역할 |
|---|---|---|---|---|
| `vd-linux` | ChanpacaLaptop (Linux Mint 22.3) — Tailscale `100.65.55.115` | x86_64 · 32C · 62GB | 8.0.424 + 10.0.400 | `linux-x64` 빌드 |
| `vd-mac` | Mac mini M2 (macOS 26.5.2) — LAN `192.168.0.127` / Tailscale `100.88.141.44` | arm64 | 8.0.424 + 10.0.400 | `osx-arm64` 빌드 (+iOS 임시) |
- **접속**: SSH 키 인증(`~/.ssh/id_ed25519_vd`, `~/.ssh/config` 별칭). 엔드포인트·자격증명은 `.env`(git 무시).
- **빌드 명령**: `bash build/remote/build-remote.sh [linux|mac|all]` — git HEAD 소스를 머신에 전송 → Cli+Avalonia RID별 self-contained publish → 산출물 tar.gz 수집(`out/remote/<rid>/`).
- **검증(2026-08-15)**: linux-x64·osx-arm64 양쪽 4산출물 생성(ELF/Mach-O arm64 매직 확인), **양 머신에서 네이티브 실행 E2E 통과** — HLS 테스트 스트림 64세그먼트 다운로드+병합 EXIT=0.
- **운영 지식**: Avalonia 12.1 게터는 .NET 10 SDK 필요(8만 있으면 CS0103). 빌드머신 절전 시 SSH 끊김 → 재연결 감지 폴러 패턴으로 자동 재개 검증됨. Mac 무헤드 운용 시 "네트워크 접근 시 깨우기" 활성화 권장.
- GitHub Actions(§5)는 리포지토리 공개 시 **자동 백업 채널**로 병행. 두 머신 모두 2026-08-17 부터
Forgejo 러너(host 모드)로도 등록되어 CI 잡을 직접 수행한다(§5-bis).
## 1. 제품 × 아티팩트 매트릭스
| 제품 | 플랫폼 | 아티팩트 | 채널 | 서명 |
|---|---|---|---|---|
| **App (WPF+WebView2)** — 주력 | Windows x64 | `VideoDownloader-Setup-x64.exe` (Inno, 기존) | GitHub Releases | Authenticode (선택, 후순위) |
| | Windows arm64 | `VideoDownloader-Setup-arm64.exe` (기존) | 〃 | 〃 |
| **App (Avalonia 셸)** — 크로스플랫폼 이관 | Linux x64/arm64 | `videodownloader-linux-x64.tar.gz` (기본) + `.AppImage` + `.deb` | GitHub Releases | (GPG 서명 선택) |
| | macOS x64/arm64 | `VideoDownloader-<arch>.dmg` (+ `.app` in DMG) | GitHub Releases | Developer ID + 공증 필수 |
| **Mobile (MAUI)** | Android | `VideoDownloader-<ver>-arm64.apk` | GitHub Releases + Obtainium | Keystore (CI 시크릿) |
| | Android (Play, 선택) | `.aab` | Google Play (추출코드 없는 빌드) | Play App Signing |
| | iOS | `.ipa` | TestFlight → App Store | Apple 배포 인증서 |
| **Server / 웹 컴패니언** | 데스크톱 앱에 내장 | 별도 배포 없음 (앱이 Kestrel 서빙) | — | 앱 서명에 포함 |
**버저닝**: `Major.Minor.Patch` 세마버 + 태그 `v*`. 모든 프로젝트 공통 버전(csproj `Version` 일괄 주입 `-p:Version=`).
---
## 2. 데스크톱 상세
### 2.1 Windows (현재 자산 유지)
- 기존 체계 그대로: `dotnet publish -c Release -r win-x64/arm64 --self-contained`(폴더 배포) → ISCC 2회 → `out/Setup-*.exe`. `build/publish.ps1` 스크립트를 CI 잡으로 감싸기만 하면 됨.
- Windows arm64 는 x64 러너에서 교차 publish 가능(현재 방식 그대로 CI 호환).
### 2.2 macOS (Avalonia 셸)
1. `dotnet publish -c Release -r osx-arm64/-x64 --self-contained` (폴더; **CEF/단일파일 불가 원칙** — 네이티브 WebView 라면 폴더 배포로 충분)
2. `.app` 래핑: `Contents/MacOS/`(호스트) · `Contents/Resources/` · `Info.plist` (Avalonia 공식 가이드)
3. **universal 보다 아키텍처별 DMG 2개가 저렴** (lipo 병합은 호스트만 가능, CEF 프레임워크는 별도)
4. 서명/공증 파이프라인:
```
codesign --force --options runtime --timestamp --sign "Developer ID Application: ..." App.app
xcrun notarytool store-credentials NOTARY --apple-id ... --team-id ... --password ...
xcrun notarytool submit App.dmg --keychain-profile NOTARY --wait
xcrun stapler staple App.app
```
- DMG 생성: `create-dmg`/`dmgbuild` (macOS 러너에서만)
- LAN 페어링(모바일 연동) 시 macOS 로컬 네트워크 프라이버시 프롬프트 대응 안내 UI 필요
5. **툴체인 Gatekeeper 주의**: 앱이 HttpClient 로 내려받는 yt-dlp/deno/ffmpeg 는 quarantine xattr 이 안 붙음 → 런타임 자동다운로드 설계가 Gatekeeper 이슈를 자동 회피 (현재 설계 유지가 정답)
### 2.3 Linux (Avalonia 셸)
- **기본 = tar.gz self-contained** (모든 배포판 보장), **편의 = AppImage** (linuxdeploy/appimagetool), **선택 = .deb** (dpkg-deb, `Depends:` 는 네이티브만).
- AppImage 함정: Ubuntu 24.04 는 libfuse2 부재 → tar.gz 병행 의무화.
- Avalonia(X11) 의존: `libx11-6 libice6 libsm6 libfontconfig1` (+브라우저 엔진이 WebKitGTK면 `libwebkit2gtk-4.1`, CEF면 Chrome 셋: `libnss3 libgbm1 libasound2 libatk1.0 libcups2 libxkbcommon0 libxcomposite1 libxdamage1 libxrandr2 libdbus-1-3 libdrm2` + mesa).
- 네이티브 데스크톱 항목(파일 다이얼로그 등)에 `libgtk-3` 선택 의존 가능.
### 2.4 크로스플랫폼 브라우저 엔진 전략 (수정)
| OS | 1순위 | 대안 | 감지(스니핑) 전망 |
|---|---|---|---|
| Windows | **WebView2** (현행) | CefGlue | 최상 (WebResourceResponseReceived) |
| macOS | **WKWebView** (WebView.Avalonia) | CefGlue(동작 보고됨) | WKURLSchemeHandler/프록시 조합 필요 — 품질 게이트 필수 |
| Linux | **WebKitGTK** (WebView.Avalonia) | CEF(**미지원 이슈 #189**) | WebKit의 리소스 인터셉트로 제한적 — 품질 게이트 필수 |
→ **Gate #1'**: 3OS 각각 "HLS/DASH/MP4 직링크 감지 + 쿠키 전달" E2E 통과 시에만 해당 OS 베타 출시. 통과 못하면 해당 OS 는 "링크 붙여넣기 다운로더"(브라우저 없음, 현재 Avalonia 앱 형태)로 출시.
---
## 3. 모바일 상세
### 3.1 Android
```bash
dotnet publish src/Mobile -f net10.0-android -c Release \
-p:AndroidPackageFormat=apk -p:RuntimeIdentifiers=android-arm64 \
-p:AndroidKeyStore=true -p:AndroidSigningKeyStore=$KS \
-p:AndroidSigningKeyAlias=vd -p:AndroidSigningKeyPass=... -p:AndroidSigningStorePass=...
```
- 배포: GitHub Releases APK + **Obtainium 지원** (README에 `app.json` 원탭 설정 배포 → GitHub Release 만으로 자동 업데이트 채널 확보)
- Play (선택, 후순위): `AndroidPackageFormat=aab` + 사이트 특화 추출 코드 제거 빌드 변형
### 3.2 iOS
- TestFlight 외부 10,000명 (베타 리뷰 24-48h). 내부 100명 무리뷰.
- **필수**: `PrivacyInfo.xcprivacy` (2024-05부터 누락 시 ITMS-91053 리젝 — MAUI 바인딩 항목 포함 점검)
- **심사 프레이밍 (가이드라인 2.5.13 부합)**: "사용자 소유 PC 원격 제어 + 자기 라이브러리 시청" — 심사 메모에 자기 PC 연결 데모 영상 첨부. 5.2.3 회피: 기기 내 추출 코드 없음(전부 PC 실행) 명시.
- CI: macOS 러너에서 빌드+서명 (인증서/프로비저닝 시크릿), 업로드는 App Store Connect API.
---
## 4. 툴체인 바이너리 매핑 (GitHub Releases 검증 완료, 2026-08)
| 툴 | Windows x64/arm64 | macOS (universal/x64/arm64) | Linux x64/arm64 |
|---|---|---|---|
| yt-dlp | `yt-dlp.exe` / `yt-dlp_arm64.exe` | `yt-dlp_macos` (universal2) ✅ | `yt-dlp_linux` / `yt-dlp_linux_aarch64` ✅ |
| ffmpeg | BtbN `win64-gpl` / `winarm64-gpl` | ⚠️ BtbN 없음 → **ffmpeg-static releases** (x64+arm64 darwin) | BtbN `linux64-gpl` / `linuxarm64-gpl` ✅ |
| deno | `deno-x86_64-pc-windows-msvc.zip` | `deno-aarch64/x86_64-apple-darwin.zip` ✅ | `deno-x86_64/aarch64-unknown-linux-gnu.zip` ✅ |
- 공통 패턴: `https://github.com/<owner>/<repo>/releases/latest/download/<asset>` + SHA256 검증파시(.sha256sum/SUMS) — 기존 `YtDlpRunner`/`DenoRunner` 자동설치 메커니즘을 `Core/Platform/IToolLocator` 추상화 아래 **OS/아키텍처 매니페스트 테이블**로 일반화 (재구성 계획 ②와 동일 작업).
- ffmpeg macOS 공급처 이원화(BtbN/ffmpeg-static)는 `IToolLocator` 구현체의 플랫폼별 다운로드 소스 매핑으로 흡수.
---
## 5. CI/CD (GitHub Actions)
```yaml
# .github/workflows/release.yml (개요)
on: { push: { tags: ['v*'] } }
jobs:
test: # dotnet test (단위+E2E) — 전 플랫폼 빌드의 관문
desktop:
strategy:
matrix:
include:
- { os: windows-latest, rid: win-x64 }
- { os: windows-latest, rid: win-arm64 } # 교차 publish
- { os: ubuntu-latest, rid: linux-x64 }
- { os: ubuntu-24.04-arm, rid: linux-arm64 }
- { os: macos-latest, rid: osx-arm64 } # 무료 M1 러너(공개 저장소)
- { os: macos-13, rid: osx-x64 }
steps: [checkout, setup-dotnet(8/10), publish(폴더/Inno/AppImage/deb/DMG), 서명·공증(macOS만), upload-artifact]
android: [ubuntu-latest, JDK21+MAUI 워크로드, dotnet publish apk, 서명, upload]
ios: [macos-latest, 워크로드, 서명(ipa), TestFlight 업로드]
release:
needs: [test, desktop, android]
steps: [download-artifact, softprops/action-gh-release@v2 (draft: true)]
```
- **시크릿**: `MACOS_P12`(base64)/`KEYCHAIN_PASS`/`NOTARY_PROFILE`(Apple ID·팀·앱비밀번호) · `ANDROID_KEYSTORE/ALIAS/PASS` · (iOS) `ASC_KEY`.
- macOS 서명 함정: 키체인 자동 잠금 방지 타임아웃 설정.
- 공개 저장소 기준 러너 무료(macOS 포함). 비공개 전환 시 macOS 10× 과금 유의.
- QA 통과 후 Draft → Publish 수동 승격.
## 5-bis. CI/CD 현행 채널 — Forgejo Actions 자체 러너 (2026-08-17 가동)
저장소가 자체 Forgejo(`https://git.chanpaca.net/Video-Downloader/client`)로 이관되고 org 러너 3대가
등록되어, §5(GitHub) 대신 **자체 러너로 전 아티팩트를 빌드·배포**한다. §5 는 저장소 GitHub 공개 시
백업 채널로 유지(`.github/workflows/release.yml` 존치).
| 러너 | 머신 | 라벨(모두 host 모드) | 담당 잡 |
|---|---|---|---|
| `yunchan-win` | ALPACA-HOME (Windows 11, 개발 PC) | `windows`, `windows-amd64` | test 관문 · Windows 설치자(x64/arm64) · Android APK |
| `kd-desktop` | ChanpacaLaptop (§0.5 `vd-linux`) | `linux-builder` | linux-x64/arm64 tar.gz |
| `yunchan-mac` | Mac mini M2 (§0.5 `vd-mac`) | `macos`, `macos-arm64` | osx-arm64/x64 tar.gz |
- **워크플로**: `.forgejo/workflows/release.yml` — 태그 `v*` 푸시 → test(전체 xUnit) 관문 → 빌드 잡 병렬
→ 각 잡이 draft 릴리스에 자산을 직접 업로드. host 러너에 Node 가 없어도 되도록 `uses:` 액션 없이
순수 `run:` 스텝으로만 구성(체크아웃도 git 직접).
- **업로드 헬퍼**: `build/ci/upload-release-asset.ps1`/`.sh` — draft 릴리스 확보(병렬 잡 경합 대응) +
동명 자산 교체(재실행 멱등). Windows Git Bash 의 CRLF 오염 방지 처리 포함.
- **리허설**: workflow_dispatch → `ci-rehearsal` draft prerelease 로 태그 없이 전 파이프라인 검증.
- **시크릿**: `RELEASE_TOKEN`(Forgejo PAT, `write:repository`) — 릴리스 생성·자산 업로드. 체크아웃은 잡
자동 토큰(`github.token`). `ANDROID_KEYSTORE/ALIAS/PASS` 등록 전까지 APK 는 디버그 서명.
- **업로드 대상**: 공개 배포 저장소 **`Video-Downloader/releases`**(워크플로 env `RELEASE_REPO`).
소스 저장소(client)는 비공개라 자산 익명 다운로드가 불가해 분리했다. draft 는 익명에게 보이지
않으므로 "빌드 → draft → QA → 수동 Publish" 흐름은 그대로다. Publish 하면 §5-ter 사이트가 노출한다.
- **머신 전제**: win = SDK 8/10 + `maui-android` 워크로드 + JDK 17 + Inno Setup 6 ·
linux/mac = `~/.dotnet` SDK 8.0.424 + 10.0.400 (§0.5).
- **갭**: §6 자동 업데이트 v1(`UpdateChecker`)은 GitHub Releases API 를 폴링하므로 GitHub 공개 전까지
미동작 — Forgejo Releases API(`/repos/{owner}/{repo}/releases/latest`, 동일 형태) 대응은 후속 항목.
대상은 공개 저장소 `Video-Downloader/releases` 가 되어야 한다.
## 5-ter. 배포 사이트 — MEDIABROWSER (Cloudflare Pages, 2026-08-18 가동)
제품 배포명은 **MEDIABROWSER** 로 하고, 프로모션/다운로드/사용 안내 3페이지 정적 사이트를
Cloudflare Pages 에 올렸다. **https://mediabrowser-7r4.pages.dev** (mediabrowser 서브도메인 선점으로
접미 부여 — 커스텀 도메인 연결은 후속).
- **소스**: `site/` — `index.html`(프로모션: 라이트 글래스모피즘 + CSS scroll-driven 패럴랙스,
모션 축소·투명도 축소 미디어쿼리 존중) · `releases.html`(플랫폼별 다운로드) · `guide.html`(사용 안내).
히어로/가이드의 다운로드 패널 이미지는 격리 프로필(`VD_DATA_DIR`)로 띄운 실제 앱 캡처다.
- **릴리스 데이터**: 브라우저에서 Forgejo API 를 직접 부르면 CORS 에 막히므로, 배포 시점에
`site/fetch-releases.mjs` 가 공개 저장소 릴리스를 `site/releases.json`(git 무시)으로 굽는다.
published 릴리스만 포함(draft 제외), 최신판 강조 + 이전 버전 접힘 + OS 자동 감지 권장 표시.
- **배포**: `./build/deploy-site.ps1` — .env 의 `CLOUDFLARE_API_TOKEN/ACCOUNT_ID` 로
`wrangler pages deploy site --project-name mediabrowser`. **릴리스를 Publish 한 뒤 이 스크립트를
다시 실행해야 사이트 목록이 갱신된다**(후속: 릴리스 CI 에 사이트 재배포 잡 추가).
- **후속**: 커스텀 도메인 · 설치자/실행 파일의 MEDIABROWSER 개명(제품명 통일) · Obtainium `app.json`
의 URL 을 공개 저장소로 갱신.
## 6. 업데이트 체계
| 대상 | 방식 |
|---|---|
| Windows/Linux/macOS v1 | `GET /repos/:owner/:repo/releases/latest` 태그 비교 → "다운로드·설치" 버튼(설치 파일 열기) |
| Windows v2 | **Velopack** (델타+자동적용; Inno → Velopack 설치기 일회 마이그레이션 릴리스) |
| Android | Obtainium (GitHub Releases 연동) / Play (후순위) |
| iOS | TestFlight·App Store 표준 흐름 |
| 툴체인 | 기존 yt-dlp 자동갱신 + `IToolLocator` 버전 체크 확장 |
---
## 7. 로드맵 (배포 관점) — 진행 상태 2026-08-16
| 단계 | 내용 | 전제 | 상태 |
|---|---|---|---|
| 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. 리스크 요약
1. **CEF Linux 미지원** — 네이티브 WebView 폴백 확정, 감지 품질 게이트로 방어 (§2.4)
2. macOS 공증 = Apple Developer Program 필수 (미가입 시 macOS 배포 중단)
3. AppImage/libfuse2, ffmpeg macOS 공급처 부재(BtbN) → ffmpeg-static 대체 (§4)
4. iOS 프라이버시 매니페스트 누락 리젝 (ITMS-91053)
5. 비공개 리포지토리 전환 시 macOS 러너 비용 10×
## 출처 (핵심)
- CefGlue Linux 미지원: [OutSystems/CefGlue #189](https://github.com/OutSystems/CefGlue/issues/189) · [CefGlue.Avalonia NuGet](https://www.nuget.org/packages/CefGlue.Avalonia)
- macOS 배포: [Avalonia macOS 가이드](https://avaloniaui.net/blog/the-definitive-guide-to-building-and-deploying-avalonia-applications-for-macos) · [.NET macOS publish](https://learn.microsoft.com/en-us/dotnet/core/deploying/macos) · [notarytool 워크플로](https://developer.apple.com/documentation/security/customizing-the-notarization-workflow)
- Linux: [Avalonia Linux 의존성](https://docs.avaloniaui.net/docs/deployment/linux) · [deb-control](https://man7.org/linux/man-pages/man5/deb-control.5.html)
- CI: [GitHub M1 러너](https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/) · [애플 인증서 설치](https://docs.github.com/actions/use-cases-and-examples/deploying/installing-an-apple-certificate-on-macos-runners-for-xcode-development) · [action-gh-release](https://github.com/softprops/action-gh-release)
- 툴체인: [yt-dlp releases](https://github.com/yt-dlp/yt-dlp/releases) · [BtbN ffmpeg](https://github.com/btbn/ffmpeg-builds/releases) · [ffmpeg-static](https://github.com/eugeneware/ffmpeg-static) · [deno releases](https://github.com/denoland/deno/releases)
- 모바일: [MAUI publish-cli](https://learn.microsoft.com/en-us/dotnet/maui/android/deployment/publish-cli?view=net-maui-10.0) · [TestFlight 한도](https://developer.apple.com/help/app-store-connect/test-a-beta-version/invite-external-testers/) · [가이드라인 2.5.13](https://developer.apple.com/app-store/review/guidelines/) · [Obtainium](https://github.com/ImranR98/Obtainium)
- 업데이트: [Velopack](https://github.com/velopack/velopack) · [cross-compile](https://docs.velopack.io/packaging/cross-compiling)