Fix clue leak, stop the 404 fallback, bust the proxy asset cache

세 가지를 함께 고쳤다.

러시아 편에서 고리키와 어머니의 단서가 서로의 정답을 그대로 담고 있어 두 칸이
한꺼번에 풀렸다. 양쪽 단서에서 상대 이름을 뺐다.

nginx 의 try_files 폴백을 =404 로 바꿨다. 페이지가 여럿이 된 뒤로는 없는 경로도
200 으로 셸을 내려주어, 배포가 안 됐는데도 정상으로 보이는 일이 있었다.

프록시(NPM)가 js/css 에 제 캐시 헤더를 덧붙여 원본의 no-cache 를 덮어쓴다.
이미지 빌드 때 자산 내용의 sha256 앞 열 자리를 뽑아 각 페이지의 링크를
assets/crossword.js?v=<해시> 로 바꾸는 단계를 Dockerfile 에 넣었다. 저장소의
HTML 은 해시 없는 상태로 두고, 자산이 바뀌면 URL 이 저절로 바뀐다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 17:56:43 +09:00
co-authored by Claude Opus 5
parent 23d9bd6862
commit 9cb8915173
4 changed files with 34 additions and 5 deletions
+13 -1
View File
@@ -33,7 +33,7 @@
| `site/assets/crossword.css` | 각 편이 공유하는 화면 양식 |
| `site/assets/crossword.js` | 각 편이 공유하는 게임 엔진 (한글 IME 입력, 검사/힌트/타이머) |
| `nginx/default.conf` | nginx 설정 (8080 리슨, `/healthz` 헬스체크) |
| `Dockerfile` | nginx:1.27-alpine 정적 서빙 이미지 |
| `Dockerfile` | 자산 URL 에 내용 해시를 박는 단계 + nginx:1.27-alpine 정적 서빙 |
| `k8s/deployment.yaml` | Deployment + NodePort Service (31380) |
| `Jenkinsfile` | Checkout → 이미지 빌드/푸시 → kubectl apply |
@@ -65,6 +65,18 @@ nginx 로 파일만 내려주면 끝.
낱말 풀은 작품과 작가만으로는 성글다. 특히 원어 표기의 음절이 서로 겹치지 않는
편(독일 편)에서는 **등장인물과 작품 속 핵심어까지 넣어야** 교차 지점이 생긴다.
## 캐시
프록시(NPM)가 `js` / `css` 응답에 제 캐시 헤더를 덧붙인다. 원본 nginx 가
`no-cache` 를 줘도 덮어써지므로, 브라우저가 옛 자산을 계속 쓰는 일을 막기 위해
**이미지 빌드 때 자산 URL 에 내용 해시를 박는다.**
- `Dockerfile` 의 `stamp` 단계가 `crossword.css` + `crossword.js` 의 sha256 앞
열 자리를 뽑아 각 페이지의 링크를 `assets/crossword.js?v=<해시>` 로 바꾼다
- 자산 내용이 바뀌면 해시가 바뀌고 URL 도 바뀌므로 캐시가 저절로 무효화된다
- 저장소의 HTML 은 해시 없는 상태로 두면 된다. 손으로 붙일 필요 없다
- HTML 자체는 프록시가 캐시하지 않으므로 새 해시가 바로 전달된다
## 배포
Jenkins 잡(`crossword`)을 돌리면 아래가 순서대로 진행된다.