← 아티클 목록

개발일지WhoAmI — 공부 기록을 발행 가능한 형태로 좁힌 파이프라인 →

쓰는 쪽만 보고 만든 사이트를 읽는 쪽에서 열었다

글을 쌓는 장치는 만들었지만 독자가 키워드로 찾고 긴 글을 훑고 코드를 가져가는 길은 부족했다. 검색·목차·코드 복사·분량 표시와 이동 경로를 보완하며 확인한 선택과 한계를 정리한다.

목차 4

2026-08-09 업데이트 — CSS soft wrap과 innerText의 관계, 수동 복사 가능성을 바로잡았다. 검색 결과 범위와 색인 차단, 다크 토큰 중복, 404 유입에 대한 설명도 현재 동작에 맞게 조정했다.

앞의 열세 편은 전부 글을 쌓는 쪽 이야기였다. 관리자, 스키마 게이트, 볼트에서 사이트로 오는 통로, 자격증명 스캐너, 배포 경로, 공개 범위. 하나같이 쓰는 사람이 막히던 자리다. 그것들을 메우는 동안 글은 서른 편을 넘겼고, 오늘은 반대쪽 의자에 앉아 봤다. 주소만 아는 사람이 이 사이트에 들어와서 실제로 무엇을 할 수 있는가.

이 질문이 여기서는 조금 더 날카롭다. 사이트가 색인 차단 모드로 떠 있어서 「사이트명 + 키워드」 검색 유입을 기대하기 어렵다. 다만 이것은 접근 제어도, 모든 검색 결과에서 반드시 사라진다는 보장도 아니다. Google도 noindex는 크롤러가 읽어야 적용되고 robots.txt로 크롤을 막으면 URL이 결과에 남을 수 있다고 설명한다. 주소를 아는 사람은 그대로 열 수 있다. 검색 유입을 줄인 상태라면 사이트 안에서 글을 찾는 길이 더 중요하다는 데까지만 이 전제를 쓴다.

찾고, 훑고, 가져가는 세 동작

제목·설명·태그 같은 글 메타데이터에 키워드를 넣어 찾는 검색부터 없었다. 본문 전체는 지금도 검색 대상에 넣지 않는다. 카테고리·태그·이전·다음 링크는 이미 있었으므로 목록 훑기가 문자 그대로 유일한 길은 아니었지만, 이름이나 키워드를 알고도 여러 목록과 링크를 돌아야 했다. 검색을 하나가 아니라 둘로 나눠 넣었다. 헤더의 것은 전역 빠른 이동이라 상위 8개만 드롭다운으로 보여 주고, /articles 안쪽의 것은 카드·설명·태그·연도 묶음을 유지한 목록 검색이다. 드롭다운 아래 링크는 검색어를 /articles?q=로 넘겨 아티클·개발일지·프로젝트 결과로 잇는다. 현재 헤더 색인에는 시리즈도 들어가지만 /articles 인라인 결과에는 시리즈가 없으므로, 이 링크를 모든 유형을 포괄하는 「전체 결과」라고 부를 수는 없다. 인라인 쪽은 결과를 스크립트가 그리지 않고 이미 그려진 카드에 hidden만 토글한다 — 스크립트가 그리기 시작하면 카드 마크업이 컴포넌트와 스크립트 두 곳에 생기고, 그때부터 둘은 조용히 어긋난다.

검색은 만들자마자 다른 문제를 하나 메웠다. 개발일지는 아티클 목록에서 뺀 글이라 「목록에서만 빠질 뿐 검색은 그대로」라고 적어 두었는데, 정작 그 검색이 없어서 사이트 UI 안의 주된 진입점은 소속 프로젝트 상세였다. 프로젝트 자체에는 별도 목록이 이미 있었다. 이제 검색어가 있을 때 개발일지와 프로젝트가 별도 묶음으로 나온다. 기본 아티클 목록에 섞지는 않는다 — 섞으면 개발일지를 뺀 이유가 그대로 무너진다.

훑기. 긴 글은 ## 이 열 개까지 가는데 절 사이를 건너뛸 방법이 없었다. 목차는 새로 만든 게 거의 없다. 헤딩에 id 가 이미 붙어 있고 스크롤 여백도 걸려 있어서, 렌더러가 주는 헤딩 목록만 받아 쓰면 됐다. h2 만, 세 개 이상일 때만 그린다. 목록 태그는 ol 이지만 번호는 지웠다 — 이 사이트 h2 의 절반이 이미 「1.」로 시작해서 「3. 1. …」이 된다.

가져가기. 생성된 코드블록은 white-space: pre-wrap이라 긴 명령이 화면 폭에서 접힌다. 포인터나 터치로 긴 범위를 고르기 번거로울 수 있지만, 드래그 선택과 키보드·문맥 메뉴 복사는 그대로 가능하다. 복사 버튼은 유일한 수단이 아니라 코드블록 전체를 한 번에 가져가는 편의 기능이다. 당시 137개 코드블록에 자리를 붙였고, 현재 구현은 navigator.clipboard.writeText가 있는 환경에서만 버튼을 만든다. Clipboard API는 권한과 사용자 에이전트 정책의 영향을 받으므로 버튼이 없거나 쓰기가 실패해도 수동 선택 경로는 남는다. W3C Clipboard API도 비동기 클립보드 접근을 권한이 통제하는 기능으로 정의한다.

복사할 문자열은 지금도 innerText가 아니라 textContent로 읽는다. 다만 이유를 고쳐야 한다. WHATWG HTML의 innerText 알고리즘은 렌더된 텍스트와 요소 구조에서 생기는 필수 줄바꿈을 반영하지만, CSS의 시각적 soft wrap을 자동으로 LF로 직렬화한다고 규정하지 않는다. 반면 DOM 표준의 textContent는 하위 Text 노드의 데이터를 트리 순서로 합친다. 이 구현에서 textContent를 택한 근거는 CSS 렌더링 상태와 무관하게 코드 DOM에 들어 있는 원문을 가져가기 위해서다. 당시 781630c 커밋에는 복사 결과의 exactMatch를 브라우저에서 확인한 기록이 있다. 이번 정정에서도 현재 생성 HTML과 구현·표준을 대조하고, Chromium 320px에서 한 줄 명령이 두 줄로 접힌 사례를 직접 확인했다. 그 사례에서는 innerText, textContent, 선택 문자열이 같았고 포인터로 원문 전체를 선택할 수 있었다. 이는 한 브라우저·한 사례의 확인이며 브라우저별 전수 결과는 아니다.

목록 카드도 이 김에 답을 두 개 더 하게 만들었다. 「실습 기록인가 개념 정리인가」는 이 블로그가 스스로 내세우는 구분인데 글을 열어야만 보였고, 2분짜리와 9분짜리를 고르는 값도 카드에 없었다. 분량은 코드블록을 빼고 산문만 분당 500자로 센다. 당시 코드블록 137개 중 72개가 plaintext 또는 text였고, 그중 다수는 명령 출력이었다. 모든 독자가 출력을 읽지 않는다고 볼 수는 없지만, 이 글들의 긴 출력은 대개 전체를 정독하기보다 필요한 줄을 훑는 자료로 썼다. ed93918 커밋에 남긴 단일 글 실측에서는 6,406자 중 65%가 코드였고 전부 세면 13분, 산문만 세면 5분이었다. 이는 독자 연구가 아니라 표시 규칙을 고르기 위한 한 사례다. 코드에도 시간이 들기 때문에 어느 쪽도 정확한 독서 시간은 아니고, 그래서 화면에는 「N분 분량」이라고만 적었다.

본문 이미지도 함께 고쳤다. 치수도 지연 로딩도 없어서 스크린샷이 도착할 때마다 본문이 밀렸다. 원본을 Astro의 소스 자산 경로로 옮기는 방법 대신 다 끝난 빌드 산출물의 HTML만 고치는 쪽을 골랐고, 그 이유는 아래에 적는다. webp는 무손실을 먼저 시도한다 — 당시 빌드 작업에 남긴 21장 비교에서는 콘솔 스크린샷의 무손실 합계가 457KB, 손실 합계가 642KB로 무손실이 오히려 작았다. 이 자료 집합에서 관성대로 손실을 썼다면 더 큰 파일을 받으면서 작은 글자까지 흐려질 수 있었다.

이미 있는데 닿을 길이 없던 자리

만들어 놓고 문을 안 단 것이 셋 있었다.

시리즈는 카테고리와 대등한 축으로 설계해 두고 정의·목차·배너·구조화 데이터까지 붙여 놨는데, 「어떤 묶음이 있는가」를 보는 화면이 없었다. /series/<id>는 있었지만 사이트 UI에서 시리즈 목록으로 들어가는 길은 없었고, 직접 주소를 제외하면 시리즈 글을 먼저 연 뒤 배너를 따라가는 경로가 전부였다. 인덱스를 만들되 내비에는 넣지 않았다. 한글 라벨이 여섯 개가 되면 320px에서 내비 줄이 셸을 넘긴다. 대신 글을 고르는 자리인 /articles 헤더에 한 줄을 두고, 시리즈 상세 앞에 「시리즈 전체」 칩을 세웠다.

다크 테마도 같은 경우였다. 처음부터 같은 정체성의 두 번째 얼굴로 설계해서 색온도를 맞추고 순검정을 금지하고 대비를 전량 재검증해 뒀는데, 거기 닿는 길이 OS 설정뿐이었다. 라이트로 쓰는 기기에서 이 사이트만 어둡게 보고 싶은 사람에게는 그 얼굴이 없는 것과 같다. 토글은 시스템 → 라이트 → 다크 세 상태로 돌게 했다. 저장 상태를 라이트와 다크 두 값으로만 순환시키면 이 UI 안에서는 시스템 설정을 따르는 상태로 돌아갈 수 없다. 낮과 밤에 OS 테마가 바뀌는 사람을 위해 세 번째 상태를 명시적으로 남겼다.

현재 CSS 구현은 「시스템이 어두울 때」의 @media (prefers-color-scheme: dark) 경로와 「다크를 고른 때」의 [data-theme='dark'] 경로에 같은 토큰 집합을 각각 둔다. 이것은 CSS가 보편적으로 같은 값을 공유할 수 없어서가 아니라, 이 두 선택자 경로로 구성한 현재 설계에서 생긴 중복이다. 손으로 일치를 지키지 않기로 하고 빌드 시작에서 두 블록을 대조해 다르면 세우는 검사를 붙였다. 경고가 아니라 중단인 이유는 어긋난 색이 시스템 다크로 보는 사람과 토글로 켠 사람에게만 다르게 보여서 눈으로는 거의 못 찾기 때문이다. 자격증명 스캐너를 경고가 아니라 게이트로 둔 것과 같은 판단이고, 당시 d347e3f 커밋에는 토큰 하나를 일부러 어긋내 중단을 확인한 기록이 있다.

세 번째는 아예 막다른 칸이었다. 이전·다음 글의 사슬 끝에서 「아직 없습니다」라는 상자를 그리고 있었다. 누를 수도 없고 알려 주는 것도 없는데 카드 한 칸을 차지하는데, 정작 사슬의 끝이야말로 다음 갈 곳이 가장 필요한 자리다. 그 자리를 이 사슬이 나온 목록으로 채웠다. 홈의 카테고리 줄에서는 「전체」에 선택 표시가 붙어 있었다 — 전부 다른 페이지로 나가는 링크인데 선택된 것처럼 보이는 칸이 있으면 필터로 읽힌다. 404는 버튼 두 개뿐이라 찾던 글로 가려면 목록을 한 번 더 거쳐야 했다. 옛 링크나 오타는 가능한 유입 경로지만 방문자 대부분이 그렇다는 분석 자료는 없었다. 한 단계를 덜 거치게 하려는 설계 판단으로 최근 글 네 편을 깔았다.

화면에서 뺐는데 검색에는 남아 있었다

마지막 작업은 오전에 만든 검색이 도로 물어 온 것이다.

어제 개발일지 열세 편을 쓰고 나서, 프로젝트 상세의 목록에서 카테고리 칸을 뺐다. 열세 편이 전부 같은 값이라 구분이 아니라 잡음이었다. 그때는 스키마가 카테고리를 요구하니 값은 계속 붙이되 그것이 화면에서 편을 구분해 주기를 기대하지 않는다고 계획서에 적어 뒀다. 화면에서 안 보이니 없는 것과 같다고 본 것이다.

오늘 검색을 붙이고 「클라우드」로 찾아 보니 클라우드와 무관한 개발일지 열세 편이 딸려 나왔다. 그 값은 화면에서만 빠졌을 뿐 검색 건초더미에는 그대로 있었다. 화면에서 안 보이는 값도 검색에는 보인다.

고친 방향은 값을 지우는 게 아니라 칸을 없애는 것이다. 스키마에서 카테고리를 선택 항목으로 바꾸고 열세 편에서 그 줄을 지웠다. 대신 「비워도 된다」로 끝내면 다음에는 아티클이 카테고리 없이 나갈 수 있으므로, 아티클에는 반드시 있어야 하고 개발일지에는 있으면 안 된다는 양방향 규칙을 검증 스크립트에 넣었다. 스키마 혼자서는 이 판정을 못 한다 — 어떤 글이 개발일지인지는 글 파일이 아니라 프로젝트 파일의 devlog 칸에 적혀 있어서, 둘을 같이 봐야 답이 나온다. 관리자 쪽도 같은 규칙으로 막고, 개발일지를 열면 카테고리 선택을 「(없음)」에 고정한 채 잠근다. 화면에서 값을 안 보이게 하는 것과 값을 없애는 것은 다른 일이고, 어제는 앞의 것을 하고 뒤의 것을 했다고 적었다.

버린 것

본문 이미지는 원본을 Astro의 소스 자산 경로로 옮겨 처리하지 않았다. 옮기면 당시 본문 21곳과 저작 도구 세 곳을 함께 고쳐야 했고, 마크다운 처리 경로도 바꿔야 했다. 저작 규약과 원본을 그대로 두고 빌드 산출물만 고치는 쪽이 얻는 것에 비해 건드리는 곳이 적었다. 대신 이 처리는 빌드 뒤에만 존재해서 개발 서버에서는 보이지 않는다.

인라인 검색 결과를 스크립트로 그리는 방법도 버렸다. 페이지에 이미 있는 카드를 감췄다 보이는 쪽이 마크업이 한 벌로 유지된다.

시리즈를 내비에 넣지 않았고, 테마 토글을 라이트·다크 두 상태로만 만들지 않았고, 다크 토큰 두 벌의 일치를 사람의 기억에 맡기지 않았다. 각각 좁은 화면의 가로 용량, 시스템 상태로 돌아가는 경로, 눈으로 찾기 어려운 어긋남을 기준으로 고른 결과다.

읽는 분량은 초 단위로 맞추려 하지 않았다. 코드를 세도 안 세도 정확하지 않은 값이라, 정확해질 수 없는 숫자를 정확한 것처럼 표시하지 않는 쪽을 골랐다.

오늘 고친 것들은 성격이 하나로 모인다. 검색·목차·코드 복사·분량 표시·테마 전환을 추가했고, 시리즈 인덱스와 글 사슬 끝·404는 이미 있는 콘텐츠로 가는 경로를 고쳤다. 이미지 후처리는 읽는 동안 화면이 밀리는 문제를 줄이는 별도 작업이었다. 만드는 동안에는 이런 독자 쪽 경계가 잘 보이지 않는다. 만든 사람은 시리즈가 있다는 것도, 다크가 있다는 것도, 개발일지가 어디에 묶이는지도 이미 알고 들어오기 때문이다.

사이트는 계속 고치겠지만 고친 것마다 한 편씩 붙이지는 않는다. 이 기록이 남기려던 것은 파일 목록이 아니라 그때 무엇을 놓고 무엇을 골랐는가다. 이날 저장소에 반영한 코드 변경은 781630c부터 991231a까지의 커밋 diff에 남아 있다. 커밋이 브라우저 상태와 판단 맥락까지 전부 보존하는 것은 아니므로, 직접 확인한 결과는 각 커밋의 검증 메모와 이 글에서 따로 범위를 밝힌다.

함께 보면 좋은 글

이 기록과 태그가 겹치는 아티클입니다.