d3ro-voice/docs/REFACTOR_WAVE3_REPORT.md
Yun Chan e87ce63440 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.
2026-09-26 16:02:44 +09:00

5.2 KiB
Raw Blame History

Refactor Wave 3 — 표면·계약 단일화 (2026-09-26)

사용자 지시: "두 벌씩 만든 것을 전부 하나로 합쳐 정리." 정책은 docs/REFACTOR_POLICY.md Wave 3 절(W3-1~W3-8).

커밋

커밋 WS 내용
e689683 선행 랜딩 사이트를 코드로 확인한 사실 기준으로 재작성(접근성·10개 언어)
88f24d8 WS-A 가격·쿼터·공개 URL 정본 packages/core 두 파일 + Deno 생성 사본(contract:check)
b6fe588 WS-B 웹앱 /app basePath·standalone·NAS 컨테이너, 모든 결제 진입을 billingUrl()로, 브리지 워커 /app 라우팅
cd9d199 WS-C wwwroot·apps/web·바이너리 중복 삭제(바이너리 19개 ≈ 568 MiB), API 정적 서빙 제거
dc43884 WS-D .github 삭제, Forgejo로 CI·payple-renew 이식, 사이트 배포 워크플로 하나로
9297860 사이트 히어로 반복 예시(앱 녹음 캡슐 재현), 404.html, 법률 페이지 색
(이 커밋) 문서 보고서, 백로그, NAS compose 드리프트 병합(whisper)

정본 지도 (전 → 후)

개념 전 후
요금 Payple 9,900/29,900 · admin ₩12,900/₩24,900·$9.9/$19.9 · 사이트 2,900/8,900 plan-catalog.ts 하나(2,900/8,900) → Deno 생성 사본
쿼터 core PREMIUM_MODEL_LIMITS · Deno quota.ts · desktop QUOTA_LIMITS · 사이트 PLAN_QUOTA 하나에서 파생
결제 URL d3ro.dev/billing(해석 불가) · d3ro.chanpaca.net/billing(랜딩으로 폴백) billingUrl() → /app/billing
랜딩·다운로드·법률·초대·assetlinks site · api-server wwwroot · apps/web site 한 벌
설치 파일 저장소 3곳 추적 + Forgejo feed Forgejo feed만
CI .github(한 번도 실행 안 됨) · .forgejo 2벌 사이트 배포 · GitLab Forgejo(+ Android 서명 릴리스는 GitLab)
사이트 배포 Cloudflare Pages · GitHub Pages · NAS wwwroot 복사 Cloudflare Pages
NAS compose 운영본(whisper 포함) ≠ 저장소 저장소에 whisper 병합(교체는 GAP-OPS-01)

운영 반영

  • Supabase Edge Functions: payple-checkout/renew/webhook/manage v9, billing-catalog v5 — 청구 금액 ₩2,900/₩8,900. 새 CLI는 functions/deno.json 임포트 맵을 자동으로 쓰지 않아 --import-map supabase/functions/deno.json이 필요했다.
  • Cloudflare Pages d3ro: 커밋 9297860 게시(release-identity.json 확인), 없는 경로 404.
  • NAS: d3ro_voice_web(3002) 기동, /app/login 200. 공개는 터널 호스트 추가 대기(GAP-WEB-01).

검증

  • npm run typecheck(모노레포) EXIT 0 · 변경 파일 eslint errors 0.
  • contract:check·version:check·release:metadata:test(음성 14)·release:mobile:boundary:test·security:secrets·assetlinks GREEN.
  • Deno _shared/+payple-webhook/ 81/81. core vitest 131/131. api-server dotnet test 28/28.
  • 데스크톱 vitest 1520/1522 — 실패 2건은 기록된 환경 의존 건(캡션 타임아웃, 임베딩 서버 부재). Node 23으로 돌리면 better-sqlite3 ABI 불일치(130/131)로 365건이 가짜 실패한다. Electron 런타임으로 실행해야 한다: ELECTRON_RUN_AS_NODE=1 ../../node_modules/electron/dist/electron.exe ../../node_modules/vitest/vitest.mjs run --config vitest.config.ts.
  • web·admin 프로덕션 빌드 GREEN, web 이미지 로컬 스모크(/app→login, /app/download→사이트 308).
  • 사이트: 10개 언어 × 320/390/1440 가로 넘침 0, axe(wcag2a·aa·21aa·22aa·best-practice) 위반 0, 감소 모션·일시정지 확인.

SKIP / 남은 일

  • 외부 설정(사용자): 터널 공개 호스트 + WEB_APP_ORIGIN, Supabase Redirect URLs /app/**, Forgejo 시크릿 SUPABASE_URL·CRON_SECRET, Payple 클라이언트 키, Stripe·Play 가격, NAS .env 누락 변수 → docs/map/11-gap-backlog.md GAP-BILL-02, GAP-WEB-01, GAP-OPS-01.
  • packages/i18n(12개 언어 JSON)과 site/src/i18n(10개 언어 TS)은 체계가 다르다. 사이트는 정적 번들 크기·독립 배포 때문에 유지 — 다음 wave 후보.
  • 티어 타입('pro' | 'pro_plus') 정의가 core·api-client·Deno에 여러 벌 남아 있다 — 다음 wave 후보.
  • 캡슐 CSS 값은 사이트가 앱 style.css를 옮겨 적었다(Electron 팝업 CSS 직접 import 불가). design.md에 두 곳 동시 수정 규칙을 적었다.

메타 학습

  1. "안 돌던 것"도 중복이다. .github는 원격이 없어 실행된 적이 없었고, 그 안의 Payple 갱신 cron 때문에 정기 결제가 멈춰 있었다. 정리 전에 "이 파일은 실제로 실행되는가"를 원격·러너 기준으로 확인한다.
  2. 운영 서버의 사본도 중복이다. NAS compose가 저장소와 달라져 있었다(서비스 추가, 필수 변수 누락). 배포 전 운영본과 diff한다.
  3. Windows에서 Python 텍스트 쓰기는 CRLF를 만든다. version:check가 바이트 비교라 깨졌다. newline=''로 쓰거나 Edit 도구를 쓴다. 비 raw 문자열의 \\b는 백스페이스 문자가 될 수 있다 — 정규식 편집은 Edit 도구로.
  4. Tailwind 내장 유틸리티와 이름이 같은 사용자 클래스는 무력화된다(break-keep). 프로젝트 전용 이름을 쓴다(keep-ko).