빌더·백엔드에서 이 시연본을 실제 생성 파이프라인으로 옮기려는 사람이, 화면을 보고 역산해야 하는 상태였다. 시연본은 payload 가 없는 목업이라 "화면에 있는 것"과 "제품이 만들 수 있는 것"이 갈라져 있는데 그 간격이 어디에 얼마나 있는지 적힌 곳이 없었다. 섹션마다 값이 오는 payload 자리 · 계약 유무 · 프롬프트 위치 · 목업이 손으로 한 것을 적고, 계약에 아예 없는 셋(히어로 캐치프레이즈 · 자작곡 플레이어 · 일정 규칙)은 추가할 타입과 프롬프트 초안까지 넣었다. - SECTIONS.md 신설: 22개 섹션표 · 새로 만들어야 할 6가지 · 프롬프트 작성 규칙 · 검증 - README.md: 제품으로 옮기는 사람을 SECTIONS.md 로 보낸다. 감사 항목 수 33 → 34 정정 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
343 lines
20 KiB
Markdown
343 lines
20 KiB
Markdown
# `/s/stay` 시연본을 만드는 스크립트 — 인수인계 문서
|
|
|
|
`https://web4ai.o2osolution.ai/s/stay` (로컬 `http://localhost/s/stay`) 한 페이지를 만드는
|
|
도구 모음이다. **고칠 자리는 전부 이 디렉토리 안에 있다.**
|
|
|
|
> **이어받는 사람에게 — 먼저 읽을 세 줄**
|
|
> 1. 이 사이트는 **payload 가 없는 목업**이다. 백엔드·DB·프리렌더를 건드리지 않는다.
|
|
> 고치는 것은 구워진 `index.html` 하나이고, 그 파일이 유일본이다.
|
|
> 2. **렌더러(`solution/site/src`)를 고치지 않는다.** 고치면 번들 해시가 바뀌어
|
|
> 전 사이트 재굽기 + 전체 재업로드가 따라온다. 목업에만 필요한 것은 `inject.css`/`inject.js` 로 덮는다.
|
|
> 3. 무엇을 고치든 **`node audit-all.mjs` 가 34개 항목 전부 통과**해야 끝난 것이다.
|
|
> "코드에서 빠졌으니 됐다" 로 끝내면 안 된다 — 실제로 그렇게 틀린 적이 있다(§7).
|
|
|
|
> **빌더·백엔드에서 이걸 제품으로 옮기는 사람은 [SECTIONS.md](SECTIONS.md) 부터 읽는다.**
|
|
> 섹션 22개마다 "목업은 무엇으로 만들었고, 제품은 무엇으로 만들어야 하나" 를 적었다 —
|
|
> 계약(payload 필드) · 프롬프트 · 아직 없는 것 셋(캐치프레이즈 · 자작곡 · 일정 규칙).
|
|
|
|
---
|
|
|
|
## 0. 먼저 알아야 할 것 — 왜 스크립트인가
|
|
|
|
`/s/stay` 는 **payload 가 없는 목업**이다(`stay2` · `stay3` 도 같다).
|
|
프리렌더는 payload 를 받은 사이트만 굽기 때문에, 이 사이트는 **재굽기 대상이 아니다.**
|
|
고칠 자리는 이미 구워져 있는 `index.html` 하나이고, 그 파일이 유일본이다.
|
|
|
|
그래서 손으로 열어 고치지 않는다. 이 스크립트들이 **원본 + 바꿀 것 → 새 index.html** 을 만든다.
|
|
두 번째로 고칠 때 "무엇을 왜 바꿨는지" 가 파일이 아니라 여기 남아야 하기 때문이다.
|
|
|
|
```
|
|
stay-payload.json 원본 payload (건드리지 않는다 · 되돌릴 때 기준)
|
|
orig/index.html 원본 HTML (건드리지 않는다)
|
|
│
|
|
├─ build_itinerary.py 여행 일정을 계산해 넣는다
|
|
├─ build_story.py 가요 다방 · 인물 열전을 넣는다
|
|
└─ patch_stay.py 캐치프레이즈 · 객실 사진 · 자작곡 · 주입 CSS/JS 를 넣고 HTML 조립
|
|
│
|
|
▼
|
|
build/index.html ← 배포하는 파일
|
|
```
|
|
|
|
---
|
|
|
|
## 1. 한 번에 굽기
|
|
|
|
```bash
|
|
cd solution/site/scripts/mockup
|
|
python3 build_itinerary.py && python3 build_story.py && python3 patch_stay.py
|
|
```
|
|
|
|
**순서를 지킨다.** `build_itinerary.py` 가 `stay-payload.json`(원본)을 읽어
|
|
`stay-payload-new.json` 을 만들고, 뒤 둘이 그 파일을 이어서 고친다.
|
|
순서를 바꾸면 앞 단계 결과가 지워진다.
|
|
|
|
로컬 반영:
|
|
|
|
```bash
|
|
docker cp build/index.html o2o-web4ai-solution-prerender:/app/solution/site/out/s/stay/index.html
|
|
```
|
|
|
|
검사:
|
|
|
|
```bash
|
|
node audit-all.mjs # 34개 항목 전수 점검 (로컬)
|
|
node audit-all.mjs https://web4ai.o2osolution.ai/s/stay # 킹서버
|
|
```
|
|
|
|
---
|
|
|
|
## 2. 무엇을 어디서 고치나
|
|
|
|
### 히어로 문구 (캐치프레이즈 100개) → `patch_stay.py`
|
|
|
|
화면 맨 위, 상호 아래에서 **7초마다 단어 단위로 바뀌는 한 줄**이다.
|
|
|
|
| 자리 | 줄 | 무엇 |
|
|
|---|---|---|
|
|
| `GENERAL` | `patch_stay.py:20` | 일반 40개 — 언제 나와도 되는 문구 |
|
|
| `SEASON` | `patch_stay.py:62` | 계절별 24개 — 봄/여름/가을/겨울 각 6개 |
|
|
| `MONTH` | `patch_stay.py:72` | 월별 24개 — 1~12월 각 2개 |
|
|
| `WEATHER` | `patch_stay.py:87` | 날씨별 12개 — 맑음/구름많음/흐림/비/눈 |
|
|
|
|
문장만 더하거나 지우면 된다. 개수 제한은 없다.
|
|
|
|
**나오는 순서**는 `inject.js` 의 `buildCycle()` 이 정한다 —
|
|
`일반 → 계절 → 일반 → 월 → 일반 → 날씨` 한 바퀴를 만들고 그 바퀴를 돈다.
|
|
일반은 자루에서 뽑아 쓰고 비면 다시 채운다(같은 문장이 연달아 나오지 않게).
|
|
|
|
- **계절 구분은 3개월 단위**다: 3~5 봄 · 6~8 여름 · 9~11 가을 · 12~2 겨울
|
|
(`inject.js` `SEASON_OF_MONTH`)
|
|
- **날씨는 실시간**이다. `/v1/local/weather` 를 10분마다 읽어 분류한다.
|
|
분류 기준은 렌더러(`site/src/lib/use-live-weather.ts`)와 같은 값을 쓴다 — 갈리면
|
|
화면의 날씨와 문구가 어긋난다.
|
|
- 못 받아 오면 날씨 문구는 **순환에서 빠진다**(거짓말을 하지 않는다).
|
|
- 구워진 첫 문장은 5초 두고 시작한다. 들어오자마자 바뀌면 읽던 것을 놓친다.
|
|
- `prefers-reduced-motion` 이면 애니메이션 없이 글자만 바뀐다.
|
|
|
|
### 여행 일정 → `build_itinerary.py`
|
|
|
|
**사람은 "어느 자리에 어느 장소" 만 고르고, 시각은 스크립트가 계산한다.**
|
|
|
|
| 자리 | 줄 | 무엇 |
|
|
|---|---|---|
|
|
| `PLACES` | `:40` | **장소 대장** — 좌표 · 지도 검색어 · 체류시간(최소/기본/최대) · **거기서 무엇을 하는지** |
|
|
| `STAY_ACTION` | `:108` | 머뭄 칸의 행위 — 체크인 · 아침 · 아침(퇴실) · 쉼 · 쉬는 날 · 머뭄으로 · 마무리 |
|
|
| `WINDOW` | `:156` | **시간대가 정해진 자리** — 입실 15:00+ · 점심 11:30~13:30 · 저녁 17:30~20:00 … |
|
|
| `SKELETON` | `:182` | **하루 뼈대** — 자리 이름만 나열. `@` 가 붙은 것은 머뭄 |
|
|
| `THEMES` | `:368` | **테마 21개** — 이름 · 기간 · 누구에게 · 왜 · [(뼈대, [장소…])] |
|
|
| `PACING` | `:470` | 테마별 시작 시각과 체류 배율(쉬러 오면 1.25배, 사진 찍으면 0.8배) |
|
|
|
|
**새 장소를 넣으려면** `PLACES` 에 한 줄 더한다. 좌표는 카카오 로컬 검색에서 받은 실제 값이어야
|
|
한다(지어내지 않는다). 그다음 `THEMES` 의 원하는 자리에 이름을 적는다.
|
|
|
|
**새 테마를 넣으려면** `THEMES` 에 한 덩이, `PACING` 에 한 줄 더한다.
|
|
뼈대의 `@` 없는 자리 수와 장소 개수가 같아야 한다 — 틀리면 빌드가 멈추고 알려 준다.
|
|
|
|
**계산되는 것 (손으로 적지 않는다)**
|
|
- **이동시간** — 좌표에서. 1.5km 까지 도보 4km/h, 그 위는 차 25km/h + 주차 5분, 최소 3분
|
|
- **도착·출발 시각** — 시작 시각부터 누적
|
|
- **끼니 시각 맞추기** — 창을 벗어나면 **앞 칸 체류를 범위 안에서 늘이고 줄인다**.
|
|
(사람이 실제로 그렇게 한다 — 밥 때가 이르면 박물관을 조금 더 본다.)
|
|
그래도 안 맞으면 시작 시각을 10분씩 옮긴다. 그래도 안 되면 **그 조합을 만들지 않는다.**
|
|
|
|
### 가요 다방 · 인물 열전 → `build_story.py`
|
|
|
|
| 자리 | 줄 | 무엇 |
|
|
|---|---|---|
|
|
| `SONGS` | `:28` | 군산을 노래한 25곡 — 곡명·가수·작사·작곡·연도·라벨색·한 줄 |
|
|
| `PEOPLE` | `:109` | 인물 57명 — 위키 문서 제목 · 표시 이름 · 연도 · 하는 일 · 한 줄 |
|
|
|
|
- 노래 출처는 '음악의 오솔길' 군산 지역노래 정리. **연도·작사·작곡을 모르면 비운다**
|
|
("미상"이라고 적지 않는다 — 렌더러가 없는 칸을 안 그린다).
|
|
- 듣기 링크는 **유튜브 검색 주소**다. 영상 ID 를 박으면 틀린 영상이 붙을 수 있고
|
|
한 곡씩 확인하지 않았다. 검색은 틀릴 수가 없다.
|
|
- 인물 사진은 두 곳에서 온다.
|
|
① `people-photos.json` — 위키백과 **문서 대표 사진**(pageimages) 중 자유 라이선스가
|
|
확인된 17장(CC BY / CC BY-SA / KOGL / 공용). CC BY-SA 는 저작자 표시가
|
|
**라이선스 조건**이라 화면에 그대로 찍는다 — 지우면 침해다.
|
|
② 원본 payload 에 있던 사진 — 위키에 사진이 없는 사람(채만식)은 이 사이트가 **원래 쓰던**
|
|
미러 사진으로 되돌린다. 새로 가져오는 게 아니라 자리로 돌리는 것이다.
|
|
- ★ **이름만으로 커먼즈를 검색해 사진을 붙이지 않는다.** 동명이인이 잡힌다 —
|
|
실측(2026-09-11): 이수현(독립운동가)에 걸그룹 멤버, 은성수(금융위원장)에 축구선수,
|
|
박성현(양궁)에 골퍼, 전진(비전향 장기수)에 아이돌, 이길여에 건물 사진이 왔다.
|
|
**틀린 사진은 없는 것만 못하다.** 그 사람의 문서가 대표로 쓰는 사진만 신뢰한다.
|
|
- 숙소가 만든 곡은 **이 섹션에 넣지 않는다.** 도시의 노래를 모으는 자리다.
|
|
|
|
### 객실 사진 · 자작곡 · 대표 사진 → `patch_stay.py`
|
|
|
|
| 자리 | 줄 | 무엇 |
|
|
|---|---|---|
|
|
| `OWN_SONGS` | `:109` | 머뭄이 만든 5곡 — 플레이어만 읽는다(`narrative.ownSongs`) |
|
|
| `ROOM_PHOTOS` | `:142` | 객실 사진 배정 — A동 12 · B동 10 · 공용 |
|
|
| `HERO_PHOTO` | `:179` | 대표 사진. `None` 이면 **원본 사진이 계속 대표**(지금 그렇다) |
|
|
|
|
★ **객실 A/B 배정은 눈으로 하지 않는다.** 야놀자 등록본의 Next.js 데이터에
|
|
`roomTypes[].photos` 가 객실별로 들어 있고, 그걸 뽑아 둔 것이 `rooms.json` 이다.
|
|
눈으로 갈랐을 때 11/5 가 나왔고 실제는 12/10 이었다.
|
|
|
|
★ 히어로와 소개 사진은 **원본(네이버 예약본 미러)** 을 쓴다.
|
|
히어로는 `isPrimary`, 소개는 **대표가 아닌 첫 사진**을 쓰는 구조라
|
|
(`site/src/sections/HeroSection.tsx:40` · `AboutSection.tsx:23`),
|
|
원본 사진을 목록 앞에 두고 등록본 사진을 뒤에 붙인다. **순서가 곧 그 두 자리다.**
|
|
|
|
### 화면에 덧대는 것 → `inject.css` · `inject.js`
|
|
|
|
렌더러(`solution/site/src`)를 고치면 **다른 사이트까지 바뀌고 전체 재굽기가 따라온다.**
|
|
그래서 이 목업에만 필요한 것은 `index.html` 안에 주입한다.
|
|
|
|
`inject.js` 가 하는 일 다섯:
|
|
|
|
1. **캐치프레이즈 순환** — React 가 그린 `<p>` 를 찾아 단어 단위로 갈아 끼운다
|
|
2. **헤더 미니 플레이어** — 카세트 아이콘 + 재생/멈춤 + 목록. 자작곡 5곡, 랜덤 재생
|
|
3. **링크 걸기** — 일정 정거장 187개 · 엽서 4개를 네이버 지도로
|
|
4. **사진 저작자 표시** — 이 목업이 물고 있는 번들이 옛 판이라 `imageCredit` 을 안 그린다
|
|
5. **카로셀 제어** — 만지는 동안 멈추고, 직접 민 레일은 다시 안 돈다
|
|
|
|
★ **카로셀 (`tameRails`) 은 렌더러 정책을 덮는 것이다.**
|
|
렌더러의 자동 넘김(`site/src/lib/ui/use-rail-autoplay.ts`)은 4.5초 **고정 타이머**이고,
|
|
정지는 `held` 카운터 하나로 센다 — 레일 위 `pointerdown` 에 올리고 window `pointerup`·
|
|
`pointercancel` 에 내린다. 주입분은 타이머를 건드리지 않고 **그 카운터만** 쓴다
|
|
(`pointerdown` 을 `button: 2` 로 쏜다 — embla 는 주 버튼이 아닌 것을 드래그로 치지 않는다).
|
|
구현이 둘(embla · 스크롤 상자)이어도 카운터는 하나라 한 번에 걸린다.
|
|
|
|
규칙 셋:
|
|
|
|
| | 언제 | 얼마나 |
|
|
|---|---|---|
|
|
| 쿨타임 | 무엇이든 만지면(세로 스크롤·휠·키보드 포함) | 7초 |
|
|
| 손이 닿아 있는 동안 | 손가락·마우스 버튼이 내려가 있는 내내 | 뗄 때까지 |
|
|
| 영구 정지 | **레일이 실제로 가로로 움직였을 때** | 그 레일은 끝 |
|
|
|
|
★ **손가락 수로 센다 — pointer 로 세면 안 된다** (2026-09-11).
|
|
브라우저는 터치가 페이지 스크롤로 넘어가는 순간 **손가락이 아직 닿아 있는데
|
|
`pointercancel` 을 쏜다.** 훅의 정지가 거기서 풀려, 손가락 밑에서 카드가 넘어간다.
|
|
실측: touchstart 0.0s → pointercancel 7.5s → 8.4s 에 넘어감. 그래서 `event.touches.length`
|
|
로 센다 — 손이 떨어져야 0 이 된다.
|
|
|
|
★ **"만졌다" 와 "밀었다" 를 가른다** (2026-09-11).
|
|
전에는 레일 위 pointerdown·wheel 이면 곧바로 영구 정지였다. 그런데 일정 카로셀은 화면
|
|
가운데를 가득 채워서 페이지를 세로로 내릴 때 손가락·커서가 거의 언제나 그 위를 지난다 —
|
|
**한 번 스크롤하면 그 레일이 영영 멈췄다**(실측: 세로 휠 한 번 → 20초 0px). 지금은 제스처
|
|
시작 때 위치를 적어 두고 손을 뗀 뒤(관성 350ms) 다시 재서, 8px 넘게 달라졌을 때만 영구 정지다.
|
|
|
|
★ **호버 정지는 렌더러 것이고 그대로 둔다** — 커서를 얹으면 "읽는 중"이 맞다(사장님 확인).
|
|
|
|
검증: `node rails-test.mjs` — 레일 13개를 데스크톱·모바일에서 ①가만히 ②만지는 중
|
|
③민 뒤로 각각 잰다.
|
|
→ **운영 사이트에는 이 문제들이 그대로 있다.** 훅을 고치는 것은 별도 작업이다(§8).
|
|
|
|
★ **React 가 다시 그리면 사라진다.** 그래서
|
|
- 플레이어 목록·패널은 `#root` **밖**(body 직속)에 둔다
|
|
- 헤더에 꽂는 단추는 `MutationObserver` 로 감시해 다시 꽂는다
|
|
- 캐치프레이즈는 노드를 들고 있지 않고 **매 순환마다 다시 찾는다**
|
|
|
|
★ **`window.load` 를 기다리지 않는다.** 이 페이지는 경로 지도 때문에 OSM 타일 `<img>` 가
|
|
140장이라 `load` 는 그게 다 끝나야 나온다 — 타일이 느리면 영원히 안 뜬다.
|
|
|
|
---
|
|
|
|
## 3. 규칙 검사 — 어기면 빌드가 멈춘다
|
|
|
|
`build_itinerary.py` 의 `audit()`(`:526`)이 매 실행 검사한다.
|
|
하나라도 어기면 **payload 파일을 쓰지 않고** 위반 목록을 찍고 멈춘다.
|
|
|
|
| | 규칙 | 이 규칙이 없어서 났던 일 |
|
|
|---|---|---|
|
|
| 1 | 하루의 첫 칸·마지막 칸은 스테이 머뭄 | 출발지가 화면에서 사라졌다 |
|
|
| 2 | **같은 자리가 연달아 서지 않는다** | `아침 · 머뭄` 다음이 `체크아웃 · 머뭄` |
|
|
| 3 | 가운데 머뭄 칸은 '쉼'·'쉬는 날' 뿐 | 마지막 날 머뭄이 3번 |
|
|
| 4 | 이동시간 = 좌표 계산값 | 담 하나 건넌 곳 8분, 45분 걸리는 섬 10분 |
|
|
| 5 | 입실·점심·늦은 점심·저녁·밤 산책 시간대 | 점심 09:40, 저녁 13:09 |
|
|
| 6 | 퇴실 11:00 전 | 체크아웃 11:35 |
|
|
| 7 | 21:00 초과 금지 | 렌더러가 그 칸을 **조용히 버린다** |
|
|
| 8 | 끼니 자리에는 먹는 곳만 | |
|
|
| 9 | 같은 날 같은 식당 두 번 금지 | |
|
|
| 10 | 한 테마 안에서 같은 곳 반복 금지 | 같은 테마에 한일옥이 두 번 |
|
|
| 11 | "비가 와도 되는" 테마는 실내만 | 비 코스에 야외 두 곳 |
|
|
| 12 | "걸어서만/차 없이" 테마에 차 필요한 곳 금지 | |
|
|
| 13 | 1박 2일 = 2일, 2박 3일 = 3일 | |
|
|
| 14 | 아이 동반 테마에 술집 금지 | |
|
|
|
|
★ **왜 빌드 안인가** — 전에는 이 검사를 매번 따로 쓴 일회용 스크립트로 돌렸다.
|
|
그래서 뼈대를 고칠 때마다 "이번에 안 본 규칙"이 생겼고 사장님이 화면에서 먼저 찾으셨다.
|
|
**검사가 빌드의 일부가 아니면 검사한 적 없는 것과 같다.**
|
|
|
|
`audit-all.mjs` 는 그다음 단계다 — 구워진 HTML 을 **실제 브라우저로 열어**
|
|
34개 항목을 센다(캐치프레이즈 개수, 링크 개수, 사진 개수, 모바일 레이아웃, 404, 콘솔 오류…).
|
|
|
|
---
|
|
|
|
## 4. 배포
|
|
|
|
### 로컬
|
|
|
|
```bash
|
|
docker cp build/index.html o2o-web4ai-solution-prerender:/app/solution/site/out/s/stay/index.html
|
|
```
|
|
|
|
`/s/` 는 **5분 캐시**(`max-age=300`)다 — 확인할 때 ⌘⇧R.
|
|
|
|
### 킹서버
|
|
|
|
```bash
|
|
tar czf /tmp/stay-bundle.tgz -C . build/index.html img audio
|
|
scp -C /tmp/stay-bundle.tgz King_admin:~/data2/o2o-site-AEO/tmp-stay-deploy/
|
|
ssh King_admin "cd ~/data2/o2o-site-AEO/tmp-stay-deploy && rm -rf build img audio && tar xzf stay-bundle.tgz
|
|
C=o2o-web4ai-solution-prerender
|
|
docker exec \$C mkdir -p /app/solution/site/out/s/stay/img/people /app/solution/site/out/s/stay/audio
|
|
docker cp build/index.html \$C:/app/solution/site/out/s/stay/index.html
|
|
for f in img/*.jpg; do docker cp \"\$f\" \$C:/app/solution/site/out/s/stay/img/ ; done
|
|
for f in img/people/*; do docker cp \"\$f\" \$C:/app/solution/site/out/s/stay/img/people/ ; done
|
|
for f in audio/*.mp3; do docker cp \"\$f\" \$C:/app/solution/site/out/s/stay/audio/ ; done"
|
|
```
|
|
|
|
확인: `md5 -q build/index.html` 과
|
|
`ssh King_admin "docker exec o2o-web4ai-solution-site md5sum /srv/sites/s/stay/index.html"` 이 같아야 한다.
|
|
그다음 `node audit-all.mjs https://web4ai.o2osolution.ai/s/stay`.
|
|
|
|
되돌리기: 컨테이너 안에 `index.html.bak-20260910` 이 있다.
|
|
|
|
---
|
|
|
|
## 5. 밟으면 조용히 틀리는 자리
|
|
|
|
- **`out/assets` 에 파일을 넣지 않는다.** 거기는 프리렌더가 관리한다(해시 번들 대장 ·
|
|
30일 보관). 손으로 넣은 사진·음원은 `/s/stay/img/` · `/s/stay/audio/` 에 둔다 —
|
|
nginx 의 `^~ /s/` 가 그대로 서빙하고(Range 206 확인) 정리 대상이 아니다.
|
|
- **마크업을 고쳐 지우지 않는다.** React 가 payload 로 다시 그리면서 되돌린다.
|
|
화면에서 없애야 하면 **주입 CSS** 로 끈다(이용 정보 맨 아래 가로선이 그 경우다).
|
|
- **렌더러가 21시를 넘기는 칸을 조용히 버린다**(`shared/section-data.ts` `PLAN_ENDS_BY`).
|
|
적어 놓고 화면에 안 나오는 칸이 생긴다 — 규칙 7이 이걸 막는다.
|
|
- **`imageCredit` 은 문자열이다**(`site/src/sections/items/common.tsx:206`).
|
|
객체를 넣으면 조용히 안 나오고, 그건 라이선스 위반이 된다.
|
|
- **자동 넘김을 끄려고 렌더러를 고치지 않는다.** 번들 해시가 바뀌면 이 목업은 옛 해시를
|
|
가리킨 채 남고(보관 기간 안에는 살아 있다), 다른 사이트는 전부 재굽기 대상이 된다.
|
|
- **크롤러가 보는 HTML 은 옛 내용이다.** 이 페이지는 payload 로 하이드레이션해서 화면을
|
|
바꾸는 것이라, SSR 마크업과 `llms.txt` 는 구운 날 그대로다. 시연에는 문제없지만
|
|
검색·AI 에 인용되는 값은 아니다.
|
|
|
|
---
|
|
|
|
## 6. 남아 있는 일 · 넘기는 판단
|
|
|
|
| | 상태 |
|
|
|---|---|
|
|
| 하루에 숙소가 3번 서는 날(`아침 → … → 쉼 → 저녁 → 복귀`) | **사장님 컨펌 대기.** 점심~저녁 4시간을 바깥 두 곳으로 못 채워 넣은 칸이다. 빼려면 오후 정거장을 하나 더 넣어야 한다 |
|
|
| 가요 다방 25곡 (목표 50) | 출처에서 확인되는 군산 곡이 거기까지다. 더 채우려면 **지어내야 한다** — 하지 않는다 |
|
|
| 인물 사진 18/57 | 위키 문서에 사진이 있는 사람이 18명뿐이다. 동명이인 함정 때문에 이름 검색으로 늘리지 않는다 |
|
|
| 렌더러의 카로셀 자동 넘김 | 운영 사이트에 그대로 있다. 고치려면 `use-rail-autoplay.ts` 에 "손님이 직접 밀면 타이머를 끝낸다" 를 넣고 **전체 재굽기 + republish_all** |
|
|
| `og:image` | 구운 head 에 옛 주소가 남아 있다. 화면은 새 사진, 카톡 공유 썸네일만 옛것 |
|
|
|
|
---
|
|
|
|
## 7. 이 목업을 고치다 실제로 틀렸던 방식 — 되풀이하지 말 것
|
|
|
|
| 한 짓 | 어떻게 틀렸나 | 대신 할 것 |
|
|
|---|---|---|
|
|
| 코드에서 빠진 것만 보고 "고쳤다" 고 보고 | 화면에는 그대로 있었다 | `node audit-all.mjs` 로 **브라우저에서** 확인하고 숫자를 적는다 |
|
|
| 지시받은 한 줄만 고침 | "1번은 숙소" 를 넣으면서 그 하루 전체를 안 읽어 숙소가 3번 서고 두 칸이 연달아 섰다 | 한 곳을 고치면 **같은 종류를 전수 검사**한다 |
|
|
| 규칙 검사를 매번 일회용 스크립트로 | 뼈대를 고칠 때마다 "이번에 안 본 규칙" 이 생겼다 | 검사를 **빌드 안**에 둔다(`build_itinerary.py` `audit()`) |
|
|
| 사진을 눈으로 보고 A/B 배정 | 11/5 가 나왔는데 실제는 12/10 이었다 | 등록본 데이터(`rooms.json`)를 쓴다 |
|
|
| 마크업을 고쳐서 요소 제거 | 하이드레이션이 되돌렸다 | 주입 CSS 로 끈다 |
|
|
| 이름으로 사진 검색 | 동명이인이 붙었다 | 그 사람 문서의 대표 사진만 |
|
|
|
|
---
|
|
|
|
## 8. 파일 목록
|
|
|
|
| 파일 | 무엇 |
|
|
|---|---|
|
|
| `build_itinerary.py` | 여행 일정 계산 + 규칙 14종 검사 |
|
|
| `build_story.py` | 가요 다방 · 인물 열전 |
|
|
| `patch_stay.py` | 캐치프레이즈 · 객실 · 자작곡 · HTML 조립 |
|
|
| `inject.css` · `inject.js` | 화면에 덧대는 것(플레이어 · 문구 순환 · 링크 · 크레딧) |
|
|
| `audit-all.mjs` | 브라우저로 34개 항목 전수 점검 |
|
|
| `verify.mjs` · `player.mjs` · `check2.mjs` · `kingcheck.mjs` · `rail.mjs` · `arrow.mjs` | 부분 점검 |
|
|
| `stay-payload.json` · `orig/index.html` | **원본. 건드리지 않는다** |
|
|
| `stay-payload-new.json` | 중간 산출물 |
|
|
| `build/index.html` | 배포하는 파일 |
|
|
| `img/` (28장) · `img/people/` (17장) · `audio/` (5곡) | 같이 올리는 자산 |
|
|
| `rooms.json` · `people-photos.json` · `people-raw.json` · `coords.json` | 외부에서 뽑아 둔 원자료 |
|
|
| `REVIEW-2026-09-11.md` | 스케줄 오류 보고서(사장님 보고용) |
|
|
| `PROMPTS.md` | 이 콘텐츠를 만드는 프롬프트 — 제품으로 옮길 자리까지 |
|