<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Sveltekitblog Engine</title>
        <link>https://sveltekitblogblog.pages.dev</link>
        <description>새로운 블로그에 오신 것을 환영합니다. (설정에서 이 문구를 수정하세요.)</description>
        <language>ko</language>
        <atom:link href="https://sveltekitblogblog.pages.dev/rss.xml" rel="self" type="application/rss+xml"/>
        <lastBuildDate>Sat, 20 Jun 2026 05:30:09 GMT</lastBuildDate>
        <item>
            <title><![CDATA[블로그 및 관리자 기능 통합 소개]]></title>
            <link>https://sveltekitblogblog.pages.dev/general-guide/general-integration-guide</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/general-guide/general-integration-guide</guid>
            <pubDate>Tue, 16 Jun 2026 15:10:13 GMT</pubDate>
            <description><![CDATA[블로그 앱의 레이아웃과 소통 기능, 그리고 관리자 모드의 다국어 글쓰기 및 실시간 디자인 설정 등 시스템이 제공하는 주요 기능 문서들을 통합 소개합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="블로그-및-관리자-기능-통합-소개">📖 블로그 및 관리자 기능 통합 소개</h1>
<p>본 문서는 블로그 서비스 및 관리자 기능(어드민)의 핵심 구성을 한눈에 파악할 수 있도록 개별 소개 문서들을 연계하여 안내합니다.</p>
<p><em>참고: 각 기능의 세부적인 연동 방법 및 상세 매뉴얼은 추후 별도 포스팅을 통해 순차적으로 안내될 예정입니다.</em></p>
<hr>
<h2 id="사용자-기능-소개-목록">📂 사용자 기능 소개 목록</h2>
<ul>
<li><strong>관리자(어드민) 기능 소개</strong><ul>
<li><strong><a href="../admin-guide/admin-install-and-deploy">CMD 원클릭 설치 및 배포 소개</a></strong>: 명령어 한 줄로 블로그 인프라를 클라우드에 배포하고 복구하는 방법에 관한 개요입니다.</li>
<li><strong><a href="../admin-guide/admin-getting-started">관리자 초기 설정 및 로그인</a></strong>: 초기 비밀번호 로그인, 접속 허용 IP(화이트리스트) 관리 및 환경설정 개요를 다룹니다.</li>
<li><strong><a href="../admin-guide/admin-core-features">어드민 핵심 기능 및 듀얼 에디터 소개</a></strong>: HTML 비주얼 에디터와 마크다운 에디터를 전환하며 글을 쓰고, 기기별 레이아웃 위젯을 배치하는 방식을 소개합니다.</li>
<li><strong><a href="../admin-guide/admin-design-editor">디자인 에디터 및 배경 설정 소개</a></strong>: 블로그 테마 색상 및 단색, 그라디언트, 배경 이미지와 캔버스 스크립트 등 배경 설정에 관한 내용을 제공합니다.</li>
<li><strong><a href="../admin-guide/admin-faq">관리자 자주 묻는 질문 (FAQ)</a></strong>: 백업/복원 원인 파악 및 이미지 저장소 설정 시 주요 점검 사항을 확인합니다.</li>
</ul>
</li>
<li><strong>블로그 기능 소개</strong><ul>
<li><strong><a href="../blog-guide/blog-guideblog-getting-started">블로그 첫 화면 구성 및 로그인</a></strong>: 블로그 화면 레이아웃 구성과 이메일/소셜 가입 방식을 소개합니다.</li>
<li><strong><a href="../blog-guide/blog-guideblog-core-features">독자 소통 및 다국어 서비스 소개</a></strong>: 포스트 본문의 다국어 실시간 전환 방식과 댓글, 비밀 방명록을 통한 소통 구조를 다룹니다.</li>
<li><strong><a href="../blog-guide/blog-guideblog-faq">독자 자주 묻는 질문 (FAQ)</a></strong>: 회원 탈퇴 시 작성 데이터 처리 원칙 및 이용 제한 조치에 관해 확인합니다.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="블로그-관리-기본-프로세스">🚀 블로그 관리 기본 프로세스</h2>
<p>블로그 관리자 권한을 설정하고 글 작성을 시작하는 기본 흐름의 개요입니다.</p>
<h3 id="1-ip-허용-목록-적용-및-로그인">1. IP 허용 목록 적용 및 로그인</h3>
<ul>
<li>처음 관리자 화면에 접근 시 보안을 위해 본인의 인터넷 공인 IP가 허용 목록(<code>ALLOWED_IP</code>)에 주입되어 있어야 차단 페이지(403)를 우회할 수 있습니다.</li>
<li>로그인 화면에서 설정해 둔 마스터 비밀번호를 입력해 접속합니다.</li>
</ul>
<h3 id="2-다국어-글-일괄-저장">2. 다국어 글 일괄 저장</h3>
<ul>
<li>글쓰기 메뉴에서 제공되는 다국어 탭을 전환하며 본문을 각각 기재한 후, 하단 저장 버튼을 클릭해 데이터베이스에 다국어 글 묶음을 일괄 저장합니다.</li>
</ul>
<h3 id="3-실시간-테마-적용">3. 실시간 테마 적용</h3>
<ul>
<li>디자인 에디터에서 테마 색상, 폰트 종류, 배경 효과(Canvas, 이미지 등)를 저장하면 재빌드 과정 없이 방문자 브라우저 화면에 실시간으로 즉시 적용됩니다.</li>
</ul>
]]></content:encoded>
            <category>통합 가이드</category>
        </item>
        <item>
            <title><![CDATA[독자 정책 및 자주 묻는 질문 (FAQ)]]></title>
            <link>https://sveltekitblogblog.pages.dev/blog-guide/blog-faq</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/blog-guide/blog-faq</guid>
            <pubDate>Tue, 16 Jun 2026 15:09:13 GMT</pubDate>
            <description><![CDATA[회원 탈퇴 시의 작성 데이터(댓글, 방명록) 처리 정책 및 이용 제한 정책의 기본 원칙을 소개합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="독자-정책-및-자주-묻는-질문-faq">❓ 독자 정책 및 자주 묻는 질문 (FAQ)</h1>
<p>본 문서는 블로그 서비스 이용 시 발생할 수 있는 회원 탈퇴에 따른 개인정보 및 작성 데이터 처리 방식, 이용 제한 정책 등의 기본 원칙을 소개합니다.</p>
<hr>
<h2 id="q1-회원-탈퇴-시-기존에-작성했던-댓글과-방명록은-어떻게-되나요">🚪 Q1. 회원 탈퇴 시 기존에 작성했던 댓글과 방명록은 어떻게 되나요?</h2>
<p>블로그 시스템은 독자분의 개인정보 보호와 사이트 내 대화 흐름의 무결성을 동시에 유지하기 위해 **&#39;작성자 익명화 처리 정책&#39;**을 적용하고 있습니다.</p>
<h3 id="탈퇴-시-개인정보-처리-원칙">💡 탈퇴 시 개인정보 처리 원칙</h3>
<ol>
<li><strong>개인 식별 정보 삭제</strong>:<ul>
<li>회원 탈퇴 진행 시 로그인 이메일 주소, 소셜 프로필 이미지, 닉네임 등 회원을 식별할 수 있는 고유 데이터는 데이터베이스에서 즉시 삭제됩니다.</li>
</ul>
</li>
<li><strong>작성 데이터 보존</strong>:<ul>
<li>작성하셨던 본문 댓글과 방명록 글은 기존 토론 맥락과 대화 흐름을 보존하기 위해 텍스트 내용은 화면에 유지됩니다.</li>
</ul>
</li>
<li><strong>닉네임 익명화 처리</strong>:<ul>
<li>작성자 닉네임과 계정 간의 연결 정보가 해제되며, 작성자 표시명은 **&quot;알 수 없음&quot;**으로 자동 일괄 전환됩니다. 이에 따라 이전 작성자가 실제로 누구였는지 시스템적으로 역추적하는 것이 방지됩니다.</li>
</ul>
</li>
</ol>
<ul>
<li><em>참고: 관리자가 회원 정보를 직접 완전히 삭제하는 경우에는 작성하셨던 댓글과 글이 함께 지워질 수 있습니다.</em></li>
</ul>
<hr>
<h2 id="q2-댓글-등록-등의-활동이-제한되거나-안내-문구가-나타납니다">🚫 Q2. 댓글 등록 등의 활동이 제한되거나 안내 문구가 나타납니다.</h2>
<p>스팸 성격의 광고나 비방 등 운영 정책을 위배하여 서비스 이용에 제한(Ban) 조치가 적용된 경우의 확인 사항입니다.</p>
<h3 id="이용-제한-적용-시-확인-사항">💡 이용 제한 적용 시 확인 사항</h3>
<ol>
<li><strong>기능 제한</strong>:<ul>
<li>이용 제한 조치가 적용되면 로그인은 유지되나, 댓글 작성, 대댓글 등록, 방명록 등록 등 사이트 내 직접적인 활동이 일시적으로 제한됩니다.</li>
</ul>
</li>
<li><strong>제한 정보 조회</strong>:<ul>
<li>제한 조치 적용 시, 화면 안내 메시지나 회원 정보란을 통해 구체적인 제한 사유와 제한 해제 시점(만료일)을 확인할 수 있습니다.</li>
</ul>
</li>
<li><strong>활동 재개</strong>:<ul>
<li>관리자가 임시로 지정한 제한 기간이 경과하거나 운영정책 검토를 통해 조치가 철회되는 경우, 이전 상태로 다시 정상적인 활동이 가능합니다.</li>
</ul>
</li>
</ol>
]]></content:encoded>
            <category>사용자 가이드</category>
        </item>
        <item>
            <title><![CDATA[블로그 핵심 기능 및 다국어 서비스 소개]]></title>
            <link>https://sveltekitblogblog.pages.dev/blog-guide/blog-core-features</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/blog-guide/blog-core-features</guid>
            <pubDate>Tue, 16 Jun 2026 15:08:16 GMT</pubDate>
            <description><![CDATA[다국어 본문 실시간 전환 및 미번역 시 대체 처리 로직, 계층형 댓글 구조와 비밀 방명록 등 블로그 서비스의 주요 사용자 기능을 소개합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="블로그-핵심-기능-및-다국어-서비스-소개">🌐 블로그 핵심 기능 및 다국어 서비스 소개</h1>
<p>본 문서는 일반 방문자가 블로그의 다국어 번역 글을 조회하고, 댓글 및 방명록을 통해 다른 독자들과 이야기를 나누는 핵심 기능의 명세를 소개합니다.</p>
<hr>
<h2 id="1-다국어-본문-실시간-전환-i18n">🌐 1. 다국어 본문 실시간 전환 (i18n)</h2>
<p>이 블로그는 메뉴나 버튼 등의 기본 UI뿐 아니라, <strong>작성된 포스트 본문 내용 자체</strong>도 여러 언어 버전으로 전환하여 읽을 수 있는 실시간 다국어 번역 뷰어를 제공합니다.</p>
<h3 id="동작-방식-및-특징">⚙️ 동작 방식 및 특징</h3>
<ul>
<li><strong>언어별 URL 라우팅</strong>: 상단 지구본 아이콘 또는 글 제목 옆의 언어 선택 버튼을 클릭하면, URL 주소에 언어 접두사(예: <code>/en</code>, <code>/ja</code>)가 붙으며 해당 언어의 전용 페이지로 즉시 라우팅됩니다. 기본 제공되는 언어(한국어, 영어, 일본어) 외에도, 관리자가 다국어 번역 사전(딕셔너리)을 추가 정의하면 새로운 외국어 버전을 제한 없이 추가로 발행할 수 있습니다.</li>
<li><strong>수동 작성 데이터 로드 (실시간 자동 번역이 아님)</strong>: 시스템이 텍스트를 기계적으로 실시간 자동 번역해 주는 것이 아닙니다. 작성자가 각 언어 탭에 번역된 포스트 본문 데이터를 직접 작성하여 개별 저장해 두면(외부 AI나 번역기로 가공하여 데이터베이스에 각각 등록), 방문자가 선택한 언어에 대응하는 포스트 데이터를 데이터베이스에서 정확하게 호출하여 화면에 렌더링하는 방식입니다.</li>
<li><strong>본문 및 메타데이터 동시 로드</strong>: 단순 텍스트 교체에 그치지 않고, 데이터베이스에 각 언어별로 등록된 제목, 요약, 태그, 본문 HTML이 완전히 선택된 언어의 개별 데이터로 교체되어 출력됩니다.</li>
<li><strong>미번역 글 대체(Fallback) 처리</strong>: 작성자가 특정 언어의 번역 글을 등록하지 않은 경우에는 방문자가 글을 읽지 못하는 상황을 방지하기 위해, 번역이 준비되지 않았다는 안내와 함께 기본 작성 언어(예: 한국어 본문)로 본문 내용을 대체하여 매끄럽게 보여줍니다.</li>
</ul>
<hr>
<h2 id="2-댓글-및-답글대댓글-기능">💬 2. 댓글 및 답글(대댓글) 기능</h2>
<p>각 게시글 하단에는 비로그인 방문자 또는 회원이 의견을 공유할 수 있는 댓글 영역이 배치되어 있습니다.</p>
<ul>
<li><strong>의견 공유</strong>: 로그인한 사용자는 댓글 입력란에 본문을 작성하고 등록하여 즉시 생각을 공유할 수 있습니다.</li>
<li><strong>계층형 답글(대댓글)</strong>: 특정 댓글 하단에 답글을 달 수 있어 토론 흐름을 트리 구조로 한눈에 알아보기 쉽게 정렬합니다.</li>
<li><strong>보안 및 무결성 유지</strong>: 본인이 작성한 댓글은 삭제가 가능합니다. 단, 이미 하위에 대댓글이 달린 댓글을 삭제하는 경우 전체 토론 맥락이 깨지는 것을 방지하기 위해 &quot;삭제된 댓글입니다.&quot;라는 대체 문구로 마스킹 처리되어 계층 구조를 보존합니다.</li>
</ul>
<hr>
<h2 id="3-방명록-및-비밀글-작성">📖 3. 방명록 및 비밀글 작성</h2>
<p>블로그 방명록 공간(<code>Guestbook</code>)을 통해 사이트 개설자와 소통할 수 있는 기능을 제공합니다.</p>
<h3 id="비밀-방명록-기능">⚙️ 비밀 방명록 기능</h3>
<ul>
<li><strong>비밀글 쓰기</strong>: 글 작성 시 <strong>[🔒 비밀글로 작성]</strong> 체크박스를 활성화하면 보안 글 작성이 가능합니다.</li>
<li><strong>노출 권한 차단</strong>: 비밀글로 저장된 방명록은 제3자(다른 방문자 또는 비로그인 타인)의 목록에는 노출되지 않고 완전히 배제됩니다.</li>
<li><strong>안전한 대화</strong>: 오직 해당 방명록을 작성한 본인(로그인 상태)과 사이트 관리자에게만 본문 내용이 보이며, 안전하게 소통을 나눌 수 있습니다.</li>
</ul>
]]></content:encoded>
            <category>사용자 가이드</category>
        </item>
        <item>
            <title><![CDATA[블로그 첫 화면 구성 및 로그인 시작하기]]></title>
            <link>https://sveltekitblogblog.pages.dev/blog-guide/blog-getting-started</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/blog-guide/blog-getting-started</guid>
            <pubDate>Tue, 16 Jun 2026 15:04:15 GMT</pubDate>
            <description><![CDATA[블로그 첫 화면의 기본 레이아웃 구성과 회원가입 및 로그인 방식의 개요를 소개합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="블로그-첫-화면-구성-및-로그인-시작하기">🌐 블로그 첫 화면 구성 및 로그인 시작하기</h1>
<p>본 문서는 블로그(<code>apps/blog</code>) 첫 화면의 레이아웃 구성과 기본적인 회원가입 및 로그인 방식을 간략히 소개합니다.</p>
<hr>
<h2 id="1-블로그-화면-구성-및-레이아웃">🎨 1. 블로그 화면 구성 및 레이아웃</h2>
<p>블로그 화면은 방문자가 정보를 신속하게 찾을 수 있도록 직관적인 레이아웃(헤더, 본문, 사이드바, 푸터)으로 설계되어 있습니다.</p>
<ol>
<li><strong>상단 네비게이션 헤더 (Header)</strong>:<ul>
<li><strong>사이트 로고</strong>: 클릭 시 첫 홈화면으로 복귀합니다.</li>
<li><strong>단축 메뉴 바</strong>: 카테고리 바로가기나 외부 채널 연결 등 주요 링크들이 나열됩니다.</li>
<li><strong>다국어 스위칭</strong>: 지구본 아이콘 클릭 시 사이트 전체의 메뉴 언어 및 게시글 번역본이 실시간으로 전환되어 표시됩니다.</li>
</ul>
</li>
<li><strong>사이드바 영역 (Sidebar)</strong>:<ul>
<li>PC 화면에서는 카테고리 목록, 블로그 운영자 프로필 카드, 인기 태그 등이 노출되어 독자의 탐색을 돕습니다.</li>
<li>모바일 기기 접속 시에는 본문 가독성을 위해 자동으로 감춰집니다.</li>
</ul>
</li>
<li><strong>메인 콘텐츠 영역 (Main Content)</strong>:<ul>
<li>최신 발행 게시글 목록과 카테고리 필터가 카드 디자인 형식으로 배치되어 있습니다.</li>
</ul>
</li>
</ol>
<hr>
<h2 id="2-회원가입-및-로그인">🔑 2. 회원가입 및 로그인</h2>
<p>댓글 작성 및 방명록 참여를 위한 계정 생성과 로그인 기능을 지원합니다.</p>
<h3 id="로그인-및-가입-지원-방식">⚙️ 로그인 및 가입 지원 방식</h3>
<ul>
<li><strong>기본 이메일 로그인/가입 (Default)</strong>:<ul>
<li>설치 직후 기본 활성화되는 로그인 방식입니다. 이메일 주소, 디스플레이 네임(닉네임), 그리고 비밀번호를 등록하여 신규로 가입할 수 있으며, 가입 즉시 자동 로그인이 적용됩니다.</li>
</ul>
</li>
<li><strong>소셜 로그인 (Better-Auth)</strong>:<ul>
<li>내부적으로 Better-Auth 엔진을 탑재하고 있어 구글(Google), 깃허브(GitHub), 카카오, 네이버 등을 포함한 <strong>총 21종의 소셜 프로바이더 로그인</strong>을 지원합니다.</li>
<li>다만, 소셜 로그인은 사이트 구축 후 관리자가 각 소셜 플랫폼에서 획득한 클라이언트 ID 및 비밀키를 설정 환경변수에 수동으로 주입해야만 로그인 화면에 노출되고 작동합니다. (소셜 프로바이더별 구체적인 연동 가이드는 추후 별도 문서로 안내됩니다.)</li>
</ul>
</li>
<li><strong>로그인 상태 표시</strong>:<ul>
<li>로그인이 완료되면 오른쪽 위 버튼이 사용자의 프로필 이미지 아이콘과 마이페이지 바로가기로 변경됩니다.</li>
<li><em>참고: 사용자 프로필 사진을 실제 연동하여 표시하는 기능은 현재 완벽히 작동하지 않을 수 있으며, 기본 이미지 아이콘 등으로 대체 표시될 수 있습니다.</em></li>
</ul>
</li>
</ul>
]]></content:encoded>
            <category>사용자 가이드</category>
        </item>
        <item>
            <title><![CDATA[어드민 자주 묻는 질문 (FAQ)]]></title>
            <link>https://sveltekitblogblog.pages.dev/admin-guide/admin-faq</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/admin-guide/admin-faq</guid>
            <pubDate>Tue, 16 Jun 2026 15:01:11 GMT</pubDate>
            <description><![CDATA[데이터 백업/복원, 외부 이미지 저장소 설정 시의 오류 원인 및 대시보드 통계 차트 설정 등을 확인합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="어드민-자주-묻는-질문-faq">❓ 어드민 자주 묻는 질문 (FAQ)</h1>
<p>본 문서는 어드민 페이지 관리 시 발생할 수 있는 백업 복원, 외부 이미지 저장소 연동, 대시보드 통계 관련 자주 묻는 질문의 원인과 확인 사항을 안내합니다.</p>
<hr>
<h2 id="q1-백업-데이터-가져오기restore-시-오류가-발생합니다">🗄️ Q1. 백업 데이터 가져오기(Restore) 시 오류가 발생합니다.</h2>
<p>백업 파일 선택 후 복원 진행 시 오류가 발생하는 경우의 점검 사항입니다.</p>
<h3 id="주요-점검-사항">💡 주요 점검 사항</h3>
<ol>
<li><strong>백업 파일 손상</strong>:<ul>
<li>다운로드 중 텍스트가 정상적으로 저장되지 않은 경우 복원에 실패할 수 있습니다. <code>.json</code> 파일을 메모장 등으로 열어 온전한 데이터 형식인지 확인합니다.</li>
</ul>
</li>
<li><strong>메뉴 경로 불일치</strong>:<ul>
<li>데이터 종류에 맞는 복원 메뉴를 사용해야 합니다. 포스트 데이터는 <strong><code>콘텐츠 백업</code></strong> 메뉴의 <strong><code>데이터 백업 및 복원</code></strong> 섹션, 이미지 미디어 파일은 <strong><code>콘텐츠 백업</code></strong> 메뉴의 <strong><code>미디어 백업 및 복원</code></strong> 섹션, 전체 시스템 데이터는 <strong><code>사이트 설정</code></strong> 메뉴의 <strong><code>시스템 전체 백업 및 복원</code></strong> 섹션에서 복원을 수행해야 합니다.</li>
</ul>
</li>
<li><strong>데이터베이스(D1) 연결 바인딩</strong>:<ul>
<li>Cloudflare의 데이터베이스(D1) 연결 정보가 정상적으로 연동되어 있는지 관리 콘솔에서 확인합니다.</li>
</ul>
</li>
</ol>
<hr>
<h2 id="q2-이미지-저장소-변경-후-업로드-또는-표시-오류가-발생합니다">📂 Q2. 이미지 저장소 변경 후 업로드 또는 표시 오류가 발생합니다.</h2>
<p>기본 저장소(KV)에서 R2, Supabase, ImageKit 등으로 변경한 후 업로드 오류가 발생하거나 이미지가 표시되지 않는 현상에 대한 원인 분석입니다.</p>
<h3 id="주요-점검-사항-1">💡 주요 점검 사항</h3>
<ol>
<li><strong>Cloudflare R2</strong>:<ul>
<li>프로젝트 설정에 <code>IMAGES</code> R2 버킷 바인딩이 연결되어 있는지 확인합니다 (<code>wrangler.json</code>).</li>
</ul>
</li>
<li><strong>Supabase Storage</strong>:<ul>
<li>입력한 API 주소(<code>supabase_storage_url</code>), 서비스 롤 키(<code>supabase_storage_key</code>), 버킷명(<code>supabase_storage_bucket</code>)의 정확성을 확인합니다. 특히 버킷의 접근 권한이 **Public(공개)**으로 설정되어야 이미지가 정상 노출됩니다.</li>
</ul>
</li>
<li><strong>ImageKit.io</strong>:<ul>
<li>엔드포인트 주소(<code>imagekit_url_endpoint</code>)의 형식을 확인하고, 도메인 간 보안 차단(CORS) 설정을 점검합니다.</li>
</ul>
</li>
<li><strong>업로드 크기 제한</strong>:<ul>
<li>에지 서버 환경의 1회 전송 용량 제한으로 인해 대용량 이미지는 업로드에 실패할 수 있으므로, 원본 이미지의 크기를 조정하여 업로드합니다.</li>
</ul>
</li>
</ol>
<hr>
<h2 id="q3-대시보드-통계-그래프가-데모-데이터로만-표시됩니다">📊 Q3. 대시보드 통계 그래프가 데모 데이터로만 표시됩니다.</h2>
<p>대시보드 메인 화면에 실제 방문 트래픽 통계 대신 데모 데이터가 표시되는 경우의 확인 사항입니다.</p>
<h3 id="주요-점검-사항-2">💡 주요 점검 사항</h3>
<ul>
<li><strong>원인</strong>: 구글 애널리틱스 4(GA4) API 환경변수가 입력되지 않았거나 비정상적인 경우, 오류 방지를 위해 임시 데모 데이터가 대체 표시됩니다.</li>
<li><strong>설정 방법</strong>: Cloudflare Pages 설정에 아래 환경변수를 입력하고 다시 배포합니다.<ul>
<li><code>GA4_PROPERTY_ID</code>: 구글 애널리틱스 속성 ID</li>
<li><code>GA4_CLIENT_EMAIL</code>: 구글 클라우드 서비스 계정 이메일</li>
<li><code>GA4_PRIVATE_KEY</code>: 구글 서비스 계정 비공개 키</li>
</ul>
</li>
<li><strong>구글 애드센스</strong>: 수익 대시보드 연동을 원할 경우 <code>ADSENSE_ACCOUNT_ID</code> 환경변수 키 값이 바르게 입력되었는지 확인합니다.</li>
</ul>
]]></content:encoded>
            <category>관리자 가이드</category>
        </item>
        <item>
            <title><![CDATA[실시간 디자인 에디터 및 배경 연출 소개]]></title>
            <link>https://sveltekitblogblog.pages.dev/admin-guide/admin-design-editor</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/admin-guide/admin-design-editor</guid>
            <pubDate>Tue, 16 Jun 2026 14:55:17 GMT</pubDate>
            <description><![CDATA[재빌드와 재배포 없는 1초 실시간 테마 반영]]></description>
            <content:encoded><![CDATA[<h1 id="실시간-디자인-에디터-및-배경-연출-소개">🎨 실시간 디자인 에디터 및 배경 연출 소개</h1>
<p>본 문서는 재빌드 및 재배포 없이 테마 설정을 실시간으로 반영하는 시스템과 4가지 배경 설정(단색, 그라디언트, 배경 이미지, 커스텀 자바스크립트 캔버스)에 대한 기본 구성을 소개합니다.</p>
<hr>
<h2 id="1-실시간-디자인-에디터-개요">🌌 1. 실시간 디자인 에디터 개요</h2>
<p>디자인 에디터에서 설정값을 변경하고 저장할 때 블로그 서버나 CDN 서비스를 다시 빌드하고 배포할 필요가 전혀 없습니다.<br>저장 즉시 데이터베이스가 갱신되며, 방문자의 브라우저 화면에 <strong>CSS 변수와 배경 렌더링 모듈이 1초 만에 실시간으로 반영</strong>됩니다.</p>
<h3 id="테마-기본-설정-항목">🎨 테마 기본 설정 항목</h3>
<ul>
<li><strong>기본 색상 구성</strong>: 주 테마 색상(Primary), 보조 색상(Secondary), 본문 글자 색상(Text), 포인트 강조 색상(Accent), 카드 및 위젯 배경(Card Bg), 테두리 색상(Border) 등을 조절할 수 있습니다.</li>
<li><strong>레이아웃 세부 수치</strong>: 좌우 여백(Side Margin), 전체 화면 최대 가로 폭(Max Width), 카드 모서리 둥글기(Border Radius), 입체감을 주는 그림자 효과(Box Shadow)를 지원합니다.</li>
<li><strong>타이포그래피 설정</strong>: Google Fonts 목록에서 원하는 글꼴 이름을 기입해 서체를 적용하고, 본문 폰트 종류와 기본 글자 크기(Base Font Size)를 설정할 수 있습니다.</li>
</ul>
<hr>
<h2 id="2-기기별-독립-위젯-배치">🧱 2. 기기별 독립 위젯 배치</h2>
<p>레이아웃 설계 시 마우스 드래그 앤 드롭으로 위젯의 위치와 순서를 지정할 수 있으며, 접속하는 독자의 기기 크기에 맞춰 레이아웃을 다르게 구성할 수 있는 필터링 기능을 제공합니다.</p>
<ul>
<li><strong>Desktop (데스크톱 전용)</strong>: 화면이 넓은 PC 환경에서만 해당 위젯(예: 태그 클라우드, 카테고리 트리 등)을 출력합니다. 모바일 접속 시에는 HTML 단계에서 요소를 사전에 제외하여 로딩 속도를 유지해 줍니다.</li>
<li><strong>Mobile (모바일 전용)</strong>: 데스크톱에서는 보이지 않고, 스마트폰 화면 크기에서만 모바일 친화적으로 단독 출력되도록 제한합니다.</li>
</ul>
<hr>
<h2 id="3-4가지-배경-설정-종류">🌈 3. 4가지 배경 설정 종류</h2>
<p>블로그 전체의 감성을 완성하는 배경 화면은 총 4가지 타입을 지원합니다.</p>
<h3 id="solid-단색-배경">① Solid (단색 배경)</h3>
<ul>
<li>선호하는 색상의 헥스(HEX) 코드(예: <code>#3b82f6</code>)나 HSL 색상 코드를 지정하여 가장 깔끔하고 포스트 본문에 집중하기 좋은 화면을 만듭니다.</li>
</ul>
<h3 id="gradient-그라디언트-배경">② Gradient (그라디언트 배경)</h3>
<ul>
<li><strong>그라디언트 빌더(Gradient Builder)</strong> 도구를 사용하여 여러 컬러가 자연스럽게 섞이는 선형 그라디언트를 구성합니다.</li>
<li><strong>각도 조절(Direction)</strong> 슬라이더와 **색상 정지점(Stops)**을 마우스로 추가하고 이동하며 시작색, 중간 경유색, 종점색을 배합할 수 있습니다.</li>
</ul>
<h3 id="image-배경-이미지-amp-글래스모피즘-필터-조합">③ Image (배경 이미지 &amp; 글래스모피즘 필터 조합)</h3>
<ul>
<li>배경으로 사용할 사진의 주소(URL)를 입력하거나, 업로드(Upload) 버튼을 사용해 미디어 파일을 보관함에 추가합니다.</li>
<li><strong>업로드 이미지 최적화</strong>: 이미지를 등록하면 시스템이 WebP 형식으로 자동 변환하여 로딩 성능 저하를 방지합니다.</li>
<li><strong>글래스모피즘 효과</strong>: 배경 이미지가 텍스트 가독성을 저해하지 않도록, 아래의 제어 설정을 활용해 반투명 유리창 스타일을 구현할 수 있습니다.</li>
</ul>
<table>
<thead>
<tr>
<th align="left">설정 항목</th>
<th align="center">권장 조작 범위</th>
<th align="left">상세 설명</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>배경 블러 (Glass Blur)</strong></td>
<td align="center"><code>5px ~ 15px</code></td>
<td align="left">글자가 놓이는 콘텐츠 카드 하단에 투명한 유리 재질 느낌의 필터를 입힙니다.</td>
</tr>
<tr>
<td align="left"><strong>유리창 틴트 농도 (Overlay Opacity)</strong></td>
<td align="center"><code>10% ~ 30%</code></td>
<td align="left">유리창 뒤편에 깔리는 반투명 마스크의 불투명도를 결정합니다.</td>
</tr>
<tr>
<td align="left"><strong>유리창 틴트 색상 (Overlay Color)</strong></td>
<td align="center"><code>#000000</code> 또는 <code>#ffffff</code></td>
<td align="left">마스크 색상을 어둡게(Dark) 혹은 밝게(Light) 연출하여 글자의 선명한 대비(Contrast)를 확보합니다.</td>
</tr>
</tbody></table>
<h3 id="custom-javascript-커스텀-자바스크립트-및-canvas-배경">④ Custom JavaScript (커스텀 자바스크립트 및 Canvas 배경)</h3>
<ul>
<li>방문자 브라우저에서 배경용 Canvas 애니메이션을 직접 구동할 수 있도록 커스텀 자바스크립트 입력을 지원합니다.</li>
<li>캔버스 요소(<code>canvas id=&quot;bg-canvas&quot;</code>)에 직접 렌더링을 제어할 수 있으며, 이와 연동되는 세부 보안 및 절전 시스템은 아래 <strong>[4. 커스텀 자바스크립트 연동 사양]</strong> 에서 설명합니다.</li>
</ul>
<hr>
<h2 id="4-커스텀-자바스크립트-연동-사양">⚡ 4. 커스텀 자바스크립트 연동 사양</h2>
<p>보안 사고를 예방하고 모바일 기기 배터리를 보존하기 위해 아래와 같은 격리 정책 및 절전 시스템이 적용됩니다.</p>
<h3 id="격리-보안-시스템-sandbox-amp-csp">🔒 격리 보안 시스템 (Sandbox &amp; CSP)</h3>
<p>블로그 어드민일지라도 악성 스크립트 유입으로 인한 보안 사고를 막기 위해 다음과 같은 보안 정책이 상시 가동됩니다.</p>
<ol>
<li><strong>격리된 Sandbox 구조</strong>: 캔버스 코드는 오직 스크립트 실행만 인가된 격리된 <code>iframe</code> 내부에서 구동됩니다. 부모 페이지의 DOM 노드나 로그인 정보 등에 접근하여 데이터를 탈취하거나 위변조하는 동작이 기술적으로 차단됩니다.</li>
<li><strong>콘텐츠 보안 정책 (CSP) 제한</strong>: 외부 서버와의 네트워크 통신 및 외부 스크립트 호출이 전면 차단됩니다. 따라서 외부 서버로 데이터를 유출하는 것이 불가능합니다.</li>
<li><strong>JS API 허용 차단</strong>: 보안을 해칠 수 있는 <code>fetch</code>, <code>XMLHttpRequest</code>, <code>WebSocket</code>, <code>eval</code>, <code>new Function</code>, <code>document.cookie</code>, <code>localStorage</code> 등의 API가 감지되면 보안 필터(<code>jsValidator.ts</code>)가 이를 자동으로 주석 처리(<code>/* f_e_t_c_h (blocked) */</code>)하여 무력화합니다.</li>
</ol>
<h3 id="배터리-보존-및-절전-기술">🔋 배터리 보존 및 절전 기술</h3>
<ul>
<li><strong>화면 밖 자동 일시정지</strong>: 사용자가 화면을 스크롤하여 배경 애니메이션이 완전히 시야에서 사라지면, 브라우저가 CPU/GPU를 낭비하지 않도록 프레임 렌더링 루프를 <strong>일시정지(Sleep)</strong> 상태로 전환합니다. 화면에 다시 노출되면 즉각 재생(Resume)됩니다.</li>
<li><strong>모바일 프레임 스로틀링</strong>: 스마트폰이나 태블릿 등 모바일 기기로 접속하는 경우 기기 발열 방지를 위해 기본적으로 애니메이션이 정지됩니다. <strong>&quot;모바일 기기에서도 애니메이션 구동&quot;</strong> 옵션을 명시적으로 체크하면 실행할 수 있으며, 이때 성능에 부담이 가지 않도록 파티클 개수를 자동으로 축소 제어하는 매개변수가 연동됩니다.</li>
</ul>
<hr>
<h2 id="5-예제-스크립트-코드-3종">📝 5. 예제 스크립트 코드 3종</h2>
<p>배경 설정 메뉴에서 **[Custom JavaScript]**를 선택하고, 아래 코드 중 하나를 복사하여 적용할 수 있습니다.</p>
<blockquote>
<p>[!NOTE]<br>스크립트를 작성할 때에는 배경을 그릴 대상 캔버스 요소를 찾기 위해 반드시 <code>document.getElementById(&#39;bg-canvas&#39;)</code> 아이디명을 사용하여 컨텍스트를 획득해 주시기 바랍니다.</p>
</blockquote>
<h3 id="예제-a-겨울-눈송이-snowfall">❄️ 예제 A. 겨울 눈송이 (Snowfall)</h3>
<p>화면 위에서 눈송이들이 아래로 천천히 떨어지는 배경 애니메이션입니다.</p>
<pre><code class="language-javascript">(function() {
  const canvas = document.getElementById(&#39;bg-canvas&#39;);
  if (!canvas) return;
  const ctx = canvas.getContext(&#39;2d&#39;);
  
  let width = canvas.width = window.innerWidth;
  let height = canvas.height = window.innerHeight;
  
  // 모바일 스로틀 감지
  const divisor = (window.bgConfig &amp;&amp; window.bgConfig.mobileThrottleDivisor) || 1;
  const maxSnowflakes = Math.floor(100 / divisor);
  const snowflakes = [];
  
  class Snowflake {
    constructor() {
      this.reset();
      this.y = Math.random() * height; // 초기 임의 고도 설정
    }
    
    reset() {
      this.x = Math.random() * width;
      this.y = -10;
      this.radius = Math.random() * 3 + 1;
      this.speed = Math.random() * 1 + 0.5;
      this.opacity = Math.random() * 0.6 + 0.2;
    }
    
    update() {
      this.y += this.speed;
      // 부드러운 흔들림 주기
      this.x += Math.sin(this.y / 30) * 0.5;
      
      if (this.y &gt; height || this.x &lt; 0 || this.x &gt; width) {
        this.reset();
      }
    }
    
    draw() {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      ctx.fillStyle = `rgba(25, 25, 255, ${this.opacity})`;
      ctx.fill();
    }
  }
  
  // 파티클 생성
  for (let i = 0; i &lt; maxSnowflakes; i++) {
    snowflakes.push(new Snowflake());
  }
  
  function animate() {
    ctx.clearRect(0, 0, width, height);
    
    for (let i = 0; i &lt; snowflakes.length; i++) {
      snowflakes[i].update();
      snowflakes[i].draw();
    }
    requestAnimationFrame(animate);
  }
  
  // 창 크기 조절 이벤트
  window.addEventListener(&#39;resize&#39;, () =&gt; {
    width = canvas.width = window.innerWidth;
    height = canvas.height = window.innerHeight;
  });
  
  animate();
})();
</code></pre>
<hr>
<h3 id="예제-b-별자리-연결망-constellation-network">🕸️ 예제 B. 별자리 연결망 (Constellation Network)</h3>
<p>파티클 노드들이 무작위로 부유하며, 서로 가까워지면 얇은 선으로 연결되어 그물 형태를 구성하는 배경 애니메이션입니다.</p>
<pre><code class="language-javascript">(function() {
  const canvas = document.getElementById(&#39;bg-canvas&#39;);
  if (!canvas) return;
  const ctx = canvas.getContext(&#39;2d&#39;);
  
  let width = canvas.width = window.innerWidth;
  let height = canvas.height = window.innerHeight;
  
  const divisor = (window.bgConfig &amp;&amp; window.bgConfig.mobileThrottleDivisor) || 1;
  const particleCount = Math.floor(80 / divisor);
  const particles = [];
  const connectionDistance = 100;
  
  class Particle {
    constructor() {
      this.x = Math.random() * width;
      this.y = Math.random() * height;
      this.vx = (Math.random() - 0.5) * 0.8;
      this.vy = (Math.random() - 0.5) * 0.8;
      this.radius = Math.random() * 2 + 1.5;
    }
    
    update() {
      this.x += this.vx;
      this.y += this.vy;
      
      // 화면 경계 튕기기
      if (this.x &lt; 0 || this.x &gt; width) this.vx *= -1;
      if (this.y &lt; 0 || this.y &gt; height) this.vy *= -1;
    }
    
    draw() {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      ctx.fillStyle = &#39;rgba(99, 102, 241, 0.4)&#39;; // 파스텔 인디고 컬러
      ctx.fill();
    }
  }
  
  for (let i = 0; i &lt; particleCount; i++) {
    particles.push(new Particle());
  }
  
  function drawLines() {
    for (let i = 0; i &lt; particles.length; i++) {
      for (let j = i + 1; j &lt; particles.length; j++) {
        const dx = particles[i].x - particles[j].x;
        const dy = particles[i].y - particles[j].y;
        const dist = Math.sqrt(dx * dx + dy * dy);
        
        if (dist &lt; connectionDistance) {
          const alpha = (connectionDistance - dist) / connectionDistance * 0.18;
          ctx.beginPath();
          ctx.moveTo(particles[i].x, particles[i].y);
          ctx.lineTo(particles[j].x, particles[j].y);
          ctx.strokeStyle = `rgba(99, 102, 241, ${alpha})`;
          ctx.lineWidth = 1;
          ctx.stroke();
        }
      }
    }
  }
  
  function animate() {
    ctx.clearRect(0, 0, width, height);
    for (let i = 0; i &lt; particles.length; i++) {
      particles[i].update();
      particles[i].draw();
    }
    drawLines();
    requestAnimationFrame(animate);
  }
  
  window.addEventListener(&#39;resize&#39;, () =&gt; {
    width = canvas.width = window.innerWidth;
    height = canvas.height = window.innerHeight;
  });
  
  animate();
})();
</code></pre>
<hr>
<h3 id="예제-c-파도-일렁임-fluid-sine-waves">🌊 예제 C. 파도 일렁임 (Fluid Sine Waves)</h3>
<p>화면 하단에서 여러 갈래의 반투명 파도가 부드럽게 일렁이는 배경 애니메이션입니다.</p>
<pre><code class="language-javascript">(function() {
  const canvas = document.getElementById(&#39;bg-canvas&#39;);
  if (!canvas) return;
  const ctx = canvas.getContext(&#39;2d&#39;);
  
  let width = canvas.width = window.innerWidth;
  let height = canvas.height = window.innerHeight;
  
  let wave1 = {
    y: height * 0.85,
    length: 0.005,
    amplitude: 25,
    frequency: 0.012
  };
  
  let wave2 = {
    y: height * 0.88,
    length: 0.008,
    amplitude: 15,
    frequency: 0.022
  };
  
  let increment = 0;
  
  function animate() {
    ctx.clearRect(0, 0, width, height);
    
    // 첫 번째 뒷 파도 그리기 (반투명 파스텔 청록)
    ctx.beginPath();
    ctx.moveTo(0, height);
    for (let i = 0; i &lt; width; i++) {
      ctx.lineTo(i, wave1.y + Math.sin(i * wave1.length + increment) * wave1.amplitude);
    }
    ctx.lineTo(width, height);
    ctx.fillStyle = &#39;rgba(45, 212, 191, 0.1)&#39;;
    ctx.fill();
    
    // 두 번째 앞 파도 그리기 (반투명 파스텔 하늘)
    ctx.beginPath();
    ctx.moveTo(0, height);
    for (let i = 0; i &lt; width; i++) {
      ctx.lineTo(i, wave2.y + Math.sin(i * wave2.length - increment * 1.5) * wave2.amplitude);
    }
    ctx.lineTo(width, height);
    ctx.fillStyle = &#39;rgba(56, 189, 248, 0.15)&#39;;
    ctx.fill();
    
    // 모바일 환경에 따른 속도 차등 제어
    const speedFactor = (window.bgConfig &amp;&amp; window.bgConfig.mobileThrottleDivisor) ? 0.3 : 1;
    increment += wave1.frequency * speedFactor;
    
    requestAnimationFrame(animate);
  }
  
  window.addEventListener(&#39;resize&#39;, () =&gt; {
    width = canvas.width = window.innerWidth;
    height = canvas.height = window.innerHeight;
    wave1.y = height * 0.85;
    wave2.y = height * 0.88;
  });
  
  animate();
})();
</code></pre>
<hr>
<h2 id="6-모바일-개별-배경-설정">📱 6. 모바일 개별 배경 설정</h2>
<p>기기 환경에 맞춰 배경 설정을 차별화하여 성능을 최적화할 수 있습니다.</p>
<ol>
<li><strong>데스크톱 배경</strong>: 데스크톱 환경에서는 <strong>Custom JavaScript</strong>를 선택하여 원하는 Canvas 애니메이션을 구동할 수 있습니다.</li>
<li><strong>모바일 개별 배경 체크</strong>: <strong>[모바일 기기에서 데스크톱과 다른 배경 설정 사용]</strong> 스위치를 활성화합니다.</li>
<li><strong>모바일 배경 경량화</strong>: 독립된 모바일 설정에서 배경을 <strong>Solid(단색)</strong> 또는 **Gradient(그라디언트)**로 선택하여 모바일 리소스 부하를 최소화합니다.</li>
<li><strong>효과</strong>: 배터리 소모와 성능이 중요한 모바일 기기에서는 스크립트 실행 부하가 없는 가벼운 배경을 제공하고, PC 환경에서는 다채로운 시각 효과를 온전히 표현하도록 이원화할 수 있습니다.</li>
</ol>
]]></content:encoded>
            <category>관리자 가이드</category>
        </item>
        <item>
            <title><![CDATA[어드민 핵심 기능 및 듀얼 에디터 개요]]></title>
            <link>https://sveltekitblogblog.pages.dev/admin-guide/admin-core-features</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/admin-guide/admin-core-features</guid>
            <pubDate>Tue, 16 Jun 2026 14:54:27 GMT</pubDate>
            <description><![CDATA[다국어 글 동시 저장, 비주얼과 마크다운 듀얼 에디터 전환 및 기기별 독립 위젯 배치 방법 등 어드민 핵심 기능을 간단히 소개합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="어드민-핵심-기능-및-듀얼-에디터-소개">🎨 어드민 핵심 기능 및 듀얼 에디터 소개</h1>
<p>본 문서는 다국어 동시 발행, 기기별 레이아웃 배치, 실시간 디자인 에디터 등 관리자 페이지(어드민)가 제공하는 핵심 기능들의 기본 구성과 개요를 소개합니다.</p>
<hr>
<h2 id="1-다국어-글-작성-및-듀얼-에디터">📝 1. 다국어 글 작성 및 듀얼 에디터</h2>
<p>글 작성 메뉴에 진입하면 여러 언어 탭이 한 화면에 나란히 배열된 다국어 작성 환경이 제공됩니다.</p>
<h3 id="다국어-글-일괄-작성-및-저장">① 다국어 글 일괄 작성 및 저장</h3>
<ul>
<li><strong>작성 흐름</strong>: 상단 언어 탭(KO, EN, JA 등)을 전환하며 제목, 요약, 슬러그(주소명) 및 본문을 각 언어에 맞게 작성합니다.</li>
<li><strong>일괄 저장</strong>: 하단의 <strong>[모든 탭 동시 저장하기]</strong> 버튼을 통해 작성한 모든 언어의 글들을 데이터베이스에 한 번에 저장할 수 있습니다. <strong>발행</strong> 설정이 되지 않은 언어는 자동으로 <strong>초안</strong>으로 저장되며, 비워둔 언어 탭은 데이터가 생성되지 않고 제외됩니다.</li>
</ul>
<h3 id="듀얼-에디터-지원-비주얼-vs-마크다운">② 듀얼 에디터 지원 (비주얼 vs 마크다운)</h3>
<ul>
<li><strong>비주얼 HTML 에디터 (Visual)</strong>: 일반적인 웹 에디터처럼 서식을 지정하고 미디어를 임베드하며 직관적으로 작성하는 방식입니다. 이미지 파일은 툴바 업로드 버튼으로 본문에 간편하게 삽입할 수 있습니다.</li>
<li><strong>마크다운 에디터 (Markdown)</strong>: 마크다운 문법을 선호하는 사용자를 위해 제공됩니다. 제목, 요약, 카테고리, 태그 등의 정보는 마크다운 헤더 영역에 Front Matter(<code>---</code>) 형식으로 자동 관리됩니다. 저장 시 마크다운 원문과 변환된 HTML 본문이 함께 저장됩니다.</li>
</ul>
<h3 id="대표-이미지썸네일-자동-지정">③ 대표 이미지(썸네일) 자동 지정</h3>
<ul>
<li>별도로 대표 이미지를 지정하지 않은 경우, 시스템이 본문 내용을 분석하여 썸네일을 자동으로 설정합니다.<ul>
<li><strong>1순위</strong>: 본문 내용에 삽입된 가장 첫 번째 이미지</li>
<li><strong>2순위</strong>: 본문에 이미지가 없고 유튜브 링크나 iframe 임베드가 포함된 경우, 해당 비디오의 공식 고해상도 썸네일 주소</li>
</ul>
</li>
</ul>
<hr>
<h2 id="2-기기별데스크톱모바일-독립-위젯-배치">🧱 2. 기기별(데스크톱/모바일) 독립 위젯 배치</h2>
<p>레이아웃 에디터에서는 마우스 드래그 앤 드롭으로 사이드바와 본문 영역의 위젯 카드 순서를 조정할 수 있으며, 방문자의 기기 유형(데스크톱 또는 모바일)에 따라 독립된 위젯 노출 설정을 구성할 수 있습니다.</p>
<figure data-align="left"><img src="/images/posts/admin-core-features/desktop/img-admin-guide-admin-core-features-001.webp" alt="img-admin-guide-admin-core-features-001" data-align="left" data-caption="데스크탑/모바일 선택버튼" /><figcaption>데스크탑/모바일 선택버튼</figcaption></figure><h3 id="기기별-위젯-노출-조건">⚙️ 기기별 위젯 노출 조건</h3>
<ol>
<li><strong><code>디자인 에디터</code></strong> 메뉴 내 <strong><code>블로그 구조</code></strong> 탭에서 전체 레이아웃의 컬럼 구성 및 너비 비율을 선택합니다.</li>
<li>각 위젯 추가 및 변경 시 노출 기기 조건(Device)을 지정할 수 있습니다.<ul>
<li><strong>Desktop(데스크톱 전용)</strong>: 화면 폭이 넓은 PC 화면에만 위젯을 노출하며, 모바일 접속 시에는 불필요한 리소스 로드를 차단합니다.</li>
<li><strong>Mobile(모바일 전용)</strong>: PC 화면에서는 숨겨지고 스마트폰 및 태블릿 모바일 해상도에서만 표시되도록 제한합니다.</li>
</ul>
</li>
<li><strong>효과</strong>: 모바일 사용자에게 불필요하거나 무거운 위젯의 렌더링과 다운로드를 생략하여, 접속 속도와 스크롤 성능을 최적화합니다.</li>
</ol>
<hr>
<h2 id="3-실시간-디자인-에디터-및-테마-설정">🎨 3. 실시간 디자인 에디터 및 테마 설정</h2>
<p>디자인 에디터에서 변경한 테마 색상 및 스타일 정보는 서버 재빌드나 배포 과정 없이 저장 즉시 방문자 브라우저의 CSS 변수로 반영됩니다.</p>
<ul>
<li><strong>4가지 배경 타입</strong>: 단색(Solid), 그라디언트(Gradient), 배경 이미지(Image), HTML5 Canvas 애니메이션(Canvas) 형식을 선택할 수 있습니다.</li>
<li><strong>글래스모피즘 효과</strong>: 이미지 배경 사용 시 텍스트 가독성을 확보할 수 있도록 불투명도(Opacity)와 흐림(Blur) 수치를 조절하는 유리창 효과 설정을 지원합니다.</li>
<li><strong>인터랙티브 캔버스</strong>: 샌드박스로 격리된 안전한 캔버스 내에서 눈송이, 물결, 별자리 등 움직이는 모션 아트워크를 배경으로 구동할 수 있습니다.</li>
</ul>
<blockquote>
<p>[!TIP]<br>배경 설정 옵션의 종류와 예시 스크립트는 <strong><a href="./admin-design-editor.md">디자인 에디터 설정 소개</a></strong> 문서에서 확인하실 수 있습니다.</p>
</blockquote>
<hr>
<h2 id="4-미디어-저장소storage-지원">💾 4. 미디어 저장소(Storage) 지원</h2>
<p>본문에 사용하는 미디어가 저장될 클라우드 스토리지를 필요에 따라 유연하게 전환하여 운용할 수 있습니다.</p>
<ol>
<li><strong><code>미디어 라이브러리</code></strong> 메뉴 하단의 <strong><code>저장소 설정</code></strong> 영역으로 이동합니다.</li>
<li>연동할 스토리지 유형을 선택하고 정보를 입력합니다.<ul>
<li><strong>Cloudflare KV</strong>: 에지 노드의 KV 저장소에 에셋을 보관하여 신속하게 서빙합니다.</li>
<li><strong>Cloudflare R2</strong>: 대용량 오브젝트 스토리지를 사용하여 비용 효율적으로 이미지를 관리합니다.</li>
<li><strong>Supabase Storage</strong>: Supabase 스토리지 버킷 경로에 미디어를 업로드하여 안전하게 보관합니다.</li>
<li><strong>ImageKit.io</strong>: 글로벌 이미지 CDN 플랫폼을 연동하여, 업로드한 이미지의 해상도 최적화 및 압축 처리를 활용합니다.</li>
</ul>
</li>
<li><strong>저장소 실시간 전환</strong>: 변경 사항 저장 즉시 업로드 엔진이 해당 저장소로 전환되어 구동됩니다.</li>
</ol>
<blockquote>
<p>[!NOTE]<br><strong>기본 미디어 저장소(Cloudflare KV)의 탐색기 기능 제한</strong><br>Cloudflare KV는 Workers 사용량 및 비용 최적화를 위해 이미지 탐색기 내 목록 조회(조회 API 호출)를 지원하지 않습니다. 반면 Cloudflare R2, Supabase Storage, ImageKit.io 등의 외부 저장소를 설정하여 연결하는 경우에는 업로드된 이미지들의 목록 조회와 미리보기 탐색 기능을 모두 사용할 수 있습니다.</p>
</blockquote>
]]></content:encoded>
            <category>관리자 가이드</category>
            <enclosure url="/images/posts/admin-core-features/desktop/img-admin-guide-admin-core-features-001.webp" length="0" type="image/webp"/>
        </item>
        <item>
            <title><![CDATA[어드민 최초 진입 및 환경설정 시작하기]]></title>
            <link>https://sveltekitblogblog.pages.dev/admin-guide/admin-getting-started</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/admin-guide/admin-getting-started</guid>
            <pubDate>Tue, 16 Jun 2026 14:37:59 GMT</pubDate>
            <description><![CDATA[관리자가 블로그 시스템을 제어하기 위해 어드민 앱에 안전하게 접근하고, 최초 권한을 획득하며 다국어 UI 사전을 활용하는 방법에 대해 안내합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="어드민-최초-진입-및-환경설정-시작하기">🔑 어드민 최초 진입 및 환경설정 시작하기</h1>
<p>본 문서는 블로그 시스템을 제어하기 위해 관리자가 어드민 페이지에 안전하게 접근하고, 로그인 세션을 유지하며, 화면 상의 각종 문구(다국어 사전)를 손쉽게 조작하는 방법을 안내합니다.</p>
<hr>
<h2 id="1-어드민-로그인-전-ip-보안-통제-정책">🔒 1. 어드민 로그인 전 IP 보안 통제 정책</h2>
<p>이 블로그 엔진은 외부 해킹 시도나 포스팅 등록 권한 탈취를 완벽하게 방지하기 위해 <strong>접속 IP 필터링</strong> 보안 정책을 고수하고 있습니다. 배포 시점에 감지된 관리자의 공인 IP 주소만이 허용 목록(<code>ALLOWED_IP</code>)으로 클라우드 서버에 등록되어 접근을 허용합니다.</p>
<blockquote>
<p>[!IMPORTANT]</p>
<h3 id="안전지대-중심의-운영-원칙-공공장소-사용-금지">🛡️ 안전지대 중심의 운영 원칙 (공공장소 사용 금지)</h3>
<p>본 블로그의 어드민 관리는 반드시 <strong>집이나 신뢰할 수 있는 개인 사무실 등 물리적·네트워크 보안이 확보된 장소</strong>에서만 수행하셔야 합니다.<br>불특정 다수가 이용하고 해킹 위험에 직접 노출된 <strong>PC방, 도서관, 공공 와이파이 환경 등 공공장소에서는 보안 유출 방지를 위해 어드민 접속 자체를 절대 권장하지 않으며 지양해 주시기 바랍니다.</strong></p>
</blockquote>
<p>만약 사용 중인 안전한 장소 내에서 공유기 재부팅이나 인터넷 회선 사정으로 공인 IP 주소가 바뀌어 <code>403 Forbidden</code> 차단 화면을 만나게 된다면, 아래의 절차에 따라 허용 목록을 수동 갱신해 주어야 합니다.</p>
<h3 id="허용-ip-주소-갱신-절차-재배포-필요">⚙️ 허용 IP 주소 갱신 절차 (재배포 필요)</h3>
<ol>
<li>변경된 인터넷 환경에서 터미널을 열고, 블로그 서비스 어드민을 다시 한 번 **재배포(Redeploy)**하는 명령을 실행해야 합니다.</li>
<li><strong>작업 과정 안내</strong>: 데이터베이스 내부를 직접 편집하여 IP를 강제로 기입하는 극단적인 작동 방식보다는 안전하지만, 재배포 명령어가 가동되면서 매번 빌드 프로세스와 파일 업로드 대기 시간이 수 분간 소요되므로 실질적으로 꽤나 번거롭고 불편함이 수반되는 과정입니다.</li>
<li>배포 스크립트가 실행되는 동안 현재 연결된 컴퓨터의 새 공인 IP 주소를 탐지하여 원격 서버의 허용 IP 목록을 최신으로 교체합니다.</li>
<li>배포 처리가 최종 마무리된 후에 어드민 주소로 재접속하면 정상적으로 로그인 화면이 다시 활성화됩니다.</li>
<li>어드민 페이지만 재배포 하시면 됩니다.</li>
</ol>
<hr>
<h2 id="2-관리자-로그인-및-세션-관리">🔑 2. 관리자 로그인 및 세션 관리</h2>
<p>로그인 차단이 정상 해제되면, 최초 구축 시 설정했던 관리자 마스터 비밀번호(<code>ADMIN_PASSWORD</code>)를 입력하여 접속합니다.</p>
<ul>
<li><strong>보안 세션 유지</strong>: 브라우저의 전용 보안 쿠키 설정을 활용하여 30일 동안 어드민 로그인 세션이 안전하게 유지됩니다. </li>
<li><strong>공공 컴퓨터 및 위험 지역 접근 금지</strong>:<br>보안이 입증되지 않은 PC방이나 공용 기기 환경에서는 어드민 로그인 자체를 시도하지 않는 것이 가장 확실한 보안법입니다. 만약 피치 못할 사정으로 공공 환경에서 로그인했다면, 작업을 마친 직후 반드시 어드민 하단의 <strong>[로그아웃]</strong> 단추를 누르고, 추가로 터미널에 <code>npx wrangler logout</code>을 입력하여 로컬 컴퓨터에 기록된 클라우드플레어 관리 계정 정보까지 확실하게 연동 해제(로그아웃)해 주셔야 유출 사고를 방지할 수 있습니다.</li>
</ul>
<blockquote>
<p>[!WARNING]</p>
<h3 id="어드민-접속-주소도메인-노출-최소화-권장">🔒 어드민 접속 주소(도메인) 노출 최소화 권장</h3>
<p>어드민은 허용 IP 목록을 통해 이중으로 안전하게 보호되고 있으나, 악성 공격의 표적이 되는 공격 표면(Attack Surface) 자체를 줄이는 것이 가장 확실한 보안법입니다.</p>
<p>따라서 <code>admin.myblog.com</code>과 같이 알기 쉬운 커스텀 주소를 굳이 연결하지 마시고, Cloudflare Pages에서 기본으로 제공하는 무작위의 서브도메인 주소(예: <code>[프로젝트명].pages.dev</code>)를 그대로 사용하여 어드민의 접속 경로를 비밀스럽게 숨겨두실 것을 강력히 권장합니다.</p>
</blockquote>
<hr>
<h2 id="3-다국어-사전i18n-설정-가이드">🌐 3. 다국어 사전(i18n) 설정 가이드</h2>
<p>포스트 본문 외에 사이트 화면에 고정되어 있는 공통 문구(메뉴 명칭, 댓글 달기 버튼, 로그인 메시지 등)는 소스코드를 한 줄도 수정하지 않고도 어드민 사전 기능을 통해 한국어/영어/일본어 등으로 즉시 고쳐 쓸 수 있습니다. </p>
<ol>
<li>어드민 좌측 메뉴에서 <strong><code>언어 설정</code></strong> 메뉴로 이동합니다.</li>
<li>현재 사이트 전역에 사용되는 각종 번역 사전 키와 저장된 문구 리스트가 하단의 <strong><code>UI 다국어 사전 편집기</code></strong> 구역에 제공됩니다.</li>
<li>번역을 수정하고 싶은 키의 입력란에 원하는 문구(한국어, 영어, 일본어)를 작성하고, 해당 행 오른쪽 끝에 있는 <strong><code>저장</code></strong> 아이콘을 클릭합니다.</li>
<li>저장과 동시에 사이트에 바로 적용되며, 방문자가 블로그에서 언어를 스위칭할 때 실시간으로 변경된 문구로 매끄럽게 번역되어 표시됩니다.</li>
</ol>
]]></content:encoded>
            <category>관리자 가이드</category>
        </item>
        <item>
            <title><![CDATA[CMD 원클릭 설치 및 클라우드플레어 배포 가이드]]></title>
            <link>https://sveltekitblogblog.pages.dev/admin-guide/admin-install-and-deploy</link>
            <guid isPermaLink="true">https://sveltekitblogblog.pages.dev/admin-guide/admin-install-and-deploy</guid>
            <pubDate>Tue, 16 Jun 2026 14:29:15 GMT</pubDate>
            <description><![CDATA[터미널(CMD/PowerShell) 환경에서 자동화 스크립트 한 줄로 클라우드플레어 에지 인프라를 구축하고 어드민/블로그 앱을 동시에 배포 및 동기화하는 가장 빠른 설치법을 기술합니다.]]></description>
            <content:encoded><![CDATA[<h1 id="cmd-원클릭-설치-및-클라우드플레어-배포-가이드">🚀 CMD 원클릭 설치 및 클라우드플레어 배포 가이드</h1>
<p>본 가이드는 터미널(CMD 또는 PowerShell) 환경에서 자동화 명령어 한 줄(<code>npm run setup</code>)을 실행하여 Cloudflare 에지 인프라를 구축하고, 어드민과 블로그 앱을 동시에 배포 및 동기화하는 가장 쉽고 안전한 방법을 안내합니다.</p>
<hr>
<h2 id="1-원클릭-배포-자동화-소개">🛠️ 1. 원클릭 배포 자동화 소개</h2>
<p>스벨트킷 블로그 엔진은 복잡한 서버 리소스 생성과 설정 파일 편집 과정을 터미널의 <strong>대화형 설치 도구</strong>를 통해 완전히 자동화했습니다. </p>
<p>블로그 소스 코드의 압축을 풀거나 <code>git clone</code>으로 컴퓨터에 저장한 후, 터미널을 열어 프로젝트 루트 폴더로 이동한 뒤 아래 명령어를 차례대로 실행하기만 하면 됩니다.</p>
<pre><code class="language-bash"># 필수 패키지 설치
npm install
</code></pre>
<ul>
<li><strong>의존성 라이브러리 설치</strong>: 터미널에 <code>npm install</code>을 입력하여 필요한 패키지를 모두 설치합니다. 설치가 완료된 후 터미널 창에 보안 경고(vulnerabilities) 메시지가 나타난다면, <code>npm audit fix</code> 명령어를 입력해 안전하게 최신 보안 패치를 적용해 주는 것을 권장합니다.</li>
</ul>
<p>패키지 설치가 끝난 후 <code>npm run setup</code>을 실행하면, 터미널 창 안내에 따라 아래 과정이 자동으로 처리됩니다.</p>
<ul>
<li><strong>Cloudflare 계정 간편 인증</strong>: 클릭 한 번으로 배포 계정 연동 완료</li>
<li><strong>DB 및 저장 리소스 생성</strong>: 블로그 전용 D1 데이터베이스 2개와 이미지 보관용 KV 저장소 자동 신규 생성</li>
<li><strong>설정 파일 실시간 갱신</strong>: 생성된 데이터베이스 고유 ID를 감지하여 모노레포 설정 파일(<code>wrangler.json</code>)에 자동으로 주입</li>
<li><strong>데이터베이스 기본 데이터 주입</strong>: 테이블을 생성하고, 선택한 기본 언어에 맞춰 샘플 게시글과 기초 환경설정 정보를 자동 등록</li>
<li><strong>비밀 보안 변수 및 접속 허용 IP 업로드</strong>: 어드민 접속을 위해 배포자의 현재 공인 IP 주소(<code>ALLOWED_IP</code>)와 비밀번호 환경변수를 클라우드에 자동 전송</li>
<li><strong>통합 빌드 및 웹 서비스 배포</strong>: 블로그 및 어드민 SvelteKit 프로젝트를 통합 빌드하여 Cloudflare Pages에 즉시 업로드 배포</li>
</ul>
<hr>
<h2 id="2-배포-전-확인사항">📋 2. 배포 전 확인사항</h2>
<p>안전한 설치를 시작하기 전에 아래 사항이 모두 준비되어 있는지 확인해 주세요.</p>
<ol>
<li><strong>Node.js 설치</strong>: 컴퓨터에 Node.js(버전 18 이상)가 작동하고 있어야 합니다.</li>
<li><strong>Cloudflare 계정</strong>: 블로그 사이트와 데이터베이스가 호스팅될 클라우드플레어 계정(무료 제공 수준으로 충분)이 필요합니다.</li>
<li><strong>비밀 환경변수 파일(.dev.vars) 생성 (필수)</strong>:<ul>
<li>배포 시작 전에 <code>apps/admin/</code> 폴더와 <code>apps/blog/</code> 폴더 밑에 각각 <code>.dev.vars</code> 파일을 <strong>직접 생성</strong>해 주어야 합니다.</li>
<li><code>apps/admin/.dev.vars</code> 파일에는 <code>ADMIN_PASSWORD=어드민로그인비밀번호</code>를 작성합니다.</li>
<li><code>apps/blog/.dev.vars</code> 파일에는 <code>BETTER_AUTH_SECRET=임의의작성문자열</code>을 작성합니다.</li>
<li><blockquote>
<p>[!WARNING]<br>이 환경변수 설정이 되어 있지 않으면 <code>npm run setup</code> 실행 즉시 정상적 작동을 위해 <strong>설치 도구가 중단</strong>됩니다.</p>
</blockquote>
</li>
</ul>
</li>
</ol>
<hr>
<h2 id="3-npm-run-setup-단계별-설명">⚙️ 3. npm run setup 단계별 설명</h2>
<p>터미널을 열고 블로그 프로젝트 루트 경로에서 <code>npm run setup</code>을 입력한 뒤 엔터를 누릅니다.</p>
<h3 id="step-0-비밀-환경변수-사전-검사-pre-validation"><strong>Step 0. 비밀 환경변수 사전 검사 (Pre-Validation)</strong></h3>
<ul>
<li>실행 즉시 어드민과 블로그 폴더 안의 <code>.dev.vars</code> 파일 및 필수 비밀 변수(<code>ADMIN_PASSWORD</code>, <code>BETTER_AUTH_SECRET</code>)가 입력되었는지 검사합니다.</li>
<li>값 설정이 누락되었다면 가이드 로그를 띄운 뒤 종료되니, 사전에 꼭 기재해 주시기 바랍니다.</li>
</ul>
<h3 id="step-1-배포-프로젝트명도메인-주소-설정"><strong>Step 1. 배포 프로젝트명(도메인 주소) 설정</strong></h3>
<ul>
<li>독자들이 블로그에 접속할 때 사용하게 될 주소(예: <code>[입력한프로젝트명].pages.dev</code>)를 정하는 단계입니다.</li>
<li>배포 타겟인 블로그와 어드민의 이름 2가지를 입력받습니다. 복구 모드(<code>--restore</code>)로 실행하는 경우 기존 백업 정보 파일(<code>wrangler.backup.json</code>)로부터 기존 이름을 자동으로 읽어와 세팅합니다.</li>
</ul>
<h3 id="step-2-cloudflare-계정-로그인-인증"><strong>Step 2. Cloudflare 계정 로그인 인증</strong></h3>
<ul>
<li>클라우드플레어 인증을 확인합니다. 기존에 로그인한 이력이 있다면 자동으로 세션을 감지하여 스킵합니다.</li>
<li>로그인되어 있지 않다면 브라우저 창이 열리며 인증 요청 화면이 나타납니다. **[Allow / 허용]**을 클릭해 계정 연동을 승인해 주시면 됩니다.</li>
<li><em>보안 정보: 본 자동화 도구는 인프라 생성 및 배포에 필요한 최소한의 계정 API 권한만을 요청하므로 안심하고 진행하셔도 됩니다.</em></li>
</ul>
<h3 id="step-3-리소스-생성-및-환경설정-연동"><strong>Step 3. 리소스 생성 및 환경설정 연동</strong></h3>
<ul>
<li>실제 서비스 작동을 위한 데이터베이스와 미디어 저장소를 클라우드에 생성하는 단계입니다. 터미널의 안내 문구를 보고 알맞은 번호를 입력하세요.<ol>
<li><strong><code>1</code> (완전 초기화 / Fresh Install)</strong>: 이전에 만들어진 데이터베이스와 저장소를 <strong>완전히 삭제하고 새롭게 다시 만듭니다.</strong> 기존 데이터가 모두 지워지므로 유의해야 합니다.</li>
<li><strong><code>2</code> (기존 데이터 유지 / Keep Existing Data) [권장]</strong>: 이미 생성된 리소스가 있다면 데이터를 안전하게 지키면서 연결 정보만 매칭시켜 줍니다.</li>
</ol>
</li>
<li>연동 완료 즉시 새롭게 발급된 DB 및 KV 고유 ID가 모노레포의 각 설정 파일(<code>wrangler.json</code>)에 자동으로 업데이트됩니다.</li>
</ul>
<h3 id="step-4-웹-프로젝트-사전-생성"><strong>Step 4. 웹 프로젝트 사전 생성</strong></h3>
<ul>
<li>배포의 완성도를 높이기 위해, 클라우드플레어 에지에 비어 있는 웹 프로젝트를 선제적으로 등록 및 선점합니다.</li>
<li>이미 같은 이름의 주소가 점유되어 있다면 <strong>기존 주소를 재활용</strong>하여 안전하게 다음 단계로 자동 전환됩니다.</li>
</ul>
<h3 id="step-5-비밀-환경변수-원격-동기화"><strong>Step 5. 비밀 환경변수 원격 동기화</strong></h3>
<ul>
<li>앞서 로컬에 작성했던 <code>.dev.vars</code> 안의 마스터 비밀번호 등 비밀 값들을 클라우드로 안전하게 업로드하여 동기화합니다.</li>
<li><strong>접속 IP 자동 등록</strong>: 특히 이 단계에서 배포를 가동 중인 관리자 컴퓨터의 공인 IP 주소를 실시간 감지하여 <code>ALLOWED_IP</code> 변수로 자동 주입해 줍니다. 덕분에 배포 직후 로그인 창에 처음 들어갈 때 IP가 차단되어 접근하지 못하는 일을 원천 예방합니다.</li>
</ul>
<h3 id="step-6-데이터베이스-테이블-구성-및-기본-테마-구축"><strong>Step 6. 데이터베이스 테이블 구성 및 기본 테마 구축</strong></h3>
<ul>
<li>블로그 기능 동작에 필요한 DB 테이블을 구성하고 초기 설정값을 이식합니다.</li>
<li>화면 안내에 따라 주로 사용할 기본 언어(한국어, 영어, 일본어)를 선택하면 번역 시스템이 구축되고 샘플 카테고리와 헤더 메뉴 뼈대, 기본 환영 게시글이 자동으로 세팅됩니다.</li>
</ul>
<h3 id="step-7-웹-서비스-빌드-및-최종-배포"><strong>Step 7. 웹 서비스 빌드 및 최종 배포</strong></h3>
<ul>
<li>전체 모노레포 앱의 통합 빌드를 진행하고, Cloudflare 서버에 배포 명령을 자동 실행하여 설치 프로세스를 마칩니다. 배포가 완료되면 블로그와 어드민의 Pages 접속 주소가 표시됩니다.</li>
</ul>
<hr>
<blockquote>
<p>[!TIP]</p>
<h3 id="비밀-값-자동-설정과-즉시-접속-지원">💡 비밀 값 자동 설정과 즉시 접속 지원</h3>
<p>본 프로젝트의 설치 프로세스는 리소스 생성, 웹 프로젝트 확보, 비밀 환경변수 전송까지 유기적으로 이어서 처리합니다.<br>배포 완료와 동시에 로그인 비밀번호 및 IP 허용 설정이 원격 서버에 완벽하게 세팅되므로, 별도의 추가 수동 조작 없이도 즉시 작동합니다.</p>
</blockquote>
<hr>
<h2 id="4-블로그-업데이트-및-데이터-복원-배포-npm-run-restore">🔄 4. 블로그 업데이트 및 데이터 복원 배포 (npm run restore)</h2>
<p>블로그를 운영하던 중 <strong>새로운 패치 버전이나 버그가 수정된 최신 릴리즈 코드가 배포되었을 때</strong>, 기존에 써왔던 게시글 데이터와 주소를 유실 없이 안전하게 승계하며 새 코드로 화면을 교체하는 방법입니다.</p>
<h3 id="새-버전-마이그레이션-4단계-절차">💡 새 버전 마이그레이션 4단계 절차</h3>
<p>어드민의 데이터 백업과 <strong><code>npm run restore</code></strong> 명령어를 사용하면 데이터 유실 없이 안전하게 업그레이드를 완료할 수 있습니다.</p>
<ol>
<li><strong>[1단계] 기존 데이터 및 배포 설정 백업</strong>:<ul>
<li>운영 중인 어드민의 <strong><code>콘텐츠 백업</code></strong> 메뉴 및 <strong><code>디자인 에디터</code></strong> 메뉴 하단 백업 섹션에 접속해 포스트 본문 데이터와 테마 디자인 설정을 각각 컴퓨터로 내려받습니다.</li>
<li>또한 <strong><code>콘텐츠 백업</code></strong> 메뉴의 <code>설정 백업 다운로드</code> 단추를 눌러 [wrangler.backup.json] 파일을 PC에 저장해 둡니다. (이는 기존 상용 서버의 데이터베이스 고유 ID 연동을 유지하는 가장 중요한 파일입니다.)</li>
</ul>
</li>
<li><strong>[2단계] 새 코드 격리 테스트</strong>:<ul>
<li>새로 내려받은 신버전 코드 폴더 안에서 <code>npm run setup</code>을 가동해 <strong>테스트용 임시 DB</strong>와 <strong>테스트용 Pages 임시 배포명</strong>을 입력해 별도 배포합니다.</li>
<li>임시 배포된 새 어드민에 로그인하여 1단계에서 저장해 두었던 백업 데이터 파일들을 가져오기(Import)하여 데이터가 무사히 불려오는지 사전 확인합니다.</li>
</ul>
</li>
<li><strong>[3단계] 기존 상용 서버로 바인딩 복원 (<code>npm run restore</code>)</strong>:<ul>
<li>검증이 끝났다면, 신버전 프로젝트 폴더의 루트 디렉터리에 1단계에서 따로 내려받아 두었던 <code>wrangler.backup.json</code> 파일을 복사해 붙여넣습니다.</li>
<li>터미널에서 <strong><code>npm run restore</code></strong> 명령을 기동하면, 도구 스크립트가 해당 백업 내용에 기재된 <strong>기존의 상용 DB와 KV의 고유 ID 정보</strong>를 읽어와 새 코드 설정 파일에 덮어쓰기 방식으로 자동 연결해 줍니다.</li>
</ul>
</li>
<li><strong>[4단계] 스키마 동기화 및 덮어쓰기 배포</strong>:<ul>
<li>복원 스크립트는 기존 상용 DB의 테이블 구조 뼈대만 최신 사양으로 안전하게 갱신하므로, <strong>이미 적재되어 있던 실제 게시글이나 데이터는 훼손되거나 지워지지 않고 완벽히 보존</strong>됩니다.</li>
<li>이어서 <code>npm run deploy:blog</code> 와 <code>npm run deploy:admin</code>을 각각 실행하면, 사용 중이던 주소 그대로 <strong>최신 업그레이드된 블로그 시스템만 안전하게 덮어쓰기 배포</strong>됩니다.</li>
</ul>
</li>
</ol>
<hr>
<h2 id="5-백업-파일의-종류와-기능">📦 5. 백업 파일의 종류와 기능</h2>
<p>어드민 백업 메뉴에서 안전하게 가져오고 내보낼 수 있는 개별 파일들의 역할은 아래 표를 참고해 주세요.</p>
<table>
<thead>
<tr>
<th align="left">백업 유형</th>
<th align="left">추출 경로</th>
<th align="left">권장 파일명 예시</th>
<th align="left">상세 기능 및 보존 내용</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><strong>1. 콘텐츠 DB 데이터</strong></td>
<td align="left"><strong><code>콘텐츠 백업</code></strong> 메뉴</td>
<td align="left"><code>blog-content-backup-[날짜].json</code></td>
<td align="left">작성된 모든 블로그 포스트 본문, 생성된 카테고리 정보, 태그 목록 및 기본 시스템 설정값 보존</td>
</tr>
<tr>
<td align="left"><strong>2. 배포 설정 백업</strong></td>
<td align="left"><strong><code>콘텐츠 백업</code></strong> 메뉴</td>
<td align="left"><code>wrangler.backup.json</code></td>
<td align="left">Cloudflare D1 DB 및 KV 저장소 연동에 필요한 배포명과 고유 UUID 정보를 안전하게 보존 (<strong>서버 마이그레이션 시 필수</strong>)</td>
</tr>
<tr>
<td align="left"><strong>3. 미디어 파일 백업</strong></td>
<td align="left"><strong><code>콘텐츠 백업</code></strong> 메뉴의 <code>미디어 백업 및 복원</code> 섹션<br>또는 <strong><code>미디어 라이브러리</code></strong> 메뉴 우측 상단 <code>[백업 / 복원]</code> 단추</td>
<td align="left"><code>[스토리지이름]-images-backup-[날짜].zip</code> <br>(예: <code>r2-images-backup-[날짜].zip</code>)</td>
<td align="left">활성화된 이미지 저장소(R2, Supabase 등)에 업로드된 전체 이미지 미디어 파일을 ZIP 형식으로 압축 다운로드하여 보존</td>
</tr>
<tr>
<td align="left"><strong>4. 디자인 설정 백업</strong></td>
<td align="left"><strong><code>디자인 에디터</code></strong> 메뉴 하단</td>
<td align="left"><code>blog-design-backup-[날짜].json</code></td>
<td align="left">디자인 에디터에서 설정한 블로그 테마 컬러 정보, 배경 타입 및 기기별(데스크톱/모바일) 위젯 배치 구조 보존</td>
</tr>
<tr>
<td align="left"><strong>5. 시스템 전체 백업</strong></td>
<td align="left"><strong><code>사이트 설정</code></strong> 메뉴 하단</td>
<td align="left"><code>full-system-backup-[날짜].json</code></td>
<td align="left">두 개 데이터베이스(BLOG_DB, USER_DB) 내 모든 테이블의 원천 데이터를 하나의 JSON 파일로 모아 전체 백업 및 복원</td>
</tr>
</tbody></table>
]]></content:encoded>
            <category>관리자 가이드</category>
        </item>
    </channel>
</rss>