지역 이름이 들어간 페이지는 사람이 읽기 쉽지만 주소 인코딩과 파일 생성이 서로 어긋나면 찾기 어려운 문서가 된다. 실제 지역 페이지 생성기를 읽고 경로를 만드는 기준과 결과를 대조하는 작은 모듈로 분리했다.
주소와 파일 이름은 같은 문자열이 아니다
원래 생성기는 지역과 시설 조합으로 페이지를 만든다. 브라우저 경로는 인코딩된 문자열이고 출력 파일은 사람이 읽는 폴더 이름일 수 있다. 둘을 무조건 같은 문자열로 비교하면 정상 파일을 누락으로 보거나 다른 경로를 같은 문서로 착각할 수 있다. 새 예제는 문서의 세그먼트를 공통 입력으로 쓴다.
합성 지역·공간 두 세그먼트에서 상대 주소와 지역/공간/index.html을 함께 만든다. 실제 업체 도메인과 지역 사업 목록은 넣지 않았다. 이 모듈은 경로 계약의 검산이며 실서버가 해당 문서를 제공하는지 확인하는 HTTP 검사는 별도의 일이다.
눈에 같아 보이는 한글도 정규화했다
같은 글자가 서로 다른 유니코드 조합으로 표현될 수 있으므로 NFC로 맞춘 뒤 인코딩한다. 정규화 후 같은 주소가 두 번 나오면 거절한다. 기존 목록을 사전으로 바꾼 뒤 중복을 보려 하면 이미 한쪽이 덮였을 수 있어 변환 전에 확인하는 방향으로 만들었다.
세그먼트에는 슬래시, 역슬래시, 물음표와 퍼센트 같은 경로 제어 문자를 허용하지 않는다. 이미 인코딩된 구분자를 다시 받아 통과시키지 않기 위한 좁은 입력 계약이다. 모든 웹 주소를 처리하는 범용 URL 파서가 아니라 문서 생성용 이름 목록을 안전하게 제한한 함수다.
문서가 만들어졌는지와 검색 목록을 나눠 봤다
manifest는 path, file, audience와 사이트맵 포함 여부를 만든다. reconcile은 예상 파일과 전달받은 실제 출력 목록, 예상 검색 목록과 전달받은 사이트맵을 비교해 누락과 초과를 따로 반환한다. 파일이 있다고 사이트맵까지 맞는 것은 아니고 사이트맵에 있다고 파일이 존재하는 것도 아니다.
합성 예제는 정확히 일치하는 경우와 모든 페이지가 빠진 경우를 남겼다. 출력 목록 자체에 중복이 있어도 거절한다. 실제 빌드 디렉터리를 자동 스캔하거나 기존 업체 사이트에 파일을 쓰지는 않는다. 호출자가 확인한 출력 목록을 이 계약에 연결해야 한다.
하나의 문서가 하나의 결과에 대응하게 한다
정규화와 인코딩은 사람이 읽는 이름을 없애려는 작업이 아니다. 읽을 이름과 운반할 표현을 따로 만들어 같은 문서 식별에 연결하는 작업이다. 원래 명칭을 표시용으로 보존하더라도 주소 비교는 같은 정규화 기준을 사용해야 한다. 그래야 겉보기에 같은 두 페이지가 빌드 과정에서 서로 덮이는 위험을 줄일 수 있다.
새 모듈은 실제 파일을 쓰지 않으므로 file 필드가 있다고 생성이 성공한 것은 아니다. 생성기에서 나온 출력 목록을 받아 다시 대조하는 단계가 필요하다. 오류를 고칠 때도 주소를 바꿨는지 파일 위치를 바꿨는지 사이트맵만 바꿨는지 구별하면 영향을 설명하기 쉽다.
범용화를 한다면 호스트 이름과 확장자 정책, 리디렉션을 별도 구성으로 붙일 수 있다. 다만 이번 작은 계약은 상대 경로와 index 파일만 다룬다. 확인하지 않은 플랫폼별 동작을 미리 약속하지 않고 실제 필요가 생긴 경계부터 확장하는 방식으로 남겼다.
경로 계약을 배포 결과로 과장하지 않았다
소스와 ZIP 추출 환경에서 8개 테스트가 통과했다. 한글 인코딩과 조합형 중복, 위험한 세그먼트, 보관·비공개 구분과 목록 불일치를 확인했다. DNS 연결과 실제 검색엔진 색인, 서버의 인증 설정을 검수한 것은 아니다. 모듈의 선언과 운영의 적용을 구분해 둔다.
지역 페이지를 늘릴 때는 페이지 수보다 한 문서가 어떤 주소·파일·검색 목록에 대응하는지 다시 설명할 수 있어야 한다. 나는 생성 성공이라는 출력 하나에 기대기보다 결과를 재현 가능한 목록으로 대조하는 구조를 공유하고 싶었다. 다음 글은 참고 보관본의 공개 경계를 이어서 다룬다.
실제 생성기와 연결할 때는 예상 목록을 만들기 전에 같은 입력을 재사용하고, 빌드 후에는 관측한 파일 목록을 새로 읽어야 한다. 예상 목록을 실제 결과인 것처럼 다시 넘기면 검사의 의미가 사라진다.