diff --git a/.forgejo/workflows/portable.yml b/.forgejo/workflows/portable.yml index 4472b63..205659b 100644 --- a/.forgejo/workflows/portable.yml +++ b/.forgejo/workflows/portable.yml @@ -51,6 +51,9 @@ jobs: - name: 데스크톱 번들 빌드 run: npm run build --workspace=@d3ro/desktop + - name: 데스크톱 렌더러 번들 검증 + run: node scripts/ci/verify-desktop-renderer-bundles.mjs + - name: 휴대용 ZIP + Scoop 매니페스트 생성 run: node scripts/ci/build-portable.mjs diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index 3159540..d42bffd 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -62,6 +62,7 @@ jobs: throw "로컬 개발 인증서는 production 서명 identity가 아닙니다." } npm run build --workspace=@d3ro/desktop + node scripts/ci/verify-desktop-renderer-bundles.mjs Push-Location apps/desktop npx electron-builder --win --x64 --config electron-builder.yml --publish never node scripts/ci/verify-native-abi.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0694180..0db2b41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -169,6 +169,10 @@ jobs: - name: Build Target Workspace run: ${{ matrix.cmd }} + - name: Verify Desktop Renderer Bundles + if: matrix.target == 'desktop' + run: node scripts/ci/verify-desktop-renderer-bundles.mjs + # ────────────────────────────────────────────────────────────────── # 4. Android x86_64 artifacts and native dependency gate # ────────────────────────────────────────────────────────────────── diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e5c634..75e3d44 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,6 +109,9 @@ jobs: npm run typecheck npm run build --workspace=@d3ro/desktop + - name: Verify Desktop Renderer Bundles + run: node scripts/ci/verify-desktop-renderer-bundles.mjs + - name: Build STT Sidecar (local transcription engine) run: | # Local transcription depends on the faster-whisper sidecar; a release @@ -189,6 +192,9 @@ jobs: npm run typecheck npm run build --workspace=@d3ro/desktop + - name: Verify Desktop Renderer Bundles + run: node scripts/ci/verify-desktop-renderer-bundles.mjs + - name: Build STT Sidecar (local transcription engine) run: | # Local transcription depends on the faster-whisper sidecar; a release diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f813e..f3aaa8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Cloud-optional backup (encrypted, opt-in) - Plugin system for custom pipelines +## [1.3.7] - 2026-09-19 + +### Fixed +- **Recording and live caption overlays never worked in installed builds.** Popup + pages loaded their scripts as classic ` + + diff --git a/apps/desktop/src/renderer/popups/command-popup/index.html b/apps/desktop/src/renderer/popups/command-popup/index.html index 664087f..996a62f 100644 --- a/apps/desktop/src/renderer/popups/command-popup/index.html +++ b/apps/desktop/src/renderer/popups/command-popup/index.html @@ -19,6 +19,7 @@ - + + diff --git a/apps/desktop/src/renderer/popups/history-popup/index.html b/apps/desktop/src/renderer/popups/history-popup/index.html index 780a1fb..0a461e5 100644 --- a/apps/desktop/src/renderer/popups/history-popup/index.html +++ b/apps/desktop/src/renderer/popups/history-popup/index.html @@ -17,6 +17,7 @@ - + + diff --git a/apps/desktop/src/renderer/popups/recording-tip/index.html b/apps/desktop/src/renderer/popups/recording-tip/index.html index 58ea4ba..623064c 100644 --- a/apps/desktop/src/renderer/popups/recording-tip/index.html +++ b/apps/desktop/src/renderer/popups/recording-tip/index.html @@ -34,6 +34,7 @@ - + + diff --git a/apps/desktop/src/renderer/popups/result-popup/index.html b/apps/desktop/src/renderer/popups/result-popup/index.html index 552fe47..6457d33 100644 --- a/apps/desktop/src/renderer/popups/result-popup/index.html +++ b/apps/desktop/src/renderer/popups/result-popup/index.html @@ -23,6 +23,7 @@ - + + diff --git a/apps/mobile-rn/android/app/build.gradle b/apps/mobile-rn/android/app/build.gradle index 745b471..b71db41 100644 --- a/apps/mobile-rn/android/app/build.gradle +++ b/apps/mobile-rn/android/app/build.gradle @@ -151,8 +151,8 @@ def versionSettingsValid = configuredVersionName != null && configuredVersionName ==~ strictSemver && configuredVersionCodeValue != null && configuredVersionCodeValue <= 2100000000L -def resolvedVersionName = versionSettingsValid ? configuredVersionName : "1.3.6" -def resolvedVersionCode = versionSettingsValid ? configuredVersionCodeValue.toInteger() : 1031006 +def resolvedVersionName = versionSettingsValid ? configuredVersionName : "1.3.7" +def resolvedVersionCode = versionSettingsValid ? configuredVersionCodeValue.toInteger() : 1031007 def requiredReleaseSettings = [ D3RO_RELEASE_STORE_FILE: releaseStoreFilePath, diff --git a/apps/mobile-rn/ios/D3ROVoice.xcodeproj/project.pbxproj b/apps/mobile-rn/ios/D3ROVoice.xcodeproj/project.pbxproj index faf7162..24b59d2 100644 --- a/apps/mobile-rn/ios/D3ROVoice.xcodeproj/project.pbxproj +++ b/apps/mobile-rn/ios/D3ROVoice.xcodeproj/project.pbxproj @@ -257,7 +257,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 1031006; + CURRENT_PROJECT_VERSION = 1031007; ENABLE_BITCODE = NO; INFOPLIST_FILE = D3ROVoice/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; @@ -265,7 +265,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.6; + MARKETING_VERSION = 1.3.7; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -287,14 +287,14 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 1031006; + CURRENT_PROJECT_VERSION = 1031007; INFOPLIST_FILE = D3ROVoice/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.6; + MARKETING_VERSION = 1.3.7; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", diff --git a/apps/mobile-rn/metadata/android/en-US/changelogs/1031007.txt b/apps/mobile-rn/metadata/android/en-US/changelogs/1031007.txt new file mode 100644 index 0000000..2ea3629 --- /dev/null +++ b/apps/mobile-rn/metadata/android/en-US/changelogs/1031007.txt @@ -0,0 +1 @@ +Overlay fixes: the recording waveform/timer and live captions now display correctly. diff --git a/apps/mobile-rn/metadata/android/ko-KR/changelogs/1031007.txt b/apps/mobile-rn/metadata/android/ko-KR/changelogs/1031007.txt new file mode 100644 index 0000000..031c828 --- /dev/null +++ b/apps/mobile-rn/metadata/android/ko-KR/changelogs/1031007.txt @@ -0,0 +1 @@ +오버레이 수정: 녹음 파형/타이머와 실시간 자막이 정상 표시됩니다. diff --git a/apps/mobile-rn/package-lock.json b/apps/mobile-rn/package-lock.json index 351b628..e3cbe30 100644 --- a/apps/mobile-rn/package-lock.json +++ b/apps/mobile-rn/package-lock.json @@ -1,12 +1,12 @@ { "name": "@d3ro/mobile-rn", - "version": "1.3.6", + "version": "1.3.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@d3ro/mobile-rn", - "version": "1.3.6", + "version": "1.3.7", "dependencies": { "@d3ro/api-client": "file:../../packages/api-client", "@d3ro/core": "file:../../packages/core", @@ -62,7 +62,7 @@ }, "../..": { "name": "d3ro-voice-monorepo", - "version": "1.3.6", + "version": "1.3.7", "license": "MIT", "workspaces": [ "apps/desktop", @@ -81,7 +81,7 @@ }, "../../packages/api-client": { "name": "@d3ro/api-client", - "version": "1.3.6", + "version": "1.3.7", "license": "MIT", "dependencies": { "@d3ro/core": "*", @@ -98,7 +98,7 @@ }, "../../packages/core": { "name": "@d3ro/core", - "version": "1.3.6", + "version": "1.3.7", "license": "MIT", "dependencies": { "docx": "^9.6.1" @@ -109,7 +109,7 @@ }, "../../packages/i18n": { "name": "@d3ro/i18n", - "version": "1.3.6", + "version": "1.3.7", "license": "MIT", "devDependencies": { "@types/react": "^19.0.0" @@ -120,7 +120,7 @@ }, "../../packages/ui-native": { "name": "@d3ro/ui-native", - "version": "1.3.6", + "version": "1.3.7", "license": "MIT", "devDependencies": { "@types/react": "*" diff --git a/apps/mobile-rn/package.json b/apps/mobile-rn/package.json index d18dab4..81ef219 100644 --- a/apps/mobile-rn/package.json +++ b/apps/mobile-rn/package.json @@ -1,6 +1,6 @@ { "name": "@d3ro/mobile-rn", - "version": "1.3.6", + "version": "1.3.7", "private": true, "scripts": { "android": "react-native run-android", diff --git a/apps/web/package.json b/apps/web/package.json index 137143b..8fbf2a1 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@d3ro/web", - "version": "1.3.6", + "version": "1.3.7", "private": true, "description": "D3RO Voice 웹 앱 — Next.js 기반 SaaS 인터페이스", "scripts": { diff --git a/apps/web/src/components/layout/sidebar.tsx b/apps/web/src/components/layout/sidebar.tsx index b678848..e4a0264 100644 --- a/apps/web/src/components/layout/sidebar.tsx +++ b/apps/web/src/components/layout/sidebar.tsx @@ -139,7 +139,7 @@ export function Sidebar(): React.ReactElement { - v1.3.6 + v1.3.7 diff --git a/docs/map/00-index.md b/docs/map/00-index.md index bda0005..d3413ac 100644 --- a/docs/map/00-index.md +++ b/docs/map/00-index.md @@ -2,7 +2,8 @@ > Status: ACTIVE > Last full audit: 2026-09-13 -> Scope: entire monorepo `D:/workspace/D3ROVoice` at product version `1.3.0` +> Last update: 2026-09-19 — GAP-INFRA-05 (desktop renderer popup bundle verification wired into CI); 1.3.7 published to the updater feed +> Scope: entire monorepo `D:/workspace/D3ROVoice` at product version `1.3.7` > Purpose: let any agent (or human) answer two questions in under a minute: > 1. **What infrastructure exists?** (build, CI, services, APIs, data, packages, deploy) > 2. **How far is each feature developed?** (per surface, with file anchors and status) diff --git a/docs/map/02-infrastructure.md b/docs/map/02-infrastructure.md index 6411555..32507a0 100644 --- a/docs/map/02-infrastructure.md +++ b/docs/map/02-infrastructure.md @@ -78,6 +78,7 @@ npm run release:metadata[:test] npm run release:forgejo[:check] # canonical Forgejo publisher/feed npm run release:tag # annotated/signed immutable release tag npm run security:secrets[:test] # hardcoded-secret scanner +npm run check:desktop-renderer[:test] # built renderer pages reference only assets on disk npm run test:e2e:red # content-report red e2e npm run release:mobile:boundary[:test] npm run release:mobile:config[:test] @@ -136,7 +137,7 @@ See [`03-shared-packages.md`](./03-shared-packages.md). Summary: ### GitLab CI (`.gitlab-ci.yml`) -Stages `validate → test → build → e2e → package → publish → deploy`. Primary pipeline for desktop Windows/macOS releases (Forgejo Generic Registry is the canonical updater feed; GitLab project 1172 is a legacy mirror) and production mobile releases (`mobile-production-release`, manual/protected). Admin NAS deploy job is intentionally **disabled**. `package-windows`/`package-macos` build the faster-whisper sidecar (`sidecar:setup` → `sidecar:build`) and run `scripts/ci/verify-sidecar-bundle.mjs` before electron-builder, so a release can never ship without the local STT engine. +Stages `validate → test → build → e2e → package → publish → deploy`. Primary pipeline for desktop Windows/macOS releases (Forgejo Generic Registry is the canonical updater feed; GitLab project 1172 is a legacy mirror) and production mobile releases (`mobile-production-release`, manual/protected). Admin NAS deploy job is intentionally **disabled**. `package-windows`/`package-macos` build the faster-whisper sidecar (`sidecar:setup` → `sidecar:build`) and run `scripts/ci/verify-sidecar-bundle.mjs` before electron-builder, so a release can never ship without the local STT engine. Every pipeline that runs `npm run build --workspace=@d3ro/desktop` (`.forgejo` release/portable, `.github` CI/release) then runs `scripts/ci/verify-desktop-renderer-bundles.mjs`, which fails packaging when a renderer page references an asset the build did not emit (GAP-INFRA-05). ### Forgejo Actions (`.forgejo/workflows/`) `portable.yml` — 태그/수동 실행으로 **서명 없이** portable 채널(95MiB 7z 분할 볼륨 + Scoop 매니페스트 + 설치 스크립트)을 게시한다. `WIN_CSC_*` 불필요, updater feed는 건드리지 않는다. @@ -191,7 +192,7 @@ Full detail: [`09-supabase-backend.md`](./09-supabase-backend.md). | File | Purpose | |---|---| -| `release/product-version.json` | version `1.3.0`, `androidVersionCode`/`iosBuildNumber` `1030001`, releaseDate, desktop license keyId | +| `release/product-version.json` | version `1.3.7`, `androidVersionCode`/`iosBuildNumber` `1031007`, releaseDate, desktop license keyId | | `release/android-release-identity.json` | package `com.d3ro.voice`, Play app ID, app-signing SHA-256, upload cert SHA-256, evidence keyId, AdMob unit IDs | | `release/desktop-license-public.pem` | Ed25519 public key for desktop offline licenses | | `release/mobile-release-evidence-public.pem` | Ed25519 public key for mobile release evidence | diff --git a/docs/map/04-desktop-app.md b/docs/map/04-desktop-app.md index dd6e5df..317ae42 100644 --- a/docs/map/04-desktop-app.md +++ b/docs/map/04-desktop-app.md @@ -146,6 +146,12 @@ Preload exposes **`window.electronAPI`** with 33 namespaces: `platform, audio, c `windows/WindowManager.ts` creates 6 windows: main (borderless, custom TitleBar; macOS `hiddenInset`), recording-tip, result-popup, history-popup, command-popup, caption-overlay. Injects popup theme CSS + i18n strings; 2-phase resize. `windows/TrayManager.ts` — tray icon + menu + double-click show. +**Popup invariants** (each shipped broken once — do not regress): + +- 팝업 HTML의 스크립트는 반드시 `') + const goodProblems = collectProblems(goodRoot, pages) + if (goodProblems.length !== 0) { + failures.push(`complete build reported problems: ${goodProblems.join('; ')}`) + } + + const brokenRoot = path.join(tmpRoot, 'broken') + bundlePage(brokenRoot, '') + const brokenProblems = collectProblems(brokenRoot, pages) + if (!brokenProblems.some((problem) => problem.includes('missing asset'))) { + failures.push('missing asset was not detected') + } + if (!brokenProblems.some((problem) => problem.includes('classic script'))) { + failures.push('classic script tag was not detected') + } + + const missingPageProblems = collectProblems(goodRoot, ['popups/absent/index.html']) + if (!missingPageProblems.some((problem) => problem.startsWith('missing built page'))) { + failures.push('missing page was not detected') + } + } finally { + rmSync(tmpRoot, { recursive: true, force: true }) + } + + if (failures.length > 0) { + console.error('verify-desktop-renderer-bundles self-test failed:') + for (const failure of failures) console.error(`- ${failure}`) + process.exit(1) + } + console.log('verify-desktop-renderer-bundles self-test: OK') +} + +if (process.argv.slice(2).includes('--self-test')) { + selfTest() +} else if (!existsSync(builtRendererDir)) { + console.error(`Renderer build not found: ${builtRendererDir}`) + console.error(' build: npm run build --workspace=@d3ro/desktop') + process.exit(1) +} else { + const pages = expectedPages() + const problems = collectProblems(builtRendererDir, pages) + + if (problems.length > 0) { + console.error('Desktop renderer bundle verification failed:') + for (const problem of problems) console.error(`- ${problem}`) + console.error(' rebuild: npm run build --workspace=@d3ro/desktop') + process.exit(1) + } + + console.log(`Desktop renderer bundle verification passed: ${pages.length} page(s) with all assets on disk`) +} \ No newline at end of file diff --git a/site/package-lock.json b/site/package-lock.json index e3778a9..4e3c001 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1,12 +1,12 @@ { "name": "d3ro-voice-site", - "version": "1.3.6", + "version": "1.3.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "d3ro-voice-site", - "version": "1.3.6", + "version": "1.3.7", "dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0" diff --git a/site/package.json b/site/package.json index 2a62652..87c082a 100644 --- a/site/package.json +++ b/site/package.json @@ -1,7 +1,7 @@ { "name": "d3ro-voice-site", "private": true, - "version": "1.3.6", + "version": "1.3.7", "type": "module", "scripts": { "dev": "vite --port 5199 --host",