docs: record Wave 3 surface consolidation and fold NAS-only whisper into compose
- docs/REFACTOR_WAVE3_REPORT.md and the Wave 3 policy: canonical map, production changes, verification and remaining external steps. - Gap backlog: GAP-BILL-01 resolved; new GAP-BILL-02 (Payple renewal never ran, Payple client key never set), GAP-WEB-01 (tunnel host for /app), GAP-OPS-01 (NAS compose/.env drift), GAP-CI-01, GAP-I18N-02, GAP-TEAM-02. - design.md: hero loop decision (numbers taken from the app capsule), pricing mismatch closed; feature catalog SHELL-11 updated. - docs/map, release guide and mobile release docs no longer describe the deleted wwwroot, binaries, Dockerfile.admin, NAS site copy or .github CI. - docker-compose.nas.yml gains the d3ro-whisper service that only existed in the NAS copy, so the repository file is the complete definition. - refactor-wave skill: Wave 3 index and lessons P10-P12.
This commit is contained in:
parent
92978607da
commit
e87ce63440
17 changed files with 187 additions and 46 deletions
|
|
@ -11,7 +11,7 @@
|
|||
D:/workspace/D3ROVoice
|
||||
├── apps/
|
||||
│ ├── desktop/ Electron app (npm workspace @d3ro/desktop)
|
||||
│ ├── web/ Next.js console (npm workspace @d3ro/web)
|
||||
│ ├── web/ Next.js console (npm workspace @d3ro/web); basePath `/app`, served at `d3ro.chanpaca.net/app`
|
||||
│ ├── admin/ Next.js back office (npm workspace @d3ro/admin)
|
||||
│ ├── mobile-rn/ React Native product mobile app (NOT an npm workspace)
|
||||
│ ├── api-server/ ASP.NET Core 10 API (D3ROVoice.Api)
|
||||
|
|
@ -25,8 +25,9 @@ D:/workspace/D3ROVoice
|
|||
│ └── api-client/ @d3ro/api-client — Supabase wrapper + shared types
|
||||
├── server/
|
||||
│ ├── supabase/ Supabase project: config.toml, migrations/, functions/, tests/
|
||||
│ └── cloudflare-worker/ Edge gateway (wrangler.toml + src/index.ts)
|
||||
├── site/ Vite landing site (deployed to Cloudflare Pages + GitHub Pages)
|
||||
│ ├── cloudflare-worker/ Edge gateway (wrangler.toml + src/index.ts)
|
||||
│ └── cloudflare-site-bridge/ Site bridge worker: forwards `/app/*` to WEB_APP_ORIGIN, rewrites upstream redirects, else proxies to Pages
|
||||
├── site/ Vite landing site (deployed to Cloudflare Pages; GitHub Pages removed 2026-09-26, Wave 3)
|
||||
├── resources/ icons/ (empty), sox/ (bundled Windows SoX binaries)
|
||||
├── release/ Version identity SSOT + license/evidence public keys
|
||||
├── scripts/ ~145 automation scripts + scripts/ci/ (31) + scripts/lib/
|
||||
|
|
@ -35,11 +36,10 @@ D:/workspace/D3ROVoice
|
|||
├── tests/e2e/, test-results/ Root-level e2e + last-run artifacts
|
||||
├── scratch/ Large local evidence (APKs, screenshots, DBs) — not build input
|
||||
├── supabase/ Empty scaffolding (.branches/, snippets/) — real project is server/supabase
|
||||
├── .github/workflows/ GitHub Actions (6)
|
||||
├── .gitlab-ci.yml GitLab CI (primary desktop/mobile release pipeline)
|
||||
├── .forgejo/workflows/ Forgejo Actions (site deploy to Cloudflare Pages)
|
||||
├── .forgejo/workflows/ Forgejo Actions (CI, site deploy to Cloudflare Pages, payple-renew cron, portable/release)
|
||||
├── docker-compose.yml, docker-compose.nas.yml
|
||||
├── Dockerfile.admin, apps/api-server/Dockerfile, apps/admin/Dockerfile
|
||||
├── apps/api-server/Dockerfile, apps/admin/Dockerfile, apps/web/Dockerfile
|
||||
├── turbo.json, tsconfig.json, tsconfig.base.json, pnpm-workspace.yaml
|
||||
├── package.json monorepo root, npm workspaces
|
||||
├── CLAUDE.md Claude-specific project rules
|
||||
|
|
@ -126,25 +126,22 @@ See [`03-shared-packages.md`](./03-shared-packages.md). Summary:
|
|||
|
||||
## 5. CI/CD
|
||||
|
||||
### GitHub Actions (`.github/workflows/`)
|
||||
|
||||
| Workflow | Purpose |
|
||||
|---|---|
|
||||
| `ci.yml` | Main CI: `code-quality` (secret scan, mobile release/config/build-config self-tests, Play asset contract, lint, typecheck), `api-server-tests`, `edge-functions-quality` (Deno), `test-matrix` (win/mac/ubuntu vitest), `build-validation` (desktop win, admin ubuntu), `mobile-android` (debug/CSPRNG/E2E APKs + verifiers), `mobile-emulator-e2e` (API 35 + Maestro 2.7.0) |
|
||||
| `release.yml` | On tag `v*.*.*`: preflight → `package-windows` (NSIS) → `package-macos` (DMG/ZIP arm64) → `package-android` (signed APK/AAB + evidence) → `package-admin-docker` (GHCR) → `publish-release` (checksums + GitHub Release + Forgejo canonical publish) |
|
||||
| `deploy-site.yml` | On `site/**`: build Vite site, boundary self-test, deploy GitHub Pages |
|
||||
| `build-mac.yml` | Manual macOS build (arm64/x64), sox + PyInstaller sidecar + electron-rebuild |
|
||||
| `payple-renew.yml` | Daily cron → `payple-renew` edge function |
|
||||
| `release-signing-ca.yml` | Manual Windows (Azure Trusted Signing) / macOS notarize build+sign |
|
||||
> `.github/workflows/` was deleted 2026-09-26 (Wave 3, dc43884): the repository has Forgejo and GitLab
|
||||
> remotes but no GitHub remote, so nothing under it ever ran — including the daily Payple renewal cron.
|
||||
> CI now runs only on Forgejo Actions (`.forgejo/workflows/`); see below.
|
||||
|
||||
### 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. 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).
|
||||
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` CI/release/portable) 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/`)
|
||||
`ci.yml` — CI is now Forgejo-only (`.github/workflows` deleted 2026-09-26, Wave 3, dc43884). Jobs: `quality` (`version:check`, `contract:check`, `release:metadata:test`, secret scan, mobile release/config/build-config self-tests, Play asset contract, lint, typecheck, Vitest), `build-validation`, `mobile-quality`, `edge-functions` (Deno), `api-server-tests`.
|
||||
|
||||
`payple-renew.yml` — daily cron (+ manual dispatch) → `payple-renew` edge function; ported from the never-run `.github/workflows/payple-renew.yml` because the repository has no GitHub remote. Requires Forgejo secrets `SUPABASE_URL`, `CRON_SECRET`.
|
||||
|
||||
`portable.yml` — 태그/수동 실행으로 **서명 없이** portable 채널(95MiB 7z 분할 볼륨 + Scoop 매니페스트 + 설치 스크립트)을 게시한다. `WIN_CSC_*` 불필요, updater feed는 건드리지 않는다.
|
||||
|
||||
`deploy-site.yml` / `deploy-site-windows.yml` — build `site`, write release identity, deploy to Cloudflare Pages `d3ro` (`d3ro.pages.dev`), verify live commit/version, app-links, legal URLs. 커스텀 도메인 `d3ro.chanpaca.net` 은 Pages 커스텀 도메인이 DNS CNAME을 요구하므로, DNS를 건드릴 수 없는 동안은 Workers 라우트 브리지 `server/cloudflare-site-bridge/`(`d3ro.chanpaca.net/*` → Pages 프록시, 수동 `npx wrangler deploy`)가 서빙한다. CNAME을 추가한 뒤 브리지를 삭제하면 Pages 커스텀 도메인으로 직접 서빙된다(GAP-REL-09b).
|
||||
`deploy-site.yml` — 유일한 사이트 배포 경로(Linux, Cloudflare Pages). Windows 수동 중복 워크플로(`deploy-site-windows.yml`)는 2026-09-26 삭제됐다(dc43884). build `site`, write release identity, deploy to Cloudflare Pages `d3ro` (`d3ro.pages.dev`), verify live commit/version, app-links, legal URLs. 커스텀 도메인 `d3ro.chanpaca.net` 은 Pages 커스텀 도메인이 DNS CNAME을 요구하므로, DNS를 건드릴 수 없는 동안은 Workers 라우트 브리지 `server/cloudflare-site-bridge/`(`d3ro.chanpaca.net/*` → Pages 프록시, 수동 `npx wrangler deploy`)가 서빙한다. CNAME을 추가한 뒤 브리지를 삭제하면 Pages 커스텀 도메인으로 직접 서빙된다(GAP-REL-09b).
|
||||
`release.yml` — tag-triggered Windows build (signed) + `publish-forgejo-release.mjs` to the canonical Forgejo feed/release hub.
|
||||
|
||||
---
|
||||
|
|
@ -153,15 +150,15 @@ Stages `validate → test → build → e2e → package → publish → deploy`.
|
|||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `Dockerfile.admin` | 3-stage Next.js admin build (node 24.19.0-alpine, port 3001) |
|
||||
| `apps/admin/Dockerfile` | Next.js standalone runner for `.next/standalone` |
|
||||
| `apps/api-server/Dockerfile` | Multi-stage .NET 10 (sdk → aspnet runtime), port 5000, `VOLUME /app/data` |
|
||||
| `docker-compose.yml` | Dev/self-host: `d3ro-api-server` (5050→5000, `./data` volume), `d3ro-admin` (3001), optional `ollama` (profile `ai`, 11434) |
|
||||
| `docker-compose.nas.yml` | NAS: prebuilt `d3ro-voice-api:latest` + `d3ro-voice-admin:latest`; API mounts `/volume1/docker/d3ro/wwwroot/{privacy,terms,delete-account,legal.css}` read-only |
|
||||
| `apps/admin/Dockerfile` | Next.js standalone runner for `.next/standalone` (the old root `Dockerfile.admin` 3-stage build was a duplicate, deleted 2026-09-26, Wave 3, cd9d199) |
|
||||
| `apps/api-server/Dockerfile` | Multi-stage .NET 10 (sdk → aspnet runtime), port 5000, `VOLUME /app/data`; no longer serves static files (`wwwroot` removed — see `07-api-server.md`) |
|
||||
| `apps/web/Dockerfile` | Next.js standalone runner for `@d3ro/web`, basePath `/app`, port 3002 (added 2026-09-26, Wave 3, b6fe588) |
|
||||
| `docker-compose.yml` | Dev/self-host: `d3ro-api-server` (5050→5000, `./data` volume), `d3ro-admin` (3001), `d3ro-web` (3002, `@d3ro/web` basePath `/app`, Supabase/Payple keys as build args), optional `ollama` (profile `ai`, 11434) |
|
||||
| `docker-compose.nas.yml` | NAS: prebuilt `d3ro-voice-api:latest` / `d3ro-voice-admin:latest` / `d3ro-voice-web:latest` (3002) / `d3ro-whisper` (faster-whisper, OpenAI-compatible). No legal-doc `wwwroot` mount and no `NEXT_PUBLIC_API_URL` — both were dropped 2026-09-26 (Wave 3, b6fe588); legal pages are served only from `site/public`. |
|
||||
|
||||
Deploy scripts: `scripts/deploy-nas.ps1`, `scripts/deploy-nas.sh`, `scripts/deploy-site-to-nas.js`, `scripts/nas-control.sh` (start/stop/restart/status/logs/backup/update).
|
||||
Deploy scripts: `scripts/deploy-nas.ps1`, `scripts/deploy-nas.sh`, `scripts/nas-control.sh` (start/stop/restart/status/logs/backup/update). `scripts/deploy-site-to-nas.js` was deleted 2026-09-26 (Wave 3, cd9d199) — site deploy is Cloudflare Pages only (`.forgejo/workflows/deploy-site.yml`).
|
||||
|
||||
Public endpoints (production): `https://d3ro.chanpaca.net` — **랜딩/다운로드 센터**(2026-09-19부터 Pages `d3ro` 배포본을 Workers 라우트 브리지가 서빙; 그 이전에는 바인딩이 없어 빈 404였다), `https://admin.chanpaca.net` (admin CRM). Edge: `server/cloudflare-worker` proxying to the NAS origin, plus a **Cron Trigger** (`* * * * *`) that drains the Supabase push outbox via `send-push?mode=drain` (`src/push-drain.ts`; needs `SUPABASE_URL` var + `SUPABASE_SERVICE_ROLE_KEY` secret). Tunnel: Cloudflare Tunnel `kd-nas` (NAS 포털/API는 현재 이 호스트네임에 바인딩되어 있지 않다).
|
||||
Public endpoints (production): `https://d3ro.chanpaca.net` — **랜딩/다운로드 센터**(site/, Pages `d3ro` 배포본을 Workers 라우트 브리지가 서빙), `https://d3ro.chanpaca.net/app` — **웹앱**(`apps/web`, basePath `/app`; 사이트 브리지 워커가 `WEB_APP_ORIGIN`(터널 호스트)으로 전달하며, 호스트가 비어 있으면 `/app`은 503을 반환한다 — 터널 호스트 설정 대기), `https://admin.chanpaca.net` (admin CRM). Edge: `server/cloudflare-worker` proxying to the NAS origin, plus a **Cron Trigger** (`* * * * *`) that drains the Supabase push outbox via `send-push?mode=drain` (`src/push-drain.ts`; needs `SUPABASE_URL` var + `SUPABASE_SERVICE_ROLE_KEY` secret). Tunnel: Cloudflare Tunnel `kd-nas` (NAS 포털/API는 현재 이 호스트네임에 바인딩되어 있지 않다).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -178,8 +175,8 @@ Full detail: [`09-supabase-backend.md`](./09-supabase-backend.md).
|
|||
|
||||
## 8. `scripts/` groups
|
||||
|
||||
- **CI (`scripts/ci/`, 33 files):** build/version/release (`build-all`, `sync-version`, `generate-checksums`, `verify-release-metadata`, `create-release-tag`, `extract-release-notes`), security (`check-no-hardcoded-secrets`), mobile release gates (`verify-mobile-release-boundary/-config/-build-config`, `verify-android-artifact/-app-links`, `verify-play-store-assets`, `prepare-whisper-model`, `create-mobile-release-evidence`, `prepare-mobile-release-publication`, emulator/CSPRNG gates), keys (`create-desktop-license-keypair`, `create-release-evidence-key`, etc.), publish (`publish-forgejo-release` canonical, `publish-gitlab-release` mirror; legacy `sync-and-publish-forgejo-release`, `upload-asset-to-forgejo-release`), env/tooling (`bootstrap-linux-toolchain.sh`, `audit-nas-stt-config.ps1`, mobile local E2E scripts).
|
||||
- **Deploy/release:** `deploy-nas.ps1/.sh`, `deploy-site-to-nas.js`, `nas-control.sh`, `publish-gh.ps1`, `gen-keystore.js`.
|
||||
- **CI (`scripts/ci/`, 33 files):** build/version/release (`build-all`, `sync-version`, `generate-checksums`, `verify-release-metadata`, `create-release-tag`, `extract-release-notes`), security (`check-no-hardcoded-secrets`), mobile release gates (`verify-mobile-release-boundary/-config/-build-config`, `verify-android-artifact/-app-links`, `verify-play-store-assets`, `prepare-whisper-model`, `create-mobile-release-evidence`, `prepare-mobile-release-publication`, emulator/CSPRNG gates), keys (`create-desktop-license-keypair`, `create-release-evidence-key`, etc.), publish (`publish-forgejo-release` canonical, `publish-gitlab-release` mirror; the legacy `sync-and-publish-forgejo-release`/`upload-asset-to-forgejo-release` scripts were deleted 2026-09-26, Wave 3, cd9d199), env/tooling (`bootstrap-linux-toolchain.sh`, `audit-nas-stt-config.ps1`, mobile local E2E scripts).
|
||||
- **Deploy/release:** `deploy-nas.ps1/.sh`, `nas-control.sh`, `publish-gh.ps1`, `gen-keystore.js` (`deploy-site-to-nas.js` deleted 2026-09-26, Wave 3, cd9d199 — site deploy is Cloudflare Pages only).
|
||||
- **GCP/Google OAuth automation + inspection (~70 `*.mjs`):** `auto-configure-oauth`, `automate-google-oauth`, `setup-consent`, `create-*-client`, `check-*`, `inspect-*` — mostly one-off/browser-driven console automation.
|
||||
- **AdMob console automation:** `admob-probe.mjs` (read-only login/app/ad-unit probe), `admob-login.mjs` + `run-admob-login.bat` (one interactive headful Chrome login into a persistent profile), `admob-automate.mjs` (dry-run by default; `--apply` creates/verifies banner+rewarded units and reports Play-store link). Uses `playwright` with `channel: 'chrome'` and the gitignored `.chrome-playwright-profile`.
|
||||
- **E2E / verification:** `e2e-desktop-*.js`, `real-app-multi-tab-e2e.js`, `test-and-capture-all-10-ad-services.js`, `verify-live-production-d3ro.js`.
|
||||
|
|
@ -201,7 +198,7 @@ Full detail: [`09-supabase-backend.md`](./09-supabase-backend.md).
|
|||
| `apps/desktop/electron-builder.yml` | appId `com.d3ro.voice`, NSIS x64 (forced code signing), macOS DMG/ZIP arm64, generic Forgejo publish feed, asarUnpack native modules + `@ffmpeg-installer`, extraResources (icons, sounds, sox, **sidecar**, ffmpeg, ollama) |
|
||||
| `apps/desktop/src/main/update-feed.ts` | Auto-update feed SSOT (canonical Forgejo + legacy GitLab mirror, channels) |
|
||||
| `release/update-policy.json` | Update policy SSOT (channels, minimum supported version, forced update, delta/full, staged rollout, kill switch) |
|
||||
| `apps/web/src/lib/desktop-release.ts`, `site/src/release.ts` | Download-center desktop release contract (installer filename + release date); version and date are kept on the SSOT by `npm run version:sync` (drifted to 1.2.0 once — GAP-REL-08) |
|
||||
| `site/src/release.ts` | Download-center desktop release contract (installer filename + release date); version and date are kept on the SSOT by `npm run version:sync` (drifted to 1.2.0 once — GAP-REL-08). `apps/web/src/lib/desktop-release.ts` and the `apps/web` download/releases pages were deleted 2026-09-26 (Wave 3, cd9d199) — `site/` is the only download surface, and `/download`/`/releases` on `apps/web` now redirect to it |
|
||||
| `apps/desktop/src/main/update-policy.ts` | Policy parsing/decision logic |
|
||||
| `scripts/ci/publish-forgejo-release.mjs` | Canonical Forgejo registry + Release + feed publisher |
|
||||
|
||||
|
|
@ -227,5 +224,5 @@ Version sync is enforced by `scripts/ci/sync-version.mjs` and `verify-release-me
|
|||
|
||||
See [`11-gap-backlog.md`](./11-gap-backlog.md) for the maintained list (`INFRA-*`). Headlines:
|
||||
- `apps/mobile-rn` is not an npm workspace member; use `typecheck:mobile`/`lint:mobile`/`test:mobile` or `verify:all`.
|
||||
- Admin NAS deploy job disabled in GitLab CI; admin ships via GitHub/GHCR + manual NAS compose.
|
||||
- Admin NAS deploy job disabled in GitLab CI; the `package-admin-docker`→GHCR publish step lived only in the now-deleted `.github/workflows/release.yml` (2026-09-26, dc43884) and was not ported to Forgejo, so admin image publish + NAS compose update is manual (`GAP-INFRA-02`).
|
||||
- Two identity systems (.NET JWT/SQLite vs Supabase); a canonical resolver now exists in `@d3ro/core/entitlement` but web/mobile/.NET adoption is incremental (`11` GAP-ID-02).
|
||||
|
|
|
|||
|
|
@ -13,9 +13,8 @@
|
|||
- **Policies:** `ManagerOrAbove` (manager/admin/superadmin), `AdminOrAbove` (admin/superadmin), `SuperAdminOnly` (superadmin). Role normalization strips `_`/`-`, lowercases.
|
||||
- **CORS/Hosts:** strict origin validation (`CORS_ALLOWED_ORIGINS`), `ALLOWED_HOSTS` required outside Development.
|
||||
- **Startup DB init:** `EnsureCreated()`, raw `CREATE TABLE IF NOT EXISTS` for admin operation/audit tables, legacy SHA-256 password lockdown (`IsActive=false`, `Role="LegacyDisabled"`), idempotent env admin provisioning (`ADMIN_EMAIL`/`ADMIN_PASSWORD`, only when no active user), default LLM/STT endpoints seeded.
|
||||
- **Middleware order:** Swagger (dev) → CORS → invite-page hardening (CSP/no-store) → default files → mobile/legacy asset block (404 for `.apk`/`.aab`/signed zips + legacy bundles) → static files → rate limiter → authentication → authorization.
|
||||
- **Middleware order:** Swagger (dev) → CORS → rate limiter → authentication → authorization. The API no longer serves static files: `wwwroot` (stale site build, download/invite pages, `.well-known` copy, legacy embedded admin SPA, 1.0.0 binaries) was deleted 2026-09-26 (Wave 3, cd9d199), and `UseStaticFiles`/the mobile-asset-block fallbacks were removed from `Program.cs` along with it. The Next.js admin (`apps/admin`) is the only admin UI.
|
||||
- **Health:** `GET /health`, `GET /api/health` → `{status, service, version, uptimeSeconds, database, timestamp}`.
|
||||
- **Fallbacks:** `/accept-invite` → `accept-invite.html`; `/admin/{*path}` → legacy embedded admin SPA in `wwwroot/admin`.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -102,6 +101,6 @@ DTOs (`Dtos/Dtos.cs`): auth, license audit, LLM, admin/model endpoints, STT (tra
|
|||
- Known intentional states (not bugs):
|
||||
- Legacy SHA-256 users force-disabled.
|
||||
- No hardcoded/seeded admin credentials.
|
||||
- Mobile/legacy release assets blocked with 404.
|
||||
- No static file serving — `wwwroot` and its mobile/legacy release asset block were deleted 2026-09-26 (Wave 3, cd9d199); downloads/releases are served only from `site/`.
|
||||
- `LlmProxyService` Mock fallback.
|
||||
- This backend holds a **separate identity** from Supabase; see `11-gap-backlog.md` `ID-01`.
|
||||
|
|
|
|||
|
|
@ -88,4 +88,4 @@ Root files: `instrumentation.ts` (startup security validation), `proxy.ts` (edge
|
|||
- `admin-payments` Payple live history → `501`.
|
||||
- `UnavailableAdminPanel` whenever Supabase env absent; writes disabled, no sample metrics.
|
||||
- `/pipelines` and dashboard node/error sections render only measured data.
|
||||
- Deploy: `Dockerfile.admin` / `apps/admin/Dockerfile` → GHCR + NAS compose; GitLab admin NAS deploy job disabled.
|
||||
- Deploy: `apps/admin/Dockerfile` → GHCR + NAS compose; the duplicate root `Dockerfile.admin` was deleted 2026-09-26 (Wave 3, cd9d199) since `apps/admin/Dockerfile` is the one actually used. GitLab admin NAS deploy job disabled.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ Migration numbering referenced in SSOT goes up to `00028`; CI verifies `migratio
|
|||
| `send-push` | Push delivery |
|
||||
| `account-delete` | Account deletion cascade + provider unlink |
|
||||
| `admin-users` / `admin-subscriptions` / `admin-payments` / `admin-audit-log` | Admin operations |
|
||||
| `billing-catalog` | Server pricing catalog |
|
||||
| `billing-catalog` | Server pricing catalog. Prices/quotas read `PLAN_PRICE_KRW`/`PLAN_QUOTA` from `functions/_shared/core-contract.generated.ts`, generated from `packages/core/src/plan-catalog.ts` by `scripts/ci/sync-core-contract.mjs` (`npm run contract:check` fails on drift; added 2026-09-26, Wave 3, 88f24d8) |
|
||||
| `stripe-checkout` / `stripe-portal` / `stripe-webhook` | Stripe billing |
|
||||
| `payple-checkout` / `payple-manage` / `payple-renew` / `payple-webhook` | Payple billing (Korea) |
|
||||
| `iap-verify` | Google Play / App Store purchase verification |
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ end-to-end behaviour has **not been verified by typing in a real app** (`11` GAP
|
|||
| SHELL-08 | Auto-update | [x] | [-] | [!] | [-] | Desktop electron-updater; Forgejo canonical feed; channels + mandatory/major-vs-delta policy (`release/update-policy.json`); mobile store updates |
|
||||
| SHELL-09 | Support / diagnostics | [x] | [ ] | [ ] | [~] | Desktop `SupportModal`; admin `/support` stub |
|
||||
| SHELL-10 | Download center / releases | [-] | [x] | [-] | [x] | Web `/download`, admin `/releases`, Forgejo |
|
||||
| SHELL-11 | Landing site / legal pages | [-] | [-] | [-] | [-] | `site/` — privacy/terms/delete-account live; 2026-09-26 truthfulness/a11y cleanup (facts from code SSOT, pricing `site/src/pricing.ts`, 10 locales fully translated, footer links legal pages) — see `design.md` |
|
||||
| SHELL-11 | Landing site / legal pages | [-] | [-] | [-] | [-] | `site/` — the only landing/download/legal/invite/assetlinks surface (Wave 3, 2026-09-26: copies in api-server wwwroot and apps/web removed; 404.html; hero loops a copy of the app recording capsule). Prices/URLs from `packages/core` plan-catalog/web-urls — see `design.md` |
|
||||
| SHELL-12 | Notifications (in-app / desktop) | [x] | [ ] | [x] | [x] | Desktop events; mobile push |
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -26,7 +26,13 @@ Legend: `[ ]` open · `[~]` in progress · `[!]` blocked externally · `[x]` res
|
|||
| GAP-REL-08 | Release | 다운로드 센터가 **존재하지 않는 설치 파일**을 가리켰다. `apps/web/src/lib/desktop-release.ts`와 `site/src/release.ts`의 `DESKTOP_VERSION`이 `1.2.0`에 멈춰 있어 설치 URL이 `D3RO-Voice-Setup-1.2.0-x64.exe`였고, 그 경로는 피드에서 404다(실측: 1.2.0=404, 1.3.7=206). `version:sync`가 이 두 표면을 덮지 않아 계속 어긋났다. | `scripts/ci/sync-version.mjs`, `apps/web/src/lib/desktop-release.ts`, `site/src/release.ts` | `[x]` 2026-09-19: 두 다운로드 계약 파일을 `sync-version.mjs` 대상에 추가해 버전·릴리스일이 SSOT에서 자동 반영되도록 하고, 현재 값(1.3.7 / 2026-09-19)으로 정정했다. `version:check`·typecheck·site 빌드 GREEN. |
|
||||
| GAP-REL-09 | Release | 랜딩 사이트가 **재배포되지 않는다**. `deploy` 워크플로가 main push마다 실패한다. 실측 원인(run#66 로그): `site/src/sections/Hero.tsx`가 타이머 ref를 `NodeJS.Timeout`으로 타이핑해 `@types/node` 네임스페이스가 필요했고, 배포 잡은 `npm ci --prefix site`만 하므로 조상 `node_modules`의 hoisted 타입이 없어 `tsc -b`가 `TS2503: Cannot find namespace 'NodeJS'`로 실패한다. 그래서 `https://d3ro.chanpaca.net/release-identity.json`이 404다(공개 버전 검증 불가). | `.forgejo/workflows/deploy-site.yml`, `site/src/sections/Hero.tsx` | `[x]` 2026-09-19: ref를 `ReturnType<typeof setTimeout>`으로 바꿔 hoisted 타입 의존을 제거했다(격리 `--typeRoots`로 CI 조건 재현 → 수정 전 TS2503, 수정 후 clean). 같은 수정을 push하자 `deploy` run#67이 사이트 빌드를 통과해 `dist/`를 만들었고, 실패는 다음 단계(Cloudflare)로 이동했다. |
|
||||
| GAP-REL-09b | Release | `d3ro.chanpaca.net`이 404였던 직접 원인: 이 Cloudflare 계정에 Pages 프로젝트 `d3ro`/`d3ro-voice`가 **존재하지 않아** 커스텀 도메인 바인딩이 없었다(빈 본문 404, `cf-ray`만 반환). Pages 커스텀 도메인은 존 DNS CNAME(`d3ro → d3ro.pages.dev`)을 요구하는데 기존 `d3ro` 레코드가 남아 있어 `CNAME record not set`으로 pending에 머물렀고, 로컬 wrangler 자격증명에는 DNS 스코프가 없다(403 Authentication error). `deploy-site.yml`은 `CF_API_TOKEN` 시크릿이 없어 마지막 게시 단계에서도 `exit 1`이다. | `server/cloudflare-site-bridge/`, `.forgejo/workflows/deploy-site.yml`, `docs/map/02-infrastructure.md` | `[x]` 2026-09-19: Pages 프로젝트 `d3ro` 생성 + `site/dist` production 배포(`d3ro.pages.dev` 200, `release-identity.json` = commit `2407f5a` / 1.3.7) + 커스텀 도메인 연결. DNS 없이 도메인을 살리기 위해 Workers 라우트 브리지(`server/cloudflare-site-bridge`, `d3ro.chanpaca.net/*` → Pages 프록시, `npx wrangler deploy`)를 배포 → 라이브 확인: `/`·`/privacy/`·`/terms/`·`/delete-account/` 200, 라이브 번들이 설치 파일명을 `1.3.7`로 계산, `/download.html` → `/#download`. 남은 정리 2건: (1) 대시보드에 CNAME을 추가한 뒤 브리지 워커 삭제, (2) CI 자동 게시를 위해 `CF_API_TOKEN`(Pages/Workers Edit) + `CF_ACCOUNT_ID`=`8e83cc130e7329c160cf2b88d6b4c20a`를 Forgejo 시크릿에 등록. **2026-09-23:** CI `deploy`(deploy-site.yml)는 `CF_API_TOKEN` 부재로 run#71까지 여전히 실패한다. 로컬 인증 wrangler(pages:write)로 `npm run build --prefix site` → release-identity 작성 → `npx wrangler pages deploy site/dist --project-name d3ro --branch main`을 수동 배포했고, 라이브 `https://d3ro.chanpaca.net/release-identity.json`이 commit `5c11ee2` / version `1.5.0`을, 라이브 번들이 설치 파일명 `D3RO-Voice-Setup-1.5.0-x64.exe`를 보고한다. 자동 게시에는 여전히 시크릿 등록이 필요하다. |
|
||||
| GAP-BILL-01 | Billing | 랜딩 사이트 가격(Pro ₩2,900 / Pro+ ₩8,900, 2026-09-26 사용자 확정)과 서버 결제 카탈로그(Payple Pro ₩9,900 / Pro+ ₩29,900)가 다르다. 결제 진입 URL도 `payment-handlers.ts`(`d3ro.chanpaca.net/billing`)와 `license-handlers.ts`(`d3ro.dev/billing`)로 갈린다. | `site/src/pricing.ts`, `server/supabase/functions/_shared/payple.ts`, `server/supabase/functions/_shared/billing-catalog.ts`, `apps/desktop/src/main/ipc/license-handlers.ts` | `[ ]` 2026-09-26: 사이트는 새 가격을 표시하고 `d3ro.chanpaca.net/billing?tier=`로 연결한다. 서버 카탈로그 금액 변경(Payple·Stripe 가격 ID)과 결제 URL 정본 확정이 남았다. |
|
||||
| GAP-BILL-01 | Billing | 사이트 가격과 서버 청구 금액·결제 진입 URL이 제각각이었다. | `packages/core/src/plan-catalog.ts`, `packages/core/src/web-urls.ts`, `scripts/ci/sync-core-contract.mjs` | `[x]` 2026-09-26 (Wave 3, 88f24d8·b6fe588): 가격·쿼터·공개 URL 정본을 core 두 파일로 합치고 Deno는 생성 사본(`contract:check`). Payple 함수 4종+billing-catalog 운영 재배포(payple-* v9, billing-catalog v5) → 신규·갱신 모두 ₩2,900/₩8,900. 결제 진입은 `/app/billing` 하나. |
|
||||
| GAP-BILL-02 | Billing | **Payple 정기 갱신이 한 번도 실행되지 않았다.** 갱신 cron(`payple-renew`)이 `.github/workflows`에만 있었는데 GitHub 원격이 없다. 또 웹 Payple 결제용 `NEXT_PUBLIC_PAYPLE_CLIENT_KEY`가 어디에도 설정된 적이 없어 웹 Payple 결제 버튼이 꺼져 있다. | `.forgejo/workflows/payple-renew.yml`, `apps/web/src/components/billing/payple-checkout-button.tsx`, `apps/web/Dockerfile` | `[!]` EXT 2026-09-26: 워크플로는 Forgejo로 이식(dc43884). 남은 일 — Forgejo 시크릿 `SUPABASE_URL`·`CRON_SECRET` 등록, Payple 클라이언트 키를 웹 이미지 build arg로 넣어 재빌드, Stripe(USD)·Google Play 가격을 각 콘솔에서 새 가격으로. |
|
||||
| GAP-WEB-01 | Web | 웹앱(`apps/web`)이 공개되지 않았다(배포 경로가 없었음). | `apps/web/Dockerfile`, `docker-compose.nas.yml`, `server/cloudflare-site-bridge` | `[~]` 2026-09-26: `/app` basePath·standalone 이미지·NAS 컨테이너 `d3ro_voice_web`(3002). 남은 일(EXT) — Cloudflare Tunnel 공개 호스트(예: `d3ro-app.chanpaca.net` → NAS 3002) 추가 후 브리지 워커 `WEB_APP_ORIGIN` 설정·배포, Supabase 대시보드 Redirect URLs에 `https://d3ro.chanpaca.net/app/**` 추가. 그 전까지 `/app/*`는 사이트 404. |
|
||||
| GAP-OPS-01 | Ops | NAS 운영 compose가 저장소와 어긋나 있다. 운영본은 JWT 비밀값 기본값 폴백·법률 wwwroot 마운트를 쓰고, `.env`에 `ADMIN_BOOTSTRAP_TOKEN`·`API_SERVER_URL`·`SUPABASE_URL`·`SUPABASE_SERVICE_ROLE_KEY`가 없어 저장소 compose(`:?` 필수)로 바꾸면 api/admin이 기동하지 않는다. | `docker-compose.nas.yml`, NAS `/volume1/docker/d3ro/.env` | `[ ]` 2026-09-26: 운영본에만 있던 `d3ro-whisper`는 저장소로 합쳤다. 누락 변수를 채운 뒤 저장소 compose로 교체해야 한다. |
|
||||
| GAP-CI-01 | CI | macOS 빌드·서명 러너가 없다. `.github`의 build-mac·release-signing-ca는 실행된 적 없이 삭제됐다. | `.forgejo/workflows/*`, `.gitlab-ci.yml` | `[!]` EXT: Mac 호스트에 Forgejo runner(`macos` 라벨)를 붙이거나 GitLab `package-macos` 사용. 서명된 Android 릴리스는 GitLab `mobile-production-release`가 정본. |
|
||||
| GAP-I18N-02 | Desktop | 녹음 캡슐의 "처리 중..."이 `recording-tip/index.html`에 한국어로 고정돼 앱 언어를 따르지 않는다. | `apps/desktop/src/renderer/popups/recording-tip/*`, `WindowManager.getPopupI18nStrings` | `[ ]` 2026-09-26 발견. |
|
||||
| GAP-TEAM-02 | Team | 브라우저에서 초대를 수락하는 경로가 없다. 웹 `accept-invite` 페이지는 발급 링크가 가리키지 않고 로그인 후 토큰을 읽는 곳이 없어 끊겨 있었으므로 삭제했다(사이트 `/accept-invite/`는 앱 딥링크만). | `site/public/accept-invite/`, `server/supabase/functions/team-accept` | `[ ]` 2026-09-26: 데스크톱 전용 사용자를 위한 웹 수락 흐름이 필요하면 `/app` 아래에 다시 설계. |
|
||||
| GAP-REL-10 | Release | `release-windows`(태그 파이프라인)는 서명 가드에 도달하기 **전에** sidecar 단계에서 죽는다. 이 러너 컨텍스트에서는 `sidecar:setup`이 Python 3.11+를 찾지 못한다(`Python 3.11+ 를 찾을 수 없습니다`) → `sidecar:build` → `verify-sidecar-bundle.mjs` 연쇄 실패(실측: run#65 `v1.3.7`, run#61 `v1.3.6`). 같은 러너의 portable 잡은 `py -3.11 → Python 3.11.9`를 찾아 사이드카 빌드에 성공하므로, 워크플로/컨테이너 간 PATH 차이다. | `.forgejo/workflows/release.yml`, `apps/desktop/scripts/setup-sidecar.mjs` | `[!]` 2026-09-19: 러너에 Python 3.11+(`py` 런처 포함)를 보장하거나 워크플로에 `actions/setup-python` 단계를 추가한다. 그 전까지 서명 게시는 불가능하다(GAP-REL-02와 별개 선행 차단). |
|
||||
| GAP-REL-11 | Release | portable 워크플로의 마지막 `actions/upload-artifact@v4` 단계가 Forgejo 러너에서 `GHESNotSupportedError`로 실패한다(증거 보존만 실패, 게시는 성공). | `.forgejo/workflows/portable.yml` | `[x]` 2026-09-19: `v1.3.7` portable 게시는 run#64에서 성공(7z 단일 볼륨 83.7MB + zip 2부, `portable-latest/portable.json`이 1.3.7 보고). 남은 조치: upload-artifact 단계를 제거하거나 v3/다른 보존 방식으로 바꿔 워크플로를 GREEN으로 만든다. |
|
||||
| GAP-REL-12 | Release | Forgejo generic registry는 파일 단위 덮어쓰기를 거부(HTTP 409)하는데, portable 게시 스크립트의 "동일 파일 건너뛰기"가 1MiB 초과 파일을 **크기만** 비교했다. 그래서 새 runtime의 sidecar 볼륨 `.001`이 이전 볼륨과 정확히 같은 94,371,840 bytes였고, 내용이 다른데도 "동일"로 오판해 `runtime-latest`가 낡은 `.001` + 새 `.002`로 갈라졌다(다운로드 시 손상). | `scripts/ci/publish-portable-release.mjs` | `[x]` 2026-09-23: 파일 목록 API(`GET /api/v1/packages/{owner}/generic/{name}/{version}/files`)의 sha256으로 정확히 비교하고, 내용이 다른 파일이 하나라도 있으면 해당 별칭 버전 전체를 삭제 후 재업로드하도록 수정했다. 이미 발생한 `runtime-latest`는 버전을 지우고 재게시해 4개 파일 모두 로컬 해시와 일치함을 확인했다. |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue