프로젝트 관련 질문·작업이면 답변·수정 전에 hsol-info-blob/vault/README.md 를 먼저 읽고
관련 디렉토리를 탐색한다. 대화 중 vault 에 없는 새 사실을 알게 되면 답변 직후 능동적으로
vault 에 반영한다. 상세 트리거·절차·예외는 hsol-info-blob/CLAUDE.md 의 "절대 규칙" 두
섹션을 그대로 따른다. 단 object-views/site-data.json 과 datasources/<출처>/ 본문은
생성기·sync 도구 전용이므로 직접 편집하지 않는다.
- 일반 대화 응답에서는 저장소 안의 소스 경로나 파일명을 직접 나열하지 말고, 모듈·기능·역할로만 짚길 기대한다(코드 인용 블록이 꼭 필요한 경우는 예외).
- Vercel CLI의 자동 링크(
vercel link --yes등)가 대시보드에서 쓰는 프로젝트와 다르면, 지정한 팀·프로젝트로 다시 맞추길 기대한다. - 포트폴리오 상세에서 Ask Hansol(ChatDock)은 데스크톱에서는 기본으로 열리되, 모바일 뷰포트(약
max-width: 768px)에서는 기본으로 닫힌 상태를 기대한다. - Ask Hansol 답변에는 "vault에서 확인", "Blob에서", "운영 매뉴얼상…"처럼 내부 출처·저장소 이름·조회 과정을 드러내는 표현을 넣지 않길 기대한다.
- 가족·배우자·결혼 여부 등은 vault에 적혀 있으면 Ask 답변에 말해도 되고, 운영 매뉴얼의 "외부 비공개" 문구만으로 vault에 있는 사실을 숨기거나 거절하는 답은 원하지 않는다.
- ChatDock이 열릴 때는 플로팅 ASK 버튼을 숨기고(투명 영역의 × FAB로 바꾸지 않음), 닫기는 헤더의 ×만 쓰길 기대한다.
- Ask Hansol(특히 드래그·선택 텍스트로 이어지는 질문)은 과친한 칭찬·환호로 시작하는 도입부 없이 담백하게 본론 위주로 답하길 기대한다. 쉬운 풀이식 설명보다는 포트폴리오 본문만으로 부족할 때 보완하는 수준의 밀도를 선호한다.
content:refresh:claude로 채워지는 방문자 노출 한국어 카피는 자기소개서형 첫 문장·이름 주도 템플릿(예: 「저는 ~로」「~은」으로 문단 시작)을 피하고, 해당 스크립트에 적어 둔 전역 산문 문체 규칙을 따르길 기대한다.- Google Analytics 등 선택적 측정·분석 스크립트는 대응하는 환경 변수가 없거나 비어 있으면 레이아웃에 포함하지 않길 기대한다.
- 이 저장소의 Vercel 배포 대상 프로젝트는 팀
hsol의hsol-info이다(vercel link --scope hsol --project hsol-info로 맞출 수 있다). Web Analytics를 쓰려면 해당 프로젝트에서 기능을 활성화하고 루트 레이아웃에@vercel/analytics/next의<Analytics />를 둔다(시작 가이드). Google Analytics 4(gtag)는NEXT_PUBLIC_GA_MEASUREMENT_ID가 비어 있지 않을 때만 스크립트와 클라이언트page_path갱신을 넣고, 없으면 넣지 않는다. vercel env pull은 기본이 development 환경이라, Production·Preview에만 있는 변수는.env.local에 포함되지 않을 수 있다.- 이 저장소는 Vercel 서버 렌더로 배포한다.
next.config.ts에output: "export"가 없고force-dynamic라우트(/resume,/api/*,/manage/*등)가 여럿이라, 정적보내기 전제(산출물out/,app/api/*미배포로/api/*404,force-dynamic금지,vercel.json의outputDirectory중복 주의)는 지금 이 저장소에 적용되지 않는다. 다시 정적 export 로 돌린다면 그 넷을 함께 되짚어야 한다. getSiteData()는 OneDrive(vault/object-views/site-data.json, Graph) -> 로컬hsol-info-blob/vault/object-views/site-data.json-> 커밋된src/data/site.ts의HSOL_DATA순으로 폴백한다.- 2026-09-27 부터 콘텐츠의 정본이자 유일한 저장소는 개인 OneDrive 의
hsol-info-blob폴더다(/Users/hsol/OneDrive/hsol-info-blob). GitHubhsol-info-blob저장소, 서브모듈, Vercel Blob 은 쓰지 않는다. 로컬의hsol-info-blob/는 git 이 추적하지 않는 링크 폴더로,vault등은 OneDrive 를,scripts,newsletter-ops,ask-hansol-seeding은 이 저장소의ops/를 가리킨다. 사이트 런타임은src/lib/onedrive/graph.ts로 OneDrive 를 직접 읽는다(site-data, 원페이저, 이력서 PDF, Ask Hansol 문맥,/files/<키>=assets/<키>). 토큰은 Neononedrive_token에 암호화해 두고 런타임과 CI 가 같이 갱신한다(ops/scripts/lib/onedrive-token.mjs).watch-onedrive.yml(매시,ops/scripts/watch-onedrive.mjs)이 vault 변경을 감지해 뉴스룸 기사 Neon 미러와 dbId 역기록을 하고, 바뀐 경로 목록과 함께build-with-vault-refresh.yml을 디스패치한다. 빌드는 rclone 으로 vault 를hsol-info-blob/vault에 받아 쓰고(ops/scripts/with-onedrive.mjs), 바뀐 생성물(site-data.json,onepager-*.html,onepager-*.pdf,hsol-info-parent-ref.json)을 OneDrivevault/object-views/에 직접 쓴다(ops/scripts/publish-generated.mjs).content:refresh:claude실패 시generated/content-refresh-failures/를 아티팩트로 올린다. scripts/refresh-site-data-with-claude.ts는ANTHROPIC_MAX_TOKENS(기본 64000)로 출력 상한을 두며, 응답이stop_reason=max_tokens로 잘리면 파싱하지 않고 실패·덤프한다. 실패 본문은 기본적으로generated/content-refresh-failures/에 쓴다.tool_use페이로드에서 문자열로 감긴 JSON·루트 래핑(data/siteData등)·모델이 자주 내는 대체 키 형태는 정규화·매핑 후 스키마 검증을 다시 시도한다.- Ask Hansol API(
src/app/api/ask-hansol/route.ts)는 시스템 프롬프트에vault/README.md(vault 탐색·읽기 절차용 지침이며 답변 사실을 채우는 발췌 문서가 아님)와vault/object-views/AI-클론-운영-매뉴얼.md를 넣는다. vault 원본은 개인 OneDrivehsol-info-blob/vault/이고src/lib/onedrive/graph.ts가 Graph 로 읽는다(토큰은 Neononedrive_token). Claude는vault_lookup으로 본문 근거 문서를 추가 조회한다. - Ask Hansol API가 서버 함수로 실제 배포되는 환경에서는 세션 히스토리 GET이 DB를 읽으므로
export const dynamic = "force-dynamic"으로 두고, 클라이언트 히스토리·질문fetch에는cache: "no-store"를 쓴다(force-static이면 GET이 빌드·CDN에 고정되어 대화 목록이 비어 보일 수 있다). 순수 정적 export만 쓰는 빌드와는 타깃이 다를 수 있다. - Ask Hansol 답변 URL 처리는
src/lib/ask-hansol/answer-linkify.ts에서 마크다운·괄호 등을 평문으로 정리한 뒤 클라이언트에서 분리 렌더하며,https/http뿐 아니라www.접두·스킴 없는 호스트 형태·mailto:등도 링크로 인식한다. - Preview Deployment Protection 환경에서
ask-hansol-selection이ask-hansol로 서버-서버 재호출할 때는 원 요청의cookie/authorization을 전달해야 내부 호출 401을 피할 수 있다. - 포트폴리오 등에서 쓰는 대형 Mermaid
classDef클래스명은 페이지 전역 CSS(예:.view)와 선택자 충돌하지 않도록mermaid-같은 접두를 둔다.siteData.career[].points는 항목당 3개 이상 5개 이하만 유효하다(Zod 및 refresh 폴백이 맞춘다). - 페르소나 페이지(hire·collab·builder·curious)는
composition.pages[key].nodes트리로 렌더되고(BlockList → composition 우선 → ComposeRenderer), 이 트리는scripts/refresh-site-data-with-claude.ts의generateComposition이 한 페이지씩 독립 호출로 생성한다. 페이지 간 통일성이 어긋나면(예: /collab만 헤더가 다르게 렌더) 산출물(site-data.json)을 직접 손대지 말고 이 생성기(프롬프트 원칙 #6 또는enforceCompositionSkeleton/ensureRequiredComposeNodes같은 결정적 가드레일)에서 고친다. 섹션 헤더 규약(네 페이지 동일, 프롬프트 #6에 명문화):Sectionprops =title(한국어만, 제목 안 괄호 영문 금지) +eyebrow(영문 kicker 한 곳에만) +num("01" 2자리, § 직접 금지 —SecHead가 "§ " 자동 부착) +dataSection(필수 소문자 슬러그, Ask '지금 보는 섹션' 추적용).meta는 헤더 우측에 라벨을 또 렌더해 eyebrow와 이중 표기되므로 쓰지 않는다. /sitemap.xml은 빌드 산출물이 아니라 런타임 라우트다.src/app/sitemap.xml/route.ts와 확장자 없는 하위호환src/app/sitemap/route.ts가src/lib/seo/sitemap.ts의buildMainSitemapXml()을 불러 응답하며(revalidate = 3600),next-sitemap도postbuild도 쓰지 않는다. URL 목록의 단일 출처는src/content/site-structure.ts의SITE_STRUCTURE[key].inSitemap이고(/architecture는inSitemap: false라 빠진다), 여기에sitemap.ts의EXTRA_ROUTES(/resume) 와SUBDOMAIN_ENTRIES(blog.hsol.info,news.hsol.info루트)가 더해진다. 뉴스룸 개별 기사는src/app/news/sitemap이 따로 책임진다.<urlset>은 sitemaps.org 단일 네임스페이스만 사용한다(deprecatedxmlns:mobile등 next-sitemap 기본 네임스페이스는 GSC 진단 노이즈 원인이라 제거). 루트 URL은<link rel="canonical">매칭을 위해 trailing slash 없이https://hsol.info로 둔다.robots는src/app/robots.ts하나뿐이고(정적public/robots.txt없음), Yandex 전용host디렉티브를 두지 않는다.