132 lines
8.2 KiB
Markdown
132 lines
8.2 KiB
Markdown
# Find-Word v0.2.5 정적 배포 인계
|
||
|
||
이 문서는 **Neo가 검토 후 수행할 절차**다. Codex는 서버, DNS, 인증정보에
|
||
접근하지 않았고 배포·서비스 생성·Git commit/push도 하지 않았다.
|
||
|
||
## 산출물
|
||
|
||
Node.js 최소 **22.22.2** (`>=22.22.2`)의 지원 LTS 환경에서 `npm ci`, `npm run lint`, `npm test`,
|
||
`npm run build`를 실행한다. `dist/` 전체를 하나의 릴리스로 전달한다.
|
||
`dist/audio/`의 24kHz neural WAV 101개와 version 0.2.5 manifest가 반드시 포함되어야 한다.
|
||
`dist/ambience/`의 고유 현장 WAV 8개·manifest와 `dist/ambience/AMBIENCE_NOTICES.md`도 필수다.
|
||
런타임은 Nginx 정적 파일만 필요하며 Node 서버·TTS 엔진·DB·환경변수·API 키는 필요 없다.
|
||
잠긴 jsdom 계열 의존성 때문에 24.x는 24.15.0 이상, 26.x는 26.0.0 이상이어야 한다.
|
||
브라우저 검증의 Chromium sandbox는 기본 활성화다. sandbox를 지원하지 않는
|
||
격리된 개발 환경에서만 `PLAYWRIGHT_NO_SANDBOX=1`로 명시적으로 끈다.
|
||
|
||
Canonical repository는 [OZ-Group/Find-Word](https://source.ibit.kr/OZ-Group/Find-Word)다.
|
||
프로젝트 자체는 private / all-rights-reserved이며 [LICENSE](../LICENSE)를 따른다.
|
||
생성 음성은 프로젝트의 독점 권리 주장 대상이 아니며 provider 조건은
|
||
[AUDIO_PROVENANCE](AUDIO_PROVENANCE.md)에 기록한다.
|
||
React, ReactDOM, scheduler의 MIT 전문을 담은 `dist/THIRD_PARTY_NOTICES.md`도
|
||
반드시 배포한다. `build` 검증기는 고지 파일이 없거나 축약·변조되면 실패한다.
|
||
|
||
현재 앱은 도메인 루트(`/`) 배포 기준이다. 하위 경로 배포 시 Vite base뿐 아니라
|
||
음성 URL도 함께 변경하고 테스트해야 한다. 예정 도메인은 `findword.heart-m.com`이다.
|
||
|
||
## Nginx 예시
|
||
|
||
아래 root는 예시다. 실제 경로·기존 서버 블록·인증서는 Neo가 확인한다.
|
||
기존 서비스 설정을 덮어쓰지 않고 검토 후 적용한다.
|
||
|
||
```nginx
|
||
# 정적 릴리스 디렉터리를 가리킨다. 인증서와 HTTPS 설정은 운영자가 별도 추가한다.
|
||
server {
|
||
listen 80;
|
||
server_name findword.heart-m.com;
|
||
root /var/www/findword/current;
|
||
index index.html;
|
||
|
||
# 기본 MIME 정의로 JS/CSS/WAV가 올바른 타입으로 제공되게 한다.
|
||
include /etc/nginx/mime.types;
|
||
add_header X-Content-Type-Options nosniff always;
|
||
add_header Referrer-Policy no-referrer always;
|
||
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; media-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" always;
|
||
|
||
# 파일명이 해시로 바뀌는 번들만 장기 캐시한다.
|
||
location /assets/ {
|
||
try_files $uri =404;
|
||
expires 1y;
|
||
}
|
||
|
||
# 앱은 intro·목표 모두 같은 자산 버전 query를 붙여 이전 캐시와 구분한다.
|
||
# $uri는 query를 제외한 실제 WAV 경로다. 누락 시 index.html 대신 404로 응답한다.
|
||
location /audio/ {
|
||
try_files $uri =404;
|
||
expires 7d;
|
||
}
|
||
|
||
# 현장음도 누락 시 SPA HTML로 대체하지 않는다.
|
||
location /ambience/ {
|
||
try_files $uri =404;
|
||
expires 7d;
|
||
}
|
||
|
||
# SPA의 직접 진입·새로고침을 index.html로 받되 HTML은 재검증한다.
|
||
location / {
|
||
try_files $uri $uri/ /index.html;
|
||
expires -1;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 인수 확인
|
||
|
||
1. 서버에 적용하기 전 `nginx -t`, 기존 서비스 충돌, 파일 읽기 권한을 확인한다.
|
||
2. TLS/HTTPS와 DNS를 운영자가 확인한다. 실제 도메인에서 시작 후 음성이 들리는지 확인한다.
|
||
3. `audio/intro.wav?v=0.2.5`와 목표 WAV의 같은 버전 query가 정상 응답하고
|
||
존재하지 않는 오디오는 query가 있어도 404인지 확인한다.
|
||
4. 모바일 Safari/Chrome, 데스크톱에서 음량·중단·다시 듣기·3문항 완주·다음 난이도·시작 단계·SNR 변경·중도 종료를 직접 확인한다.
|
||
5. 원자적으로 릴리스 디렉터리를 전환하고 이전 디렉터리를 보관해 되돌릴 수 있게 한다.
|
||
|
||
오프라인 캐시를 제공하는 PWA는 아니다. 정적 자산의 최초 로드에는 해당 서버
|
||
연결이 필요하다. HTML은 재검증하고, 오디오는 URL의 자산 버전으로 구분한다.
|
||
같은 파일명으로 WAV를 교체할 때 `src/audio/assets.ts`의 `AUDIO_ASSET_VERSION`도
|
||
갱신한다. 제품 버전을 유지하는 음성 수정에서도 새 자산 버전이 필요하다.
|
||
이 query는 로컬 정적 파일 요청에만 사용하며 런타임 외부 요청을 추가하지 않는다.
|
||
|
||
|
||
## 0.2.5 독립 인수와 릴리스 (Neo 수행, 이 작업에서는 미실행)
|
||
|
||
1. `.agent/RESULT-v0.2.5.md`와 RED/GREEN 원문, 원본/배포 해시, 라이선스 고지를 검토한다.
|
||
2. sandboxed system Chrome desktop/mobile suite와 `npm audit`를 다시 실행한다.
|
||
3. 검토 완료 후 feature branch push, main fast-forward, annotated `v0.2.5` tag,
|
||
fresh-clone readback으로 commit과 자산 해시를 확인한다.
|
||
4. commit-addressed release 디렉터리로 dist를 복사하고 current 심볼릭 링크를 원자 전환한다.
|
||
이전 release는 rollback 대상으로 보존한다.
|
||
5. 공개 HTTPS에서 title/UI 0.2.5, WAV MIME·SHA-256·cache-busting query, 누락 자산 404,
|
||
시작 단계·3문항 완료→다음 단계·SNR·중도 종료를 실제 Chrome으로 재검증한다.
|
||
|
||
이 문서의 Nginx 설정은 인계 예시이며 실행 증거가 아니다. 이번 작업은 localhost의
|
||
production preview만 사용하며 Git commit/push/merge/tag, 외부 배포, secrets 사용은 하지 않는다.
|
||
|
||
|
||
v0.2.3 리뷰 검증은 `.agent/evidence-v0.2.3/review-fixes/`에 별도로 보존한다.
|
||
`check-build`는 앱 콘텐츠로 구성한 **정확히 101개**의 음성 파일명과 dist 파일 집합을 독립 대조하므로,
|
||
manifest와 디렉터리를 함께 축약하거나 추가 WAV를 넣어도 실패한다. 현장음은 승인 계획의 출처 수치와
|
||
각 notice 항목의 저작자·primary URL·direct URL·라이선스 링크·outputLicense·변경 고지까지 검사한다.
|
||
현장음 notice의 배포 URL은 `/ambience/AMBIENCE_NOTICES.md`다. 고지는 음원/manifest와 함께
|
||
원자 교체하는 같은 디렉터리 안에 있으며, 기존 루트의 notice 사본은 제거했다.
|
||
|
||
|
||
## v0.2.5 음원 인수 추가 항목
|
||
|
||
**현재 exact 자산은 Oz의 새 소유자 청취 승인으로 릴리스 gate를 통과한다.** 새 market WAV의 동일
|
||
faster-whisper/VAD 검사는 1개 segment, `requiredEmptyPassed=false`인 상태 그대로다.
|
||
`python3 scripts/release_approval.py`는 자동 empty-ASR OR 유효한 exact-byte 소유자 승인을 검사하며,
|
||
현재 통과 경로는 [승인 기록](../.agent/RELEASE-APPROVAL-v0.2.5.json)뿐이다. manifest/WAV/notice 또는
|
||
검수 ZIP 바이트가 달라지면 이 승인은 유효하지 않다. 법적/privacy clearance는 false다.
|
||
[RESULT](../.agent/RESULT-v0.2.5.md)와 [실패 원문](../.agent/evidence-v0.2.5/review-fixes/final-asr.json)을 확인한다.
|
||
|
||
- 수용 계기는 전용 `ebur128=peak=true`이며 loudnorm input_i의 이전 0.01 LU 주장은 거부한 역사 기록이다.
|
||
- 원본/구간/라이선스와 101 voice bytes는 불변이다. 새 8 WAV의 목표는 **−32.5 LUFS ±0.2**, spread≤0.4 LU,
|
||
true peak≤−6 dBTP다. 12초/24kHz/mono/PCM16/50ms fade를 유지한다. 생성기 내부 ceiling은 −6.2 dBTP다.
|
||
- loudness 수치는 ebur128 0.0 LU spread, 독립 pyloudnorm 0.2.0 0.0772 LU spread로 통과했다.
|
||
버전·입력 통계·정확한 gain/filter·iterations·최종 ebur128 통계와 독립 측정 hash를 보존한다.
|
||
- 향후 별도로 배포할 때 공개 HTTPS의 109 WAV hash/bytes/MIME와 `?v=0.2.5`를 검사하고,
|
||
다운로드한 최종 WAV를 새 ebur128 프로세스로 재측정해야 한다.
|
||
- 실제 Chrome의 master=1, SNR −12/0/+12, 8환경 배경 GainNode는 고정 0.41988845여야 한다.
|
||
voice만 SNR에 반응하며 3문항·다음 단계·재청취·중도 종료를 유지한다.
|
||
- 새 WAV의 Oz 청취 인수 시각은 2026-10-14T11:29:51Z다. 이 인수는 법적/privacy clearance를 제공하지 않는다.
|
||
- 이번 작업에서 commit/push/merge/tag/deploy는 실행하지 않았다. production 검증도 미실행이다.
|