feat(release): prepare 1.1.0 candidate
This commit is contained in:
parent
5a34f66981
commit
5205dcdfa9
736 changed files with 115667 additions and 12203 deletions
|
|
@ -1,111 +1,102 @@
|
|||
# D3RO Voice 릴리스 가이드
|
||||
|
||||
agent-switchboard-client의 릴리스 체계를 이식한 멀티플랫폼 배포 파이프라인.
|
||||
기준일: 2026-08-29. 이 문서는 desktop GitLab 패키지·자동 업데이트와 mobile store release의 경계를 분리한다. 태그 생성이나 HTTP 200 하나만으로 배포 완료를 선언하지 않는다.
|
||||
|
||||
## 파이프라인 개요
|
||||
## 현재 release identity
|
||||
|
||||
```
|
||||
git tag vX.Y.Z → push
|
||||
├─ package-windows (runner: build-win-x64, TW-VIVEN-BUILD) → NSIS exe + latest.yml
|
||||
├─ package-macos (runner: build-mac-arm64, TW-BUILD-MAC-ARM64) → dmg + zip + latest-mac.yml [D3RO_MAC_RUNNER="true"일 때만]
|
||||
└─ release-create (runner: build-linux-x64 Docker, TW-BUILD01)
|
||||
├─ Generic Package Registry 업로드
|
||||
│ ├─ d3ro-voice/<version>/ (버전별 보관)
|
||||
│ └─ d3ro-voice/latest/ (electron-updater feed — 매 릴리스 갱신)
|
||||
└─ GitLab Release 생성 + asset 링크
|
||||
```
|
||||
|
||||
- 버전은 태그에서 자동 동기화된다 (`scripts/ci/sync-version.mjs` — `v0.2.0` → package.json `0.2.0`).
|
||||
- macOS artifacts가 없으면 Windows 단독으로 릴리스가 생성된다 (경고 로그만).
|
||||
|
||||
## 릴리스 절차
|
||||
|
||||
```bash
|
||||
git tag v0.2.0
|
||||
git push origin v0.2.0
|
||||
```
|
||||
|
||||
끝. 파이프라인이 패키징 → 레지스트리 업로드 → Release 생성까지 자동 수행한다.
|
||||
|
||||
## 사용자가 1회 설정해야 하는 것
|
||||
|
||||
### 1. macOS runner (2026-07-21 기준 완료됨)
|
||||
|
||||
사내 공용 runner `TW-BUILD-MAC-ARM64`(tags: `build-mac-arm64`)가 온라인이며,
|
||||
CI 변수 `D3RO_MAC_RUNNER="true"`도 설정 완료. 별도 등록 불필요.
|
||||
|
||||
Mac runner 환경 전제조건 (미충족 시 package-macos 잡 실패 — allow_failure라 릴리스는 진행):
|
||||
- Xcode Command Line Tools, Node 22+(또는 volta), Python 3.11+
|
||||
- `brew install sox` — install-sox.sh가 이 바이너리를 번들함
|
||||
|
||||
### 2. 자동 업데이트 활성화 (Windows) — 2026-07-21 기준 완료됨
|
||||
|
||||
1. 프로젝트 ID = **1172** (기입 완료)
|
||||
2. **두 곳**에 같은 feed URL 기입 (어긋나면 안 됨):
|
||||
- `apps/desktop/src/main/update-feed.ts`의 `UPDATE_FEED_URL` ✅
|
||||
- `apps/desktop/electron-builder.yml`의 `publish.url` ✅
|
||||
```
|
||||
https://gitlab.twentyoz.kr:8443/api/v4/projects/1172/packages/generic/d3ro-voice/latest
|
||||
```
|
||||
`publish` 섹션은 latest.yml/latest-mac.yml **생성**을 트리거하는 필수 설정이다
|
||||
(없으면 electron-builder가 update info 파일을 아예 만들지 않음).
|
||||
3. `package_registry_access_level=public` 설정 완료 ✅ (2026-07-21, API로 적용) —
|
||||
앱의 무인증 다운로드/랜딩 페이지 다운로드 링크의 전제. 비공개로 되돌리면 자동 업데이트가 401로 조용히 중단됨.
|
||||
4. v0.1.1-alpha부터 배포된 앱이 4시간 주기로 업데이트를 체크한다
|
||||
|
||||
### 산출물 파일명 규칙
|
||||
|
||||
파일명에 공백 금지 — GitLab Generic Package Registry가 공백을 불허해
|
||||
latest.yml의 url과 레지스트리 파일명이 어긋나면 업데이트 다운로드가 404 난다.
|
||||
|
||||
- Windows: `D3RO-Voice-Setup-<version>-x64.exe`
|
||||
- macOS: `D3RO-Voice-<version>-arm64.dmg` / `.zip`
|
||||
|
||||
## 알려진 제약 / 후속 단계
|
||||
|
||||
| 항목 | 현재 상태 | 후속 |
|
||||
| 항목 | 정본 | 현재 판정 |
|
||||
|---|---|---|
|
||||
| macOS 서명/공증 | ❌ ad-hoc 서명 (`identity=-`, switchboard 검증 조합) — Gatekeeper가 차단하면 우클릭→열기 또는 `xattr -dr com.apple.quarantine "/Applications/D3RO Voice.app"` | Apple Developer 계정($99/년) 확보 시 switchboard의 prepare/cleanup-macos-keychain.mjs + 공증 패턴 이식. 주의: D3RO는 asarUnpack native 모듈 + ollama/sox 바이너리 다중 서명 필요 |
|
||||
| macOS 자동 업데이트 | ❌ 미지원 (Squirrel.Mac이 서명 요구) | 서명 도입 후 latest-mac.yml feed 연결 |
|
||||
| 업데이트 무결성 서명 | latest.yml SHA-512 (electron-builder 기본) | switchboard의 Ed25519 update-policy 매니페스트 체계 이식 검토 |
|
||||
| CHANGELOG | ✅ v0.2.0-alpha부터 운영 | `publish-gitlab-release.mjs`가 `## [버전]` 섹션을 Release 노트로 자동 추출. CHANGELOG를 풍부하게 = Release 페이지 품질 직결 |
|
||||
| 제품 버전 | `release/product-version.json`: `1.1.0` | source SSOT 확정 |
|
||||
| Android | versionCode `1010001` | production AAB 미생성 |
|
||||
| iOS | build `1010001` | production archive 미검증 |
|
||||
| Android upload key | alias `d3ro-upload-20260821`, cert SHA-256 `4F:AC:69:24:...:15:2B:54` | external PKCS12·user-only ACL·Credential Manager·private-key readback GREEN; CI secret·복구 백업·AAB signer 대조 대기 |
|
||||
| release evidence | Ed25519 public `release/mobile-release-evidence-public.pem`, keyId `2797d3e6...4a890b7f` | external private key ACL·roundtrip GREEN; CI private-key secret·복구 백업 대기 |
|
||||
| desktop offline license | Ed25519 public `apps/desktop/resources/license/production-public.pem`, keyId `5c52b765...81a887f` | 새 전용 keypair·external private ACL·roundtrip·desktop production build GREEN; admin `ADMIN_LICENSE_PRIVATE_KEY` secret 주입 대기 |
|
||||
| Firebase | Console `u/0`, `u/1` 모두 D3RO project 없음 | 사용자 승인 후 project·Android app 생성 필요 |
|
||||
| AdMob | app `ca-app-pub-1039714767792854~6427959892`; banner `/9840591290`; rewarded `/2255790918` | SSOT 확정. `검토 필요`·`광고 게재 제한`·store 미연결·결제 프로필 미완료 |
|
||||
| updater feed | `https://gitlab.twentyoz.kr:8443/api/v4/projects/1172/packages/generic/d3ro-voice/latest` | public `latest.yml`은 아직 `0.2.1-alpha`; `1.1.0` 미배포 |
|
||||
| release notes | `CHANGELOG.md` `## [1.1.0]` | 태그 전 확정·검증 필수 |
|
||||
|
||||
## Release 페이지 운영 (v0.2.0-alpha부터)
|
||||
source SSOT와 live updater metadata의 버전이 다르므로 아직 `1.1.0` 배포 완료가 아니다.
|
||||
|
||||
GitLab Release 페이지는 **CHANGELOG가 단일 진실 원천**이다. 릴리스 품질을 올기려면 CHANGELOG를 잘 쓴다.
|
||||
## GitLab desktop 파이프라인
|
||||
|
||||
### Release 노트 = CHANGELOG 섹션 (자동)
|
||||
`publish-gitlab-release.mjs`의 `extractChangelogSection(changelog, version)`가 태그 버전(`0.2.0-alpha`)과 매칭되는 `## [0.2.0-alpha]` 섹션을 Release 노트로 추출. **CHANGELOG를 고치면 Release 노트에 자동 반영** — 릴리스 후수정해도 다음 릴리스에 반영되지 않으니 릴리스 "전"에 CHANGELOG를 확정.
|
||||
|
||||
### 권장 섹션 구조 (Keep a Changelog)
|
||||
```text
|
||||
authoritative release commit
|
||||
→ version/check/test/build GREEN
|
||||
→ tag v1.1.0
|
||||
→ package-windows (build-win-x64)
|
||||
→ package-macos (build-mac-arm64)
|
||||
→ publish-release (build-linux-x64)
|
||||
├─ packages/generic/d3ro-voice/1.1.0/ 버전별 보존
|
||||
├─ packages/generic/d3ro-voice/latest/ latest updater feed
|
||||
└─ GitLab Release + CHANGELOG release notes
|
||||
```
|
||||
## [버전] - YYYY-MM-DD
|
||||
> 다운로드 안내 (Windows exe / macOS dmg 파일명 + 자동업데이트/서명 메모)
|
||||
### Added / Changed / Fixed / Removed / Internal
|
||||
|
||||
- `scripts/ci/sync-version.mjs --check --tag v1.1.0`는 태그, `release/product-version.json`, package/lockfile, Android/iOS 버전 면의 일치를 fail-closed로 검증한다.
|
||||
- `scripts/ci/verify-release-metadata.mjs`는 배포 메타데이터와 CI/publisher 계약을 검증한다.
|
||||
- 같은 gate는 desktop license public key가 Ed25519이고 `release/product-version.json`의 `desktopLicensePublicKeyId`와 일치하는지 검증한다. `electron.vite.config.ts`는 이 파일을 직접 읽으므로 누락·손상된 키로는 build가 시작되지 않는다.
|
||||
- `scripts/ci/publish-gitlab-release.mjs`는 버전별 패키지를 먼저 올리고, `latest` 파일에서 설치 자산 참조를 검증한 후 update metadata를 마지막에 게시한다.
|
||||
- Windows installer와 `latest.yml`은 필수다. macOS 산출물이 없는 Windows-only release를 의도했다면 그 판단을 release record에 남긴다.
|
||||
|
||||
## 자동 업데이트 계약
|
||||
|
||||
`apps/desktop/src/main/update-feed.ts`와 `apps/desktop/electron-builder.yml`은 버전 없는 같은 public Generic Package Registry URL을 가리켜야 한다.
|
||||
|
||||
```text
|
||||
https://gitlab.twentyoz.kr:8443/api/v4/projects/1172/packages/generic/d3ro-voice/latest
|
||||
```
|
||||
- 상단 인용 블록(`>`)에 다운로드 파일명·자동업데이트·macOS 서명 안내를 적으면 사용자가 Release 페이지에서 바로 확인.
|
||||
- 내부 작업(refactor-wave 등)은 `### Internal`로 분리 — 사용자 관심사(Added/Fixed)가 위에 오도록.
|
||||
|
||||
### 릴리스 체크리스트
|
||||
1. CHANGELOG `[버전]` 섹션 작성 (위 구조)
|
||||
2. `memory/project_status.md` 최신화 (규칙 13)
|
||||
3. `git tag vX.Y.Z && git push origin vX.Y.Z`
|
||||
4. GitLab 파이프라인 모니터링 (package-windows / package-macos / release-create)
|
||||
5. Release 페이지에서 노트·asset 링크·latest.yml 확인
|
||||
6. (검증) 기존 앱에서 자동 업데이트 수신 확인
|
||||
아래 면이 하나라도 깨지면 release를 중단한다.
|
||||
|
||||
### 버전 정책
|
||||
- `0.x.y-alpha`: 개발 프리릴리스 (현재 단계). 자동업데이트 feed는 alpha 체널.
|
||||
- minor 범프: 대규모 재설계/정리(Midnight Glass v2, refactor-wave). patch: 버그 수정 중심.
|
||||
- alpha→정식 전환은 기능·안정성 기준 충족 시 (별도 합의).
|
||||
| mac x64 (Intel) | 빌드 안 함 (사이드카가 arm64 전용) | 수요 발생 시 Intel Mac runner 추가 |
|
||||
| **Linux (deb/AppImage)** | ❌ 미지원 — 사이드카 Linux 빌드·TTS 백엔드 부재 | **별도 Phase**(2026-07-22 합의). 사이드카 Linux PyInstaller(ctranslate2) + TTS 백엔드 신규(espeak-ng/Piper — 현재 Windows SAPI 전용) + electron-builder linux(deb+AppImage, afterInstall로 sox/의존 안내) + CI package-linux 잡(TW-BUILD01 Docker 툴체인 확장) + QA(Ubuntu/Debian/Fedora). switchboard 원본도 Windows-only라 참조 패턴 없음 |
|
||||
1. package registry의 무인증 public pull이 허용됐다.
|
||||
2. `latest.yml`의 `version`이 태그와 일치한다.
|
||||
3. `latest.yml` URL/path가 같은 `latest` 경로의 실제 installer를 참조한다.
|
||||
4. installer 파일명에 공백이 없다: `D3RO-Voice-Setup-<version>-x64.exe`.
|
||||
5. metadata SHA-512와 다운로드한 installer가 일치한다.
|
||||
6. 이전 실제 설치본이 feed를 탐지하고, 다운로드·재시작·버전 상승을 끝까지 완료한다.
|
||||
|
||||
2026-08-29 live `latest.yml`의 버전은 `0.2.1-alpha`다. 이는 updater endpoint가 응답한다는 증거일 뿐 `1.1.0` 게시 증거가 아니다.
|
||||
|
||||
## `1.1.0` 릴리스 절차
|
||||
|
||||
1. `release/product-version.json`의 version/build 값과 모든 버전 면을 `npm run version:check`로 대조한다.
|
||||
2. `CHANGELOG.md` `## [1.1.0] - 2026-08-29` 섹션을 사용자 변경점 중심으로 확정한다. publisher는 이 섹션이 없으면 실패해야 한다.
|
||||
3. dirty/untracked 작업을 임의로 reset·clean하지 말고, release 범위만 검토 가능한 authoritative commit으로 보존한다.
|
||||
4. 같은 commit에서 lint, typecheck, test, build, release metadata·security·artifact gate를 전부 GREEN으로 만든다.
|
||||
5. desktop offline license를 제공한다면 external private key를 admin의 `ADMIN_LICENSE_PRIVATE_KEY` secret로 주입하고, 저장소 public key와 sign/verify roundtrip 및 발급 감사 로그를 확인한다.
|
||||
6. 이전 버전보다 높은 태그 `v1.1.0`을 생성해 push한다. 태그는 게이트를 시작하는 후속 단계지 검증을 대체하지 않는다.
|
||||
7. GitLab에서 package-windows, package-macos, publish-release와 의도한 mobile job 상태를 모두 확인한다. pending/stuck/skipped를 GREEN으로 기록하지 않는다.
|
||||
8. 버전별 package, GitLab Release note/asset, `latest.yml`, installer hash를 외부 public URL에서 다시 검증한다.
|
||||
9. 이전 설치본에서 자동 업데이트 E2E를 실행하고 실행 중 버전·프로세스·사용자 데이터 보존을 확인한다.
|
||||
|
||||
## mobile release와의 경계
|
||||
|
||||
Desktop GitLab Release를 게시해도 Android production 출시가 자동으로 완료되지 않는다. Android는 다음을 별도로 증명한다.
|
||||
|
||||
- 준비된 local upload/evidence key와 AdMob identity를 protected CI secret에 주입하고, 사용자 승인 후 생성한 production Firebase config와 함께 version `1.1.0`, versionCode `1010001` AAB 생성
|
||||
- package/config/upload signer/ABI/16 KB page size/signed provenance GREEN
|
||||
- public APK 게시 없이 Play internal track에 제한 업로드
|
||||
- Play-signed 실기기 E2E, 12명·연속 14일 closed test, production access 승인
|
||||
- Data safety/App content/production 선언은 사용자의 action-time 검토·승인 후에만 제출
|
||||
|
||||
현재 local upload/evidence key는 존재하지만 CI secret 주입·복구 백업·production Firebase·AAB가 없고 Play production access도 disabled이므로 Android production 출시는 RED다.
|
||||
|
||||
## rollback
|
||||
|
||||
- Desktop: 게시 전이면 `latest` metadata를 바꾸지 않는다. 이미 업데이트된 클라이언트는 downgrade하지 말고 더 높은 patch 버전으로 forward-fix한다.
|
||||
- Play: staged rollout을 중단하고 더 높은 versionCode의 수정 AAB를 새로 검증·배포한다.
|
||||
- 복구 작업도 release record에 artifact hash, 시각, 판단자, 영향 범위를 남긴다.
|
||||
|
||||
## 참고 파일
|
||||
|
||||
- `.gitlab-ci.yml` — 파이프라인 정의
|
||||
- `scripts/ci/sync-version.mjs` — 태그 → package.json 버전 동기화
|
||||
- `scripts/ci/publish-gitlab-release.mjs` — 레지스트리 업로드 + Release 생성
|
||||
- `apps/desktop/src/main/services/UpdateService.ts` — 자동 업데이트 (electron-updater)
|
||||
- `apps/desktop/src/main/update-feed.ts` — feed URL SSOT
|
||||
- 원본 패턴: `D:\workspace\agent-switchboard-client` (.gitlab-ci.yml, scripts/publish-gitlab-release.mjs)
|
||||
- `release/product-version.json` — 제품 version/build SSOT
|
||||
- `release/android-release-identity.json` — Play app/package/certificate identity
|
||||
- `release/mobile-release-evidence-public.pem` — release evidence public key
|
||||
- `apps/desktop/resources/license/production-public.pem` — desktop offline license public key SSOT
|
||||
- `scripts/ci/sync-version.mjs` — 버전 면 동기화·검증
|
||||
- `scripts/ci/verify-release-metadata.mjs` — release metadata 자가 검증
|
||||
- `scripts/ci/publish-gitlab-release.mjs` — registry·Release·updater feed publisher
|
||||
- `apps/desktop/src/main/update-feed.ts` — runtime updater URL SSOT
|
||||
- `apps/desktop/electron-builder.yml` — builder publish URL·artifact contract
|
||||
- `docs/v3/play/04-release-checklist.md` — Play Console·AAB·closed test·production gate
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue