# Find-Word v0.2.3 정적 배포 인계 이 문서는 **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.3 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.3`와 목표 WAV의 같은 버전 query가 정상 응답하고 존재하지 않는 오디오는 query가 있어도 404인지 확인한다. 4. 모바일 Safari/Chrome, 데스크톱에서 음량·중단·다시 듣기·3문항 완주·다음 난이도·시작 단계·SNR 변경·중도 종료를 직접 확인한다. 5. 원자적으로 릴리스 디렉터리를 전환하고 이전 디렉터리를 보관해 되돌릴 수 있게 한다. 오프라인 캐시를 제공하는 PWA는 아니다. 정적 자산의 최초 로드에는 해당 서버 연결이 필요하다. HTML은 재검증하고, 오디오는 URL의 자산 버전으로 구분한다. 같은 파일명으로 WAV를 교체할 때 `src/audio/assets.ts`의 `AUDIO_ASSET_VERSION`도 갱신한다. 제품 버전을 유지하는 음성 수정에서도 새 자산 버전이 필요하다. 이 query는 로컬 정적 파일 요청에만 사용하며 런타임 외부 요청을 추가하지 않는다. ## 0.2.3 독립 인수와 릴리스 (Neo 수행, 이 작업에서는 미실행) 1. `.agent/RESULT-v0.2.3.md`와 RED/GREEN 원문, 원본/배포 해시, 라이선스 고지를 검토한다. 2. sandboxed system Chrome desktop/mobile suite와 `npm audit`를 다시 실행한다. 3. 검토 완료 후 feature branch push, main fast-forward, annotated `v0.2.3` tag, fresh-clone readback으로 commit과 자산 해시를 확인한다. 4. commit-addressed release 디렉터리로 dist를 복사하고 current 심볼릭 링크를 원자 전환한다. 이전 release는 rollback 대상으로 보존한다. 5. 공개 HTTPS에서 title/UI 0.2.3, 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 사본은 제거했다.