<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[RSS Feed of JavaPark]]></title><description><![CDATA[AI 시대의 개발자 도구, 실전 경험을 공유합니다]]></description><link>http://blog.javapark.kr</link><generator>GatsbyJS</generator><lastBuildDate>Sat, 04 Apr 2026 09:59:19 GMT</lastBuildDate><item><title><![CDATA[AI 에이전트란? 2026년 현재 총정리 — 챗봇과 뭐가 다르고, 뭘 할 수 있나]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. "AI 에이전트가 대세라는데, 그게 ChatGPT랑 뭐가 다른 건가요?" 솔직히 말하면, 저도 처음엔 헷갈렸습니다. 챗봇, 코파일럿, 에이전트 — 다 AI…]]></description><link>http://blog.javapark.kr/ai-agent-guide-2026/</link><guid isPermaLink="false">http://blog.javapark.kr/ai-agent-guide-2026/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/ai-agent-guide-2026.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;AI 에이전트가 대세라는데, 그게 ChatGPT랑 뭐가 다른 건가요?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;솔직히 말하면, 저도 처음엔 헷갈렸습니다. 챗봇, 코파일럿, 에이전트 — 다 AI 아닌가? 근데 직접 써보면 &lt;strong&gt;완전히 다른 경험&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;결론부터 말씀드리면 — &lt;strong&gt;챗봇은 대화하고, 코파일럿은 도와주고, 에이전트는 직접 일합니다.&lt;/strong&gt; 2026년 현재 AI 에이전트 시장은 $7.6B 규모로, 챗봇 시장 성장률의 2배 속도로 커지고 있습니다. 오늘은 이 모든 것을 한 번에 정리해보겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;AI 에이전트란? — 30초 정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AI 에이전트(AI Agent)는 목표를 받으면, 스스로 계획을 세우고, 도구를 사용해서, 여러 단계에 걸쳐 작업을 실행하는 AI 시스템&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;비유하자면 이렇습니다:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;챗봇&lt;/th&gt;
&lt;th&gt;코파일럿&lt;/th&gt;
&lt;th&gt;AI 에이전트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;비유&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;안내 데스크 직원&lt;/td&gt;
&lt;td&gt;옆에서 도와주는 동료&lt;/td&gt;
&lt;td&gt;업무를 위임받은 대리인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;하는 일&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;질문에 답변&lt;/td&gt;
&lt;td&gt;작업을 보조&lt;/td&gt;
&lt;td&gt;목표를 받아 자율적으로 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;자율성&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;낮음 (반응형)&lt;/td&gt;
&lt;td&gt;중간 (제안형)&lt;/td&gt;
&lt;td&gt;높음 (실행형)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;작업 범위&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;대화창 안&lt;/td&gt;
&lt;td&gt;특정 앱 안&lt;/td&gt;
&lt;td&gt;여러 시스템을 넘나듦&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;인간 개입&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;매번 필요&lt;/td&gt;
&lt;td&gt;승인/거절&lt;/td&gt;
&lt;td&gt;최소한의 감독&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;한 줄로 요약하면:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;챗봇&lt;/strong&gt; → 대화를 최적화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;코파일럿&lt;/strong&gt; → 개인 생산성을 최적화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;에이전트&lt;/strong&gt; → 프로세스 처리량을 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;AI 에이전트 실전 예시 — 챗봇·코파일럿과 비교&lt;/h2&gt;
&lt;p&gt;같은 작업을 세 가지 방식으로 비교해보면 차이가 확 느껴집니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;매월 12개 부서 보고서를 합쳐서 경영진 요약 보고서를 만들어라&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;실제 작업 과정&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;챗봇&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&quot;보고서를 합치는 방법을 알려줘&quot; → 방법을 텍스트로 설명 → &lt;strong&gt;사람이 직접 실행&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;코파일럿&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;엑셀에서 작업 중 &quot;이 수식 추천해줘&quot; → 수식 제안 → &lt;strong&gt;사람이 수락하고 실행&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;에이전트&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&quot;12개 파일 합쳐서 요약 보고서 만들어줘&quot; → &lt;strong&gt;파일 읽기 → 데이터 합치기 → 분석 → 보고서 생성까지 직접 수행&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;에이전트는 결과물까지 만들어냅니다.&lt;/strong&gt; 사람은 최종 확인만 하면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2026년 AI 에이전트 주요 플랫폼 — 한눈에 비교&lt;/h2&gt;
&lt;h3&gt;코딩 에이전트&lt;/h3&gt;
&lt;p&gt;개발자에게 가장 직접적인 AI 에이전트 카테고리입니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;도구&lt;/th&gt;
&lt;th&gt;개발사&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;작동 방식&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;서브에이전트, Hook, 1M 컨텍스트, MCP&lt;/td&gt;
&lt;td&gt;터미널 / VS Code / 브라우저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;클라우드 샌드박스, 병렬 실행&lt;/td&gt;
&lt;td&gt;터미널&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gemini CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Gemini 3, 1M 컨텍스트, Extensions&lt;/td&gt;
&lt;td&gt;터미널&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Anysphere&lt;/td&gt;
&lt;td&gt;$500M+ ARR, 병렬 에이전트 8개&lt;/td&gt;
&lt;td&gt;IDE (VS Code 포크)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Devin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cognition&lt;/td&gt;
&lt;td&gt;가장 자율적, 클라우드 IDE&lt;/td&gt;
&lt;td&gt;웹 / Slack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;Agent Mode, VM 자동 실행, PR 생성&lt;/td&gt;
&lt;td&gt;IDE / 웹&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이 블로그에서 다뤄온 &lt;strong&gt;Claude Code, Codex CLI, Gemini CLI&lt;/strong&gt;도 모두 AI 에이전트입니다. 터미널에서 자연어로 지시하면 파일을 읽고, 코드를 작성하고, 테스트를 실행하는 — 그 전체 과정이 &quot;에이전트&quot;입니다.&lt;/p&gt;
&lt;h3&gt;브라우저 에이전트&lt;/h3&gt;
&lt;p&gt;2025~2026년 가장 폭발적으로 성장한 카테고리입니다. AI가 &lt;strong&gt;직접 브라우저를 조작&lt;/strong&gt;합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;도구&lt;/th&gt;
&lt;th&gt;개발사&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ChatGPT Agent (Operator)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;CUA 모델 기반, 스크린샷으로 화면을 &quot;보고&quot; 마우스/키보드로 &quot;조작&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Project Mariner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Chrome 확장, 동시 10개 작업, WebVoyager 83.5% (SOTA)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Atlas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;전용 AI 브라우저, Agent Mode로 다단계 작업&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;예: &quot;항공편을 검색해서 가격 비교하고, 가장 저렴한 옵션을 정리해줘&quot;
→ AI가 브라우저를 열고, 검색 사이트를 탐색하고, 결과를 표로 정리&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;워크플로우/비즈니스 에이전트&lt;/h3&gt;
&lt;p&gt;개발 없이도 업무 프로세스를 자동화합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;도구&lt;/th&gt;
&lt;th&gt;개발사&lt;/th&gt;
&lt;th&gt;규모&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Copilot Studio&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;160,000+ 조직 배포&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Agentforce&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Salesforce&lt;/td&gt;
&lt;td&gt;$540M ARR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이메일 발송, 문서 생성, CRM 업데이트, 회의 예약 등을 로우코드/노코드로 구축합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;AI 에이전트를 연결하는 두 가지 표준 — MCP와 A2A&lt;/h2&gt;
&lt;p&gt;에이전트가 강력한 이유는 &lt;strong&gt;외부 도구와 연결&lt;/strong&gt;할 수 있기 때문입니다. 2026년 현재 두 가지 표준이 자리잡았습니다.&lt;/p&gt;
&lt;h3&gt;MCP (Model Context Protocol) — AI와 도구를 연결&lt;/h3&gt;
&lt;p&gt;Anthropic이 만들고, 현재 Linux Foundation 산하로 이관된 오픈소스 표준입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;AI 모델 ←→ MCP ←→ 외부 도구 (Slack, Google Drive, Jira, DB 등)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;2024년 11월 출시 → 2026년 3월 현재 &lt;strong&gt;월간 9,700만 다운로드&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;5,800+ MCP 서버, 300+ MCP 클라이언트&lt;/li&gt;
&lt;li&gt;OpenAI, Google, Microsoft 모두 채택&lt;/li&gt;
&lt;li&gt;AI 세계의 &lt;strong&gt;&quot;USB-C&quot;&lt;/strong&gt; — 어떤 모델이든, 어떤 도구든 하나의 표준으로 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;A2A (Agent-to-Agent) — AI 에이전트 간 통신&lt;/h3&gt;
&lt;p&gt;Google이 만든 오픈 프로토콜로, &lt;strong&gt;에이전트끼리 대화하고 협업하는 표준&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;영업 에이전트 ←→ A2A ←→ 재무 에이전트 ←→ A2A ←→ HR 에이전트&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;150개 이상 조직 참여 (Atlassian, PayPal, Salesforce, SAP 등)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent Card&lt;/strong&gt;: JSON 형태로 &quot;나는 이런 일을 할 수 있어&quot;를 광고&lt;/li&gt;
&lt;li&gt;다른 에이전트가 Agent Card를 보고 최적의 협업 상대를 찾아 통신&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;MCP vs A2A 차이:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP&lt;/strong&gt; = AI ↔ 도구 (수직적 연결)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A2A&lt;/strong&gt; = AI ↔ AI (수평적 연결)&lt;/li&gt;
&lt;li&gt;둘은 경쟁이 아니라 &lt;strong&gt;상호 보완&lt;/strong&gt; 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;2026년 AI 에이전트 핵심 트렌드 5가지&lt;/h2&gt;
&lt;h3&gt;1. 멀티 에이전트 시스템의 부상&lt;/h3&gt;
&lt;p&gt;혼자 일하는 에이전트에서 &lt;strong&gt;팀으로 일하는 에이전트&lt;/strong&gt;로 전환되고 있습니다.&lt;/p&gt;
&lt;p&gt;Gartner에 따르면 멀티 에이전트 시스템 관련 문의가 &lt;strong&gt;1,445% 급증&lt;/strong&gt;했습니다. &quot;퍼핏티어(Puppeteer)&quot; 역할의 오케스트레이터가 전문 에이전트들을 조율하는 구조입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;오케스트레이터 에이전트
  ├── 코드 작성 에이전트
  ├── 코드 리뷰 에이전트
  ├── 테스트 에이전트
  └── 배포 에이전트&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2. 장기 실행 자율 워크플로우&lt;/h3&gt;
&lt;p&gt;단일 프롬프트 → 단일 응답이 아니라, &lt;strong&gt;며칠간 실행되는 작업 루프&lt;/strong&gt;가 등장했습니다.&lt;/p&gt;
&lt;p&gt;에이전트가 전체 애플리케이션을 구축하고, 인간은 전략적 결정 포인트에서만 개입합니다. Claude Code의 백그라운드 태스크, Devin의 클라우드 실행이 대표적입니다.&lt;/p&gt;
&lt;h3&gt;3. 비개발자의 에이전트 시대&lt;/h3&gt;
&lt;p&gt;Microsoft Copilot Studio, Salesforce Agentforce처럼 &lt;strong&gt;코드 없이 에이전트를 만드는 플랫폼&lt;/strong&gt;이 본격화됐습니다. &quot;비즈니스 사용자가 엔지니어가 아닌데도 에이전트를 만들고 있다&quot;는 게 2026년의 현실입니다.&lt;/p&gt;
&lt;h3&gt;4. 에이전트 프레임워크 통합&lt;/h3&gt;
&lt;p&gt;각 빅테크가 에이전트 프레임워크를 출시했습니다:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;개발사&lt;/th&gt;
&lt;th&gt;프레임워크&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Claude Agent SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Agents SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Agent Development Kit (ADK)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;Semantic Kernel + AutoGen&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;커뮤니티에서도 LangGraph, CrewAI, Mastra 등이 경쟁 중입니다.&lt;/p&gt;
&lt;h3&gt;5. MCP가 인프라 표준으로 확장&lt;/h3&gt;
&lt;p&gt;2025년이 &quot;채택의 해&quot;였다면, 2026년은 &quot;확장의 해&quot;입니다. Anthropic, OpenAI, Block이 공동 설립한 **Agentic AI Foundation(AAIF)**이 Linux Foundation 산하에서 MCP를 관리합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;AI 에이전트의 위험과 한계 — 솔직한 정리&lt;/h2&gt;
&lt;p&gt;AI 에이전트가 만능은 아닙니다. 알고 쓰는 게 중요합니다.&lt;/p&gt;
&lt;h3&gt;할루시네이션 — &quot;자신감 있게 틀리는&quot; 문제&lt;/h3&gt;
&lt;p&gt;에이전트는 &lt;strong&gt;자신의 능력 한계를 모릅니다.&lt;/strong&gt; 전문 지식이 필요한 상황인데도 자신 있게 답을 내놓을 수 있습니다. 고위험 작업에서는 반드시 사람의 검증이 필요합니다.&lt;/p&gt;
&lt;h3&gt;보안 — 과도한 권한 문제&lt;/h3&gt;
&lt;p&gt;보고에 따르면 &lt;strong&gt;90%의 에이전트가 필요한 것보다 10배 많은 권한&lt;/strong&gt;을 가지고 있습니다. 도구 연결이 늘어날수록 위험이 곱셈으로 증가합니다. 간접 프롬프트 인젝션(웹페이지에 숨겨진 악의적 지시)도 실제 위협입니다.&lt;/p&gt;
&lt;h3&gt;비용 — 과소평가되는 현실&lt;/h3&gt;
&lt;p&gt;Gartner에 따르면 CIO들이 AI 비용을 &lt;strong&gt;최대 1,000%까지 과소평가&lt;/strong&gt;한다고 합니다. 특히 에이전트를 확장하고 유지하는 비용이 예상보다 큽니다.&lt;/p&gt;
&lt;h3&gt;실패율 — 40% 이상 실패 예상&lt;/h3&gt;
&lt;p&gt;에이전트 프로젝트의 &lt;strong&gt;40% 이상이 2027년까지 실패&lt;/strong&gt;할 것이라는 Gartner 예측이 있습니다. 기술이 아니라 &lt;strong&gt;거버넌스&lt;/strong&gt;(통제, 소유권, 신뢰 관리)가 가장 큰 장벽입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;비개발자용 AI 에이전트 추천 — 지금 바로 시작하기&lt;/h2&gt;
&lt;p&gt;&quot;에이전트가 뭔지는 알겠는데, 나는 뭘 쓰면 되나요?&quot;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;목적&lt;/th&gt;
&lt;th&gt;추천 도구&lt;/th&gt;
&lt;th&gt;월 비용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;파일/데이터 정리&lt;/td&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;$20 (Pro)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;웹 작업 자동화&lt;/td&gt;
&lt;td&gt;ChatGPT Agent (Operator)&lt;/td&gt;
&lt;td&gt;$20 (Plus)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;업무 프로세스 자동화&lt;/td&gt;
&lt;td&gt;Copilot Studio&lt;/td&gt;
&lt;td&gt;M365 구독&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;코딩&lt;/td&gt;
&lt;td&gt;Claude Code, Cursor&lt;/td&gt;
&lt;td&gt;$20~&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;가장 진입 장벽이 낮은 건 &lt;strong&gt;Claude Code&lt;/strong&gt;입니다. 터미널에서 자연어로 지시하면 파일을 직접 읽고, 수정하고, 생성합니다. &lt;a href=&quot;/claude-code-codex-for-non-developers/&quot;&gt;비개발자도 쓸 수 있다는 걸 이전 포스팅에서 다뤘습니다.&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;AI 에이전트가 내 일자리를 대체하나요?&lt;/h3&gt;
&lt;p&gt;단기적으로는 &quot;대체&quot;보다 &quot;증강&quot;에 가깝습니다. 에이전트는 반복적이고 규칙적인 작업을 처리하고, 사람은 판단·창의·소통에 집중하는 구조입니다. 다만 장기적으로 자동화 가능한 업무 범위가 넓어지는 건 사실입니다.&lt;/p&gt;
&lt;h3&gt;MCP를 개인이 쓸 수 있나요?&lt;/h3&gt;
&lt;p&gt;네. Claude Code에서 MCP 서버를 설정하면 Google Drive, Slack, GitHub 등을 연결해서 사용할 수 있습니다. 설정법은 공식 문서에 잘 정리되어 있습니다.&lt;/p&gt;
&lt;h3&gt;어떤 에이전트 프레임워크를 배워야 하나요?&lt;/h3&gt;
&lt;p&gt;개발자라면 &lt;strong&gt;자신이 사용하는 AI 모델의 공식 SDK&lt;/strong&gt;부터 시작하세요. Claude 사용자라면 Claude Agent SDK, OpenAI 사용자라면 Agents SDK가 자연스럽습니다. 특정 벤더에 묶이고 싶지 않다면 LangGraph가 가장 범용적입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;AI 에이전트는 &lt;strong&gt;&quot;대화하는 AI&quot;에서 &quot;일하는 AI&quot;로의 전환&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;2026년 현재:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;코딩 에이전트&lt;/strong&gt; (Claude Code, Cursor, Devin)는 이미 실전 투입 수준&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;브라우저 에이전트&lt;/strong&gt; (Operator, Project Mariner)는 웹 작업을 자동화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP와 A2A&lt;/strong&gt;로 에이전트끼리 도구를 공유하고 협업하는 시대&lt;/li&gt;
&lt;li&gt;하지만 &lt;strong&gt;보안, 비용, 거버넌스&lt;/strong&gt; 문제는 아직 풀어야 할 숙제&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;에이전트를 &quot;써봐야 하나?&quot;고 고민 중이라면, 답은 간단합니다 — &lt;strong&gt;이미 쓰고 있을 가능성이 높습니다.&lt;/strong&gt; GitHub Copilot의 자동 완성, ChatGPT의 검색 기능, Claude Code의 파일 편집 — 이 모든 게 에이전트의 일부입니다.&lt;/p&gt;
&lt;p&gt;여러분은 어떤 AI 에이전트를 써보셨나요? 댓글로 경험을 공유해주세요!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;관련 포스팅:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/claude-code-codex-for-non-developers/&quot;&gt;비개발자가 Claude Code, Codex CLI 활용하는 법&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/ai-coding-skills-comparison/&quot;&gt;AI 코딩 도구 Skill 비교 — Claude Code vs Gemini CLI vs Codex CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;참고 자료:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code&quot;&gt;Claude Code 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://modelcontextprotocol.io&quot;&gt;MCP 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/&quot;&gt;A2A 프로토콜 — Google&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gartner.com/en/articles/intelligent-agent-in-ai&quot;&gt;Gartner AI Agent Trends 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[AI로 웹서비스 만드는 법 — Claude Code + Supabase 실전 가이드]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. 요즘 개발 환경이 빠르게 바뀌고 있습니다. 예전에는 웹서비스 하나 만들려면 프론트엔드, 백엔드, DB, 배포까지 혼자 다 해야 했습니다. 지금은 다릅니다. "아이디어만 있으면, AI…]]></description><link>http://blog.javapark.kr/ai-driven-web-development/</link><guid isPermaLink="false">http://blog.javapark.kr/ai-driven-web-development/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/ai-driven-web-development.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;요즘 개발 환경이 빠르게 바뀌고 있습니다. 예전에는 웹서비스 하나 만들려면 프론트엔드, 백엔드, DB, 배포까지 혼자 다 해야 했습니다. 지금은 다릅니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;아이디어만 있으면, AI와 함께 웹서비스를 만들 수 있는 시대&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;과장이 아닙니다. 실제로 저는 &lt;strong&gt;Claude Code + GitHub + Supabase&lt;/strong&gt; 조합으로 웹서비스를 개발하고 있고, 이 프로세스를 공유합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;AI 웹개발 도구 조합 — Claude Code, GitHub, Supabase&lt;/h2&gt;
&lt;p&gt;먼저 각 도구의 역할을 정리합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;도구&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;비유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI 코딩 에이전트 — 설계, 구현, 디버깅&lt;/td&gt;
&lt;td&gt;24시간 일하는 시니어 개발자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;코드 저장소 + 버전 관리 + 배포&lt;/td&gt;
&lt;td&gt;프로젝트의 금고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supabase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;백엔드 올인원 (DB, 인증, API, 스토리지)&lt;/td&gt;
&lt;td&gt;서버 없이 쓰는 백엔드&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이 세 가지를 조합하면, 1인 개발자가 풀스택 웹서비스를 만들 수 있는 환경이 됩니다. 서버를 직접 관리할 필요도, 인증 로직을 처음부터 짤 필요도 없습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;AI 웹서비스 개발 프로세스 — 5단계&lt;/h2&gt;
&lt;p&gt;제가 실제로 사용하는 프로세스를 단계별로 정리합니다.&lt;/p&gt;
&lt;h3&gt;1단계: 기획 — Claude Code와 대화하기&lt;/h3&gt;
&lt;p&gt;코드를 한 줄도 작성하기 전에, Claude Code에게 아이디어를 설명합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;할 일 관리 웹앱을 만들려고 합니다.
사용자 로그인, 할 일 CRUD, 카테고리 분류 기능이 필요합니다.
기술 스택은 Next.js + Supabase로 가려고 하는데, 어떻게 구조를 잡으면 좋을까요?&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Claude Code는 단순히 코드만 생성하는 게 아닙니다. 프로젝트 구조를 제안하고, 테이블 설계를 잡아주고, 필요한 패키지까지 알려줍니다.&lt;/p&gt;
&lt;p&gt;이 단계에서 중요한 건 &lt;strong&gt;&quot;무엇을 만들 것인가&quot;를 명확히 하는 것&lt;/strong&gt;입니다. AI는 방향을 알려주면 알아서 길을 찾지만, 방향이 모호하면 엉뚱한 곳으로 갑니다.&lt;/p&gt;
&lt;h3&gt;2단계: 프로젝트 셋업 — GitHub + Supabase 초기화&lt;/h3&gt;
&lt;h4&gt;GitHub 저장소 생성&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;gh repo create my-todo-app &lt;span class=&quot;token parameter variable&quot;&gt;--public&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--clone&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; my-todo-app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Supabase 프로젝트 생성&lt;/h4&gt;
&lt;p&gt;Supabase 대시보드에서 프로젝트를 만들면 바로 사용할 수 있는 것들이 생깁니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL 데이터베이스&lt;/strong&gt; — 테이블 만들면 자동으로 REST API 생성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth&lt;/strong&gt; — 이메일, Google, GitHub 로그인 내장&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage&lt;/strong&gt; — 파일 업로드/다운로드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Realtime&lt;/strong&gt; — 데이터 변경 시 실시간 동기화&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;별도의 백엔드 서버 없이, 프론트엔드에서 직접 Supabase를 호출하는 구조입니다.&lt;/p&gt;
&lt;h4&gt;환경 변수 설정&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .env.local&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;NEXT_PUBLIC_SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;https://xxxxx.supabase.co
&lt;span class=&quot;token assign-left variable&quot;&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;eyJhbGciOiJIUzI1NiIs&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;3단계: 개발 — Claude Code가 코드를 쓴다&lt;/h3&gt;
&lt;p&gt;여기서부터 Claude Code의 진가가 발휘됩니다.&lt;/p&gt;
&lt;h4&gt;DB 테이블 설계&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;Supabase에 할 일 관리용 테이블을 만들어줘.
사용자별로 할 일을 관리하고, 카테고리 분류가 가능해야 해.&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Claude Code가 SQL을 작성합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- categories 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;table&lt;/span&gt; categories &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id uuid &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  user_id uuid &lt;span class=&quot;token keyword&quot;&gt;references&lt;/span&gt; auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;cascade&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  name &lt;span class=&quot;token keyword&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at timestamptz &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- todos 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;table&lt;/span&gt; todos &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id uuid &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  user_id uuid &lt;span class=&quot;token keyword&quot;&gt;references&lt;/span&gt; auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;cascade&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  category_id uuid &lt;span class=&quot;token keyword&quot;&gt;references&lt;/span&gt; categories&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  title &lt;span class=&quot;token keyword&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  completed &lt;span class=&quot;token keyword&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at timestamptz &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- RLS(Row Level Security) 활성화&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;alter&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;table&lt;/span&gt; todos &lt;span class=&quot;token keyword&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;level&lt;/span&gt; security&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;alter&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;table&lt;/span&gt; categories &lt;span class=&quot;token keyword&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;level&lt;/span&gt; security&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- 본인 데이터만 접근 가능&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;create&lt;/span&gt; policy &lt;span class=&quot;token string&quot;&gt;&quot;Users can manage own todos&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;on&lt;/span&gt; todos &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;all&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; user_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;create&lt;/span&gt; policy &lt;span class=&quot;token string&quot;&gt;&quot;Users can manage own categories&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;on&lt;/span&gt; categories &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;all&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; user_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Supabase의 &lt;strong&gt;RLS(Row Level Security)&lt;/strong&gt; 는 꼭 설정해야 합니다. 안 그러면 모든 사용자가 다른 사람의 데이터를 볼 수 있습니다.&lt;/p&gt;
&lt;h4&gt;프론트엔드 구현&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;Next.js App Router 구조로 할 일 목록 페이지를 만들어줘.
Supabase에서 데이터 가져오고, 추가/삭제/완료 토글 기능이 필요해.&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Claude Code가 컴포넌트, API 호출, 상태 관리까지 한 번에 작성합니다. 저는 결과를 확인하고, 수정이 필요한 부분만 피드백합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;완료된 할 일은 아래쪽으로 내려가게 해줘.&quot;
&quot;카테고리 필터 버튼 추가해줘.&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이런 식으로 &lt;strong&gt;대화하면서 개발을 진행&lt;/strong&gt;합니다. 코드를 직접 쓰는 시간보다, 원하는 동작을 설명하는 시간이 더 깁니다.&lt;/p&gt;
&lt;h3&gt;4단계: 버전 관리 — GitHub으로 기록&lt;/h3&gt;
&lt;p&gt;개발 중간중간 커밋을 남깁니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;feat: todo CRUD 기능 구현&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push origin main&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Claude Code에게 &lt;code class=&quot;language-text&quot;&gt;/commit&lt;/code&gt; 명령어를 사용하면 변경 내용을 분석해서 적절한 커밋 메시지까지 작성해줍니다.&lt;/p&gt;
&lt;h3&gt;5단계: 배포 — Vercel 또는 GitHub Pages&lt;/h3&gt;
&lt;p&gt;Next.js 프로젝트라면 Vercel에 연결하는 게 가장 간단합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Vercel에 GitHub 저장소 연결&lt;/li&gt;
&lt;li&gt;환경 변수(Supabase URL, Key) 설정&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;git push&lt;/code&gt;만 하면 자동 배포&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;AI 개발의 핵심 — 사람과 AI의 역할 분담&lt;/h2&gt;
&lt;p&gt;제가 경험한 AI 기반 개발의 핵심은 &lt;strong&gt;역할 분담&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;내가 하는 일&lt;/th&gt;
&lt;th&gt;Claude Code가 하는 일&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;무엇을 만들지 결정&lt;/td&gt;
&lt;td&gt;어떻게 만들지 설계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;요구사항 설명&lt;/td&gt;
&lt;td&gt;코드 작성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;결과 확인 및 피드백&lt;/td&gt;
&lt;td&gt;수정 및 개선&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최종 판단&lt;/td&gt;
&lt;td&gt;대안 제시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;비유하자면, 저는 &lt;strong&gt;건축주&lt;/strong&gt;이고 Claude Code는 &lt;strong&gt;건축가&lt;/strong&gt;입니다. 건축주가 &quot;3층짜리 카페를 짓고 싶어요&quot;라고 말하면, 건축가가 도면을 그리고 시공합니다. 건축주가 벽돌을 쌓을 필요는 없습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Supabase vs Firebase — 백엔드 서비스 비교&lt;/h2&gt;
&lt;p&gt;백엔드 서비스는 여러 선택지가 있습니다. 비교해봤습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;서비스&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;적합한 경우&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supabase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;PostgreSQL 기반, 오픈소스, REST/GraphQL 자동 생성&lt;/td&gt;
&lt;td&gt;관계형 데이터, SQL 선호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Firebase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NoSQL(Firestore), Google 생태계&lt;/td&gt;
&lt;td&gt;빠른 프로토타이핑, 모바일 앱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PocketBase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Go 기반 단일 바이너리, 셀프호스팅&lt;/td&gt;
&lt;td&gt;가벼운 프로젝트, 직접 서버 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;제가 Supabase를 선택한 이유는 세 가지입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SQL을 쓸 수 있다&lt;/strong&gt; — NoSQL보다 익숙하고, 복잡한 쿼리가 가능합니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;무료 티어가 넉넉하다&lt;/strong&gt; — 개인 프로젝트에 충분한 용량&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claude Code와 궁합이 좋다&lt;/strong&gt; — SQL과 REST API를 AI가 잘 다룹니다&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;AI 웹개발 실전 팁 3가지&lt;/h2&gt;
&lt;h3&gt;Supabase RLS는 반드시 설정하세요&lt;/h3&gt;
&lt;p&gt;Supabase는 기본적으로 프론트엔드에서 직접 DB를 호출합니다. RLS 없이 배포하면 &lt;strong&gt;누구나 API로 모든 데이터에 접근할 수 있습니다.&lt;/strong&gt; 이건 실수가 아니라 보안 사고입니다.&lt;/p&gt;
&lt;h3&gt;Claude Code에게 컨텍스트를 충분히 주세요&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# 나쁜 예
&quot;로그인 기능 만들어줘&quot;

# 좋은 예
&quot;Supabase Auth를 사용해서 이메일/비밀번호 로그인 기능을 만들어줘.
Next.js App Router 구조이고, 로그인 후 /dashboard로 리다이렉트해야 해.
미인증 사용자가 /dashboard에 접근하면 /login으로 보내줘.&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;구체적으로 설명할수록, 수정 횟수가 줄어듭니다.&lt;/p&gt;
&lt;h3&gt;Git 커밋은 자주 하세요&lt;/h3&gt;
&lt;p&gt;AI와 개발하면 코드가 빠르게 바뀝니다. 중간중간 커밋하지 않으면, 문제가 생겼을 때 되돌릴 지점이 없습니다. &quot;동작하는 상태&quot;가 확인될 때마다 커밋하는 습관을 들이세요.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;코딩을 몰라도 AI로 웹서비스를 만들 수 있나요?&lt;/h3&gt;
&lt;p&gt;기본적인 웹 개념(HTML, API 등)을 이해하면 충분합니다. Claude Code가 코드를 작성하고, 여러분은 &quot;무엇을 만들지&quot; 설명하는 역할입니다. 다만, 결과물을 검토하고 디버깅할 때 기초 지식이 있으면 훨씬 수월합니다.&lt;/p&gt;
&lt;h3&gt;이 조합으로 개발하면 비용이 얼마나 드나요?&lt;/h3&gt;
&lt;p&gt;Supabase 무료 티어(500MB DB, 1GB 스토리지), Vercel 무료 플랜, GitHub 무료 저장소를 사용하면 &lt;strong&gt;호스팅 비용은 0원&lt;/strong&gt;입니다. Claude Code 구독 비용만 발생합니다. 개인 프로젝트나 사이드 프로젝트에는 충분한 수준입니다.&lt;/p&gt;
&lt;h3&gt;Claude Code 말고 다른 AI 코딩 도구도 사용할 수 있나요?&lt;/h3&gt;
&lt;p&gt;GitHub Copilot, Cursor 등 다른 AI 코딩 도구도 비슷한 프로세스로 활용할 수 있습니다. 다만 Claude Code는 프로젝트 전체 맥락을 이해하고 대화 기반으로 개발을 진행할 수 있다는 점에서 이 프로세스에 가장 잘 맞습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;정리하면, AI를 이용한 웹서비스 개발 프로세스는 이렇습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;기획&lt;/strong&gt; — Claude Code와 대화하며 구조 설계&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;셋업&lt;/strong&gt; — GitHub 저장소 + Supabase 프로젝트 초기화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;개발&lt;/strong&gt; — Claude Code가 코드 작성, 나는 피드백&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;관리&lt;/strong&gt; — GitHub으로 버전 관리&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;배포&lt;/strong&gt; — Vercel 연결 후 자동 배포&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;핵심은 &lt;strong&gt;&quot;코드를 직접 쓰는 것&quot;에서 &quot;무엇을 만들지 설명하는 것&quot;으로 역할이 바뀐다&lt;/strong&gt;는 점입니다.&lt;/p&gt;
&lt;p&gt;개발 경험이 많으면 더 정확한 지시를 할 수 있고, 경험이 적어도 AI와 대화하면서 배워갈 수 있습니다. 어느 쪽이든, 혼자 처음부터 끝까지 코딩하던 시대와는 확실히 다릅니다.&lt;/p&gt;
&lt;p&gt;여러분은 AI와 함께 어떤 서비스를 만들어보고 싶으신가요? 댓글로 알려주세요!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/overview&quot;&gt;Claude Code 공식 문서&lt;/a&gt; — Anthropic의 AI 코딩 에이전트 소개 및 사용법&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://supabase.com/docs&quot;&gt;Supabase 공식 문서&lt;/a&gt; — 데이터베이스, 인증, 스토리지 설정 가이드&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vercel.com/docs&quot;&gt;Vercel 공식 문서&lt;/a&gt; — Next.js 배포 및 환경 변수 설정&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/docs/app&quot;&gt;Next.js App Router 가이드&lt;/a&gt; — App Router 구조와 라우팅&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[COKACDIR — 텔레그램으로 Claude Code, Codex CLI를 원격 제어하는 법]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. "Claude Code를 쓰고 싶은데, 항상 컴퓨터 앞에 앉아 있을 수는 없잖아요." AI…]]></description><link>http://blog.javapark.kr/cokacdir-telegram-ai-coding-agent/</link><guid isPermaLink="false">http://blog.javapark.kr/cokacdir-telegram-ai-coding-agent/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/cokacdir-telegram-ai-coding-agent.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Claude Code를 쓰고 싶은데, 항상 컴퓨터 앞에 앉아 있을 수는 없잖아요.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;AI 코딩 에이전트를 써보면 한 가지 아쉬운 점이 있습니다. &lt;strong&gt;내 컴퓨터 터미널에서만 쓸 수 있다&lt;/strong&gt;는 것. 외출 중에 &quot;아 그 버그 고쳐야 하는데&quot; 싶어도, 노트북을 열 수 없으면 답이 없습니다.&lt;/p&gt;
&lt;p&gt;결론부터 말씀드리면 — &lt;strong&gt;COKACDIR을 쓰면 텔레그램 메시지 하나로 내 컴퓨터의 Claude Code를 원격 조작할 수 있습니다.&lt;/strong&gt; 새로운 AI를 설치하는 게 아니라, 이미 쓰고 있는 코딩 에이전트를 텔레그램에서 리모컨처럼 조종하는 방식입니다.&lt;/p&gt;
&lt;p&gt;저는 실제로 사내에서 봇 2개를 만들어 각각 Claude Code와 Codex CLI를 연결하고, 하나의 그룹에서 &quot;작성 → 검증&quot; 역할을 나눠 운영하고 있습니다. 직접 써본 경험까지 공유합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;COKACDIR이 뭔가?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;COKACDIR&lt;/strong&gt;(코칵디르)은 기존 AI 코딩 에이전트를 텔레그램에서 원격 제어하게 해주는 오픈소스 도구입니다.&lt;/p&gt;
&lt;p&gt;핵심 컨셉을 정리하면:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;정체&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI 코딩 에이전트 원격 제어 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;지원 에이전트&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Claude Code, Codex CLI, Gemini CLI, OpenCode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;조작 방식&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;텔레그램 봇&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;기술 스택&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rust 74.7%, TypeScript 22.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;바이너리 크기&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15~20MB (단일 바이너리)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;라이선스&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MIT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/kstost/cokacdir&quot;&gt;kstost/cokacdir&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;비유하자면&lt;/strong&gt; — Claude Code가 내 컴퓨터에서 일하는 AI 개발자라면, COKACDIR은 그 개발자에게 &lt;strong&gt;텔레그램으로 업무 지시를 보내는 채널&lt;/strong&gt;입니다. AI 자체가 아니라, 기존 AI에 리모컨을 달아주는 도구입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;왜 필요한가?&lt;/h2&gt;
&lt;h3&gt;기존 방식의 한계&lt;/h3&gt;
&lt;p&gt;Claude Code, Codex CLI 같은 코딩 에이전트는 강력하지만, &lt;strong&gt;내 컴퓨터 터미널에 직접 접속해야&lt;/strong&gt; 합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;상황&lt;/th&gt;
&lt;th&gt;기존 방식&lt;/th&gt;
&lt;th&gt;COKACDIR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;외출 중 긴급 버그 수정&lt;/td&gt;
&lt;td&gt;노트북 필요&lt;/td&gt;
&lt;td&gt;텔레그램에서 지시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;장시간 작업 모니터링&lt;/td&gt;
&lt;td&gt;터미널 열어둬야 함&lt;/td&gt;
&lt;td&gt;텔레그램으로 실시간 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;예약 작업 (야간 빌드 등)&lt;/td&gt;
&lt;td&gt;별도 CI/CD 구성&lt;/td&gt;
&lt;td&gt;cron 표현식으로 예약&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;팀원과 AI 공유&lt;/td&gt;
&lt;td&gt;각자 설치 필요&lt;/td&gt;
&lt;td&gt;그룹 채팅에서 공유 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;특히 &lt;strong&gt;스마트폰 하나로&lt;/strong&gt; AI 코딩 에이전트를 제어할 수 있다는 점이 핵심입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;설치 방법 — 5분 가이드&lt;/h2&gt;
&lt;h3&gt;Step 1: COKACDIR 설치&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;macOS / Linux:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-fsSL&lt;/span&gt; https://cokacdir.cokac.com/manage.sh &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cokacctl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Windows (관리자 PowerShell):&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;powershell&quot;&gt;&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;irm&lt;/span&gt; https:&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;cokacdir&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cokac&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;com/manage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ps1 &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;iex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; cokacctl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;설치하면 &lt;code class=&quot;language-text&quot;&gt;cokacctl&lt;/code&gt;이라는 관리 TUI가 열립니다.&lt;/p&gt;
&lt;h3&gt;Step 2: 텔레그램 봇 생성&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;텔레그램에서 &lt;strong&gt;@BotFather&lt;/strong&gt;를 검색&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;/newbot&lt;/code&gt; 명령 입력&lt;/li&gt;
&lt;li&gt;봇 이름과 아이디 설정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API 토큰&lt;/strong&gt;을 복사 (예: &lt;code class=&quot;language-text&quot;&gt;123456789:ABCdefGhIjKlmNoPqRsTuVwXyZ&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Step 3: COKACDIR 설정&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;cokacctl&lt;/code&gt; TUI에서:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;i&lt;/code&gt; 키 — 설치&lt;/li&gt;
&lt;li&gt;복사한 텔레그램 봇 토큰 입력&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;s&lt;/code&gt; 키 — 서버 시작&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 3단계면 끝입니다. 이제 텔레그램에서 내가 만든 봇에게 메시지를 보내면, 내 컴퓨터의 코딩 에이전트가 작업을 수행합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;주요 기능&lt;/h2&gt;
&lt;h3&gt;1. 텔레그램에서 코딩 에이전트 제어&lt;/h3&gt;
&lt;p&gt;텔레그램 봇에게 자연어로 메시지를 보내면, 연결된 코딩 에이전트(Claude Code 등)가 실행합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;나: src/api/auth.js에서 JWT 만료 시간을 1시간에서 24시간으로 변경해줘

봇: [Claude Code 실행 중...]
     auth.js 파일을 수정했습니다.
     - expiresIn: &apos;1h&apos; → &apos;24h&apos;
     변경 완료.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;실시간 스트리밍으로 진행 상황을 확인할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;2. 멀티 에이전트 지원&lt;/h3&gt;
&lt;p&gt;하나의 COKACDIR에서 여러 코딩 에이전트를 전환할 수 있습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;명령어&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;사용할 에이전트/모델 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/session&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;세션 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;세션 시작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;세션 중지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/clear&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;대화 초기화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;3. 예약 작업&lt;/h3&gt;
&lt;p&gt;cron 표현식이나 절대 시간으로 작업을 예약할 수 있습니다. 야간 빌드, 정기 코드 점검 같은 반복 작업에 유용합니다.&lt;/p&gt;
&lt;h3&gt;4. 파일 업로드/다운로드&lt;/h3&gt;
&lt;p&gt;텔레그램으로 파일을 보내면 서버에 업로드되고, &lt;code class=&quot;language-text&quot;&gt;/down&lt;/code&gt; 명령으로 서버의 파일을 텔레그램으로 받을 수 있습니다.&lt;/p&gt;
&lt;h3&gt;5. 보안 기능&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AES-256 암호화&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;설정 가능한 청크 분할로 파일 암호화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;접근 제어&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/allowed&lt;/code&gt;로 허용 사용자 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;도구 제한&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/allowedtools&lt;/code&gt;로 사용 가능한 도구 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;추가 기능 — 코딩 에이전트 외&lt;/h2&gt;
&lt;p&gt;COKACDIR은 원격 코딩 제어 외에도 부가 기능을 제공합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;터미널 멀티패널&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;분할 화면으로 여러 작업 동시 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;20+ 언어 구문 강조&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;코드 파일 내장 뷰어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;이미지 뷰어&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Kitty, iTerm2, Sixel 프로토콜 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Git 통합&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;상태, 커밋, 로그, 브랜치 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSH/SFTP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;원격 서버 접속&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;중복 파일 감지&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;디스크 정리 도구&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;프로세스 관리자&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;실행 중인 프로세스 모니터링&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;지원 플랫폼&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OS&lt;/th&gt;
&lt;th&gt;아키텍처&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;macOS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apple Silicon (ARM64), Intel (x86_64)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Linux&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;x86_64, ARM64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Windows&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;x86_64, ARM64&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Rust로 작성되어 단일 바이너리(15~20MB)로 배포됩니다. 별도 런타임 설치 없이 바로 실행할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;실전 활용 — 직접 써본 경험&lt;/h2&gt;
&lt;h3&gt;멀티봇 협업 구조: AI 2대를 한 그룹에서 굴리기&lt;/h3&gt;
&lt;p&gt;저는 사내에서 &lt;strong&gt;COKACDIR 봇 2개&lt;/strong&gt;를 운영하고 있습니다. 각 봇에 서로 다른 코딩 에이전트를 연결하고, 하나의 텔레그램 그룹에 초대해서 &lt;strong&gt;역할을 분리&lt;/strong&gt;했습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;봇&lt;/th&gt;
&lt;th&gt;연결 에이전트&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bot A&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;코드 작성, 아키텍처 설계, 리팩토링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bot B&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Codex CLI / Gemini CLI&lt;/td&gt;
&lt;td&gt;코드 리뷰, 테스트 작성, 검증&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;작업 흐름은 이렇습니다:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[텔레그램 그룹]

나: @BotA 사용자 인증 API를 만들어줘. 
    JWT 기반, refresh token 포함.

Bot A (Claude Code): 
    인증 API를 작성했습니다.
    - POST /auth/login
    - POST /auth/refresh
    - POST /auth/logout
    파일 3개 생성 완료.

나: @BotB 방금 Bot A가 만든 인증 API 코드를 리뷰해줘.
    보안 취약점이 있는지 확인하고, 테스트도 작성해줘.

Bot B (Codex CLI):
    리뷰 완료. 2가지 개선사항:
    1. refresh token 저장 시 해싱 필요
    2. rate limiting 미적용
    테스트 파일 생성 완료 (12 cases).

나: @BotA 리뷰 반영해서 수정해줘.

Bot A: 수정 완료. 모든 테스트 통과.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;핵심은 &quot;작성 → 검증 → 수정&quot;을 서로 다른 AI가 맡는다는 점&lt;/strong&gt;입니다. 한 AI가 만든 코드를 다른 AI가 검증하면, 한 AI에게 모든 걸 맡기는 것보다 완성도가 확실히 올라갑니다. 사람이 하는 코드 리뷰 프로세스와 똑같은 구조를 AI끼리 돌리는 셈입니다.&lt;/p&gt;
&lt;h3&gt;이 구조의 장점&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;크로스 체크&lt;/strong&gt;: AI도 실수합니다. 다른 모델이 검증하면 놓치는 부분을 잡아냅니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;역할 특화&lt;/strong&gt;: Claude Code는 코드 생성이 강하고, Codex는 테스트 작성에 능합니다. 각자 잘하는 일을 맡기면 효율적입니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;한 그룹에서 관리&lt;/strong&gt;: 팀원 모두가 대화 흐름을 볼 수 있고, 중간에 개입할 수 있습니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;기록 자동 보관&lt;/strong&gt;: 텔레그램 채팅 기록이 곧 작업 로그입니다&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;기타 활용 시나리오&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;외출 중 긴급 핫픽스:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;나: production에서 /api/users 500 에러. 로그 확인하고 수정해줘.
봇: null 참조 에러 확인. 수정 완료. 커밋할까요?
나: 응
봇: 푸시 완료.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;야간 자동 작업:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;cron 표현식으로 매일 새벽 2시에 테스트를 실행하고 결과를 텔레그램으로 받을 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;팀 공유:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;텔레그램 그룹에 봇을 추가하면 팀원 모두가 AI 에이전트를 사용할 수 있습니다. &lt;code class=&quot;language-text&quot;&gt;/allowed&lt;/code&gt; 명령으로 접근 권한을 관리합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;주의할 점&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;보안&lt;/strong&gt;: 내 컴퓨터에서 AI가 직접 실행되므로, 봇 토큰 관리와 접근 제어(&lt;code class=&quot;language-text&quot;&gt;/allowed&lt;/code&gt;)를 반드시 설정하세요&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비용&lt;/strong&gt;: COKACDIR 자체는 무료지만, 연결하는 코딩 에이전트(Claude Code 등)의 사용 요금은 별도입니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;컴퓨터 상태&lt;/strong&gt;: 내 컴퓨터가 켜져 있고 인터넷에 연결되어 있어야 합니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MIT 라이선스&lt;/strong&gt;: 소프트웨어는 &quot;AS IS&quot;로 제공되며, 데이터 손실 등에 대한 책임은 사용자에게 있습니다&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;정리&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;한 줄 요약&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;텔레그램으로 Claude Code/Codex/Gemini를 원격 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;추천 대상&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;이동 중에도 AI 코딩을 사용하고 싶은 개발자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;비용&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;COKACDIR 무료, 에이전트 비용 별도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;설치 시간&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;약 5분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/kstost/cokacdir&quot;&gt;kstost/cokacdir&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&quot;AI 코딩 에이전트는 좋은데 항상 컴퓨터 앞에 있어야 한다&quot;는 불편함을 정확히 해결하는 도구입니다. 특히 Claude Code를 주력으로 쓰는 개발자라면, 텔레그램 봇 하나 만들어두는 것만으로 활용도가 크게 올라갑니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;h3&gt;Q. Claude Code가 설치되어 있어야 하나요?&lt;/h3&gt;
&lt;p&gt;네. COKACDIR은 새로운 AI가 아니라, 기존에 설치된 코딩 에이전트의 리모컨 역할입니다. Claude Code, Codex CLI, Gemini CLI 중 하나 이상이 설치되어 있어야 합니다.&lt;/p&gt;
&lt;h3&gt;Q. 컴퓨터를 끄면 어떻게 되나요?&lt;/h3&gt;
&lt;p&gt;COKACDIR 서버가 꺼지므로 텔레그램에서 제어할 수 없습니다. 항상 접근하려면 클라우드 서버(AWS, GCP 등)에 설치하는 것을 추천합니다.&lt;/p&gt;
&lt;h3&gt;Q. 보안은 안전한가요?&lt;/h3&gt;
&lt;p&gt;텔레그램 봇 토큰과 &lt;code class=&quot;language-text&quot;&gt;/allowed&lt;/code&gt; 명령으로 접근을 제한할 수 있습니다. 다만 내 컴퓨터에서 AI가 직접 명령을 실행하므로, 봇 토큰 유출에 주의해야 합니다. AES-256 파일 암호화도 지원합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;여러분은 AI 코딩 에이전트를 어떻게 원격으로 활용하고 계신가요? 다른 방법을 쓰고 계시다면 댓글로 공유해주세요!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[AI 코딩 도구 Skill 비교 — Claude Code vs Gemini CLI vs Codex CLI 커스텀 명령어 완전 정리]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. "AI 코딩 도구마다 커스텀 명령어 만드는 방식이 다르던데, 어떤 걸 써야 하죠?" 요즘 Claude Code, Gemini CLI, OpenAI Codex CLI…]]></description><link>http://blog.javapark.kr/ai-coding-skills-comparison/</link><guid isPermaLink="false">http://blog.javapark.kr/ai-coding-skills-comparison/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/ai-coding-skills-comparison.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;AI 코딩 도구마다 커스텀 명령어 만드는 방식이 다르던데, 어떤 걸 써야 하죠?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;요즘 Claude Code, Gemini CLI, OpenAI Codex CLI 모두 &lt;strong&gt;반복 작업을 명령어 하나로 처리하는 기능&lt;/strong&gt;을 제공합니다. 이름은 조금씩 다르지만 핵심은 같습니다 — &lt;strong&gt;자주 하는 작업 지시를 파일로 저장해두고, 한 줄로 호출하는 것&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;결론부터 말씀드리면, 세 도구 모두 비슷한 목적을 달성하지만 &lt;strong&gt;설계 철학과 세부 구현이 꽤 다릅니다.&lt;/strong&gt; 직접 조사하고 비교해봤습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;한눈에 보는 3사 비교표&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;Claude Code&lt;/th&gt;
&lt;th&gt;Gemini CLI&lt;/th&gt;
&lt;th&gt;Codex CLI (OpenAI)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;커스텀 명령어&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Skill (&lt;code class=&quot;language-text&quot;&gt;SKILL.md&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Custom Command (&lt;code class=&quot;language-text&quot;&gt;.toml&lt;/code&gt;) + Agent Skill (&lt;code class=&quot;language-text&quot;&gt;SKILL.md&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Skill (&lt;code class=&quot;language-text&quot;&gt;SKILL.md&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;프로젝트 설정 파일&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;GEMINI.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;AGENTS.md&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;호출 방식&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/skill-name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/command-name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;$skill-name&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;자동 호출&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;description 기반&lt;/td&gt;
&lt;td&gt;Agent Skill만 자동&lt;/td&gt;
&lt;td&gt;description 기반&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;파일 형식&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Markdown + YAML&lt;/td&gt;
&lt;td&gt;TOML (명령어) / Markdown (스킬)&lt;/td&gt;
&lt;td&gt;Markdown + YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;쉘 명령 주입&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;!`command`&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;!{command}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;미지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;서브에이전트 분리&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;context: fork&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;미지원&lt;/td&gt;
&lt;td&gt;미지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;스킬 배포/공유&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Git으로 공유&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;.skill&lt;/code&gt; 패키지, Extensions&lt;/td&gt;
&lt;td&gt;로컬 공유&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;1. Claude Code — Skill&lt;/h2&gt;
&lt;p&gt;이전 포스팅에서 자세히 다뤘지만, 핵심만 짚겠습니다.&lt;/p&gt;
&lt;h3&gt;파일 구조&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;~/.claude/skills/blog-post/
├── SKILL.md          # 필수: 프론트매터 + 지시문
├── reference.md      # 선택: 상세 문서
└── scripts/
    └── helper.py     # 선택: 헬퍼 스크립트&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;SKILL.md 예시&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blog&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;post
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 블로그 포스팅 초안을 작성합니다
&lt;span class=&quot;token key atrule&quot;&gt;disable-model-invocation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;allowed-tools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Read&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Grep&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Glob&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WebSearch
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 블로그 포스팅 작성 스킬&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;주제($ARGUMENTS)를 받으면&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
1. 아웃라인을 먼저 잡는다
2. WebSearch로 최신 정보 확인
3. 마크다운 초안 작성&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;호출&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;/blog-post Claude Code Skill 소개&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Claude Code만의 강점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;context: fork&lt;/code&gt;&lt;/strong&gt; — 서브에이전트로 분리 실행해서 메인 대화가 오염되지 않음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;allowed-tools&lt;/code&gt;&lt;/strong&gt; — 스킬별로 사용 가능한 도구를 제한 가능&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;disable-model-invocation&lt;/code&gt;&lt;/strong&gt; — 배포 같은 위험한 작업은 수동 호출만 허용&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;!`command`&lt;/code&gt;&lt;/strong&gt; — 쉘 명령어 결과를 동적으로 프롬프트에 주입&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;2. Gemini CLI — Custom Command + Agent Skill&lt;/h2&gt;
&lt;p&gt;Gemini CLI는 커스텀 명령어 시스템을 &lt;strong&gt;두 가지로 분리&lt;/strong&gt;합니다.&lt;/p&gt;
&lt;h3&gt;(1) Custom Command — 간단한 슬래시 명령어&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;TOML 파일&lt;/strong&gt;로 작성합니다. Claude Code나 Codex와 달리 마크다운이 아니라 TOML입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;~/.gemini/commands/commit.toml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;toml&quot;&gt;&lt;pre class=&quot;language-toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token key property&quot;&gt;description&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Git 커밋 메시지를 자동 생성합니다&quot;&lt;/span&gt;
&lt;span class=&quot;token key property&quot;&gt;prompt&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&quot;
다음 diff를 기반으로 Conventional Commit 메시지를 생성해주세요:

```diff
!&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;git diff --staged&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&quot;&quot;&quot;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;
호출:
```bash
/commit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;핵심 문법:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;!{command}&lt;/code&gt; — 쉘 명령어 실행 후 결과 주입&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;{{args}}&lt;/code&gt; — 사용자 인자 전달&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@{파일경로}&lt;/code&gt; — 파일/이미지/PDF 내용 주입 (멀티모달 지원)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;하위 폴더로 네임스페이스도 지원합니다:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.gemini/commands/git/commit.toml  →  /git:commit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;(2) Agent Skill — 자동 활성화되는 전문 지식&lt;/h3&gt;
&lt;p&gt;Custom Command와 별도로, &lt;strong&gt;모델이 자동으로 판단해서 활성화하는 스킬 시스템&lt;/strong&gt;이 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.gemini/skills/code-reviewer/
├── SKILL.md
├── scripts/
└── references/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;reviewer
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 코드 리뷰를 수행합니다. 로컬 변경사항과 원격 PR 모두 지원합니다.
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Code Reviewer&lt;/span&gt;
이 스킬은 체계적인 코드 리뷰를 수행합니다.

&lt;span class=&quot;token comment&quot;&gt;## 워크플로우&lt;/span&gt;
1. 리뷰 대상 파악 (PR 번호 또는 로컬 변경사항)
2. 코드 분석
3. 리뷰 코멘트 생성&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;토큰 효율이 좋은 설계:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;세션 시작 시 이름+설명만 로드&lt;/li&gt;
&lt;li&gt;관련 작업이 감지되면 &lt;code class=&quot;language-text&quot;&gt;activate_skill&lt;/code&gt; 호출&lt;/li&gt;
&lt;li&gt;그때서야 전체 SKILL.md 본문이 컨텍스트에 주입&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;관리 명령어:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;/skills list
/skills disable code-reviewer
gemini skills &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; https://github.com/&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Gemini CLI만의 강점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TOML 기반 Command&lt;/strong&gt; — 간단한 명령어는 3줄이면 완성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;@{파일경로}&lt;/code&gt;&lt;/strong&gt; — 이미지, PDF 등 멀티모달 파일을 프롬프트에 바로 주입&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progressive Disclosure&lt;/strong&gt; — Agent Skill은 필요할 때만 전체 로드 (토큰 절약)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensions 시스템&lt;/strong&gt; — 스킬을 패키지로 묶어 설치/배포 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;3. Codex CLI (OpenAI) — Skill&lt;/h2&gt;
&lt;p&gt;Codex CLI의 Skill 시스템은 구조적으로 Claude Code와 가장 비슷합니다.&lt;/p&gt;
&lt;h3&gt;파일 구조&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.agents/skills/fix-issue/
├── SKILL.md          # 필수: 지시문
├── scripts/          # 선택: 실행 스크립트
├── references/       # 선택: 참고 문서
└── agents/
    └── openai.yaml   # 선택: UI 메타데이터&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;SKILL.md 예시&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fix&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;issue
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; GitHub 이슈를 분석하고 코드를 수정합니다
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Fix Issue&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;이슈 번호를 받으면&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
1. 이슈 내용 분석
2. 관련 코드 탐색
3. 수정 구현
4. 테스트 작성&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;호출&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$fix&lt;/span&gt;-issue &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Claude Code의 &lt;code class=&quot;language-text&quot;&gt;/&lt;/code&gt; 대신 &lt;code class=&quot;language-text&quot;&gt;$&lt;/code&gt; 기호를 사용합니다.&lt;/p&gt;
&lt;h3&gt;스킬 저장 위치&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;범위&lt;/th&gt;
&lt;th&gt;경로&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;저장소 (CWD)&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;.agents/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;저장소 (루트)&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;$REPO_ROOT/.agents/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;$HOME/.agents/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시스템&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/etc/codex/skills/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;번들&lt;/td&gt;
&lt;td&gt;Codex 내장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Codex CLI만의 강점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;openai.yaml&lt;/code&gt; 메타데이터&lt;/strong&gt; — 아이콘, 브랜드 색상 등 UI 커스터마이징&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP 의존성 선언&lt;/strong&gt; — 스킬에서 필요한 MCP 도구를 명시적으로 선언&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;5단계 스코프&lt;/strong&gt; — CWD → 저장소 루트 → 사용자 → 관리자 → 시스템까지 세분화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;30+ 내장 슬래시 명령어&lt;/strong&gt; — &lt;code class=&quot;language-text&quot;&gt;/plan&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;/diff&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;/compact&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;/review&lt;/code&gt; 등&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;프로젝트 설정 파일 비교 — CLAUDE.md vs GEMINI.md vs AGENTS.md&lt;/h2&gt;
&lt;p&gt;스킬과 함께 알아두면 좋은 게 &lt;strong&gt;프로젝트 설정 파일&lt;/strong&gt;입니다. 세 도구 모두 &quot;프로젝트 전체에 적용되는 규칙&quot;을 마크다운 파일로 관리합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;Claude Code&lt;/th&gt;
&lt;th&gt;Gemini CLI&lt;/th&gt;
&lt;th&gt;Codex CLI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;파일명&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;GEMINI.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;AGENTS.md&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;위치&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;프로젝트 루트 + 하위 디렉토리&lt;/td&gt;
&lt;td&gt;프로젝트 루트 + 하위 디렉토리&lt;/td&gt;
&lt;td&gt;프로젝트 루트 + 하위 디렉토리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;글로벌 설정&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;~/.claude/CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;~/.gemini/GEMINI.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;~/.codex/AGENTS.md&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;동적 발견&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;작업 디렉토리 기준&lt;/td&gt;
&lt;td&gt;JIT 로드 (파일 접근 시)&lt;/td&gt;
&lt;td&gt;CWD까지 누적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;크기 제한&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;32KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;자동 생성&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/init&lt;/code&gt; 명령어&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/init&lt;/code&gt; 명령어&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;비유하자면, &lt;strong&gt;CLAUDE.md/GEMINI.md/AGENTS.md는 사무실 공지사항&lt;/strong&gt;, &lt;strong&gt;Skill은 업무 매뉴얼&lt;/strong&gt;입니다. 하나는 항상 읽히고, 하나는 필요할 때만 꺼냅니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;어떤 도구를 선택해야 할까?&lt;/h2&gt;
&lt;p&gt;솔직히 말하면, Skill 기능만으로 도구를 선택하진 않습니다. 하지만 각 도구의 Skill 설계에서 &lt;strong&gt;철학의 차이&lt;/strong&gt;가 보입니다.&lt;/p&gt;
&lt;h3&gt;Claude Code가 적합한 경우&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;안전성 제어&lt;/strong&gt;가 중요할 때 — &lt;code class=&quot;language-text&quot;&gt;disable-model-invocation&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;allowed-tools&lt;/code&gt;로 세밀한 제어&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;서브에이전트 분리&lt;/strong&gt;가 필요할 때 — &lt;code class=&quot;language-text&quot;&gt;context: fork&lt;/code&gt;로 긴 작업을 깔끔하게 분리&lt;/li&gt;
&lt;li&gt;이미 Claude Code를 주력으로 사용 중일 때&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Gemini CLI가 적합한 경우&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;간단한 명령어를 빠르게&lt;/strong&gt; 만들고 싶을 때 — TOML 3줄이면 충분&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;멀티모달 입력&lt;/strong&gt;이 필요할 때 — &lt;code class=&quot;language-text&quot;&gt;@{이미지.png}&lt;/code&gt; 같은 파일 주입&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;토큰 효율&lt;/strong&gt;을 중시할 때 — Progressive Disclosure 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Codex CLI가 적합한 경우&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;조직 단위 관리&lt;/strong&gt;가 필요할 때 — 5단계 스코프로 세분화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UI 커스터마이징&lt;/strong&gt;이 필요할 때 — &lt;code class=&quot;language-text&quot;&gt;openai.yaml&lt;/code&gt;로 아이콘, 색상 설정&lt;/li&gt;
&lt;li&gt;이미 OpenAI 생태계를 사용 중일 때&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;실전 팁 — 어떤 도구든 공통으로 적용되는 원칙&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. description을 잘 쓰세요.&lt;/strong&gt;
세 도구 모두 description을 보고 자동 호출 여부를 판단합니다. 모호하면 엉뚱한 타이밍에 호출됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 부작용이 있는 작업은 수동 호출만 허용하세요.&lt;/strong&gt;
배포, 커밋, 메시지 전송 등은 실수로 자동 호출되면 큰일입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude Code: &lt;code class=&quot;language-text&quot;&gt;disable-model-invocation: true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Gemini CLI: Custom Command는 기본이 수동&lt;/li&gt;
&lt;li&gt;Codex CLI: &lt;code class=&quot;language-text&quot;&gt;allow_implicit_invocation: false&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 스킬 파일은 짧게 유지하세요.&lt;/strong&gt;
500줄 이내가 권장됩니다. 길어지면 별도 파일로 분리하고 참조하세요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 팀과 공유하려면 프로젝트 디렉토리에 저장하세요.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# Claude Code
.claude/skills/my-skill/SKILL.md

# Gemini CLI
.gemini/skills/my-skill/SKILL.md
.gemini/commands/my-command.toml

# Codex CLI
.agents/skills/my-skill/SKILL.md&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Git으로 커밋하면 팀원 모두 같은 명령어를 사용할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;SKILL.md 표준이 통일되어 있나요?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://agentskills.io&quot;&gt;Agent Skills&lt;/a&gt;라는 오픈 스탠다드가 있고, Gemini CLI와 Codex CLI가 이를 따르고 있습니다. Claude Code도 비슷한 구조를 사용하지만 프론트매터 옵션에 차이가 있습니다. 완전한 호환은 아니지만, 핵심 구조(YAML 프론트매터 + 마크다운 본문)는 동일합니다.&lt;/p&gt;
&lt;h3&gt;하나의 Skill 파일을 여러 도구에서 쓸 수 있나요?&lt;/h3&gt;
&lt;p&gt;기본 구조가 비슷해서 &lt;strong&gt;간단한 스킬은 거의 그대로 사용 가능&lt;/strong&gt;합니다. 하지만 &lt;code class=&quot;language-text&quot;&gt;allowed-tools&lt;/code&gt;(Claude Code 전용), &lt;code class=&quot;language-text&quot;&gt;!{command}&lt;/code&gt; vs &lt;code class=&quot;language-text&quot;&gt;!`command`&lt;/code&gt; 같은 도구별 고유 문법이 있어서 완전한 호환은 어렵습니다.&lt;/p&gt;
&lt;h3&gt;Skill과 프롬프트 복사-붙여넣기의 차이는 뭔가요?&lt;/h3&gt;
&lt;p&gt;프롬프트 복사-붙여넣기는 텍스트만 전달하는 거지만, Skill은 &lt;strong&gt;도구 사용 제한, 자동 호출 제어, 서브에이전트 분리, 쉘 명령어 동적 주입&lt;/strong&gt; 같은 제어가 가능합니다. 자동차와 자전거의 차이라고 보시면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;AI 코딩 도구의 &lt;strong&gt;Skill/커스텀 명령어 기능은 이제 선택이 아니라 기본&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;세 도구 모두 &quot;반복 작업을 파일로 저장하고 한 줄로 호출한다&quot;는 핵심은 같지만:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;는 안전성 제어와 서브에이전트에 강하고&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gemini CLI&lt;/strong&gt;는 간결함과 토큰 효율에 강하고&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Codex CLI&lt;/strong&gt;는 조직 관리와 UI 커스터마이징에 강합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;어떤 도구를 쓰든, 반복하는 작업이 있다면 오늘 바로 Skill 파일 하나 만들어보세요.&lt;/p&gt;
&lt;p&gt;여러분은 어떤 AI 코딩 도구를 주로 사용하고 계신가요? 댓글로 알려주세요!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/skills&quot;&gt;Claude Code 공식 문서 — Skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/google-gemini/gemini-cli&quot;&gt;Gemini CLI GitHub 저장소&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openai/codex&quot;&gt;OpenAI Codex CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://agentskills.io&quot;&gt;Agent Skills 오픈 스탠다드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[아이디어 검증부터 시작하기 — AI와 함께 기획하는 법]]></title><description><![CDATA[안녕하세요, 자바파커입니다. "아이디어는 넘치는데, 뭘 만들어야 할지 모르겠다."…]]></description><link>http://blog.javapark.kr/01-idea-validation/</link><guid isPermaLink="false">http://blog.javapark.kr/01-idea-validation/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;아이디어는 넘치는데, 뭘 만들어야 할지 모르겠다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;1인 개발자라면 한 번쯤 이런 고민을 해보셨을 겁니다. 저도 그랬고, 솔직히 지금도 그렇습니다. 문제는 아이디어가 없는 게 아니라, &lt;strong&gt;어떤 아이디어가 실제로 만들 가치가 있는지&lt;/strong&gt; 판단하기 어렵다는 점이죠.&lt;/p&gt;
&lt;p&gt;결론부터 말씀드리면 — AI를 기획 파트너로 활용하면, 혼자서도 놀라울 정도로 체계적인 기획이 가능합니다. 이번 포스팅에서는 &lt;strong&gt;아이디어 발굴부터 PRD 작성까지&lt;/strong&gt;, AI와 함께하는 1인 개발자의 기획 프로세스를 공유합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1인 개발의 현실 — 왜 기획이 가장 중요한가&lt;/h2&gt;
&lt;p&gt;1인 개발에서 가장 무서운 건 &quot;3개월 동안 만들었는데, 아무도 안 쓴다&quot;는 상황입니다. 대기업이라면 기획자, 디자이너, PM이 각각의 역할을 맡지만, 1인 개발자는 이 모든 걸 혼자 해야 합니다.&lt;/p&gt;
&lt;p&gt;그래서 &lt;strong&gt;기획 단계에서의 검증&lt;/strong&gt;이 더욱 중요합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;대기업&lt;/th&gt;
&lt;th&gt;1인 개발자&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;아이디어&lt;/td&gt;
&lt;td&gt;기획팀 브레인스토밍&lt;/td&gt;
&lt;td&gt;혼자 고민&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시장 조사&lt;/td&gt;
&lt;td&gt;리서치팀 보고서&lt;/td&gt;
&lt;td&gt;구글링 + 감&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PRD 작성&lt;/td&gt;
&lt;td&gt;PM이 작성&lt;/td&gt;
&lt;td&gt;건너뛰기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MVP 정의&lt;/td&gt;
&lt;td&gt;스프린트 플래닝&lt;/td&gt;
&lt;td&gt;&quot;일단 다 만들자&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이 표를 보면 느끼셨겠지만, 1인 개발자의 기획은 대부분 &lt;strong&gt;감에 의존&lt;/strong&gt;합니다. 하지만 AI를 활용하면 이 격차를 상당 부분 좁힐 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;아이디어 브레인스토밍 — AI와 대화하며 아이디어 발굴하기&lt;/h2&gt;
&lt;h3&gt;첫 번째 프롬프트: 넓게 펼치기&lt;/h3&gt;
&lt;p&gt;아이디어가 막연할 때는, AI에게 &lt;strong&gt;제약 조건과 함께 아이디어를 요청&lt;/strong&gt;하는 것이 효과적입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;나는 1인 개발자야. 아래 조건에 맞는 사이드 프로젝트 아이디어를 10개 제안해줘.

조건:
- 혼자서 2주 안에 MVP를 만들 수 있는 규모
- Next.js + Supabase로 구현 가능
- B2C 또는 개인용 도구
- 월 구독 모델 또는 광고 수익 가능
- 이미 레드오션인 분야는 제외

각 아이디어마다 다음을 포함해줘:
1. 서비스명 (가칭)
2. 한 줄 설명
3. 타겟 사용자
4. 수익 모델
5. 기술적 난이도 (상/중/하)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이렇게 구체적인 제약 조건을 주면, AI가 훨씬 현실적인 아이디어를 제안합니다. &quot;앱 아이디어 추천해줘&quot;라고 물어보면 뻔한 답이 나오지만, &lt;strong&gt;조건을 좁히면 좁힐수록 실용적인 결과&lt;/strong&gt;가 나옵니다.&lt;/p&gt;
&lt;h3&gt;두 번째 프롬프트: 깊게 파기&lt;/h3&gt;
&lt;p&gt;10개 아이디어 중 마음에 드는 2~3개를 골랐다면, 각각에 대해 더 깊이 파봅니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;독서 기록 웹앱&quot; 아이디어를 더 구체화해줘.

다음 질문에 답해줘:
1. 기존 서비스(밀리의 서재, 리디 독서노트, 북적북적)와 차별점은?
2. 핵심 기능 3가지는?
3. 사용자가 이 앱을 매일 열어볼 이유는?
4. 기술적으로 가장 까다로운 부분은?
5. 2주 안에 만들 수 있는 MVP 범위는?&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 단계에서 중요한 건, AI의 답변을 &lt;strong&gt;그대로 수용하지 않는 것&lt;/strong&gt;입니다. AI는 아이디어를 정리하고 구조화하는 데 탁월하지만, &quot;이게 정말 사람들이 원하는 건가?&quot;라는 판단은 결국 본인의 몫입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;시장 조사 — AI로 경쟁 서비스 분석하고 타겟 사용자 정의하기&lt;/h2&gt;
&lt;h3&gt;경쟁 서비스 분석 프롬프트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;한국에서 사용 가능한 독서 기록/관리 서비스를 조사해줘.

각 서비스에 대해 다음을 정리해줘:
- 서비스명과 URL
- 핵심 기능
- 가격 정책
- 장점과 단점
- 사용자 리뷰에서 자주 언급되는 불만 사항

마지막에 이 시장의 전체적인 트렌드와 비어있는 틈새(gap)를 분석해줘.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;AI가 제공하는 정보는 학습 데이터 시점까지의 내용이므로, &lt;strong&gt;최신 정보는 직접 확인&lt;/strong&gt;해야 합니다. 하지만 초기 리서치의 뼈대를 잡는 데는 충분합니다.&lt;/p&gt;
&lt;h3&gt;타겟 사용자 페르소나 만들기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;독서 기록 웹앱의 타겟 사용자 페르소나를 3개 만들어줘.

각 페르소나에 포함할 항목:
- 이름 (가상)
- 나이, 직업
- 독서 습관 (월 몇 권, 선호 장르)
- 현재 독서 기록 방법
- 불편한 점 (Pain Point)
- 우리 앱에서 기대하는 것&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;페르소나를 만들어두면, 이후 기능 우선순위를 정할 때 &quot;&lt;strong&gt;이 기능이 민수(페르소나)에게 정말 필요한가?&lt;/strong&gt;&quot;라는 기준으로 판단할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;PRD 작성 — AI가 만들어주는 제품 요구사항 문서&lt;/h2&gt;
&lt;p&gt;PRD(Product Requirements Document)는 &quot;무엇을 만들 것인가&quot;를 정리한 문서입니다. 1인 개발자에게는 과하게 느껴질 수 있지만, &lt;strong&gt;PRD 없이 코딩을 시작하면 중간에 방향을 잃기 쉽습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;PRD 생성 프롬프트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;독서 기록 웹앱의 PRD를 작성해줘.

서비스 개요:
- 읽은 책을 기록하고, 독서 메모를 남기고, 읽은 책 통계를 볼 수 있는 웹앱
- ISBN 바코드 스캔으로 책 정보 자동 입력
- 월간/연간 독서 통계 대시보드

PRD에 포함할 섹션:
1. 프로젝트 개요 (목적, 배경)
2. 타겟 사용자
3. 핵심 기능 목록 (우선순위 P0/P1/P2)
4. 비기능 요구사항 (성능, 보안)
5. 기술 스택
6. 마일스톤 (2주 스프린트 기준)
7. 성공 지표 (KPI)
8. 리스크 및 대응 방안&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;AI가 생성한 PRD 예시 (일부)&lt;/h3&gt;
&lt;p&gt;아래는 실제로 Claude에게 요청해서 받은 PRD의 일부입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; 독서 기록 웹앱 PRD&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 1. 프로젝트 개요&lt;/span&gt;
&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; 1.1 목적&lt;/span&gt;
독서 애호가들이 읽은 책을 쉽게 기록하고, 독서 습관을 추적할 수 있는 
웹 애플리케이션을 개발한다.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; 1.2 배경&lt;/span&gt;
기존 독서 기록 앱들은 대부분 모바일 중심이며, 
웹에서의 사용 경험이 부족하다. 또한 독서 통계 기능이 
단순 권수 집계에 그치는 경우가 많다.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 2. 핵심 기능&lt;/span&gt;

&lt;span class=&quot;token table&quot;&gt;&lt;span class=&quot;token table-header-row&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; 우선순위 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; 기능 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; 설명 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token table-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;---------&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;------&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;------&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token table-data-rows&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; P0 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 책 등록 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; ISBN 검색으로 책 정보 자동 입력 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; P0 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 독서 상태 관리 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 읽는 중/읽은 책/읽고 싶은 책 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; P0 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 독서 메모 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 책별 메모 및 인용구 저장 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; P1 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 독서 통계 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 월간/연간 독서량, 장르별 분포 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; P1 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 바코드 스캔 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 카메라로 ISBN 바코드 인식 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; P2 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 소셜 공유 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 독서 기록 공개 프로필 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; P2 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 독서 목표 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 연간 독서 목표 설정 및 추적 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 PRD를 기반으로 개발을 진행하면, &quot;&lt;strong&gt;다음에 뭘 해야 하지?&lt;/strong&gt;&quot;라는 고민 없이 체계적으로 진행할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;MVP 범위 정하기 — &quot;이것만 만들자&quot; 전략&lt;/h2&gt;
&lt;p&gt;1인 개발자의 가장 큰 적은 **스코프 크리프(Scope Creep)**입니다. &quot;이 기능도 넣으면 좋겠는데...&quot;를 반복하다 보면, 영영 출시하지 못합니다.&lt;/p&gt;
&lt;h3&gt;MVP 범위 확정 프롬프트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;위 PRD 기반으로, 2주 안에 혼자서 만들 수 있는 MVP 범위를 정해줘.

조건:
- P0 기능만 포함
- 디자인은 최소한 (Tailwind CSS 기본 컴포넌트)
- 인증은 소셜 로그인(Google)만
- 배포는 Vercel
- 바코드 스캔은 MVP에서 제외 (수동 ISBN 입력으로 대체)

결과물:
1. MVP 기능 목록
2. 2주 스프린트 일정표 (일별)
3. 각 기능의 예상 소요 시간&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;AI가 만들어준 일정표를 보면 이런 식입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Week 1:
- Day 1-2: 프로젝트 세팅 + Supabase 연동 + 인증
- Day 3-4: 책 등록 (ISBN 검색 API 연동)
- Day 5: 독서 상태 관리 (읽는 중/완료/위시리스트)

Week 2:
- Day 1-2: 독서 메모 CRUD
- Day 3: 기본 대시보드 (독서 목록 뷰)
- Day 4: UI 다듬기 + 반응형
- Day 5: 배포 + 버그 수정&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;핵심은 &lt;strong&gt;과감하게 빼는 것&lt;/strong&gt;입니다. 통계 대시보드, 바코드 스캔, 소셜 공유 — 이런 건 다 v2에서 하면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;실전 예시: &quot;독서 기록 웹앱&quot; 기획 과정 전체를 AI와 함께&lt;/h2&gt;
&lt;p&gt;이 시리즈에서는 &quot;&lt;strong&gt;독서 기록 웹앱&lt;/strong&gt;&quot;을 실제로 만들어보겠습니다. 위에서 설명한 프로세스를 그대로 따라가면서, 각 단계에서 AI를 어떻게 활용했는지 보여드리겠습니다.&lt;/p&gt;
&lt;h3&gt;전체 기획 흐름 요약&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. 아이디어 발굴
   └─ AI에게 사이드 프로젝트 아이디어 10개 요청
   └─ &quot;독서 기록 웹앱&quot; 선택

2. 아이디어 검증
   └─ 경쟁 서비스 5개 분석
   └─ 차별점 정의: &quot;웹 기반 + 깔끔한 통계 + 빠른 기록&quot;

3. 타겟 사용자 정의
   └─ 페르소나 3개 작성
   └─ 핵심 타겟: &quot;월 2-4권 읽는 20-30대 직장인&quot;

4. PRD 작성
   └─ P0/P1/P2 기능 분류
   └─ 기술 스택 확정: Next.js + Supabase + Vercel

5. MVP 범위 확정
   └─ P0 기능만 포함한 2주 스프린트
   └─ v1.0 출시 목표&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;기획에 소요된 시간&lt;/h3&gt;
&lt;p&gt;놀라운 건, 이 전체 과정이 &lt;strong&gt;약 2시간&lt;/strong&gt;이면 끝난다는 점입니다. AI 없이 혼자 했다면 최소 1-2일은 걸렸을 겁니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;AI 없이&lt;/th&gt;
&lt;th&gt;AI와 함께&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;아이디어 브레인스토밍&lt;/td&gt;
&lt;td&gt;3시간&lt;/td&gt;
&lt;td&gt;20분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;경쟁 서비스 조사&lt;/td&gt;
&lt;td&gt;4시간&lt;/td&gt;
&lt;td&gt;30분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;페르소나 작성&lt;/td&gt;
&lt;td&gt;2시간&lt;/td&gt;
&lt;td&gt;15분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PRD 작성&lt;/td&gt;
&lt;td&gt;4시간&lt;/td&gt;
&lt;td&gt;30분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MVP 범위 확정&lt;/td&gt;
&lt;td&gt;2시간&lt;/td&gt;
&lt;td&gt;15분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;합계&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15시간&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;약 2시간&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;물론 AI가 만든 결과물을 &lt;strong&gt;검토하고 수정하는 시간&lt;/strong&gt;은 별도입니다. 하지만 백지에서 시작하는 것과 초안을 수정하는 것은 완전히 다른 난이도죠.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;기획 단계에서 AI를 잘 활용하는 팁 3가지&lt;/h2&gt;
&lt;h3&gt;1. 구체적인 제약 조건을 주세요&lt;/h3&gt;
&lt;p&gt;&quot;앱 아이디어 추천해줘&quot;보다 &quot;Next.js + Supabase로 2주 안에 만들 수 있는 B2C 웹앱 아이디어&quot;가 훨씬 좋은 결과를 냅니다.&lt;/p&gt;
&lt;h3&gt;2. 대화를 이어가세요&lt;/h3&gt;
&lt;p&gt;한 번의 프롬프트로 끝내지 말고, AI의 답변에 대해 **&quot;왜?&quot;, &quot;좀 더 구체적으로&quot;, &quot;다른 관점에서&quot;**라고 계속 질문하세요. 대화가 깊어질수록 결과물의 질이 올라갑니다.&lt;/p&gt;
&lt;h3&gt;3. AI의 답변을 맹신하지 마세요&lt;/h3&gt;
&lt;p&gt;AI는 기획의 &lt;strong&gt;도구&lt;/strong&gt;이지, 기획자가 아닙니다. 최종 판단은 항상 본인이 해야 합니다. 특히 시장 데이터는 반드시 직접 확인하세요.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. ChatGPT와 Claude 중 기획에는 어떤 걸 쓰는 게 좋나요?&lt;/h3&gt;
&lt;p&gt;솔직히 말하면 기획 단계에서는 큰 차이가 없습니다. 다만 &lt;strong&gt;긴 문서(PRD) 작성&lt;/strong&gt;에는 Claude가 더 강하고, &lt;strong&gt;아이디어 브레인스토밍&lt;/strong&gt;에는 ChatGPT가 살짝 더 창의적인 편입니다. 저는 둘 다 번갈아 쓰면서 결과를 비교합니다.&lt;/p&gt;
&lt;h3&gt;Q2. AI가 만든 PRD를 그대로 써도 되나요?&lt;/h3&gt;
&lt;p&gt;초안으로는 충분합니다. 하지만 반드시 &lt;strong&gt;본인의 상황에 맞게 수정&lt;/strong&gt;해야 합니다. AI는 &quot;2주 안에 만들 수 있다&quot;고 했지만, 본인의 실력과 가용 시간에 따라 일정은 달라질 수 있습니다.&lt;/p&gt;
&lt;h3&gt;Q3. 아이디어 검증을 AI로만 해도 충분한가요?&lt;/h3&gt;
&lt;p&gt;아닙니다. AI를 통한 검증은 &lt;strong&gt;1차 필터&lt;/strong&gt; 정도로 생각하세요. 실제 타겟 사용자에게 직접 물어보는 것이 가장 확실한 검증 방법입니다. 주변 지인이나 온라인 커뮤니티에 &quot;이런 앱 있으면 쓸 건가요?&quot;라고 물어보는 것만으로도 큰 인사이트를 얻을 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;여러분은 사이드 프로젝트 기획할 때 AI를 어떻게 활용하고 계신가요? 댓글로 여러분만의 노하우를 공유해주세요!&lt;/p&gt;
&lt;p&gt;다음 포스팅에서는 &quot;&lt;strong&gt;설계는 AI에게 맡겨라 — ERD, API, 와이어프레임 자동화&lt;/strong&gt;&quot;를 주제로, Claude Code를 활용한 설계 프로세스를 다뤄보겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[AI로 풀스택 개발하기 — Claude Code + Supabase 실전]]></title><description><![CDATA[안녕하세요, 자바파커입니다. "설계까지 끝났으니, 이제 진짜 코드를 작성할 차례입니다." 지난 두 포스팅에서 AI와 함께 기획하고, ERD/API…]]></description><link>http://blog.javapark.kr/03-fullstack-development/</link><guid isPermaLink="false">http://blog.javapark.kr/03-fullstack-development/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;설계까지 끝났으니, 이제 진짜 코드를 작성할 차례입니다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;지난 두 포스팅에서 AI와 함께 기획하고, ERD/API/와이어프레임까지 설계하는 과정을 다뤘습니다. 이번 포스팅에서는 드디어 &lt;strong&gt;실제 코드를 작성&lt;/strong&gt;합니다. Claude Code와 Supabase를 활용해서 &quot;독서 기록 웹앱&quot;의 핵심 기능을 구현하는 과정을 단계별로 보여드리겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;개발 환경 세팅 — Next.js + Supabase 프로젝트 초기화&lt;/h2&gt;
&lt;h3&gt;1단계: Next.js 프로젝트 생성&lt;/h3&gt;
&lt;p&gt;터미널에서 아래 명령어를 실행합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-next-app@latest book-log &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--typescript&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--tailwind&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--eslint&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;token parameter variable&quot;&gt;--app&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  --src-dir &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
  --import-alias &lt;span class=&quot;token string&quot;&gt;&quot;@/*&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2단계: 필수 패키지 설치&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; book-log

&lt;span class=&quot;token comment&quot;&gt;# Supabase&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; @supabase/supabase-js @supabase/ssr

&lt;span class=&quot;token comment&quot;&gt;# UI 유틸리티&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; clsx tailwind-merge

&lt;span class=&quot;token comment&quot;&gt;# 아이콘&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; lucide-react

&lt;span class=&quot;token comment&quot;&gt;# 날짜 처리&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; date-fns&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;3단계: 환경 변수 설정&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;.env.local&lt;/code&gt; 파일을 생성하고, Supabase 프로젝트의 URL과 anon key를 입력합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;NEXT_PUBLIC_SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;https://your-project.supabase.co
&lt;span class=&quot;token assign-left variable&quot;&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;eyJhbGciOiJIUzI1NiIsInR&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 값은 Supabase 대시보드 &gt; Settings &gt; API에서 확인할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Supabase 셋업 — 프로젝트 생성부터 테이블 생성까지&lt;/h2&gt;
&lt;h3&gt;Supabase 프로젝트 생성&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://supabase.com&quot;&gt;supabase.com&lt;/a&gt;에서 회원가입&lt;/li&gt;
&lt;li&gt;&quot;New Project&quot; 클릭&lt;/li&gt;
&lt;li&gt;프로젝트명: &lt;code class=&quot;language-text&quot;&gt;book-log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;비밀번호 설정 (DB 접근용, 반드시 기록해두세요)&lt;/li&gt;
&lt;li&gt;리전: &lt;code class=&quot;language-text&quot;&gt;Northeast Asia (Tokyo)&lt;/code&gt; 선택&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;SQL Editor에서 테이블 생성&lt;/h3&gt;
&lt;p&gt;Supabase 대시보드 &gt; SQL Editor에서, 이전 포스팅에서 설계한 SQL을 실행합니다. 여기서 핵심 부분만 다시 정리하겠습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- 커스텀 타입&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TYPE&lt;/span&gt; reading_status &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ENUM&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;want_to_read&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;reading&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;finished&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TYPE&lt;/span&gt; memo_type &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ENUM&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;note&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;quote&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;review&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- profiles 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; profiles &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  username &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UNIQUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  avatar_url &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- books 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; books &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  isbn &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UNIQUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  title &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  author &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  publisher &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  cover_image_url &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  page_count &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  published_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  description &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- reading_records 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; reading_records &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  user_id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; profiles&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  book_id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; books&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt; reading_status &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;want_to_read&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  start_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  end_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  rating &lt;span class=&quot;token keyword&quot;&gt;SMALLINT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CHECK&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rating &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; rating &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;UNIQUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; book_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- memos 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; memos &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  user_id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; profiles&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  book_id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; books&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  content &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  page_number &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  memo_type memo_type &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;note&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;신규 가입 시 자동 프로필 생성 트리거&lt;/h3&gt;
&lt;p&gt;사용자가 가입하면 자동으로 &lt;code class=&quot;language-text&quot;&gt;profiles&lt;/code&gt; 테이블에 레코드가 생성되도록 합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handle_new_user&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;profiles &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; username&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; avatar_url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;raw_user_meta_data&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;raw_user_meta_data&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;avatar_url&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;LANGUAGE&lt;/span&gt; plpgsql SECURITY &lt;span class=&quot;token keyword&quot;&gt;DEFINER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; on_auth_user_created
  &lt;span class=&quot;token keyword&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users
  &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handle_new_user&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;인증 구현 — Supabase Auth로 소셜 로그인&lt;/h2&gt;
&lt;h3&gt;Supabase 클라이언트 설정&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/lib/supabase.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createBrowserClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@supabase/ssr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBrowserClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/lib/supabase-server.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createServerClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@supabase/ssr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cookies &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/headers&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createServerSupabaseClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookieStore &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createServerClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cookies&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cookieStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;setAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cookiesToSet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            cookiesToSet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
              cookieStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// Server Component에서는 쿠키 설정 불가&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;인증 미들웨어&lt;/h3&gt;
&lt;p&gt;인증되지 않은 사용자가 보호된 페이지에 접근하면 로그인 페이지로 리다이렉트합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/middleware.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createServerClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@supabase/ssr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NextRequest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;middleware&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; NextRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; supabaseResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; request &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; supabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createServerClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cookies&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cookies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;setAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cookiesToSet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          cookiesToSet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
            request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cookies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          supabaseResponse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; request &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          cookiesToSet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
            supabaseResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cookies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; user &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 인증되지 않은 사용자 리다이렉트&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;user &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nextUrl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nextUrl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/auth&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nextUrl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nextUrl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; supabaseResponse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  matcher&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/((?!_next/static|_next/image|favicon.ico).*)&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;로그인 페이지&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/app/login/page.tsx&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&apos;use client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/supabase&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;LoginPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; supabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleGoogleLogin&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signInWithOAuth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      provider&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;google&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        redirectTo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/auth/callback&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleGithubLogin&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;signInWithOAuth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      provider&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;github&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        redirectTo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;origin&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/auth/callback&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex min-h-screen items-center justify-center bg-gray-50&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;w-full max-w-md space-y-8 rounded-xl bg-white p-8 shadow-lg&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text-center&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1 className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text-3xl font-bold text-gray-900&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;BookLog&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mt-2 text-gray-600&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            나만의 독서 기록을 시작하세요
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;space-y-4&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
            onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleGoogleLogin&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex w-full items-center justify-center gap-3 rounded-lg border border-gray-300 bg-white px-4 py-3 text-gray-700 transition hover:bg-gray-50&quot;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;svg className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;h-5 w-5&quot;&lt;/span&gt; viewBox&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0 0 24 24&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;path
                fill&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#4285F4&quot;&lt;/span&gt;
                d&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z&quot;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;path
                fill&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#34A853&quot;&lt;/span&gt;
                d&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z&quot;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;path
                fill&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#FBBC05&quot;&lt;/span&gt;
                d&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z&quot;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;path
                fill&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#EA4335&quot;&lt;/span&gt;
                d&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z&quot;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;svg&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            Google로 로그인
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
            onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleGithubLogin&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex w-full items-center justify-center gap-3 rounded-lg bg-gray-900 px-4 py-3 text-white transition hover:bg-gray-800&quot;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;svg className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;h-5 w-5&quot;&lt;/span&gt; fill&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;currentColor&quot;&lt;/span&gt; viewBox&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;0 0 24 24&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;path d&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;svg&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            GitHub로 로그인
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;OAuth 콜백 처리&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/app/auth/callback/route.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createServerSupabaseClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/supabase-server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NextResponse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; searchParams&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; origin &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;URL&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; searchParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;code&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; supabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createServerSupabaseClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exchangeCodeForSession&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;origin&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/dashboard&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;CRUD 구현 — Claude Code로 &quot;독서 기록 CRUD 만들어줘&quot;&lt;/h2&gt;
&lt;p&gt;이제 핵심 기능인 독서 기록 CRUD를 구현합니다. Claude Code에게 아래와 같이 요청하면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;reading_records 테이블에 대한 CRUD 서비스 함수를 만들어줘.

- Supabase JS Client 사용
- TypeScript
- 에러 처리 포함
- book 정보도 함께 조회 (join)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;서비스 레이어 — 독서 기록 CRUD&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/services/records.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/supabase&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ReadingStatus &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/types/database&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; supabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 내 독서 기록 전체 조회&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getMyRecords&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;status&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ReadingStatus&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;reading_records&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      *,
      book:books(*)
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;updated_at&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ascending&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    query &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; query&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;status&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; status&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; query&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 독서 기록 생성&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createRecord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  bookId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ReadingStatus &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;want_to_read&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; user &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;인증이 필요합니다&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;reading_records&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      user_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      book_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; bookId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      status&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      start_date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;reading&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;*, book:books(*)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 독서 상태 변경&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;updateRecordStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  recordId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ReadingStatus
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updateData&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; status &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;reading&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    updateData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;start_date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;finished&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    updateData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;end_date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;reading_records&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;updateData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; recordId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;*, book:books(*)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 별점 등록&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;updateRating&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;recordId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rating&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;reading_records&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; rating &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; recordId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 독서 기록 삭제&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;deleteRecord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;recordId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;reading_records&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; recordId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;책 검색 및 등록 서비스&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/services/books.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/supabase&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; supabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 알라딘 API로 ISBN 검색 (서버사이드)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;searchBookByISBN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isbn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/api/books/search?isbn=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;isbn&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;책을 찾을 수 없습니다&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 제목으로 책 검색 (DB)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;searchBooks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;books&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;or&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;title.ilike.%&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;query&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%,author.ilike.%&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;query&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 책 등록 (DB에 없는 경우)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;registerBook&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;book&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  isbn&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  title&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  author&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  publisher&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  cover_image_url&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  page_count&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  description&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ISBN으로 중복 체크&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isbn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; existing &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;books&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;isbn&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; book&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isbn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; existing&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;books&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;ISBN 검색 API 라우트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/app/api/books/search/route.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NextResponse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ALADIN_API_KEY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALADIN_API_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; searchParams &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;URL&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isbn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; searchParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;isbn&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isbn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ISBN이 필요합니다&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 알라딘 API 호출&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;http://www.aladin.co.kr/ttb/api/ItemLookUp.aspx?&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;ttbkey=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALADIN_API_KEY&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;itemIdType=ISBN13&amp;amp;ItemId=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;isbn&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;amp;output=js&amp;amp;Version=20131101&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;item &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;책을 찾을 수 없습니다&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; item &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      isbn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; isbn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      title&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      author&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;author&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      publisher&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;publisher&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      cover_image_url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cover&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      page_count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subInfo&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;itemPage &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      published_date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pubDate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; NextResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;검색 중 오류가 발생했습니다&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;UI 구현 — Tailwind CSS로 반응형 대시보드&lt;/h2&gt;
&lt;h3&gt;대시보드 페이지&lt;/h3&gt;
&lt;p&gt;Claude Code에게 &quot;이전 포스팅의 와이어프레임 기반으로 대시보드를 구현해줘&quot;라고 요청하면 아래와 같은 코드를 생성합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/app/dashboard/page.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createServerSupabaseClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/supabase-server&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; BookList &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/components/books/BookList&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ReadingStats &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/components/records/ReadingStats&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; redirect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/navigation&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DashboardPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; supabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createServerSupabaseClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; user &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 독서 기록 조회 (책 정보 포함)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; records &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;reading_records&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;*, book:books(*)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;user_id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;updated_at&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ascending&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; reading &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; records&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;reading&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; finished &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; records&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;finished&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wantToRead &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; records&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;want_to_read&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mx-auto max-w-6xl px-4 py-8&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* 독서 통계 */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ReadingStats
        readingCount&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;reading&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        finishedCount&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;finished&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        wantToReadCount&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;wantToRead&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* 탭 기반 독서 목록 */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mt-8&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;BookList
          reading&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;reading&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          finished&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;finished&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          wantToRead&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;wantToRead&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;책 카드 컴포넌트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/books/BookCard.tsx&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&apos;use client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Image &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/image&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Link &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/link&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Star &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;lucide-react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ReadingRecord &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/types/database&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BookCardProps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  record&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ReadingRecord &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; book&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BookCard&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; record &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; BookCardProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; book&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; status&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rating &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; statusLabel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    reading&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;읽는 중&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    finished&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;완료&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    want_to_read&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;읽고 싶은&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; statusColor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    reading&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bg-blue-100 text-blue-800&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    finished&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bg-green-100 text-green-800&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    want_to_read&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bg-yellow-100 text-yellow-800&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Link href&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/books/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;group rounded-lg border border-gray-200 bg-white p-4 transition hover:shadow-md&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* 책 커버 */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;relative aspect-[3/4] w-full overflow-hidden rounded-md bg-gray-100&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cover_image_url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Image
              src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cover_image_url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
              alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; 표지&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
              fill
              className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;object-cover transition group-hover:scale-105&quot;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex h-full items-center justify-center text-gray-400&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              No Cover
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* 책 정보 */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;mt-3 space-y-1&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;inline-block rounded-full px-2 py-0.5 text-xs font-medium &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;statusColor&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;statusLabel&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h3 className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;line-clamp-2 text-sm font-semibold text-gray-900&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h3&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text-xs text-gray-500&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;author&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* 별점 */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;rating &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex gap-0.5&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Star
                  key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                  className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;h-3.5 w-3.5 &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;
                    i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; rating
                      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;fill-yellow-400 text-yellow-400&apos;&lt;/span&gt;
                      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text-gray-300&apos;&lt;/span&gt;
                  &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Link&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;독서 통계 컴포넌트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/records/ReadingStats.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; BookOpen&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CheckCircle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Bookmark &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;lucide-react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ReadingStatsProps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  readingCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  finishedCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  wantToReadCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ReadingStats&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  readingCount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  finishedCount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  wantToReadCount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ReadingStatsProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stats &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      label&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;읽는 중&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; readingCount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      icon&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; BookOpen&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text-blue-600 bg-blue-50&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      label&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;완료&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; finishedCount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      icon&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CheckCircle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text-green-600 bg-green-50&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      label&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;읽고 싶은&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; wantToReadCount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      icon&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Bookmark&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text-yellow-600 bg-yellow-50&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;grid grid-cols-3 gap-4&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;stats&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stat&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div
          key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;stat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;rounded-lg border border-gray-200 bg-white p-4&quot;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex items-center gap-3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;rounded-lg p-2 &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;stat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;color&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;stat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;icon className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;h-5 w-5&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text-2xl font-bold text-gray-900&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;stat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text-sm text-gray-500&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;stat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;Claude Code 활용 팁 — 효과적인 프롬프트 작성법&lt;/h2&gt;
&lt;h3&gt;1. CLAUDE.md로 프로젝트 컨텍스트 공유하기&lt;/h3&gt;
&lt;p&gt;프로젝트 루트에 &lt;code class=&quot;language-text&quot;&gt;CLAUDE.md&lt;/code&gt; 파일을 두면, Claude Code가 매번 새 대화를 시작할 때 자동으로 읽어서 컨텍스트를 파악합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; BookLog&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 기술 스택&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Next.js 14 (App Router, TypeScript)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Supabase (PostgreSQL, Auth, RLS)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Tailwind CSS
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Vercel 배포

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; DB 스키마&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; profiles: 사용자 프로필 (auth.users 연동)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; books: 책 정보 (ISBN, 제목, 저자)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; reading_records: 독서 기록 (상태, 별점, 날짜)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; memos: 독서 메모 (노트, 인용, 리뷰)

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 코딩 컨벤션&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 컴포넌트: src/components/ 하위 기능별 분류
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 서비스: src/services/ (Supabase 쿼리 로직)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 서버 컴포넌트 기본, 클라이언트 컴포넌트는 &apos;use client&apos; 명시
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 에러 처리: try/catch + 사용자 친화적 메시지&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2. 구체적인 지시를 내리세요&lt;/h3&gt;
&lt;p&gt;나쁜 예시:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;메모 기능 만들어줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;좋은 예시:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;memos 테이블에 대한 CRUD를 구현해줘.

- src/services/memos.ts에 서비스 함수
- src/components/memos/MemoEditor.tsx에 작성/수정 폼
- src/components/memos/MemoCard.tsx에 메모 카드
- 메모 타입: note, quote, review (라디오 버튼으로 선택)
- 인용구(quote) 타입은 페이지 번호 입력 필드 추가
- Tailwind CSS, 반응형&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;3. 단계별로 요청하세요&lt;/h3&gt;
&lt;p&gt;한 번에 모든 걸 요청하면 결과물의 품질이 떨어집니다. &lt;strong&gt;서비스 함수 -&gt; 컴포넌트 -&gt; 페이지&lt;/strong&gt; 순서로 나눠서 요청하는 것이 좋습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1단계: &quot;memos 서비스 함수만 만들어줘&quot; -&gt; 검토 -&gt; 확정
2단계: &quot;이 서비스를 사용하는 MemoEditor 컴포넌트 만들어줘&quot; -&gt; 검토 -&gt; 확정
3단계: &quot;대시보드에 메모 섹션 추가해줘&quot; -&gt; 검토 -&gt; 확정&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;테스트 — AI가 만든 코드를 검증하는 방법&lt;/h2&gt;
&lt;p&gt;AI가 생성한 코드를 &lt;strong&gt;무조건 신뢰하면 안 됩니다.&lt;/strong&gt; 특히 아래 항목은 반드시 직접 확인하세요.&lt;/p&gt;
&lt;h3&gt;수동 테스트 체크리스트&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;확인 사항&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;인증&lt;/td&gt;
&lt;td&gt;로그인/로그아웃 정상 동작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RLS&lt;/td&gt;
&lt;td&gt;다른 사용자의 데이터가 보이지 않는지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CRUD&lt;/td&gt;
&lt;td&gt;생성/조회/수정/삭제 각각 동작 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;엣지 케이스&lt;/td&gt;
&lt;td&gt;빈 입력, 긴 텍스트, 특수문자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;반응형&lt;/td&gt;
&lt;td&gt;모바일/태블릿/데스크톱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;에러 처리&lt;/td&gt;
&lt;td&gt;네트워크 오류, 서버 오류 시 UI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Claude Code로 테스트 코드 생성하기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;BookCard 컴포넌트의 단위 테스트를 작성해줘.

- Vitest + React Testing Library 사용
- 테스트 케이스:
  1. 책 제목과 저자가 렌더링되는지
  2. 상태에 따라 올바른 배지 색상이 적용되는지
  3. 별점이 올바르게 표시되는지
  4. 커버 이미지가 없을 때 대체 텍스트가 표시되는지&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;생성된 테스트 코드 예시:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/books/BookCard.test.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; render&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; screen &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@testing-library/react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; describe&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; expect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vitest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; BookCard &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./BookCard&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockRecord &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  user_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;user-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  book_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;book-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;reading&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  rating&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  start_date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2026-01-01&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  end_date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2026-01-01&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2026-01-01&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  book&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;book-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    isbn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;9788936434267&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    title&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;채식주의자&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    author&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;한강&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    publisher&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;창비&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    cover_image_url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https://example.com/cover.jpg&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    page_count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;247&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    published_date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2007-10-30&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    created_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2026-01-01&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;BookCard&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;책 제목과 저자가 렌더링된다&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;BookCard record&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;mockRecord&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;screen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;채식주의자&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBeInTheDocument&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;screen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;한강&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBeInTheDocument&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;읽는 중 상태 배지가 표시된다&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;BookCard record&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;mockRecord&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; badge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;읽는 중&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;badge&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bg-blue-100&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;별점 4개가 채워져 표시된다&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;BookCard record&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;mockRecord&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; filledStars &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.fill-yellow-400&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filledStars&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveLength&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;커버 이미지가 없으면 대체 텍스트가 표시된다&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; noCoverRecord &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;mockRecord&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      book&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;mockRecord&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;book&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cover_image_url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;BookCard record&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;noCoverRecord&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;screen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getByText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;No Cover&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBeInTheDocument&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;RLS 테스트 — 가장 중요한 보안 검증&lt;/h3&gt;
&lt;p&gt;RLS가 제대로 동작하는지 확인하는 가장 간단한 방법은 &lt;strong&gt;Supabase SQL Editor에서 직접 쿼리를 실행&lt;/strong&gt;하는 것입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- 특정 사용자로 로그인한 상태를 시뮬레이션&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jwt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claims &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;sub&quot;: &quot;user-id-here&quot;}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- 이 쿼리로 해당 사용자의 데이터만 조회되는지 확인&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; reading_records&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;개발 결과물 요약&lt;/h2&gt;
&lt;p&gt;이 세 포스팅에 걸쳐 만든 &quot;독서 기록 웹앱&quot;의 구성을 정리하면 다음과 같습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;프론트엔드&lt;/td&gt;
&lt;td&gt;Next.js 14 (App Router) + Tailwind CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;백엔드&lt;/td&gt;
&lt;td&gt;Supabase (PostgreSQL + Auth + RLS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;인증&lt;/td&gt;
&lt;td&gt;Google, GitHub 소셜 로그인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;핵심 기능&lt;/td&gt;
&lt;td&gt;책 검색/등록, 독서 기록 CRUD, 메모 CRUD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 도구&lt;/td&gt;
&lt;td&gt;Claude Code (설계, 코드 생성, 테스트)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;개발 기간&lt;/td&gt;
&lt;td&gt;약 2주 (기획 포함)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. Claude Code 없이 다른 AI 코딩 도구로도 이 과정이 가능한가요?&lt;/h3&gt;
&lt;p&gt;가능합니다. GitHub Copilot, Cursor 등도 비슷한 작업을 할 수 있습니다. 다만 Claude Code는 &lt;strong&gt;프로젝트 전체 컨텍스트를 이해&lt;/strong&gt;하고 파일 간의 관계를 파악하는 데 강점이 있어서, 이 시리즈에서는 Claude Code를 중심으로 설명했습니다.&lt;/p&gt;
&lt;h3&gt;Q2. Supabase 무료 플랜으로 실제 서비스 운영이 가능한가요?&lt;/h3&gt;
&lt;p&gt;사이드 프로젝트 수준이라면 충분합니다. 무료 플랜은 500MB 데이터베이스, 1GB 파일 스토리지, 50,000 월간 활성 사용자를 제공합니다. 다만 프로젝트가 7일간 비활성 상태면 일시 중지되므로, 실제 서비스 운영 시에는 Pro 플랜(월 $25)을 고려하세요.&lt;/p&gt;
&lt;h3&gt;Q3. AI가 생성한 코드의 품질은 믿을 만한가요?&lt;/h3&gt;
&lt;p&gt;&quot;초안&quot;으로는 훌륭하지만, &lt;strong&gt;프로덕션에 바로 쓰기에는 부족한 경우가 많습니다.&lt;/strong&gt; 특히 에러 처리, 엣지 케이스, 보안(RLS 정책) 부분은 반드시 직접 검토하세요. AI를 &quot;주니어 개발자&quot;라고 생각하면 됩니다 — 빠르게 코드를 짜지만, 시니어의 리뷰가 필요한 수준입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;여러분도 AI와 함께 사이드 프로젝트를 만들어보고 계신가요? 어떤 도구를 쓰고, 어떤 점이 좋았는지 댓글로 공유해주세요!&lt;/p&gt;
&lt;p&gt;다음 포스팅에서는 &quot;&lt;strong&gt;Vercel + GitHub Actions로 자동 배포 파이프라인 구축하기&lt;/strong&gt;&quot;를 주제로, 만든 앱을 세상에 공개하는 과정을 다뤄보겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[운영과 모니터링 — 출시 후 해야 할 것들]]></title><description><![CDATA[…]]></description><link>http://blog.javapark.kr/05-operation-monitoring/</link><guid isPermaLink="false">http://blog.javapark.kr/05-operation-monitoring/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;드디어 시리즈의 마지막 포스팅입니다. 기획부터 설계, 개발, 배포까지 해냈습니다. 축하합니다! 하지만 여기서 끝이 아닙니다. &lt;strong&gt;출시는 시작일 뿐입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;서비스를 세상에 내놓은 순간부터 진짜 게임이 시작됩니다. 사용자가 어떤 에러를 만나는지, 어떤 기능을 많이 쓰는지, 서비스가 얼마나 빠른지 -- 이 모든 것을 파악하고 개선해야 합니다. 이번 포스팅에서는 1인 개발자가 서비스를 안정적으로 운영하기 위해 꼭 해야 할 것들을 정리합니다.&lt;/p&gt;
&lt;h2&gt;출시는 시작일 뿐 -- 운영의 중요성&lt;/h2&gt;
&lt;p&gt;많은 1인 개발자들이 출시에만 집중하고, 이후 운영을 소홀히 합니다. 하지만 성공적인 서비스는 출시 이후의 운영에서 결정됩니다.&lt;/p&gt;
&lt;p&gt;운영 단계에서 해야 할 핵심 업무는 네 가지입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;에러 트래킹&lt;/strong&gt;: 사용자가 겪는 오류를 실시간으로 감지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;사용자 분석&lt;/strong&gt;: 어떤 기능이 인기 있는지, 어디서 이탈하는지 파악&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;성능 모니터링&lt;/strong&gt;: 페이지 로딩 속도, API 응답 시간 관리&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;피드백 수집&lt;/strong&gt;: 사용자의 목소리를 듣고 개선에 반영&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 네 가지를 모두 무료 도구로 구축하는 방법을 알려드리겠습니다.&lt;/p&gt;
&lt;h2&gt;에러 트래킹 -- Sentry 연동&lt;/h2&gt;
&lt;p&gt;서비스를 운영하다 보면 예상치 못한 에러가 반드시 발생합니다. 사용자가 에러를 직접 알려주기를 기대할 수 없습니다. &lt;strong&gt;Sentry&lt;/strong&gt;를 사용하면 에러가 발생하는 즉시 알림을 받을 수 있습니다.&lt;/p&gt;
&lt;h3&gt;Sentry 설치&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Sentry Next.js SDK 설치&lt;/span&gt;
npx @sentry/wizard@latest &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; nextjs&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 명령을 실행하면 Sentry 설정 마법사가 시작됩니다. Sentry 계정 로그인, 프로젝트 생성, 설정 파일 생성까지 자동으로 진행됩니다.&lt;/p&gt;
&lt;p&gt;마법사가 완료되면 아래 파일들이 자동 생성됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;sentry.client.config.ts   — 클라이언트 사이드 Sentry 설정
sentry.server.config.ts   — 서버 사이드 Sentry 설정
sentry.edge.config.ts     — Edge Runtime Sentry 설정
next.config.js             — Sentry 플러그인이 자동 추가됨
.env.sentry-build-plugin   — Sentry 인증 토큰&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Sentry 기본 설정&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// sentry.client.config.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Sentry &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@sentry/nextjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

Sentry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  dsn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SENTRY_DSN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 에러 샘플링 비율 (1.0 = 모든 에러 수집)&lt;/span&gt;
  tracesSampleRate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 프로덕션에서만 활성화&lt;/span&gt;
  enabled&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 사용자 세션 리플레이 (에러 발생 전후 화면 녹화)&lt;/span&gt;
  replaysSessionSampleRate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// 전체 세션의 10%&lt;/span&gt;
  replaysOnErrorSampleRate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// 에러 발생 시 100%&lt;/span&gt;

  integrations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    Sentry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replayIntegration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// sentry.server.config.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Sentry &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@sentry/nextjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

Sentry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  dsn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SENTRY_DSN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  tracesSampleRate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  enabled&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;커스텀 에러 캡처&lt;/h3&gt;
&lt;p&gt;자동 에러 수집 외에도 중요한 비즈니스 로직에서 직접 에러를 캡처할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// lib/api-client.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Sentry &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@sentry/nextjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchWithErrorTracking&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RequestInit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// HTTP 에러도 Sentry에 보고&lt;/span&gt;
      Sentry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;captureMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;API Error: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        level&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;warning&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        extra&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          statusText&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;statusText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 네트워크 에러 등 캡처&lt;/span&gt;
    Sentry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;captureException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      extra&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Sentry 알림 설정&lt;/h3&gt;
&lt;p&gt;에러가 발생하면 즉시 알림을 받도록 설정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Sentry 대시보드 → Settings → Alerts
→ &quot;Create Alert Rule&quot;
→ 조건: &quot;A new issue is created&quot;
→ 액션: 이메일 알림 또는 Slack 알림
→ 빈도: &quot;실시간&quot; 또는 &quot;10분마다 요약&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;1인 개발자에게는 &lt;strong&gt;Slack 알림&lt;/strong&gt;을 추천합니다. 에러 발생 시 즉시 알림을 받을 수 있고, 에러 상세 정보로 바로 이동할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;사용자 분석 -- Google Analytics 4 연동&lt;/h2&gt;
&lt;p&gt;서비스에 사용자가 어떻게 들어오고, 어떤 페이지를 보고, 어디서 떠나는지 파악하는 것은 서비스 개선의 핵심입니다.&lt;/p&gt;
&lt;h3&gt;GA4 설치&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Google Analytics 패키지 설치&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; @next/third-parties&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// app/layout.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; GoogleAnalytics &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@next/third-parties/google&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;RootLayout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  children&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  children&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ReactNode&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;html lang&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ko&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;body&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;GoogleAnalytics gaId&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_GA_ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;html&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;커스텀 이벤트 트래킹&lt;/h3&gt;
&lt;p&gt;페이지 조회 외에도 사용자의 주요 행동을 추적할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// lib/analytics.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;eventName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; parameters&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; window &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;undefined&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gtag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;gtag&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;event&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eventName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; parameters&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 사용 예시&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 회원가입 완료&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;sign_up&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;email&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// AI 기능 사용&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ai_generate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; feature&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;summary&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 유료 전환&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;purchase&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9900&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currency&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;KRW&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// components/GenerateButton.tsx&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&apos;use client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; trackEvent &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/analytics&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GenerateButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ai_generate_click&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; page&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dashboard&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// AI 생성 로직...&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;trackEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ai_generate_complete&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; duration&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2500&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleClick&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;AI&lt;/span&gt;로 생성하기
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;GA4에서 확인할 핵심 지표&lt;/h3&gt;
&lt;p&gt;1인 개발자가 꼭 봐야 할 지표입니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;지표&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;확인 위치&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;활성 사용자&lt;/td&gt;
&lt;td&gt;실제 서비스를 쓰는 사람 수&lt;/td&gt;
&lt;td&gt;홈 &gt; 개요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이벤트 수&lt;/td&gt;
&lt;td&gt;핵심 기능 사용 빈도&lt;/td&gt;
&lt;td&gt;참여도 &gt; 이벤트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이탈률&lt;/td&gt;
&lt;td&gt;첫 페이지에서 바로 떠나는 비율&lt;/td&gt;
&lt;td&gt;참여도 &gt; 페이지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자 획득&lt;/td&gt;
&lt;td&gt;어디서 유입되는지&lt;/td&gt;
&lt;td&gt;획득 &gt; 트래픽 소스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;전환율&lt;/td&gt;
&lt;td&gt;핵심 목표 달성 비율&lt;/td&gt;
&lt;td&gt;구성 &gt; 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;성능 모니터링 -- Vercel Analytics와 Core Web Vitals&lt;/h2&gt;
&lt;p&gt;서비스가 느리면 사용자는 떠납니다. 성능을 지속적으로 모니터링하고 개선해야 합니다.&lt;/p&gt;
&lt;h3&gt;Vercel Analytics 활성화&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Vercel Analytics 패키지 설치&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; @vercel/analytics&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// app/layout.tsx&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Analytics &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@vercel/analytics/react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; SpeedInsights &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@vercel/speed-insights/next&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;RootLayout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  children&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  children&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ReactNode&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;html lang&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ko&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Analytics &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SpeedInsights &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;body&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;html&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Core Web Vitals 관리&lt;/h3&gt;
&lt;p&gt;Google이 정한 웹 성능 핵심 지표입니다. SEO에도 영향을 미치므로 반드시 관리해야 합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;지표&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;목표값&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LCP (Largest Contentful Paint)&lt;/td&gt;
&lt;td&gt;가장 큰 콘텐츠가 보이기까지&lt;/td&gt;
&lt;td&gt;2.5초 이하&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INP (Interaction to Next Paint)&lt;/td&gt;
&lt;td&gt;사용자 입력에 반응하기까지&lt;/td&gt;
&lt;td&gt;200ms 이하&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLS (Cumulative Layout Shift)&lt;/td&gt;
&lt;td&gt;레이아웃이 갑자기 움직이는 정도&lt;/td&gt;
&lt;td&gt;0.1 이하&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;성능 개선 체크리스트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 이미지 최적화 — next/image 사용&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Image &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/image&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;HeroSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Image
      src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/hero.webp&quot;&lt;/span&gt;
      alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;히어로 이미지&quot;&lt;/span&gt;
      width&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      height&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;630&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      priority  &lt;span class=&quot;token comment&quot;&gt;// LCP 대상 이미지에 priority 추가&lt;/span&gt;
      placeholder&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;blur&quot;&lt;/span&gt;
      blurDataURL&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data:image/jpeg;base64,...&quot;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 동적 임포트로 초기 로딩 최적화&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; dynamic &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/dynamic&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 무거운 컴포넌트는 필요할 때만 로드&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; HeavyChart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;dynamic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@/components/HeavyChart&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;차트 로딩 중&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ssr&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;사용자 피드백 수집&lt;/h2&gt;
&lt;p&gt;데이터만으로는 알 수 없는 것들이 있습니다. 사용자의 직접적인 목소리를 듣는 것이 중요합니다.&lt;/p&gt;
&lt;h3&gt;간단한 피드백 폼 만들기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// components/FeedbackWidget.tsx&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&apos;use client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useState &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/supabase/client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FeedbackWidget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;isOpen&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setIsOpen&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;feedback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setFeedback&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setType&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bug&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;feature&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;general&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;general&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;submitted&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setSubmitted&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; supabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleSubmit&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;FormEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;feedback&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; feedback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      page&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      user_agent&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      created_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toISOString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;setSubmitted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;setIsOpen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;setSubmitted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;setFeedback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isOpen&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
        onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setIsOpen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fixed bottom-4 right-4 bg-blue-600 text-white px-4 py-2 rounded-full shadow-lg&quot;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        피드백 보내기
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fixed bottom-4 right-4 w-80 bg-white rounded-lg shadow-xl p-4 border&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;submitted &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text-center text-green-600 font-medium&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          소중한 피드백 감사합니다&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;form onSubmit&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleSubmit&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h3 className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;font-bold mb-2&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;피드백 보내기&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h3&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex gap-2 mb-3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bug&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;feature&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;general&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
                key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;
                onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;px-3 py-1 rounded text-sm &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;
                  type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bg-blue-600 text-white&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bg-gray-100&apos;&lt;/span&gt;
                &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;bug&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;버그&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; t &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;feature&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;기능 요청&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;일반&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;textarea
            value&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;feedback&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            onChange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setFeedback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            placeholder&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;의견을 자유롭게 작성해 주세요&quot;&lt;/span&gt;
            className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;w-full border rounded p-2 mb-3 h-24 resize-none&quot;&lt;/span&gt;
            required
          &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;flex justify-end gap-2&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
              type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;
              onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setIsOpen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
              className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;px-3 py-1 text-gray-500&quot;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              취소
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button
              type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;
              className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;px-3 py-1 bg-blue-600 text-white rounded&quot;&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
              보내기
            &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;form&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Supabase 피드백 테이블&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Supabase SQL Editor에서 실행&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; feedback &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CHECK&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;bug&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;feature&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;general&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  message &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  page &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  user_agent &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  is_resolved &lt;span class=&quot;token keyword&quot;&gt;BOOLEAN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;FALSE&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- RLS 정책 (누구나 피드백 작성 가능, 읽기는 관리자만)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; feedback &lt;span class=&quot;token keyword&quot;&gt;ENABLE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;LEVEL&lt;/span&gt; SECURITY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; POLICY &lt;span class=&quot;token string&quot;&gt;&quot;Anyone can insert feedback&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; feedback &lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;TO&lt;/span&gt; anon
  &lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CHECK&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;GitHub Issues 활용&lt;/h3&gt;
&lt;p&gt;피드백 폼 외에 GitHub Issues를 활용하면 개발자 커뮤니티에서 피드백을 받기 좋습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;GitHub 저장소 → Settings → Features → Issues 활성화
→ Issue Template 생성:
  - Bug Report (버그 리포트)
  - Feature Request (기능 요청)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- .github/ISSUE_TEMPLATE/bug_report.md --&gt;&lt;/span&gt;
&lt;span class=&quot;token hr punctuation&quot;&gt;---&lt;/span&gt;
name: Bug Report
about: 버그를 신고해 주세요
title: &apos;[BUG] &apos;
&lt;span class=&quot;token title important&quot;&gt;labels: bug
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;버그 설명&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;
어떤 문제가 발생했나요?

&lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;재현 방법&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt; &apos;...&apos; 페이지에 접속
&lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt; &apos;...&apos; 버튼 클릭
&lt;span class=&quot;token list punctuation&quot;&gt;3.&lt;/span&gt; 에러 발생

&lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;예상 동작&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;
어떻게 동작해야 하나요?

&lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;스크린샷&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;
가능하다면 스크린샷을 첨부해 주세요.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;업데이트 전략&lt;/h2&gt;
&lt;p&gt;서비스를 지속적으로 개선하려면 체계적인 업데이트 전략이 필요합니다.&lt;/p&gt;
&lt;h3&gt;기능 추가 우선순위 정하기&lt;/h3&gt;
&lt;p&gt;모든 피드백과 아이디어를 구현할 수는 없습니다. 우선순위를 정하는 간단한 프레임워크입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;ICE 스코어링:
- Impact (영향력): 1~10 — 얼마나 많은 사용자에게 도움이 되는가?
- Confidence (확신도): 1~10 — 실제로 효과가 있을 확신이 있는가?
- Ease (난이도): 1~10 — 얼마나 쉽게 구현할 수 있는가?

ICE Score = Impact × Confidence × Ease
→ 점수가 높은 것부터 구현&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;th&gt;Confidence&lt;/th&gt;
&lt;th&gt;Ease&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;다크모드&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;504&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;소셜 로그인&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;384&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 번역&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;버전 관리&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Semantic Versioning 사용&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# MAJOR.MINOR.PATCH&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 버그 수정&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; version patch  &lt;span class=&quot;token comment&quot;&gt;# 1.0.0 → 1.0.1&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 새 기능 추가&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; version minor  &lt;span class=&quot;token comment&quot;&gt;# 1.0.1 → 1.1.0&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 호환되지 않는 변경&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; version major  &lt;span class=&quot;token comment&quot;&gt;# 1.1.0 → 2.0.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;비용 관리 -- 무료 티어로 운영하는 전략&lt;/h2&gt;
&lt;p&gt;1인 개발자에게 비용 관리는 생존의 문제입니다. 다행히 2026년 현재 대부분의 서비스가 넉넉한 무료 티어를 제공합니다.&lt;/p&gt;
&lt;h3&gt;무료 티어 한도 정리&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;서비스&lt;/th&gt;
&lt;th&gt;무료 한도&lt;/th&gt;
&lt;th&gt;초과 시 비용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vercel (Hobby)&lt;/td&gt;
&lt;td&gt;100GB 대역폭, 무제한 배포&lt;/td&gt;
&lt;td&gt;Pro: $20/월&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supabase (Free)&lt;/td&gt;
&lt;td&gt;500MB DB, 1GB 스토리지, 50,000 MAU&lt;/td&gt;
&lt;td&gt;Pro: $25/월&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sentry (Developer)&lt;/td&gt;
&lt;td&gt;5,000 이벤트/월&lt;/td&gt;
&lt;td&gt;Team: $26/월&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GA4&lt;/td&gt;
&lt;td&gt;무제한 (무료)&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;td&gt;무제한 공개 저장소&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI API&lt;/td&gt;
&lt;td&gt;종량제 (무료 한도 없음)&lt;/td&gt;
&lt;td&gt;GPT-4o: ~$5/1M 토큰&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;비용 절약 팁&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 1. API 호출 최소화 — 캐싱 활용&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; unstable_cache &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/cache&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; getCachedData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;unstable_cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 비용이 드는 API 호출&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchFromOpenAI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;openai-cache&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; revalidate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 1시간 캐시&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 2. Supabase 쿼리 최적화 — 필요한 필드만 조회&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 나쁜 예&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;posts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 좋은 예&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;posts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id, title, created_at&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;created_at&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ascending&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 3. 이미지 최적화 — Vercel Image Optimization 활용&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// next.config.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nextConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  images&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    formats&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;image/avif&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;image/webp&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    minimumCacheTTL&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 30일 캐시&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;비용 모니터링&lt;/h3&gt;
&lt;p&gt;각 서비스의 사용량을 주기적으로 확인하세요.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;매주 월요일 체크리스트:
[ ] Vercel 대시보드 → Usage 탭 확인
[ ] Supabase 대시보드 → Settings → Billing 확인
[ ] Sentry 대시보드 → Settings → Subscription 확인
[ ] OpenAI 대시보드 → Usage 확인&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;1인 개발자의 AI 스택 시리즈 마무리&lt;/h2&gt;
&lt;p&gt;5편에 걸친 시리즈를 통해 아이디어 검증부터 운영까지 전체 과정을 다뤘습니다. 처음에는 막막해 보였을 수도 있지만, 하나씩 따라오시면 충분히 할 수 있는 과정입니다.&lt;/p&gt;
&lt;h3&gt;시리즈 전체 요약 표&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;편&lt;/th&gt;
&lt;th&gt;주제&lt;/th&gt;
&lt;th&gt;핵심 내용&lt;/th&gt;
&lt;th&gt;주요 도구&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1편&lt;/td&gt;
&lt;td&gt;아이디어 검증&lt;/td&gt;
&lt;td&gt;문제 정의, 시장 조사, MVP 범위 설정&lt;/td&gt;
&lt;td&gt;ChatGPT, Notion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2편&lt;/td&gt;
&lt;td&gt;AI 기반 설계&lt;/td&gt;
&lt;td&gt;UI/UX 디자인, DB 스키마, API 설계&lt;/td&gt;
&lt;td&gt;v0, Cursor, Supabase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3편&lt;/td&gt;
&lt;td&gt;풀스택 개발&lt;/td&gt;
&lt;td&gt;Next.js + Supabase로 MVP 구현&lt;/td&gt;
&lt;td&gt;Next.js, Supabase, Tailwind&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4편&lt;/td&gt;
&lt;td&gt;배포 자동화&lt;/td&gt;
&lt;td&gt;Vercel + GitHub 원클릭 배포&lt;/td&gt;
&lt;td&gt;Vercel, GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5편&lt;/td&gt;
&lt;td&gt;운영과 모니터링&lt;/td&gt;
&lt;td&gt;에러 트래킹, 분석, 피드백, 비용 관리&lt;/td&gt;
&lt;td&gt;Sentry, GA4, Vercel Analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;이 시리즈에서 구축한 AI 스택 전체 구조&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[사용자] → [Vercel Edge Network]
                    ↓
            [Next.js App Router]
           /        |         \
    [Server]   [Client]   [API Routes]
        ↓          ↓           ↓
  [Supabase]  [React UI]  [OpenAI API]
  (DB/Auth)   (Tailwind)  (AI 기능)
        ↓
  [Sentry]  [GA4]  [Vercel Analytics]
  (에러)    (분석)  (성능)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;다음 단계를 위한 제안&lt;/h3&gt;
&lt;p&gt;시리즈를 마쳤다면 다음 단계를 고려해 보세요.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;수익화&lt;/strong&gt;: Stripe 결제 연동으로 유료 기능 추가&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;마케팅&lt;/strong&gt;: Product Hunt 런칭, 기술 블로그 작성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;확장&lt;/strong&gt;: 모바일 앱 (React Native), 크롬 익스텐션&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;커뮤니티&lt;/strong&gt;: Discord 서버 운영, 오픈소스 기여&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1인 개발자도 AI 도구의 도움을 받으면 기획부터 운영까지 혼자 해낼 수 있는 시대입니다. 이 시리즈가 여러분의 첫 서비스를 만드는 데 도움이 되었으면 합니다.&lt;/p&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. Sentry 무료 플랜으로 충분한가요?&lt;/h3&gt;
&lt;p&gt;대부분의 초기 서비스에는 충분합니다. Sentry Developer 플랜은 월 5,000개의 에러 이벤트를 처리할 수 있습니다. 일일 방문자가 수백 명 수준이라면 무료 한도를 넘기기 어렵습니다. 만약 한도에 가까워진다면 &lt;code class=&quot;language-text&quot;&gt;tracesSampleRate&lt;/code&gt;를 낮춰서 수집 비율을 조절하세요. 예를 들어 &lt;code class=&quot;language-text&quot;&gt;0.2&lt;/code&gt;로 설정하면 전체 트랜잭션의 20%만 수집합니다.&lt;/p&gt;
&lt;h3&gt;Q2. Google Analytics 대신 다른 분석 도구를 쓸 수 있나요?&lt;/h3&gt;
&lt;p&gt;네, 프라이버시를 중시한다면 &lt;strong&gt;Plausible Analytics&lt;/strong&gt;나 &lt;strong&gt;Umami&lt;/strong&gt;를 추천합니다. 둘 다 오픈소스이고, 쿠키를 사용하지 않아서 쿠키 동의 배너가 필요 없습니다. Umami는 Vercel + Supabase에 셀프 호스팅할 수 있어서 비용도 들지 않습니다. 다만 GA4만큼 상세한 분석 기능은 제공하지 않으므로 서비스 규모에 맞게 선택하세요.&lt;/p&gt;
&lt;h3&gt;Q3. 서비스 사용자가 늘어서 무료 티어를 초과하면 어떻게 하나요?&lt;/h3&gt;
&lt;p&gt;축하할 일입니다! 사용자가 늘고 있다는 뜻이니까요. 보통 무료 티어를 초과하는 시점이면 이미 수익화를 고려할 단계입니다. 우선순위는 Supabase Pro ($25/월) &gt; Vercel Pro ($20/월) &gt; Sentry Team ($26/월) 순서로 업그레이드하는 것을 추천합니다. Supabase가 가장 먼저 한도에 도달하는 경우가 많기 때문입니다. 총 월 $71이면 안정적인 서비스 운영이 가능합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;이것으로 &quot;&lt;strong&gt;1인 개발자의 AI 스택&lt;/strong&gt;&quot; 시리즈를 마칩니다. 기획에서 운영까지, 아이디어를 현실로 만드는 전체 여정을 함께 했습니다. 이 시리즈가 여러분의 서비스 개발에 실질적인 도움이 되었기를 바랍니다. 앞으로도 1인 개발자에게 유용한 콘텐츠로 찾아뵙겠습니다. 감사합니다!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[블로그 글을 유튜브 영상으로 만드는 법 — NotebookLM 동영상 변환 가이드]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. 블로그에 글을 열심히 써도, 읽는 사람이 한정되어 있다는 걸 느낄 때가 있습니다. "이 글을 영상으로도 만들 수 있으면 좋겠는데, 촬영도 편집도 할 줄 모르는데..." 결론부터 말씀드리면 — Google…]]></description><link>http://blog.javapark.kr/blog-to-youtube-with-notebooklm/</link><guid isPermaLink="false">http://blog.javapark.kr/blog-to-youtube-with-notebooklm/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/blog-to-youtube-with-notebooklm.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;블로그에 글을 열심히 써도, 읽는 사람이 한정되어 있다는 걸 느낄 때가 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;이 글을 영상으로도 만들 수 있으면 좋겠는데, 촬영도 편집도 할 줄 모르는데...&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;결론부터 말씀드리면 — &lt;strong&gt;Google NotebookLM을 쓰면 블로그 글 하나로 AI 동영상을 만들 수 있습니다.&lt;/strong&gt; 촬영 장비도, 영상 편집 기술도 필요 없습니다. 글만 있으면 됩니다.&lt;/p&gt;
&lt;p&gt;이 글에서는 제가 실제로 블로그 포스팅을 NotebookLM 동영상으로 변환하고, 유튜브에 업로드한 전체 과정을 공유합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;전체 워크플로우 — 3단계&lt;/h2&gt;
&lt;p&gt;전체 흐름을 먼저 보면 이렇습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;블로그 글 작성 → NotebookLM에 업로드 → AI 동영상 생성 → 유튜브 업로드&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;도구&lt;/th&gt;
&lt;th&gt;소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. 글 작성&lt;/td&gt;
&lt;td&gt;티스토리 / 마크다운&lt;/td&gt;
&lt;td&gt;이미 완료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. 동영상 생성&lt;/td&gt;
&lt;td&gt;NotebookLM&lt;/td&gt;
&lt;td&gt;5~30분 (자동)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. 유튜브 업로드&lt;/td&gt;
&lt;td&gt;YouTube Studio&lt;/td&gt;
&lt;td&gt;5~10분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;핵심은 &lt;strong&gt;이미 쓴 글을 재활용&lt;/strong&gt;한다는 것입니다. 새로 콘텐츠를 만드는 게 아닙니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1단계: 블로그 글 준비&lt;/h2&gt;
&lt;h3&gt;어떤 글이 동영상으로 적합한가?&lt;/h3&gt;
&lt;p&gt;모든 글이 영상으로 잘 변환되는 건 아닙니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;적합한 글&lt;/th&gt;
&lt;th&gt;부적합한 글&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;개념 설명, 비교 분석&lt;/td&gt;
&lt;td&gt;코드 위주의 튜토리얼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;단계별 가이드&lt;/td&gt;
&lt;td&gt;짧은 팁/메모&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;도구 소개, 후기&lt;/td&gt;
&lt;td&gt;코드 스니펫 모음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FAQ, 체크리스트&lt;/td&gt;
&lt;td&gt;표만 있는 정리글&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;예를 들어, &quot;AI로 웹서비스 만드는 법&quot; 같은 글은 동영상으로 만들면 시각적으로 설명이 풍부해져서 효과적입니다. 반면 코드 줄 하나하나를 설명하는 튜토리얼은 텍스트가 더 낫습니다.&lt;/p&gt;
&lt;h3&gt;글을 준비하는 방법&lt;/h3&gt;
&lt;p&gt;NotebookLM에 소스를 넣는 방법은 여러 가지입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;웹 URL 붙여넣기&lt;/strong&gt; — 티스토리 포스팅 URL을 그대로 입력&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;텍스트 복사/붙여넣기&lt;/strong&gt; — 마크다운이나 텍스트를 직접 붙여넣기&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Docs&lt;/strong&gt; — 구글 문서로 옮긴 후 연결&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PDF 업로드&lt;/strong&gt; — 글을 PDF로 변환 후 업로드&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;가장 간단한 건 &lt;strong&gt;블로그 URL을 그대로 넣는 것&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;2단계: NotebookLM으로 AI 동영상 생성&lt;/h2&gt;
&lt;h3&gt;NotebookLM 접속 및 노트북 생성&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://notebooklm.google.com&quot;&gt;NotebookLM&lt;/a&gt; 접속 (구글 계정으로 로그인)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;새 노트북 만들기&lt;/strong&gt; 클릭&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;소스 추가&lt;/strong&gt; &gt; 웹사이트 URL 또는 텍스트 붙여넣기&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;[이미지: NotebookLM 소스 추가 화면]&lt;/p&gt;
&lt;h3&gt;Video Overview 생성&lt;/h3&gt;
&lt;p&gt;소스를 추가하면 오른쪽에 &lt;strong&gt;Studio 패널&lt;/strong&gt;이 나타납니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Studio 패널에서 &lt;strong&gt;Video Overview&lt;/strong&gt; 선택&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;동영상 형식&lt;/strong&gt; 선택&lt;/li&gt;
&lt;li&gt;필요하면 &lt;strong&gt;커스텀 프롬프트&lt;/strong&gt;로 초점을 지정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;생성&lt;/strong&gt; 클릭&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;[이미지: Video Overview 생성 버튼 클릭 화면]&lt;/p&gt;
&lt;h3&gt;동영상 형식 — 3가지 비교&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;형식&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;가격&lt;/th&gt;
&lt;th&gt;추천 용도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Brief&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1~2분, 핵심 요약&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;SNS 공유, 짧은 소개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Explainer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3~5분, 개념 설명&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;유튜브 업로드, 학습 콘텐츠&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cinematic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5분 이상, 풍부한 애니메이션&lt;/td&gt;
&lt;td&gt;Ultra ($250/월)&lt;/td&gt;
&lt;td&gt;프로 수준 프레젠테이션&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;무료 계정&lt;/strong&gt;으로는 Brief와 Explainer를 사용할 수 있습니다. 블로그 글을 유튜브 영상으로 만드는 용도라면 &lt;strong&gt;Explainer&lt;/strong&gt;가 가장 적합합니다.&lt;/p&gt;
&lt;h3&gt;커스텀 프롬프트 활용&lt;/h3&gt;
&lt;p&gt;그냥 생성해도 되지만, 프롬프트를 주면 결과물이 더 좋아집니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;이 글의 핵심 내용을 개발자 독자를 위해 설명해줘.
Claude Code와 Supabase의 조합이 왜 효과적인지에 초점을 맞춰줘.&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;프롬프트로 제어할 수 있는 것들:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;초점&lt;/strong&gt; — 어떤 부분을 중점적으로 다룰지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;톤&lt;/strong&gt; — 전문적 / 캐주얼 / 교육적&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;대상&lt;/strong&gt; — 초보자용 / 경험자용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;생성 시간&lt;/h3&gt;
&lt;p&gt;생성 버튼을 누르면 5~30분 정도 걸립니다. 페이지를 닫아도 백그라운드에서 생성이 계속됩니다. 완료되면 노트북에서 확인할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3단계: 유튜브에 업로드&lt;/h2&gt;
&lt;h3&gt;동영상 다운로드&lt;/h3&gt;
&lt;p&gt;NotebookLM에서 생성된 동영상을 &lt;strong&gt;다운로드&lt;/strong&gt; 합니다. MP4 파일로 저장됩니다.&lt;/p&gt;
&lt;h3&gt;YouTube Studio에서 업로드&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://studio.youtube.com&quot;&gt;YouTube Studio&lt;/a&gt; 접속&lt;/li&gt;
&lt;li&gt;오른쪽 상단 &lt;strong&gt;만들기&lt;/strong&gt; &gt; &lt;strong&gt;동영상 업로드&lt;/strong&gt; 클릭&lt;/li&gt;
&lt;li&gt;다운로드한 MP4 파일 선택&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;메타데이터 설정 — SEO가 여기서도 중요&lt;/h3&gt;
&lt;p&gt;블로그 SEO와 마찬가지로, 유튜브도 검색 최적화가 중요합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;팁&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;제목&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;블로그 제목을 그대로 쓰되, &quot;영상 ver.&quot; 느낌 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;설명&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;블로그 원문 링크 + 핵심 내용 요약 3~5줄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;태그&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;블로그 태그와 동일 + &quot;NotebookLM&quot;, &quot;AI 동영상&quot; 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;썸네일&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;블로그 대표이미지를 재활용하거나 약간 변형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;카테고리&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;과학/기술 또는 교육&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;설명란 템플릿&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[블로그 원문] https://javapark.tistory.com/entry/글-슬러그

이 영상은 AI JAVAPARK 블로그 포스팅을 Google NotebookLM으로
AI 동영상으로 변환한 콘텐츠입니다.

## 목차
00:00 인트로
00:30 핵심 개념
02:00 실전 예시
04:00 정리

## 키워드
#AI개발 #ClaudeCode #NotebookLM

---
AI JAVAPARK — AI와 함께 만드는 개발 이야기
Blog: https://javapark.tistory.com&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;블로그 원문 링크를 설명란 맨 위에 넣으면 &lt;strong&gt;블로그 유입&lt;/strong&gt;도 늘어나고, 구글 SEO에서도 상호 연결 효과를 얻을 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;콘텐츠 재활용 전략 — 글 하나로 3가지 만들기&lt;/h2&gt;
&lt;p&gt;이 워크플로우의 진짜 가치는 &lt;strong&gt;하나의 콘텐츠를 여러 형태로 재활용&lt;/strong&gt;하는 것입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;블로그 글 (원본)
  ├── NotebookLM Explainer → 유튜브 영상
  ├── NotebookLM Brief → SNS 숏폼 (인스타, 쇼츠)
  └── NotebookLM Audio Overview → 팟캐스트&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;콘텐츠 형태&lt;/th&gt;
&lt;th&gt;플랫폼&lt;/th&gt;
&lt;th&gt;NotebookLM 형식&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;블로그 글&lt;/td&gt;
&lt;td&gt;티스토리&lt;/td&gt;
&lt;td&gt;원본&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;유튜브 영상&lt;/td&gt;
&lt;td&gt;YouTube&lt;/td&gt;
&lt;td&gt;Explainer / Cinematic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;숏폼 영상&lt;/td&gt;
&lt;td&gt;YouTube Shorts, 인스타&lt;/td&gt;
&lt;td&gt;Brief&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;팟캐스트/오디오&lt;/td&gt;
&lt;td&gt;Spotify, 팟빵&lt;/td&gt;
&lt;td&gt;Audio Overview&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;글 하나 쓰면 4가지 채널에 콘텐츠를 배포할 수 있습니다. 1인 크리에이터에게는 이만한 효율이 없습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;주의할 점&lt;/h2&gt;
&lt;h3&gt;AI 생성 콘텐츠 표시&lt;/h3&gt;
&lt;p&gt;유튜브는 AI로 만든 영상에 대해 &lt;strong&gt;AI 생성 콘텐츠임을 표시&lt;/strong&gt;하도록 권장하고 있습니다. YouTube Studio 업로드 시 &quot;변경되거나 합성된 콘텐츠&quot; 옵션에서 해당 사항을 체크하세요.&lt;/p&gt;
&lt;h3&gt;무료 계정 제한&lt;/h3&gt;
&lt;p&gt;무료 NotebookLM 계정은 생성 횟수에 제한이 있습니다. 한 노트북당 생성 가능한 동영상 수가 정해져 있으므로, 프롬프트를 잘 작성해서 한 번에 만족스러운 결과를 얻는 게 중요합니다.&lt;/p&gt;
&lt;h3&gt;한국어 지원&lt;/h3&gt;
&lt;p&gt;Video Overview는 한국어를 포함한 여러 언어를 지원합니다. 다만 Cinematic 형식은 현재 영어만 지원됩니다. 무료로 사용하는 Brief/Explainer는 한국어로 생성 가능합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;NotebookLM Video Overview는 무료인가요?&lt;/h3&gt;
&lt;p&gt;Brief와 Explainer 형식은 무료로 사용할 수 있습니다. 구글 계정만 있으면 됩니다. Cinematic 형식만 Ultra 구독($250/월)이 필요하지만, 블로그 글을 유튜브 영상으로 만드는 용도라면 Explainer로 충분합니다.&lt;/p&gt;
&lt;h3&gt;블로그 글 URL을 넣으면 자동으로 전체 내용을 읽나요?&lt;/h3&gt;
&lt;p&gt;네, NotebookLM이 웹페이지의 텍스트 콘텐츠를 자동으로 추출합니다. 다만 이미지나 코드 블록의 세부 내용은 반영되지 않을 수 있으므로, 중요한 내용이 텍스트로 잘 작성되어 있는지 확인하세요.&lt;/p&gt;
&lt;h3&gt;생성된 동영상의 저작권은 누구에게 있나요?&lt;/h3&gt;
&lt;p&gt;NotebookLM으로 생성한 동영상의 저작권은 생성자에게 있습니다. 상업적 사용도 가능합니다. 다만 원본 블로그 글의 내용이 타인의 저작물을 포함하고 있다면 별도로 확인이 필요합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;정리하면, 블로그 글을 유튜브 영상으로 만드는 과정은 이렇습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;블로그에 글을 쓴다&lt;/strong&gt; — 이미 하고 있는 일&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NotebookLM에 URL을 넣고 Video Overview를 생성한다&lt;/strong&gt; — 5분 클릭&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;다운로드해서 유튜브에 업로드한다&lt;/strong&gt; — 메타데이터만 잘 채우면 끝&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;핵심은 &lt;strong&gt;새로운 콘텐츠를 만드는 게 아니라, 이미 쓴 글을 다른 형태로 변환하는 것&lt;/strong&gt;입니다. 글 쓰는 시간은 이미 투자했으니, 추가 10분만 투자하면 유튜브 채널까지 운영할 수 있습니다.&lt;/p&gt;
&lt;p&gt;저도 이 블로그의 포스팅을 하나씩 영상으로 변환해볼 예정입니다. 진행 과정도 공유하겠습니다.&lt;/p&gt;
&lt;p&gt;여러분은 블로그 글을 다른 형태로 재활용하고 있으신가요? 댓글로 알려주세요!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://notebooklm.google.com&quot;&gt;NotebookLM 공식 사이트&lt;/a&gt; — 구글 AI 리서치 도구&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.google.com/notebooklm/answer/16454555?hl=ko&quot;&gt;NotebookLM Video Overview 생성 가이드 (공식)&lt;/a&gt; — 동영상 개요 생성 방법&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.google/innovation-and-ai/products/notebooklm/generate-your-own-cinematic-video-overviews-in-notebooklm/&quot;&gt;Cinematic Video Overviews 출시 발표 (Google 공식 블로그)&lt;/a&gt; — 2026년 3월 신기능 소개&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.google.com/youtube/answer/57407&quot;&gt;YouTube Studio 고객센터&lt;/a&gt; — 동영상 업로드 가이드&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[설계는 AI에게 맡겨라 — ERD, API, 와이어프레임 자동화]]></title><description><![CDATA[안녕하세요, 자바파커입니다. "코드부터 짜고 싶은 충동, 이해합니다. 하지만 설계 없이 시작한 프로젝트의 결말은 대부분 같습니다." 지난 포스팅에서 AI와 함께 아이디어를 검증하고 PRD…]]></description><link>http://blog.javapark.kr/02-ai-design/</link><guid isPermaLink="false">http://blog.javapark.kr/02-ai-design/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;코드부터 짜고 싶은 충동, 이해합니다. 하지만 설계 없이 시작한 프로젝트의 결말은 대부분 같습니다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;지난 포스팅에서 AI와 함께 아이디어를 검증하고 PRD를 작성하는 과정을 다뤘습니다. 이번에는 그다음 단계인 &lt;strong&gt;설계&lt;/strong&gt;를 AI에게 맡기는 방법을 공유합니다. ERD, API 명세, 와이어프레임, 프로젝트 구조까지 — Claude Code 하나로 해결하는 과정을 보여드리겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;설계를 건너뛰면 생기는 일&lt;/h2&gt;
&lt;p&gt;1인 개발자가 가장 흔히 하는 실수 중 하나는 &quot;&lt;strong&gt;일단 코드부터 짜자&lt;/strong&gt;&quot;입니다. 저도 수없이 겪었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;테이블 하나 추가하려니 기존 구조와 충돌&lt;/li&gt;
&lt;li&gt;API 엔드포인트 네이밍이 중구난방&lt;/li&gt;
&lt;li&gt;화면을 만들다 보니 필요한 데이터가 빠져 있어서 DB 수정&lt;/li&gt;
&lt;li&gt;결국 전체 리팩토링 — 사실상 처음부터 다시 만들기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;설계에 &lt;strong&gt;2-3시간만 투자&lt;/strong&gt;하면, 개발 과정에서 수십 시간을 아낄 수 있습니다. 그리고 이제는 그 2-3시간마저 AI가 크게 줄여줍니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;ERD 설계 — Claude Code에게 데이터베이스 설계 맡기기&lt;/h2&gt;
&lt;h3&gt;프롬프트: Supabase 테이블 설계 요청&lt;/h3&gt;
&lt;p&gt;Claude Code에 아래와 같이 요청합니다. 핵심은 &lt;strong&gt;지난 포스팅에서 만든 PRD를 컨텍스트로 함께 전달&lt;/strong&gt;하는 것입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;이 PRD를 기반으로 Supabase(PostgreSQL) 데이터베이스를 설계해줘.

요구사항:
- users, books, reading_records, memos 테이블
- Supabase Auth의 auth.users와 연동
- RLS(Row Level Security) 정책 포함
- created_at, updated_at 자동 관리
- 적절한 인덱스 포함

결과물:
1. ERD (텍스트 기반)
2. Supabase SQL (테이블 생성 + RLS + 인덱스)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Claude Code가 생성한 ERD&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;┌─────────────────┐     ┌──────────────────────┐
│     profiles     │     │        books          │
├─────────────────┤     ├──────────────────────┤
│ id (uuid, PK)   │──┐  │ id (uuid, PK)         │
│ username         │  │  │ isbn (varchar, UQ)     │
│ avatar_url       │  │  │ title                  │
│ created_at       │  │  │ author                 │
│ updated_at       │  │  │ publisher              │
└─────────────────┘  │  │ cover_image_url        │
                      │  │ page_count             │
                      │  │ published_date         │
                      │  │ description            │
                      │  │ created_at             │
                      │  └──────────────────────┘
                      │
                      │  ┌──────────────────────┐
                      │  │   reading_records      │
                      │  ├──────────────────────┤
                      ├──│ user_id (uuid, FK)     │
                      │  │ book_id (uuid, FK)     │
                      │  │ status (enum)          │
                      │  │ start_date             │
                      │  │ end_date               │
                      │  │ rating (1-5)           │
                      │  │ created_at             │
                      │  │ updated_at             │
                      │  └──────────────────────┘
                      │
                      │  ┌──────────────────────┐
                      │  │       memos            │
                      │  ├──────────────────────┤
                      └──│ user_id (uuid, FK)     │
                         │ book_id (uuid, FK)     │
                         │ content (text)         │
                         │ page_number (int)      │
                         │ memo_type (enum)       │
                         │ created_at             │
                         │ updated_at             │
                         └──────────────────────┘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Supabase SQL — 테이블 생성&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- 1. 커스텀 타입 정의&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TYPE&lt;/span&gt; reading_status &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ENUM&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;want_to_read&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;reading&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;finished&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TYPE&lt;/span&gt; memo_type &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ENUM&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;note&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;quote&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;review&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- 2. profiles 테이블 (Supabase Auth 연동)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; profiles &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;users&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  username &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UNIQUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  avatar_url &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- 3. books 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; books &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  isbn &lt;span class=&quot;token keyword&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UNIQUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  title &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  author &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  publisher &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  cover_image_url &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  page_count &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  published_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  description &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- 4. reading_records 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; reading_records &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  user_id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; profiles&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  book_id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; books&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt; reading_status &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;want_to_read&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  start_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  end_date &lt;span class=&quot;token keyword&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  rating &lt;span class=&quot;token keyword&quot;&gt;SMALLINT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CHECK&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rating &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; rating &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;UNIQUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; book_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- 5. memos 테이블&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; memos &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id UUID &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; gen_random_uuid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  user_id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; profiles&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  book_id UUID &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; books&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CASCADE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  content &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  page_number &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  memo_type memo_type &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;note&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  created_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updated_at TIMESTAMPTZ &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- 6. 인덱스&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INDEX&lt;/span&gt; idx_reading_records_user &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; reading_records&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INDEX&lt;/span&gt; idx_reading_records_status &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; reading_records&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INDEX&lt;/span&gt; idx_memos_user_book &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; memos&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; book_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INDEX&lt;/span&gt; idx_books_isbn &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; books&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isbn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- 7. updated_at 자동 갱신 트리거&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; update_updated_at&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
  NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;updated_at &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;LANGUAGE&lt;/span&gt; plpgsql&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; profiles_updated_at
  BEFORE &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; profiles
  &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; update_updated_at&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; reading_records_updated_at
  BEFORE &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; reading_records
  &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; update_updated_at&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; memos_updated_at
  BEFORE &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; memos
  &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; update_updated_at&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;RLS 정책 설정 — 보안의 핵심&lt;/h3&gt;
&lt;p&gt;Supabase에서 RLS는 선택이 아니라 필수입니다. 각 사용자가 &lt;strong&gt;자신의 데이터만 읽고 쓸 수 있도록&lt;/strong&gt; 정책을 설정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- RLS 활성화&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; profiles &lt;span class=&quot;token keyword&quot;&gt;ENABLE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;LEVEL&lt;/span&gt; SECURITY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; reading_records &lt;span class=&quot;token keyword&quot;&gt;ENABLE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;LEVEL&lt;/span&gt; SECURITY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; memos &lt;span class=&quot;token keyword&quot;&gt;ENABLE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;LEVEL&lt;/span&gt; SECURITY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- profiles: 본인만 조회/수정&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; POLICY &lt;span class=&quot;token string&quot;&gt;&quot;Users can view own profile&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; profiles &lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; POLICY &lt;span class=&quot;token string&quot;&gt;&quot;Users can update own profile&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; profiles &lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- reading_records: 본인만 CRUD&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; POLICY &lt;span class=&quot;token string&quot;&gt;&quot;Users can manage own records&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; reading_records &lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ALL&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; user_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- memos: 본인만 CRUD&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; POLICY &lt;span class=&quot;token string&quot;&gt;&quot;Users can manage own memos&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; memos &lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ALL&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uid&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; user_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- books: 누구나 조회 가능, 인증된 사용자만 추가 가능&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; books &lt;span class=&quot;token keyword&quot;&gt;ENABLE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;LEVEL&lt;/span&gt; SECURITY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; POLICY &lt;span class=&quot;token string&quot;&gt;&quot;Anyone can view books&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; books &lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; POLICY &lt;span class=&quot;token string&quot;&gt;&quot;Authenticated users can insert books&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; books &lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CHECK&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;role&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;authenticated&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;API 명세 자동 생성 — RESTful 엔드포인트 설계&lt;/h2&gt;
&lt;p&gt;Supabase는 테이블 기반으로 자동 REST API를 제공하지만, 프론트엔드에서 사용할 &lt;strong&gt;서비스 레이어의 함수 명세&lt;/strong&gt;를 미리 정의해두면 개발이 훨씬 매끄럽습니다.&lt;/p&gt;
&lt;h3&gt;API 명세 생성 프롬프트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;위 DB 스키마 기반으로 프론트엔드에서 사용할 API 함수 명세를 만들어줘.

조건:
- Supabase JS Client 사용
- TypeScript 타입 정의 포함
- 에러 처리 패턴 포함

카테고리:
1. Auth (로그인, 로그아웃, 프로필)
2. Books (검색, 등록)
3. Reading Records (CRUD, 상태 변경)
4. Memos (CRUD)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;생성된 TypeScript 타입 정의&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// types/database.ts&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ReadingStatus&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;want_to_read&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;reading&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;finished&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MemoType&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;note&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;quote&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;review&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Profile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  username&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  avatar_url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  created_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  updated_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  isbn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  title&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  author&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  publisher&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  cover_image_url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  page_count&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  published_date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  created_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ReadingRecord&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  user_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  book_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ReadingStatus&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  start_date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  end_date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  rating&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  created_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  updated_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  book&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Book&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// join 시&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Memo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  user_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  book_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  page_number&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  memo_type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MemoType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  created_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  updated_at&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;서비스 함수 명세 예시&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// services/books.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; supabase &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/lib/supabase&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Book &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@/types/database&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ISBN으로 책 검색 (외부 API)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;searchBookByISBN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isbn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Book &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// 1. 먼저 DB에서 검색&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;books&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;isbn&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; isbn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 2. DB에 없으면 알라딘 API로 검색 후 DB에 저장&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bookInfo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchFromAladinAPI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isbn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;bookInfo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newBook&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;books&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bookInfo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; newBook&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 제목으로 책 검색&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;searchBooksByTitle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Book&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; supabase
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;books&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ilike&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;title&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;query&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;와이어프레임 — AI로 화면 구조 잡기&lt;/h2&gt;
&lt;p&gt;디자이너 없이 화면을 설계해야 하는 1인 개발자에게, &lt;strong&gt;텍스트 기반 와이어프레임&lt;/strong&gt;은 매우 실용적인 방법입니다.&lt;/p&gt;
&lt;h3&gt;와이어프레임 생성 프롬프트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;독서 기록 웹앱의 주요 화면 와이어프레임을 텍스트로 만들어줘.

필요한 화면:
1. 대시보드 (내 독서 목록)
2. 책 상세 페이지
3. 책 등록 페이지 (ISBN 검색)
4. 메모 작성 페이지

각 화면에 포함할 것:
- 레이아웃 구조 (ASCII 아트)
- 필요한 컴포넌트 목록
- 사용자 인터랙션 흐름&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;대시보드 와이어프레임&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;┌─────────────────────────────────────────────────┐
│  [Logo] BookLog        [검색]    [프로필 아바타] │
├─────────────────────────────────────────────────┤
│                                                  │
│  ┌─ 탭 ──────────────────────────────────────┐  │
│  │ [읽는 중 (3)]  [완료 (12)]  [읽고 싶은 (5)]│  │
│  └───────────────────────────────────────────┘  │
│                                                  │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐         │
│  │ [커버]  │  │ [커버]  │  │ [커버]  │         │
│  │ 제목    │  │ 제목    │  │ 제목    │         │
│  │ 저자    │  │ 저자    │  │ 저자    │         │
│  │ ★★★★☆ │  │ ★★★☆☆ │  │         │         │
│  │ 메모 3  │  │ 메모 1  │  │ [등록]  │         │
│  └─────────┘  └─────────┘  └─────────┘         │
│                                                  │
│              [+ 새 책 등록]                      │
│                                                  │
├─────────────────────────────────────────────────┤
│  올해 읽은 책: 12권 / 목표 24권  [████░░] 50%   │
└─────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 와이어프레임을 기반으로 실제 UI를 구현할 때, Claude Code에게 &quot;&lt;strong&gt;이 와이어프레임대로 Tailwind CSS로 구현해줘&lt;/strong&gt;&quot;라고 요청하면 꽤 정확한 결과를 얻을 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;기술 스택 선정 — Next.js + Supabase + Vercel 조합의 이유&lt;/h2&gt;
&lt;p&gt;1인 개발자에게 기술 스택 선택은 &lt;strong&gt;생산성&lt;/strong&gt;이 최우선입니다. 화려한 스택보다 &lt;strong&gt;빠르게 만들고, 쉽게 배포하고, 저렴하게 운영&lt;/strong&gt;할 수 있는 조합이 중요합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;레이어&lt;/th&gt;
&lt;th&gt;선택&lt;/th&gt;
&lt;th&gt;이유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;프론트엔드&lt;/td&gt;
&lt;td&gt;Next.js (App Router)&lt;/td&gt;
&lt;td&gt;React 생태계, SSR/SSG 지원, Vercel 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;백엔드/DB&lt;/td&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;PostgreSQL + Auth + Storage + Realtime 올인원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스타일링&lt;/td&gt;
&lt;td&gt;Tailwind CSS&lt;/td&gt;
&lt;td&gt;유틸리티 기반, AI가 생성하기 쉬움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;배포&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;Git push로 자동 배포, 무료 플랜 충분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 개발 도구&lt;/td&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;코드 생성, 리팩토링, 디버깅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;왜 Supabase인가?&lt;/h3&gt;
&lt;p&gt;솔직히 말하면, Firebase도 좋은 선택입니다. 하지만 Supabase를 선택한 이유는 세 가지입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt; — 관계형 DB의 강력함 (JOIN, 트랜잭션)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RLS&lt;/strong&gt; — 별도 백엔드 서버 없이 보안 처리 가능&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;무료 플랜&lt;/strong&gt; — 사이드 프로젝트에 충분한 무료 티어 (500MB DB, 1GB Storage)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;프로젝트 구조 생성 — Claude Code로 보일러플레이트 자동 생성&lt;/h2&gt;
&lt;h3&gt;프로젝트 구조 생성 프롬프트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Next.js 14 (App Router) + Supabase + Tailwind CSS 프로젝트 구조를 만들어줘.

구조 규칙:
- app/ 디렉토리 사용 (App Router)
- 컴포넌트는 components/ 하위에 기능별로 분류
- Supabase 클라이언트는 lib/supabase.ts
- 타입 정의는 types/
- 서비스 로직은 services/

기능:
- 인증 (로그인/회원가입)
- 책 관리 (검색, 등록)
- 독서 기록 (CRUD)
- 메모 (CRUD)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Claude Code가 생성한 프로젝트 구조&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;book-log/
├── app/
│   ├── layout.tsx              # 루트 레이아웃
│   ├── page.tsx                # 랜딩 페이지
│   ├── globals.css
│   ├── (auth)/
│   │   ├── login/page.tsx      # 로그인
│   │   └── callback/route.ts   # OAuth 콜백
│   ├── (main)/
│   │   ├── layout.tsx          # 인증된 사용자 레이아웃
│   │   ├── dashboard/page.tsx  # 대시보드
│   │   ├── books/
│   │   │   ├── page.tsx        # 책 검색/등록
│   │   │   └── [id]/page.tsx   # 책 상세
│   │   └── memos/
│   │       └── [bookId]/page.tsx # 메모 목록
│   └── api/
│       └── books/
│           └── search/route.ts  # ISBN 검색 API
├── components/
│   ├── ui/                     # 공통 UI 컴포넌트
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   ├── Card.tsx
│   │   └── Modal.tsx
│   ├── auth/
│   │   └── AuthButton.tsx
│   ├── books/
│   │   ├── BookCard.tsx
│   │   ├── BookSearch.tsx
│   │   └── BookList.tsx
│   ├── records/
│   │   ├── StatusBadge.tsx
│   │   └── RecordForm.tsx
│   └── memos/
│       ├── MemoCard.tsx
│       └── MemoEditor.tsx
├── lib/
│   ├── supabase.ts             # Supabase 클라이언트 (브라우저)
│   └── supabase-server.ts      # Supabase 클라이언트 (서버)
├── services/
│   ├── auth.ts
│   ├── books.ts
│   ├── records.ts
│   └── memos.ts
├── types/
│   └── database.ts             # DB 타입 정의
├── middleware.ts                # 인증 미들웨어
└── .env.local                  # 환경 변수&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Supabase 클라이언트 설정 코드&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// lib/supabase.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createBrowserClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@supabase/ssr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; supabase &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createBrowserClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// lib/supabase-server.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createServerClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@supabase/ssr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; cookies &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/headers&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cookieStore &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createServerClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cookies&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cookieStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;setAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cookiesToSet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          cookiesToSet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
            cookieStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;설계 단계에서 Claude Code를 잘 쓰는 팁&lt;/h2&gt;
&lt;h3&gt;CLAUDE.md 파일 활용하기&lt;/h3&gt;
&lt;p&gt;프로젝트 루트에 &lt;code class=&quot;language-text&quot;&gt;CLAUDE.md&lt;/code&gt; 파일을 만들어서 프로젝트 컨텍스트를 미리 정의해두면, Claude Code가 훨씬 일관된 결과를 생성합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; BookLog 프로젝트&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 기술 스택&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Next.js 14 (App Router)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Supabase (PostgreSQL, Auth, Storage)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Tailwind CSS
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; TypeScript

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 코딩 컨벤션&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 컴포넌트: PascalCase (BookCard.tsx)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 함수/변수: camelCase
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 타입: PascalCase (interface Book)
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 파일 구조: 기능별 분류

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; DB 스키마&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; profiles, books, reading_records, memos
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; RLS 사용, auth.uid() 기반 권한 관리&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. Supabase를 처음 쓰는데, RLS 설정이 어렵지 않나요?&lt;/h3&gt;
&lt;p&gt;솔직히 처음에는 헷갈립니다. 하지만 패턴이 정해져 있어서 한 번 이해하면 쉽습니다. 핵심은 &lt;code class=&quot;language-text&quot;&gt;auth.uid() = user_id&lt;/code&gt; 하나입니다. &quot;이 행의 user_id가 로그인한 사용자의 id와 같으면 허용&quot;이라는 뜻이죠. 이 포스팅의 SQL을 그대로 사용하셔도 됩니다.&lt;/p&gt;
&lt;h3&gt;Q2. ERD 설계를 AI에게 맡기면 문제가 생기지 않나요?&lt;/h3&gt;
&lt;p&gt;AI가 생성한 스키마를 &lt;strong&gt;그대로 프로덕션에 쓰면&lt;/strong&gt; 문제가 될 수 있습니다. 하지만 초기 설계의 출발점으로는 훌륭합니다. 중요한 건 생성된 스키마를 &lt;strong&gt;직접 검토&lt;/strong&gt;하는 것입니다. 특히 인덱스, 제약 조건, 데이터 타입은 반드시 확인하세요.&lt;/p&gt;
&lt;h3&gt;Q3. 와이어프레임을 텍스트로 만드는 게 Figma보다 나은가요?&lt;/h3&gt;
&lt;p&gt;&quot;나은가&quot;보다는 &quot;빠른가&quot;의 문제입니다. Figma로 완성도 높은 디자인을 만들 수 있지만, 1인 개발자에게 그 시간은 사치일 수 있습니다. 텍스트 와이어프레임으로 &lt;strong&gt;구조를 먼저 잡고&lt;/strong&gt;, 필요하면 나중에 Figma로 다듬는 순서를 추천합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;여러분은 사이드 프로젝트 설계할 때 어떤 도구를 쓰고 계신가요? 댓글로 공유해주세요!&lt;/p&gt;
&lt;p&gt;다음 포스팅에서는 &quot;&lt;strong&gt;AI로 풀스택 개발하기 — Claude Code + Supabase 실전&lt;/strong&gt;&quot;을 주제로, 실제 코드를 작성하며 웹앱을 완성하는 과정을 다뤄보겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[배포 자동화 — Vercel + GitHub 원클릭 배포]]></title><description><![CDATA[안녕하세요, 자바파커입니다. 지난 포스팅에서 Next.js와 Supabase로 풀스택 서비스를 개발했습니다. 이제 만든 서비스를 세상에 내놓을 차례입니다. 하지만 배포라는 단어만 들어도 머리가 아프신 분들이 많을 겁니다. 서버 세팅, SSL…]]></description><link>http://blog.javapark.kr/04-deploy-automation/</link><guid isPermaLink="false">http://blog.javapark.kr/04-deploy-automation/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;지난 포스팅에서 Next.js와 Supabase로 풀스택 서비스를 개발했습니다. 이제 만든 서비스를 세상에 내놓을 차례입니다. 하지만 배포라는 단어만 들어도 머리가 아프신 분들이 많을 겁니다. 서버 세팅, SSL 인증서, CI/CD 파이프라인 구성... 과거에는 이 모든 것을 직접 해야 했습니다.&lt;/p&gt;
&lt;p&gt;2026년 현재, &lt;strong&gt;Vercel을 사용하면 &lt;code class=&quot;language-text&quot;&gt;git push&lt;/code&gt; 한 번으로 배포가 끝납니다.&lt;/strong&gt; 이번 포스팅에서는 Vercel과 GitHub를 연동해서 완전 자동 배포 환경을 구축하는 방법을 단계별로 알려드리겠습니다.&lt;/p&gt;
&lt;h2&gt;왜 Vercel인가?&lt;/h2&gt;
&lt;p&gt;1인 개발자에게 Vercel이 최적인 이유는 명확합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js 최적화&lt;/strong&gt;: Vercel은 Next.js를 만든 회사입니다. App Router, Server Components, Edge Runtime 등 Next.js의 모든 기능을 가장 먼저, 가장 잘 지원합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;무료 티어가 넉넉합니다&lt;/strong&gt;: Hobby 플랜으로 월 100GB 대역폭, 무제한 배포, 커스텀 도메인까지 무료로 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자동 배포&lt;/strong&gt;: GitHub에 push하면 자동으로 빌드하고 배포합니다. CI/CD 파이프라인을 따로 구성할 필요가 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프리뷰 배포&lt;/strong&gt;: PR을 올리면 자동으로 프리뷰 URL이 생성됩니다. 코드 리뷰 없이도 변경 사항을 눈으로 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;글로벌 Edge Network&lt;/strong&gt;: 전 세계 어디서든 빠르게 접속할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Vercel vs Netlify vs GitHub Pages 비교&lt;/h2&gt;
&lt;p&gt;배포 플랫폼을 고민하시는 분들을 위해 비교표를 준비했습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;Vercel&lt;/th&gt;
&lt;th&gt;Netlify&lt;/th&gt;
&lt;th&gt;GitHub Pages&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Next.js 지원&lt;/td&gt;
&lt;td&gt;완벽 (공식)&lt;/td&gt;
&lt;td&gt;좋음 (플러그인)&lt;/td&gt;
&lt;td&gt;정적만 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서버리스 함수&lt;/td&gt;
&lt;td&gt;지원 (Edge/Node)&lt;/td&gt;
&lt;td&gt;지원 (Node)&lt;/td&gt;
&lt;td&gt;미지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;무료 대역폭&lt;/td&gt;
&lt;td&gt;100GB/월&lt;/td&gt;
&lt;td&gt;100GB/월&lt;/td&gt;
&lt;td&gt;100GB/월&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;빌드 시간&lt;/td&gt;
&lt;td&gt;6,000분/월&lt;/td&gt;
&lt;td&gt;300분/월&lt;/td&gt;
&lt;td&gt;2,000분/월&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프리뷰 배포&lt;/td&gt;
&lt;td&gt;자동&lt;/td&gt;
&lt;td&gt;자동&lt;/td&gt;
&lt;td&gt;미지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;커스텀 도메인&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL&lt;/td&gt;
&lt;td&gt;자동&lt;/td&gt;
&lt;td&gt;자동&lt;/td&gt;
&lt;td&gt;자동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edge Functions&lt;/td&gt;
&lt;td&gt;지원&lt;/td&gt;
&lt;td&gt;지원&lt;/td&gt;
&lt;td&gt;미지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분석 도구&lt;/td&gt;
&lt;td&gt;내장&lt;/td&gt;
&lt;td&gt;유료 애드온&lt;/td&gt;
&lt;td&gt;미지원&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;결론&lt;/strong&gt;: Next.js 프로젝트라면 Vercel이 압도적으로 유리합니다. Netlify도 훌륭하지만, Next.js의 최신 기능을 100% 활용하려면 Vercel이 최선입니다. GitHub Pages는 정적 사이트 전용이므로 풀스택 프로젝트에는 적합하지 않습니다.&lt;/p&gt;
&lt;h2&gt;Vercel 계정 생성 및 GitHub 연동&lt;/h2&gt;
&lt;h3&gt;1단계: Vercel 가입&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://vercel.com&quot;&gt;vercel.com&lt;/a&gt;에 접속해서 &lt;strong&gt;Sign Up&lt;/strong&gt; 버튼을 클릭합니다. GitHub 계정으로 가입하는 것을 추천합니다. 연동이 자동으로 이루어지기 때문입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. vercel.com 접속
2. &quot;Sign Up&quot; 클릭
3. &quot;Continue with GitHub&quot; 선택
4. GitHub 권한 허용
5. Hobby (무료) 플랜 선택&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2단계: GitHub 저장소 권한 설정&lt;/h3&gt;
&lt;p&gt;가입 후 Vercel이 GitHub 저장소에 접근할 수 있도록 권한을 설정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;GitHub Settings → Applications → Vercel
→ &quot;Repository access&quot; 에서 배포할 저장소 선택
→ 전체 저장소를 허용하거나, 특정 저장소만 선택 가능&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;보안을 위해 &lt;strong&gt;특정 저장소만 선택&lt;/strong&gt;하는 것을 추천합니다. 필요할 때 저장소를 추가하면 됩니다.&lt;/p&gt;
&lt;h2&gt;프로젝트 Import -- 첫 배포&lt;/h2&gt;
&lt;h3&gt;3단계: 프로젝트 가져오기&lt;/h3&gt;
&lt;p&gt;Vercel 대시보드에서 &quot;&lt;strong&gt;Add New Project&lt;/strong&gt;&quot; 를 클릭하고 GitHub 저장소를 선택합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. Vercel 대시보드 → &quot;Add New Project&quot;
2. &quot;Import Git Repository&quot; 에서 저장소 선택
3. Framework Preset: Next.js (자동 감지됨)
4. Root Directory: ./ (기본값)
5. &quot;Deploy&quot; 클릭&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Vercel은 &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;을 분석해서 프레임워크를 자동으로 감지합니다. Next.js 프로젝트라면 별도 설정 없이 바로 배포가 시작됩니다.&lt;/p&gt;
&lt;h3&gt;4단계: 빌드 설정 확인&lt;/h3&gt;
&lt;p&gt;대부분의 경우 기본 설정으로 충분하지만, 필요하다면 빌드 설정을 커스터마이징할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// vercel.json (프로젝트 루트에 생성)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;buildCommand&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;next build&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;outputDirectory&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.next&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;installCommand&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm install&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;framework&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nextjs&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;첫 배포가 완료되면 &lt;code class=&quot;language-text&quot;&gt;https://프로젝트명.vercel.app&lt;/code&gt; 형태의 URL이 자동으로 생성됩니다. 이 URL로 바로 접속해서 서비스를 확인할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;환경변수 설정&lt;/h2&gt;
&lt;p&gt;서비스가 정상 작동하려면 Supabase URL, API Key 등의 환경변수가 필요합니다. 로컬에서 &lt;code class=&quot;language-text&quot;&gt;.env.local&lt;/code&gt; 파일에 넣었던 값들을 Vercel에도 설정해야 합니다.&lt;/p&gt;
&lt;h3&gt;Vercel 대시보드에서 설정&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. Vercel 대시보드 → 프로젝트 선택
2. Settings → Environment Variables
3. 환경변수 추가&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아래 환경변수들을 추가합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Supabase 연동&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;NEXT_PUBLIC_SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;https://xxxx.supabase.co
&lt;span class=&quot;token assign-left variable&quot;&gt;NEXT_PUBLIC_SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;eyJhbGciOiJIUzI1NiIs&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.

&lt;span class=&quot;token comment&quot;&gt;# OpenAI API (서버 사이드 전용)&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;sk-&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.

&lt;span class=&quot;token comment&quot;&gt;# 기타 설정&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;NEXT_PUBLIC_APP_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;https://yourdomain.com&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;환경변수 스코프 설정&lt;/h3&gt;
&lt;p&gt;Vercel은 환경변수를 환경별로 분리할 수 있습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;환경&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;td&gt;실제 서비스&lt;/td&gt;
&lt;td&gt;실제 Supabase 프로젝트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preview&lt;/td&gt;
&lt;td&gt;PR 프리뷰&lt;/td&gt;
&lt;td&gt;테스트용 Supabase 프로젝트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Development&lt;/td&gt;
&lt;td&gt;로컬 개발&lt;/td&gt;
&lt;td&gt;로컬 환경변수&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Environment Variables 설정 화면에서:
→ 각 변수마다 Production / Preview / Development 체크박스로 스코프 지정
→ OPENAI_API_KEY 같은 민감한 키는 &quot;Sensitive&quot; 옵션 활성화&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;주의사항&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;NEXT_PUBLIC_&lt;/code&gt; 접두사가 붙은 변수는 클라이언트에 노출됩니다. API 시크릿 키에는 절대 &lt;code class=&quot;language-text&quot;&gt;NEXT_PUBLIC_&lt;/code&gt;을 붙이지 마세요.&lt;/p&gt;
&lt;h3&gt;Vercel CLI로 환경변수 관리&lt;/h3&gt;
&lt;p&gt;터미널에서도 환경변수를 관리할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Vercel CLI 설치&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; vercel

&lt;span class=&quot;token comment&quot;&gt;# 로그인&lt;/span&gt;
vercel login

&lt;span class=&quot;token comment&quot;&gt;# 환경변수 추가&lt;/span&gt;
vercel &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; OPENAI_API_KEY production
&lt;span class=&quot;token comment&quot;&gt;# 프롬프트에서 값 입력&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 환경변수 목록 확인&lt;/span&gt;
vercel &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 환경변수를 로컬 .env.local로 가져오기&lt;/span&gt;
vercel &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; pull .env.local&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;vercel env pull&lt;/code&gt; 명령은 팀원과 환경변수를 공유할 때 매우 유용합니다. &lt;code class=&quot;language-text&quot;&gt;.env.local&lt;/code&gt; 파일을 직접 주고받을 필요 없이, Vercel에서 바로 가져올 수 있습니다.&lt;/p&gt;
&lt;h2&gt;커스텀 도메인 연결&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;프로젝트명.vercel.app&lt;/code&gt; 도 좋지만, 자신만의 도메인으로 서비스하면 훨씬 전문적으로 보입니다.&lt;/p&gt;
&lt;h3&gt;도메인 구매&lt;/h3&gt;
&lt;p&gt;도메인은 다양한 곳에서 구매할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vercel Domains&lt;/strong&gt;: Vercel 대시보드에서 바로 구매 가능&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Namecheap&lt;/strong&gt;: 저렴한 가격&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare&lt;/strong&gt;: DNS와 함께 관리 편리&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;가비아&lt;/strong&gt;: 한국 도메인(.kr) 등록 시&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;DNS 설정&lt;/h3&gt;
&lt;p&gt;도메인을 구매했다면 DNS 레코드를 설정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. Vercel 대시보드 → 프로젝트 → Settings → Domains
2. 도메인 입력 (예: myapp.com)
3. &quot;Add&quot; 클릭
4. Vercel이 안내하는 DNS 레코드를 도메인 관리 사이트에 추가&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;일반적으로 아래 두 가지 레코드를 추가하면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# A 레코드 (루트 도메인)
Type: A
Name: @
Value: 76.76.21.21

# CNAME 레코드 (www 서브도메인)
Type: CNAME
Name: www
Value: cname.vercel-dns.com&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;SSL 인증서 -- 자동 발급&lt;/h3&gt;
&lt;p&gt;Vercel은 도메인을 연결하면 &lt;strong&gt;Let&apos;s Encrypt SSL 인증서를 자동으로 발급&lt;/strong&gt;합니다. 별도의 설정이 필요 없습니다. 인증서 갱신도 자동으로 처리됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;도메인 연결 후 약 1~5분 내에:
→ SSL 인증서 자동 발급
→ HTTP → HTTPS 자동 리다이렉트 설정
→ www → non-www (또는 반대) 자동 리다이렉트&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;프리뷰 배포 -- PR마다 자동 미리보기 URL&lt;/h2&gt;
&lt;p&gt;프리뷰 배포는 Vercel의 가장 강력한 기능 중 하나입니다. Pull Request를 올리면 자동으로 해당 변경 사항이 적용된 별도의 URL이 생성됩니다.&lt;/p&gt;
&lt;h3&gt;작동 방식&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. 새 브랜치 생성: git checkout -b feature/new-ui
2. 코드 수정 후 push: git push origin feature/new-ui
3. GitHub에서 PR 생성
4. Vercel이 자동으로 프리뷰 빌드 시작
5. PR 코멘트에 프리뷰 URL 자동 게시
   → https://프로젝트-git-feature-new-ui-username.vercel.app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;프리뷰 배포 활용법&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 기능 브랜치 생성&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout &lt;span class=&quot;token parameter variable&quot;&gt;-b&lt;/span&gt; feature/dark-mode

&lt;span class=&quot;token comment&quot;&gt;# 코드 수정&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# ...&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 커밋 및 푸시&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;feat: 다크모드 추가&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push origin feature/dark-mode

&lt;span class=&quot;token comment&quot;&gt;# GitHub에서 PR 생성 후 Vercel 프리뷰 URL로 확인&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# → 모바일에서도 접속해서 테스트 가능&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# → 팀원이나 지인에게 URL 공유해서 피드백 받기&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;1인 개발자라도 프리뷰 배포를 적극 활용하세요. 프로덕션에 바로 머지하기 전에 실제 환경에서 테스트할 수 있어서 실수를 크게 줄일 수 있습니다.&lt;/p&gt;
&lt;h3&gt;프리뷰 배포 환경변수 분리&lt;/h3&gt;
&lt;p&gt;프리뷰 배포에서는 테스트용 환경변수를 사용하는 것이 안전합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Vercel 대시보드 → Settings → Environment Variables
→ NEXT_PUBLIC_SUPABASE_URL 변수를 Preview 환경에만 따로 설정
→ 테스트용 Supabase 프로젝트 URL 입력&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이렇게 하면 프리뷰 배포에서 실수로 프로덕션 데이터를 건드리는 일을 방지할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;배포 최적화&lt;/h2&gt;
&lt;h3&gt;빌드 캐시 활용&lt;/h3&gt;
&lt;p&gt;Vercel은 빌드 캐시를 자동으로 관리합니다. 하지만 &lt;code class=&quot;language-text&quot;&gt;next.config.js&lt;/code&gt;에서 추가 최적화가 가능합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// next.config.js&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;/** @type {import(&apos;next&apos;).NextConfig} */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nextConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// 이미지 최적화&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;images&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;formats&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;image/avif&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;image/webp&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;remotePatterns&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;*.supabase.co&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 헤더 설정 (캐시 최적화)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/:path*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Cache-Control&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;s-maxage=60, stale-while-revalidate=300&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/:path*.(jpg|jpeg|png|gif|ico|svg)&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Cache-Control&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;public, max-age=31536000, immutable&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nextConfig&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Edge Functions 활용&lt;/h3&gt;
&lt;p&gt;API 응답 속도를 높이고 싶다면 Edge Functions를 활용합니다. Edge Functions는 사용자와 가장 가까운 서버에서 실행되므로 지연 시간이 크게 줄어듭니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// app/api/hello/route.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; runtime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;edge&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Edge Runtime 사용&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; searchParams &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;URL&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; searchParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;World&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello, &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;application/json&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// app/api/og/route.tsx&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// OG 이미지 동적 생성 (Edge에서 실행)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ImageResponse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;next/og&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; runtime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;edge&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; searchParams &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;URL&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; searchParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;title&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;기본 제목&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageResponse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        display&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;flex&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        fontSize&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        background&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;linear-gradient(135deg, #667eea 0%, #764ba2 100%)&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;white&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;100%&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;100%&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        alignItems&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;center&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        justifyContent&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;center&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        padding&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;630&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;빌드 시간 단축 팁&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// package.json&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;next build&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;vercel-build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;next build&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// next.config.js에 추가&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nextConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// 빌드 시 불필요한 페이지 제외 (개발용 페이지 등)&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;experimental&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 병렬 빌드 최적화&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;workerThreads&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;cpus&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;롤백 -- 문제 발생 시 이전 버전 복원&lt;/h2&gt;
&lt;p&gt;배포 후 문제가 발생했을 때 빠르게 이전 버전으로 되돌리는 것은 매우 중요합니다. Vercel은 이 과정을 매우 간단하게 만들어 줍니다.&lt;/p&gt;
&lt;h3&gt;대시보드에서 롤백&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. Vercel 대시보드 → 프로젝트 → Deployments 탭
2. 정상 작동하던 이전 배포를 찾기
3. 해당 배포의 &quot;...&quot; 메뉴 클릭
4. &quot;Promote to Production&quot; 선택
5. 즉시 이전 버전으로 복원 완료&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;CLI로 롤백&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 배포 목록 확인&lt;/span&gt;
vercel &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 특정 배포를 프로덕션으로 승격&lt;/span&gt;
vercel promote &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;deployment-url&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 예시&lt;/span&gt;
vercel promote myapp-abc123.vercel.app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;롤백 전략&lt;/h3&gt;
&lt;p&gt;1인 개발자에게 추천하는 롤백 전략입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. 배포 전: 현재 프로덕션 URL 메모
2. 배포 후: 핵심 기능 5분 내 수동 테스트
3. 문제 발견: 즉시 이전 버전으로 롤백
4. 원인 분석: 로컬에서 디버깅 후 수정 배포&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;자동 배포 워크플로 전체 요약&lt;/h2&gt;
&lt;p&gt;최종적으로 완성된 배포 워크플로를 정리합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[코드 수정] → [git push] → [Vercel 자동 빌드]
                                    ↓
                            [빌드 성공?]
                           /            \
                        Yes              No
                         ↓                ↓
                  [자동 배포]      [빌드 로그 확인]
                       ↓                  ↓
              [헬스 체크 통과?]    [코드 수정 후 재push]
                     ↓
            [프로덕션 반영 완료]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;작업&lt;/th&gt;
&lt;th&gt;소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;push&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git push origin main&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;즉시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;빌드&lt;/td&gt;
&lt;td&gt;Next.js 빌드 + 최적화&lt;/td&gt;
&lt;td&gt;1~3분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;배포&lt;/td&gt;
&lt;td&gt;Edge Network 배포&lt;/td&gt;
&lt;td&gt;30초&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL&lt;/td&gt;
&lt;td&gt;인증서 확인&lt;/td&gt;
&lt;td&gt;자동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;완료&lt;/td&gt;
&lt;td&gt;프로덕션 반영&lt;/td&gt;
&lt;td&gt;총 2~4분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. Vercel 무료 플랜으로 실제 서비스 운영이 가능한가요?&lt;/h3&gt;
&lt;p&gt;네, 가능합니다. Vercel Hobby 플랜은 월 100GB 대역폭, 무제한 배포를 제공합니다. 일일 방문자가 수천 명 수준이라면 무료 플랜으로 충분합니다. 다만, 상업적 용도(팀 프로젝트, 유료 서비스)라면 Pro 플랜을 권장합니다. Hobby 플랜은 비상업적/개인 프로젝트 용도입니다.&lt;/p&gt;
&lt;h3&gt;Q2. 환경변수를 변경하면 자동으로 재배포되나요?&lt;/h3&gt;
&lt;p&gt;아닙니다. 환경변수를 변경한 후에는 &lt;strong&gt;수동으로 재배포&lt;/strong&gt;해야 합니다. Vercel 대시보드에서 Deployments 탭의 최신 배포에서 &quot;Redeploy&quot; 를 클릭하거나, 빈 커밋을 push하면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 빈 커밋으로 재배포 트리거&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit --allow-empty &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;chore: trigger redeploy&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push origin main&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Q3. 빌드가 실패했을 때 어떻게 디버깅하나요?&lt;/h3&gt;
&lt;p&gt;Vercel 대시보드에서 실패한 배포를 클릭하면 전체 빌드 로그를 확인할 수 있습니다. 가장 흔한 빌드 실패 원인은 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;환경변수 미설정&lt;/strong&gt;: 로컬에서는 &lt;code class=&quot;language-text&quot;&gt;.env.local&lt;/code&gt;에 있지만 Vercel에 등록하지 않은 경우&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;타입 에러&lt;/strong&gt;: 로컬에서는 무시했지만 &lt;code class=&quot;language-text&quot;&gt;next build&lt;/code&gt; 시 에러가 발생하는 경우&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;의존성 문제&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt;이 커밋되지 않은 경우&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;로컬에서 &lt;code class=&quot;language-text&quot;&gt;next build&lt;/code&gt;를 먼저 실행해서 빌드 에러를 확인하는 습관을 들이세요.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;다음 포스팅에서는 서비스를 출시한 후 반드시 해야 할 &lt;strong&gt;운영과 모니터링&lt;/strong&gt; 에 대해 다룹니다. 에러 트래킹, 사용자 분석, 비용 관리까지 -- 1인 개발자가 서비스를 안정적으로 운영하는 방법을 알려드리겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[블로그 대표이미지를 코드로 만드는 법 — HTML + Playwright PNG 변환]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. 블로그 포스팅을 쓸 때마다 고민되는 게 있습니다 — 대표이미지. "포토샵은 못 쓰고, Canva는 매번 접속하기 귀찮고, 일관된 스타일을 유지하고 싶은데..." 결론부터 말씀드리면 — HTML+CSS…]]></description><link>http://blog.javapark.kr/html-to-png-image-generation/</link><guid isPermaLink="false">http://blog.javapark.kr/html-to-png-image-generation/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/html-to-png-image-generation.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;블로그 포스팅을 쓸 때마다 고민되는 게 있습니다 — &lt;strong&gt;대표이미지&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;포토샵은 못 쓰고, Canva는 매번 접속하기 귀찮고, 일관된 스타일을 유지하고 싶은데...&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;결론부터 말씀드리면 — &lt;strong&gt;HTML+CSS로 이미지를 디자인하고, Playwright로 PNG를 캡처하면 됩니다.&lt;/strong&gt; 이 블로그의 모든 대표이미지가 이 방식으로 만들어졌습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;왜 HTML로 이미지를 만드는가?&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방법&lt;/th&gt;
&lt;th&gt;장점&lt;/th&gt;
&lt;th&gt;단점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;포토샵/피그마&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;자유도 높음&lt;/td&gt;
&lt;td&gt;매번 수동 작업, 라이선스 비용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Canva&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;쉽고 빠름&lt;/td&gt;
&lt;td&gt;템플릿 느낌, 일관성 유지 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTML+CSS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;코드로 관리, 재사용, 자동화 가능&lt;/td&gt;
&lt;td&gt;CSS 지식 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;개발자에게 HTML+CSS 방식이 유리한 이유는 세 가지입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;코드 = 템플릿&lt;/strong&gt; — 한 번 만들면 텍스트만 바꿔서 재사용&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전 관리&lt;/strong&gt; — Git으로 이미지 소스를 관리할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자동화&lt;/strong&gt; — Claude Code에게 &quot;이 포스팅용 대표이미지 만들어줘&quot; 한 마디로 생성 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;전체 워크플로우&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;HTML+CSS 작성 → 브라우저에서 확인 → Playwright로 PNG 캡처 → 블로그에 사용&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;도구&lt;/th&gt;
&lt;th&gt;소요 시간&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. HTML 작성&lt;/td&gt;
&lt;td&gt;VS Code / Claude Code&lt;/td&gt;
&lt;td&gt;5~10분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. 미리보기&lt;/td&gt;
&lt;td&gt;브라우저에서 파일 열기&lt;/td&gt;
&lt;td&gt;즉시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. PNG 캡처&lt;/td&gt;
&lt;td&gt;Playwright&lt;/td&gt;
&lt;td&gt;즉시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;1단계: HTML+CSS로 이미지 디자인&lt;/h2&gt;
&lt;h3&gt;기본 구조 — 썸네일 (1200x630)&lt;/h3&gt;
&lt;p&gt;블로그 OG 이미지, 유튜브 썸네일용 비율입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;ko&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;UTF-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
  &lt;span class=&quot;token selector&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; border-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 630px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;135deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #0f172a 0%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #1e293b 50%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #0f172a 100%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Segoe UI&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Malgun Gothic&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sans-serif&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f1f5f9&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 48px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 800&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token selector&quot;&gt;h1 span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;90deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #0ea5e9&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #8b5cf6&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;-webkit-background-clip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;-webkit-text-fill-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;여기에 &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;제목&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;을&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;br&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;입력합니다&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이것만으로도 다크 배경에 그라데이션 텍스트가 들어간 이미지가 됩니다.&lt;/p&gt;
&lt;h3&gt;기본 구조 — 대표이미지 (1080x1080)&lt;/h3&gt;
&lt;p&gt;SNS 공유, 티스토리 대표이미지용 1:1 비율입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
  &lt;span class=&quot;token selector&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;box-sizing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; border-box&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1080px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1080px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1080px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1080px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* 나머지는 동일 */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;핵심:&lt;/strong&gt; 1:1 비율일 때는 &lt;code class=&quot;language-text&quot;&gt;html&lt;/code&gt;에도 &lt;code class=&quot;language-text&quot;&gt;width&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;height&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;overflow: hidden&lt;/code&gt;을 넣어야 캡처 시 여백이 생기지 않습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;2단계: 디자인 요소 추가하기&lt;/h2&gt;
&lt;p&gt;기본 구조에 시각적 요소를 더하면 완성도가 올라갑니다. 이 블로그에서 실제로 사용하는 패턴을 공개합니다.&lt;/p&gt;
&lt;h3&gt;그리드 배경&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;body::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;inset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;14&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;165&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;233&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0.06&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transparent 1px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;90deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;14&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;165&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;233&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0.06&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; transparent 1px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 40px 40px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;반투명 격자 패턴으로 &quot;기술적인 느낌&quot;을 줍니다. 배경에 깔아두면 단순한 배경이 살아납니다.&lt;/p&gt;
&lt;h3&gt;글로우 오브(Glow Orb)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.orb&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;blur&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;80px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.orb-1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 350px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 350px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #0ea5e9&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 150px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.orb-2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 280px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 280px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #8b5cf6&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;bottom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -80px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;orb orb-1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;orb orb-2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;blur&lt;/code&gt; 처리된 큰 원이 배경에 깔리면서 자연스러운 색감 변화를 만듭니다. 색상을 바꾸면 포스팅 주제별로 분위기를 다르게 줄 수 있습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;주제&lt;/th&gt;
&lt;th&gt;오브 색상&lt;/th&gt;
&lt;th&gt;느낌&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AI / 기술&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;#0ea5e9&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;#8b5cf6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;차분한 블루&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;경고 / 폐지&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;#f97316&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;#ef4444&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;긴장감 있는 오렌지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YouTube&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;#ef4444&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;#8b5cf6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;레드 + 퍼플&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;#d4a574&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;#8b5cf6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;브라운 + 퍼플&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;배지(Badge)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.badge&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;14&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;165&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;233&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0.15&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;14&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;165&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;233&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;0.3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #38bdf8&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 14px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 600&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 6px 16px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;letter-spacing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;text-transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; uppercase&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;badge&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;SEO Guide&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;상단에 카테고리 느낌의 라벨을 넣으면 한눈에 주제가 파악됩니다.&lt;/p&gt;
&lt;h3&gt;그라데이션 텍스트&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;h1 span&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;90deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #0ea5e9&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #8b5cf6&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;-webkit-background-clip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;-webkit-text-fill-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;제목의 핵심 단어에만 적용하면 강조 효과가 확실합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;3단계: Playwright로 PNG 캡처&lt;/h2&gt;
&lt;p&gt;HTML 파일을 브라우저에서 열어 확인한 후, Playwright로 캡처합니다.&lt;/p&gt;
&lt;h3&gt;Playwright MCP 사용 (Claude Code 환경)&lt;/h3&gt;
&lt;p&gt;Claude Code에서 Playwright MCP를 사용하면 대화 중에 바로 캡처할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1. playwright_navigate — HTML 파일 열기 (뷰포트 크기 지정)
2. playwright_screenshot — PNG로 저장&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;썸네일 (1200x630)&lt;/strong&gt; 캡처:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;navigate: file:///경로/thumbnail.html (width: 1200, height: 630)
screenshot: savePng → thumbnail.png&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;대표이미지 (1080x1080)&lt;/strong&gt; 캡처:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;navigate: file:///경로/cover.html (width: 1080, height: 1080)
screenshot: savePng → cover.png&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Playwright CLI 사용 (수동)&lt;/h3&gt;
&lt;p&gt;Playwright가 설치되어 있다면 스크립트로도 캡처할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// capture.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; chromium &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;playwright&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; browser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; chromium&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;launch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; page &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;newPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;viewport&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;630&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;goto&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;file:///경로/thumbnail.html&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;screenshot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;thumbnail.png&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; browser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; capture.js&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;캡처 시 주의할 점&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;문제&lt;/th&gt;
&lt;th&gt;원인&lt;/th&gt;
&lt;th&gt;해결&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;이미지가 2:1로 찍힘&lt;/td&gt;
&lt;td&gt;뷰포트와 body 크기 불일치&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;html&lt;/code&gt;에도 &lt;code class=&quot;language-text&quot;&gt;width&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;height&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;overflow: hidden&lt;/code&gt; 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;하단에 여백 발생&lt;/td&gt;
&lt;td&gt;브라우저가 html에 추가 높이 부여&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;html { overflow: hidden }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;한글 깨짐&lt;/td&gt;
&lt;td&gt;폰트 미지정&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;font-family&lt;/code&gt;에 &lt;code class=&quot;language-text&quot;&gt;&apos;Malgun Gothic&apos;&lt;/code&gt; 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;그라데이션 텍스트 안 보임&lt;/td&gt;
&lt;td&gt;Firefox에서 미지원&lt;/td&gt;
&lt;td&gt;Chromium 사용 (Playwright 기본값)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;실전 예시 — 이 블로그의 이미지 시스템&lt;/h2&gt;
&lt;p&gt;이 블로그는 모든 포스팅에 2종류의 이미지를 만듭니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;유형&lt;/th&gt;
&lt;th&gt;비율&lt;/th&gt;
&lt;th&gt;크기&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;th&gt;파일명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Thumbnail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~2:1&lt;/td&gt;
&lt;td&gt;1200x630&lt;/td&gt;
&lt;td&gt;OG 이미지, 유튜브 썸네일&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;*-thumbnail.png&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1:1&lt;/td&gt;
&lt;td&gt;1080x1080&lt;/td&gt;
&lt;td&gt;티스토리 대표이미지, SNS&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;*-cover.png&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;디자인 일관성 유지 패턴&lt;/h3&gt;
&lt;p&gt;모든 이미지에 공통으로 적용하는 요소:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;배경&lt;/strong&gt; — 다크 그라데이션 (&lt;code class=&quot;language-text&quot;&gt;#0f172a&lt;/code&gt; → &lt;code class=&quot;language-text&quot;&gt;#1e293b&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;그리드&lt;/strong&gt; — 반투명 격자 패턴&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;글로우 오브&lt;/strong&gt; — 주제별 색상 2~3개&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;배지&lt;/strong&gt; — 상단 카테고리 라벨&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;블로그명&lt;/strong&gt; — 우하단 &lt;code class=&quot;language-text&quot;&gt;AI JAVAPARK&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;텍스트와 오브 색상만 바꾸면 일관된 브랜딩을 유지하면서 포스팅별로 구분이 됩니다.&lt;/p&gt;
&lt;h3&gt;파일 구조&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;tistory/post/images/
├── post-name-thumbnail.html    ← 썸네일 소스
├── post-name-thumbnail.png     ← 썸네일 이미지
├── post-name-cover.html        ← 대표이미지 소스
└── post-name-cover.png         ← 대표이미지&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;HTML 소스를 함께 보관하면 나중에 수정이 필요할 때 바로 편집하고 다시 캡처할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Claude Code와 함께 쓰면&lt;/h2&gt;
&lt;p&gt;이 방법의 진짜 장점은 &lt;strong&gt;Claude Code와 결합했을 때&lt;/strong&gt; 나타납니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;이 포스팅에 맞는 대표이미지 만들어줘&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 한 마디면 Claude Code가:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;포스팅 내용을 읽고&lt;/li&gt;
&lt;li&gt;주제에 맞는 색상과 레이아웃을 결정하고&lt;/li&gt;
&lt;li&gt;HTML+CSS를 작성하고&lt;/li&gt;
&lt;li&gt;Playwright로 PNG를 캡처합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;실제로 이 블로그의 포스팅 6개에 대한 썸네일 6개 + 대표이미지 6개, 총 12개의 이미지를 모두 이 방식으로 만들었습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Playwright 없이 PNG로 변환할 수 있나요?&lt;/h3&gt;
&lt;p&gt;브라우저에서 HTML을 열고 개발자 도구의 &lt;strong&gt;디바이스 모드&lt;/strong&gt;에서 해상도를 맞춘 뒤 스크린샷을 찍는 방법도 있습니다. 다만 정확한 크기 제어와 자동화를 위해서는 Playwright가 훨씬 편합니다.&lt;/p&gt;
&lt;h3&gt;폰트를 웹폰트로 쓸 수 있나요?&lt;/h3&gt;
&lt;p&gt;네, &lt;code class=&quot;language-text&quot;&gt;&amp;lt;link&gt;&lt;/code&gt; 태그로 Google Fonts를 불러와서 사용할 수 있습니다. 다만 로컬 파일을 열 때 네트워크 요청이 필요하므로, Playwright 캡처 시 &lt;code class=&quot;language-text&quot;&gt;waitUntil: &apos;networkidle&apos;&lt;/code&gt; 옵션을 추가하면 폰트 로딩을 기다립니다.&lt;/p&gt;
&lt;h3&gt;다크 모드 말고 라이트 모드도 가능한가요?&lt;/h3&gt;
&lt;p&gt;물론입니다. &lt;code class=&quot;language-text&quot;&gt;background&lt;/code&gt;를 &lt;code class=&quot;language-text&quot;&gt;#ffffff&lt;/code&gt;로, 텍스트를 &lt;code class=&quot;language-text&quot;&gt;#0f172a&lt;/code&gt;로 바꾸면 됩니다. 오브 색상의 &lt;code class=&quot;language-text&quot;&gt;opacity&lt;/code&gt;를 더 낮추면 라이트 배경에서도 자연스럽습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;정리하면, HTML로 블로그 이미지를 만드는 과정은 이렇습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;HTML+CSS로 디자인&lt;/strong&gt; — body 크기로 비율 고정, CSS로 시각 요소 구성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;브라우저에서 확인&lt;/strong&gt; — 파일을 열어 결과 확인&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Playwright로 PNG 캡처&lt;/strong&gt; — 정확한 크기로 이미지 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;포토샵 없이, 코드만으로, 일관된 브랜딩의 이미지를 만들 수 있습니다. 한 번 패턴을 잡아두면 새 포스팅마다 텍스트와 색상만 바꾸면 되니, 이미지 제작에 들이는 시간이 크게 줄어듭니다.&lt;/p&gt;
&lt;p&gt;여러분은 블로그 이미지를 어떻게 만들고 있나요? 댓글로 알려주세요!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://playwright.dev/docs/screenshots&quot;&gt;Playwright 공식 문서 — Screenshots&lt;/a&gt; — 스크린샷 캡처 옵션 상세 가이드&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cssgradient.io/&quot;&gt;CSS Gradient Generator&lt;/a&gt; — 배경 그라데이션 생성 도구&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/background-clip&quot;&gt;MDN — background-clip: text&lt;/a&gt; — 그라데이션 텍스트 구현 방법&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fonts.google.com/&quot;&gt;Google Fonts&lt;/a&gt; — 무료 웹폰트&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Claude Code 입문 가이드 2026 — 설치부터 첫 프로젝트까지 완전 정리]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. "AI 코딩 도구가 너무 많은데, Claude Code는 뭐가 다른 건가요?" 솔직히 말하면 — 직접 써보기 전에는 저도 반신반의했습니다. 터미널에서 AI가 코드를 짠다고? 결국 ChatGPT…]]></description><link>http://blog.javapark.kr/beginner-guide-2026/</link><guid isPermaLink="false">http://blog.javapark.kr/beginner-guide-2026/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/claude-code-beginner-guide-2026.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;AI 코딩 도구가 너무 많은데, Claude Code는 뭐가 다른 건가요?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;솔직히 말하면 — &lt;strong&gt;직접 써보기 전에는 저도 반신반의했습니다.&lt;/strong&gt; 터미널에서 AI가 코드를 짠다고? 결국 ChatGPT에 코드 달라고 하는 거랑 뭐가 다르지?&lt;/p&gt;
&lt;p&gt;결론부터 말씀드리면 — &lt;strong&gt;완전히 다릅니다.&lt;/strong&gt; Claude Code는 대화창에서 코드를 복붙하는 게 아니라, 내 프로젝트 폴더 안에서 직접 파일을 읽고, 수정하고, 테스트까지 실행하는 AI 에이전트입니다. 오늘은 설치부터 첫 프로젝트까지 한 번에 정리해보겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Claude Code란? — 30초 정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Claude Code는 Anthropic이 만든 AI 코딩 에이전트&lt;/strong&gt;입니다. 터미널(또는 IDE)에서 자연어로 지시하면, AI가 프로젝트 전체를 이해하고 직접 코드를 작성·수정·실행합니다.&lt;/p&gt;
&lt;p&gt;기존 AI 코딩 도구와의 차이를 정리하면:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ChatGPT/웹 AI&lt;/th&gt;
&lt;th&gt;GitHub Copilot&lt;/th&gt;
&lt;th&gt;Claude Code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;작동 방식&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;대화창에서 코드 생성&lt;/td&gt;
&lt;td&gt;에디터에서 자동완성&lt;/td&gt;
&lt;td&gt;프로젝트 전체를 이해하고 직접 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;파일 접근&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;불가 (복붙 필요)&lt;/td&gt;
&lt;td&gt;현재 파일 중심&lt;/td&gt;
&lt;td&gt;프로젝트 전체 파일 읽기/쓰기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;명령 실행&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;불가&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;td&gt;터미널 명령 직접 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;컨텍스트&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;대화 내용만&lt;/td&gt;
&lt;td&gt;열린 파일 주변&lt;/td&gt;
&lt;td&gt;최대 1M 토큰 (프로젝트 전체)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;자율성&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;중간&lt;/td&gt;
&lt;td&gt;높음 (멀티스텝 작업)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;한 줄 요약: &lt;strong&gt;&quot;내 컴퓨터에서 일하는 AI 개발자&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;설치 방법 — 3분이면 끝&lt;/h2&gt;
&lt;h3&gt;시스템 요구사항&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;최소 사양&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;macOS 13+, Windows 10+, Ubuntu 20.04+, Debian 10+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RAM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4GB 이상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;필수&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Windows: Git for Windows 설치 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;설치 (권장: 네이티브 설치)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;macOS / Linux:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-fsSL&lt;/span&gt; https://claude.ai/install.sh &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Windows (PowerShell):&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;powershell&quot;&gt;&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;irm&lt;/span&gt; https:&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;claude&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ai/install&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ps1 &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;iex&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Homebrew (macOS):&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; claude-code&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;설치 후 바로 실행:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;claude&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;첫 실행 시 Anthropic 계정 로그인 화면이 나옵니다. 브라우저가 열리면 로그인하고 권한을 승인하면 끝입니다.&lt;/p&gt;
&lt;h3&gt;IDE 연동 (선택)&lt;/h3&gt;
&lt;p&gt;CLI 외에 IDE에서도 사용할 수 있습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;플랫폼&lt;/th&gt;
&lt;th&gt;설치 방법&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VS Code&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;확장 마켓플레이스에서 &quot;Claude Code&quot; 검색 → 설치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JetBrains&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;플러그인 마켓플레이스에서 &quot;Claude Code&quot; 검색 → 설치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;데스크톱 앱&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;macOS / Windows 전용 앱 (claude.ai에서 다운로드)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;웹&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;claude.ai/code 에서 바로 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;개인적으로는 &lt;strong&gt;터미널(CLI)에서 시작하는 걸 추천&lt;/strong&gt;합니다. Claude Code의 핵심 경험이 터미널에 있고, IDE 확장은 결국 내부적으로 CLI를 호출하는 구조입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;요금제 — 얼마나 드나?&lt;/h2&gt;
&lt;p&gt;Claude Code는 &lt;strong&gt;무료 플랜이 없습니다.&lt;/strong&gt; 아래 중 하나가 필요합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;플랜&lt;/th&gt;
&lt;th&gt;월 비용&lt;/th&gt;
&lt;th&gt;Claude Code 사용량&lt;/th&gt;
&lt;th&gt;추천 대상&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$20&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;td&gt;가볍게 체험&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max 5x&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;td&gt;넉넉함&lt;/td&gt;
&lt;td&gt;개인 개발자 (추천)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max 20x&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$200&lt;/td&gt;
&lt;td&gt;거의 무제한&lt;/td&gt;
&lt;td&gt;헤비 유저&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Team&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$30/인&lt;/td&gt;
&lt;td&gt;팀 공유&lt;/td&gt;
&lt;td&gt;소규모 팀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enterprise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;별도 문의&lt;/td&gt;
&lt;td&gt;커스텀&lt;/td&gt;
&lt;td&gt;대규모 조직&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;실제 비용 감각:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;일반적인 개발자 기준 &lt;strong&gt;하루 $6~12&lt;/strong&gt; 정도 사용&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;/cost&lt;/code&gt; 명령으로 현재 세션의 토큰 사용량과 비용을 실시간 확인 가능&lt;/li&gt;
&lt;li&gt;Sonnet 모델을 기본으로 쓰면 비용을 크게 줄일 수 있고, 복잡한 작업에만 Opus로 전환하는 전략이 효과적&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;처음 시작한다면 &lt;strong&gt;Pro($20)로 체험 → Max($100)로 전환&lt;/strong&gt;하는 경로를 추천합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;핵심 기능 5가지 — 이것만 알면 시작 가능&lt;/h2&gt;
&lt;h3&gt;1. 자연어로 코딩&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 로그인 API 엔드포인트를 만들어줘. Express.js 기반으로, 
  JWT 토큰 발급까지 포함해서.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Claude Code가 필요한 파일을 만들고, 패키지를 설치하고, 코드를 작성합니다. 사람은 결과를 확인하고 승인하면 됩니다.&lt;/p&gt;
&lt;h3&gt;2. 프로젝트 전체 이해&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 이 프로젝트의 인증 흐름을 설명해줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;프로젝트 전체 파일을 읽고 구조를 분석합니다. 최대 1M 토큰(약 300만 자)의 컨텍스트 윈도우 덕분에 대규모 프로젝트도 한 번에 이해합니다.&lt;/p&gt;
&lt;h3&gt;3. Git 통합&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 지금까지 변경사항을 커밋해줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;git add&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;commit&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;push&lt;/code&gt;, PR 생성까지 자연어로 처리합니다. 커밋 메시지도 변경 내용을 분석해서 자동 생성합니다.&lt;/p&gt;
&lt;h3&gt;4. CLAUDE.md — AI에게 주는 프로젝트 매뉴얼&lt;/h3&gt;
&lt;p&gt;프로젝트 루트에 &lt;code class=&quot;language-text&quot;&gt;CLAUDE.md&lt;/code&gt; 파일을 만들면, Claude Code가 매 세션마다 이 파일을 읽고 프로젝트의 규칙과 컨벤션을 따릅니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; CLAUDE.md&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 프로젝트 규칙&lt;/span&gt;
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; TypeScript strict 모드 사용
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 함수명은 camelCase
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 테스트는 Vitest로 작성
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 커밋 메시지는 한국어로&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;비유하자면 &lt;strong&gt;신입 개발자에게 주는 온보딩 문서&lt;/strong&gt;입니다. 한 번 작성하면 매번 같은 말을 반복할 필요가 없습니다.&lt;/p&gt;
&lt;h3&gt;5. MCP 서버 — 외부 도구 연결&lt;/h3&gt;
&lt;p&gt;MCP(Model Context Protocol)를 통해 Claude Code에 외부 도구를 연결할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;데이터베이스&lt;/strong&gt;: Supabase, PostgreSQL 직접 쿼리&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;브라우저&lt;/strong&gt;: Playwright로 웹 자동화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API&lt;/strong&gt;: Slack, GitHub, Jira 등 연동&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 예: Playwright MCP 서버 연결&lt;/span&gt;
claude mcp &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; playwright npx @anthropic-ai/mcp-playwright&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;연결하면 Claude Code가 브라우저를 직접 조작하거나, DB를 조회하거나, Slack에 메시지를 보낼 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;첫 프로젝트 실습 — React Todo 앱 만들기&lt;/h2&gt;
&lt;p&gt;실제로 Claude Code를 사용해서 간단한 프로젝트를 만들어보겠습니다.&lt;/p&gt;
&lt;h3&gt;Step 1: 프로젝트 시작&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; my-todo-app
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; my-todo-app
claude&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Step 2: 프로젝트 생성 요청&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; React + TypeScript로 Todo 앱을 만들어줘. 
  Vite 기반으로 세팅하고, 할 일 추가/완료/삭제 기능을 포함해줘.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Claude Code가 하는 일:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npm create vite&lt;/code&gt; 실행&lt;/li&gt;
&lt;li&gt;필요한 패키지 설치&lt;/li&gt;
&lt;li&gt;컴포넌트 파일 생성&lt;/li&gt;
&lt;li&gt;기본 스타일 적용&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Step 3: 기능 추가&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 할 일 목록을 localStorage에 저장해서 새로고침해도 유지되게 해줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Step 4: 확인 및 실행&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; dev 서버 실행해줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 과정이 &lt;strong&gt;5~10분&lt;/strong&gt; 안에 끝납니다. 물론 프로덕션 품질의 코드는 아니지만, 프로토타이핑이나 학습 목적으로는 압도적으로 빠릅니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;알아두면 좋은 명령어&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;명령어&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/help&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;도움말&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/cost&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 세션 비용 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/compact&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;컨텍스트 정리 (긴 세션에서 유용)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/memory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;프로젝트 메모리 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;/review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;코드 리뷰 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Shift+Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;모델 전환 (Opus ↔ Sonnet)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Esc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 작업 중단&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;실전 팁 5가지&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. CLAUDE.md를 먼저 만들어라&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;프로젝트 시작 전에 규칙을 정해두면 일관된 코드를 받을 수 있습니다. 없이 시작하면 매번 &quot;TypeScript로 해줘&quot;, &quot;테스트도 작성해줘&quot;를 반복하게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 작은 단위로 요청하라&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&quot;전체 쇼핑몰 만들어줘&quot; 보다 &quot;상품 목록 API 만들어줘&quot; → &quot;장바구니 기능 추가해줘&quot; 식으로 나눠서 요청하는 게 결과물 품질이 높습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. /compact를 적극 활용하라&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;긴 세션에서 컨텍스트가 쌓이면 속도가 느려지고 비용이 올라갑니다. 한 작업이 끝나면 &lt;code class=&quot;language-text&quot;&gt;/compact&lt;/code&gt;로 정리하세요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Sonnet을 기본으로, Opus는 필요할 때만&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;일상적인 코딩은 Sonnet으로 충분합니다. 복잡한 아키텍처 설계나 대규모 리팩토링에만 Opus를 사용하면 비용을 절반 이하로 줄일 수 있습니다. &lt;code class=&quot;language-text&quot;&gt;Shift+Tab&lt;/code&gt;으로 전환합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Git 커밋을 자주 하라&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Claude Code가 코드를 수정하다가 잘못된 방향으로 갈 수 있습니다. 중간중간 커밋해두면 언제든 되돌릴 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;다음 단계&lt;/h2&gt;
&lt;p&gt;이 글에서 다룬 건 기본 중의 기본입니다. Claude Code를 더 깊이 활용하고 싶다면:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP 서버 연결&lt;/strong&gt;: 데이터베이스, 브라우저, 외부 API를 Claude Code에 연결하는 방법&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hook 활용&lt;/strong&gt;: 자동 린트, 테스트 실행, 커밋 메시지 검증 자동화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;커스텀 스킬&lt;/strong&gt;: 반복 작업을 슬래시 명령어로 자동화&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 주제들은 후속 포스팅에서 다루겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;h3&gt;Q. Claude Code는 무료로 쓸 수 있나요?&lt;/h3&gt;
&lt;p&gt;아니요. 최소 Pro 플랜($20/월)이 필요합니다. 무료 체험은 제공되지 않지만, Pro 플랜으로 가볍게 시작한 뒤 필요하면 Max로 업그레이드하는 방식을 추천합니다.&lt;/p&gt;
&lt;h3&gt;Q. Windows에서도 쓸 수 있나요?&lt;/h3&gt;
&lt;p&gt;네. Windows 10 이상에서 네이티브로 지원됩니다. 단, Git for Windows가 사전 설치되어 있어야 합니다. PowerShell에서 &lt;code class=&quot;language-text&quot;&gt;irm https://claude.ai/install.ps1 | iex&lt;/code&gt; 명령으로 설치할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;Q. 인터넷이 안 되면 사용할 수 없나요?&lt;/h3&gt;
&lt;p&gt;맞습니다. Claude Code는 Anthropic 서버와 통신해서 작동하므로 인터넷 연결이 필수입니다. 오프라인 모드는 지원하지 않습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;여러분은 AI 코딩 도구를 어떻게 활용하고 계신가요? Claude Code를 써보신 경험이 있다면 댓글로 공유해주세요!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[비개발자가 Claude Code, Codex CLI 활용하는 법 — 코딩 몰라도 AI 에이전트 쓰는 시대]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. "Claude Code? Codex…]]></description><link>http://blog.javapark.kr/codex-for-non-developers/</link><guid isPermaLink="false">http://blog.javapark.kr/codex-for-non-developers/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/claude-code-codex-for-non-developers.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Claude Code? Codex? 그거 개발자만 쓰는 거 아닌가요?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;솔직히 저도 처음엔 그렇게 생각했습니다. 터미널에 명령어를 치는 도구라니, 당연히 개발자 전용이겠거니 했죠. 그런데 직접 써보니 &lt;strong&gt;코딩을 전혀 모르는 사람이야말로 이 도구들의 진짜 수혜자&lt;/strong&gt;라는 걸 깨달았습니다.&lt;/p&gt;
&lt;p&gt;결론부터 말씀드리면 — &lt;strong&gt;비개발자도 충분히 쓸 수 있고, 오히려 반복 업무 자동화에서 엄청난 효과를 볼 수 있습니다.&lt;/strong&gt; 오늘은 Claude Code와 OpenAI Codex CLI, 이 두 도구를 비개발자 관점에서 설치부터 실전 활용까지 정리해보겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;먼저, 이 도구들이 뭔가요?&lt;/h2&gt;
&lt;p&gt;쉽게 비유하자면 이렇습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ChatGPT / Claude 웹&lt;/th&gt;
&lt;th&gt;Claude Code / Codex CLI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;비유&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;카카오톡으로 비서에게 부탁&lt;/td&gt;
&lt;td&gt;비서가 직접 내 컴퓨터 앞에 앉아서 작업&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;할 수 있는 것&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;텍스트 답변, 조언&lt;/td&gt;
&lt;td&gt;파일 읽기/수정, 폴더 정리, 코드 실행, 자동화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;작업 범위&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;대화창 안에서만&lt;/td&gt;
&lt;td&gt;내 컴퓨터의 실제 파일과 폴더&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;는 Anthropic이 만든 AI 에이전트 도구이고, &lt;strong&gt;Codex CLI&lt;/strong&gt;는 OpenAI가 만든 도구입니다. 둘 다 터미널(명령 프롬프트)에서 자연어로 지시하면 &lt;strong&gt;내 컴퓨터의 파일을 직접 읽고, 수정하고, 생성&lt;/strong&gt;해줍니다.&lt;/p&gt;
&lt;p&gt;핵심은 이겁니다 — &lt;strong&gt;코딩을 해달라고 시키는 게 아니라, 일을 해달라고 시키는 겁니다.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;비개발자가 할 수 있는 일 10가지&lt;/h2&gt;
&lt;p&gt;코딩과 전혀 관련 없는 실전 활용 사례입니다.&lt;/p&gt;
&lt;h3&gt;업무 자동화&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;경비 보고서 정리&lt;/strong&gt; — 여러 신용카드 명세서(CSV)를 하나로 합치고 카테고리별로 분류&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이메일/뉴스레터 초안&lt;/strong&gt; — 프로젝트 폴더의 변경사항을 읽고 주간 보고 메일 초안 작성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;파일 정리&lt;/strong&gt; — 수백 개 파일을 날짜별, 유형별로 자동 분류하고 이름 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;콘텐츠 &amp;#x26; 마케팅&lt;/h3&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;블로그 포스팅 초안&lt;/strong&gt; — 주제를 주면 리서치 + 마크다운 초안까지 한 번에&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SNS 콘텐츠 배치 생성&lt;/strong&gt; — 하나의 긴 글에서 트위터/인스타/링크드인용 요약본 자동 생성&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO 분석&lt;/strong&gt; — 경쟁사 페이지를 분석하고 키워드 리포트 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;데이터 분석&lt;/h3&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;&lt;strong&gt;스프레드시트 가공&lt;/strong&gt; — CSV/엑셀 파일에서 특정 조건의 데이터만 추출, 피벗&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;미사용 구독 감지&lt;/strong&gt; — 은행 거래 내역에서 반복 결제를 찾아 리스트업&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;설문 결과 분석&lt;/strong&gt; — 설문 응답 데이터를 요약하고 인사이트 도출&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;일상&lt;/h3&gt;
&lt;ol start=&quot;10&quot;&gt;
&lt;li&gt;&lt;strong&gt;여행 계획&lt;/strong&gt; — 날짜, 예산, 취향을 알려주면 일정표 마크다운 파일로 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;Claude Code 설치 가이드 (비개발자용)&lt;/h2&gt;
&lt;h3&gt;사전 준비&lt;/h3&gt;
&lt;p&gt;Claude Code를 쓰려면 두 가지가 필요합니다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Anthropic 유료 구독&lt;/strong&gt; — 최소 Pro 플랜($20/월)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node.js&lt;/strong&gt; — Claude Code 설치에 필요한 기본 도구&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;1단계: Node.js 설치&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejs.org&quot;&gt;nodejs.org&lt;/a&gt; 접속 → &lt;strong&gt;LTS 버전&lt;/strong&gt; 다운로드 → 설치 (모든 옵션 기본값 OK)&lt;/p&gt;
&lt;p&gt;설치 확인:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# v22.x.x 같은 버전이 나오면 성공&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2단계: Claude Code 설치&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @anthropic-ai/claude-code&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Windows 사용자&lt;/strong&gt;: PowerShell 또는 Git Bash에서 실행하세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3단계: 실행 및 인증&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 작업할 폴더로 이동&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ~/Documents/내작업폴더

&lt;span class=&quot;token comment&quot;&gt;# Claude Code 실행&lt;/span&gt;
claude&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;처음 실행하면 브라우저가 열리면서 Anthropic 계정 인증을 요청합니다. 로그인하면 바로 사용 가능합니다.&lt;/p&gt;
&lt;h3&gt;4단계: 첫 번째 대화&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 이 폴더에 있는 파일 목록을 정리해서 summary.md로 만들어줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이게 끝입니다. 코드를 작성한 게 아니라 &lt;strong&gt;한국어로 부탁한 것&lt;/strong&gt;뿐입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Codex CLI 설치 가이드 (비개발자용)&lt;/h2&gt;
&lt;h3&gt;사전 준비&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT Plus 이상 구독&lt;/strong&gt; — Plus($20/월) 또는 Pro($200/월)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node.js 18 이상&lt;/strong&gt; (위와 동일)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;1단계: 설치&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @openai/codex&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2단계: 인증&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;codex&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;실행하면 &quot;Sign in with ChatGPT&quot; 옵션이 나옵니다. 브라우저에서 로그인하면 완료.&lt;/p&gt;
&lt;h3&gt;3단계: 첫 번째 대화&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 이 폴더의 CSV 파일들을 읽고 날짜별로 정렬해서 하나로 합쳐줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Windows 사용자 주의&lt;/strong&gt;: Codex CLI의 Windows 지원은 아직 실험적입니다. WSL2(Windows Subsystem for Linux) 환경을 권장합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;Claude Code vs Codex CLI — 비개발자 관점 비교&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;Claude Code&lt;/th&gt;
&lt;th&gt;Codex CLI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;시작 난이도&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⭐⭐ 쉬움&lt;/td&gt;
&lt;td&gt;⭐⭐ 쉬움 (Windows는 ⭐⭐⭐)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;한국어 지원&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;매우 자연스러움&lt;/td&gt;
&lt;td&gt;자연스러움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;안전성&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;변경 전 확인 요청 (감독형)&lt;/td&gt;
&lt;td&gt;full-auto 모드 있음 (비감독형 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Windows 지원&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;네이티브 지원&lt;/td&gt;
&lt;td&gt;실험적 (WSL 권장)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;최소 비용&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$20/월 (Pro)&lt;/td&gt;
&lt;td&gt;$20/월 (Plus)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;사용량 제한&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5시간 제한 (Pro)&lt;/td&gt;
&lt;td&gt;모델별 상이&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;데스크톱 앱&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;있음 (Mac/Windows)&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;웹 버전&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;있음 (claude.ai/code)&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VS Code 연동&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;있음&lt;/td&gt;
&lt;td&gt;있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;비개발자에게 추천하는 선택은?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Claude Code를 먼저 추천합니다.&lt;/strong&gt; 이유는:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;감독형 방식&lt;/strong&gt; — 파일을 수정하기 전에 항상 확인을 요청합니다. 실수로 중요한 파일을 날릴 걱정이 적습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows 네이티브 지원&lt;/strong&gt; — WSL 설치 없이 바로 사용 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;데스크톱 앱/웹 버전&lt;/strong&gt; — 터미널이 어색하면 데스크톱 앱이나 웹에서 시작할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VS Code 확장&lt;/strong&gt; — VS Code에서 직접 사용하면 터미널을 따로 열 필요도 없습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Codex CLI는 &lt;strong&gt;이미 ChatGPT Plus를 구독 중&lt;/strong&gt;이거나, &lt;strong&gt;터미널 작업에 어느 정도 익숙한 분&lt;/strong&gt;에게 적합합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;비개발자를 위한 실전 팁 5가지&lt;/h2&gt;
&lt;h3&gt;1. CLAUDE.md (또는 AGENTS.md) 파일을 활용하세요&lt;/h3&gt;
&lt;p&gt;프로젝트 폴더에 &lt;code class=&quot;language-text&quot;&gt;CLAUDE.md&lt;/code&gt; 파일을 만들어두면, Claude Code가 매번 대화를 시작할 때 이 파일을 읽습니다. 일종의 &lt;strong&gt;업무 매뉴얼&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; 이 폴더에 대한 설명&lt;/span&gt;

&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 이 폴더에는 매월 경비 보고 CSV 파일이 저장됩니다
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 파일 형식: YYYY-MM-expenses.csv
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 카테고리: 교통, 식비, 숙박, 기타
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 월말에 summary.xlsx로 합산 보고서를 만들어야 합니다&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이렇게 해두면 매번 같은 설명을 반복하지 않아도 됩니다.&lt;/p&gt;
&lt;h3&gt;2. 작업 전 백업 습관을 들이세요&lt;/h3&gt;
&lt;p&gt;AI가 파일을 직접 수정할 수 있으므로, 중요한 파일은 &lt;strong&gt;작업 전에 복사본&lt;/strong&gt;을 만들어두세요.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 작업 시작하기 전에 이 폴더를 backup 폴더로 복사해줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이것도 자연어로 시키면 됩니다.&lt;/p&gt;
&lt;h3&gt;3. 프롬프트는 구체적일수록 좋습니다&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;❌ &quot;이 파일 정리해줘&quot;
✅ &quot;expenses.csv에서 2024년 3월 데이터만 추출해서 march-report.csv로 저장해줘. 금액 기준 내림차순으로 정렬하고.&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;4. 모르겠으면 물어보세요&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 이 폴더에 어떤 파일들이 있는지 먼저 알려줘
&gt; 이 CSV 파일의 구조(컬럼)를 설명해줘
&gt; 이걸 엑셀로 변환할 수 있어?&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Claude Code와 Codex 모두 &lt;strong&gt;대화형&lt;/strong&gt;이므로, 바로 작업을 시키지 않고 먼저 상황 파악을 요청해도 됩니다.&lt;/p&gt;
&lt;h3&gt;5. 비용 관리에 신경 쓰세요&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;사용 패턴&lt;/th&gt;
&lt;th&gt;권장 플랜&lt;/th&gt;
&lt;th&gt;월 비용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;가끔 (주 1~2회)&lt;/td&gt;
&lt;td&gt;Pro / Plus&lt;/td&gt;
&lt;td&gt;~$20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;매일 가볍게&lt;/td&gt;
&lt;td&gt;Pro / Plus&lt;/td&gt;
&lt;td&gt;~$20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;매일 집중적으로&lt;/td&gt;
&lt;td&gt;Max&lt;/td&gt;
&lt;td&gt;~$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;헤비 유저&lt;/td&gt;
&lt;td&gt;Max / Pro (Codex)&lt;/td&gt;
&lt;td&gt;$100~200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;특히 Claude Code Pro 플랜은 &lt;strong&gt;5시간 사용 제한&lt;/strong&gt;이 있으므로, 가벼운 작업 위주라면 충분하지만 하루 종일 붙잡고 있으면 금방 한도에 도달합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;비개발자가 자주 하는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q. 터미널(명령 프롬프트)을 한 번도 써본 적이 없는데 괜찮을까요?&lt;/h3&gt;
&lt;p&gt;괜찮습니다. 필요한 명령어는 딱 세 개입니다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;cd 폴더경로&lt;/code&gt; — 폴더 이동&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;claude&lt;/code&gt; 또는 &lt;code class=&quot;language-text&quot;&gt;codex&lt;/code&gt; — 도구 실행&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;exit&lt;/code&gt; — 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;나머지는 전부 자연어로 대화하면 됩니다. VS Code 확장이나 데스크톱 앱을 쓰면 터미널 자체를 건드릴 일이 더 줄어듭니다.&lt;/p&gt;
&lt;h3&gt;Q. AI가 중요한 파일을 잘못 수정하면 어떡하죠?&lt;/h3&gt;
&lt;p&gt;Claude Code는 &lt;strong&gt;기본적으로 파일을 수정하기 전에 확인을 요청&lt;/strong&gt;합니다. &quot;이 파일을 이렇게 바꿔도 될까요?&quot;라고 물어보고, 사용자가 승인해야 실행됩니다. Codex CLI도 기본 모드에서는 동일합니다. 다만 Codex의 &lt;code class=&quot;language-text&quot;&gt;full-auto&lt;/code&gt; 모드는 확인 없이 바로 실행하므로, 비개발자는 기본 모드를 유지하는 것을 권장합니다.&lt;/p&gt;
&lt;h3&gt;Q. ChatGPT나 Claude 웹에서 하던 작업과 뭐가 다른가요?&lt;/h3&gt;
&lt;p&gt;가장 큰 차이는 &lt;strong&gt;내 컴퓨터의 파일에 직접 접근&lt;/strong&gt;할 수 있다는 점입니다. 채팅 인터페이스에서는 &quot;이런 코드를 만들어줘&quot;라고 하면 텍스트로 결과를 보여주기만 합니다. Claude Code나 Codex는 실제로 파일을 만들고, 기존 파일을 수정하고, 프로그램을 실행까지 해줍니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;&quot;코딩을 모르면 AI 에이전트 도구를 못 쓴다&quot;는 건 이제 옛말입니다. Claude Code와 Codex CLI는 &lt;strong&gt;자연어로 지시하면 내 컴퓨터에서 직접 작업을 수행하는 도구&lt;/strong&gt;이고, 그 지시에 코드가 필요하지 않습니다.&lt;/p&gt;
&lt;p&gt;시작이 어렵게 느껴지시면, 딱 하나만 해보세요:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
claude
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; 이 폴더에 있는 파일들을 정리해서 목록 만들어줘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 한 줄이 시작입니다. 한 번 경험하고 나면 &quot;이것도 시킬 수 있지 않을까?&quot; 하는 생각이 자연스럽게 따라올 겁니다.&lt;/p&gt;
&lt;p&gt;여러분은 AI 에이전트 도구를 어떤 업무에 활용하고 계신가요? 댓글로 공유해주세요!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;관련 포스팅:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./ai-coding-skills-comparison.md&quot;&gt;AI 코딩 도구 Skill 비교 — Claude Code vs Gemini CLI vs Codex CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;참고 문서:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code&quot;&gt;Claude Code 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openai/codex&quot;&gt;OpenAI Codex CLI 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Claude Code Skill 사용법 — 슬래시 명령어로 반복 업무 자동화]]></title><description><![CDATA[thumbnail 안녕하세요, 자바파커입니다. Claude Code…]]></description><link>http://blog.javapark.kr/skill/</link><guid isPermaLink="false">http://blog.javapark.kr/skill/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/javapark/javapark.github.io/releases/download/images-v1/claude-code-skill.png&quot; alt=&quot;thumbnail&quot;&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;Claude Code를 쓰다 보면 매번 같은 지시를 반복하는 순간이 옵니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;블로그 포스팅 써줘. 톤은 친근하게, 마크다운으로, 코드 예시 포함해서, 도입-본문-정리 구조로...&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 긴 설명을, 이렇게 한 줄로 바꿀 수 있다면 어떨까요?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/blog-post Claude Code Skill 소개&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이게 바로 &lt;strong&gt;Skill&lt;/strong&gt;입니다. 실제로 이 글도 제가 만든 블로그 포스팅 스킬로 작성했습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Claude Code Skill이란?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;반복되는 작업 지시를 파일로 저장해두고, 슬래시 명령어로 호출하는 기능&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;비유하자면, 신입에게 매번 말로 설명하던 업무 절차를 &lt;strong&gt;매뉴얼 문서로 만들어둔 것&lt;/strong&gt;과 같습니다. Claude가 그 매뉴얼을 읽고, 그대로 실행합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Skill vs Hook vs CLAUDE.md 차이점 비교&lt;/h2&gt;
&lt;p&gt;처음 접하면 헷갈리는 세 가지를 정리합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;역할&lt;/th&gt;
&lt;th&gt;비유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CLAUDE.md&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;프로젝트 전체에 적용되는 규칙&lt;/td&gt;
&lt;td&gt;사무실 벽에 붙은 공지사항&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Skill&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;특정 작업을 위한 명령어&lt;/td&gt;
&lt;td&gt;업무 매뉴얼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hook&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;이벤트 발생 시 자동 실행&lt;/td&gt;
&lt;td&gt;자동화 봇&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;핵심 차이를 한 줄로 요약하면:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CLAUDE.md&lt;/strong&gt; — 항상 적용됩니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skill&lt;/strong&gt; — 내가 호출하거나, Claude가 판단해서 호출합니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hook&lt;/strong&gt; — 특정 이벤트에 자동으로 실행됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;SKILL.md 만드는 법 — 3단계&lt;/h2&gt;
&lt;h3&gt;1단계: 폴더와 파일 만들기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;~/.claude/skills/blog-post/
└── SKILL.md&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이게 끝입니다. &lt;code class=&quot;language-text&quot;&gt;SKILL.md&lt;/code&gt; 파일 하나만 있으면 됩니다.&lt;/p&gt;
&lt;p&gt;저장 위치에 따라 적용 범위가 달라집니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;위치&lt;/th&gt;
&lt;th&gt;적용 범위&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;~/.claude/skills/&amp;lt;name&gt;/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;내 모든 프로젝트&lt;/td&gt;
&lt;td&gt;개인 스킬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;.claude/skills/&amp;lt;name&gt;/SKILL.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;해당 프로젝트만&lt;/td&gt;
&lt;td&gt;팀 공유 (Git 커밋)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;2단계: SKILL.md 작성하기&lt;/h3&gt;
&lt;p&gt;파일 구조는 &lt;strong&gt;YAML 프론트매터 + 마크다운 본문&lt;/strong&gt; 두 부분으로 되어 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blog&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;post
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 블로그 포스팅 초안을 작성합니다
&lt;span class=&quot;token key atrule&quot;&gt;disable-model-invocation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;allowed-tools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Read&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Grep&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Glob&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WebSearch
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 블로그 포스팅 작성 스킬&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;## 기본 정보&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;블로그명&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; AI JAVAPARK
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;필명&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 자바파커

&lt;span class=&quot;token comment&quot;&gt;## 작성 규칙&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 실전 경험 기반의 친근한 문체
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 어려운 개념은 비유나 실제 사례로 설명
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 도입 → 본문 → 정리 구조

&lt;span class=&quot;token comment&quot;&gt;## 포맷&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 마크다운 형식
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 코드 블록에는 언어 표기&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;---&lt;/code&gt;로 감싼 윗부분이 &lt;strong&gt;프론트매터&lt;/strong&gt;(설정), 아랫부분이 &lt;strong&gt;본문&lt;/strong&gt;(Claude에게 주는 지시)입니다.&lt;/p&gt;
&lt;h3&gt;3단계: 호출하기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;/blog-post Claude Code Skill 소개&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&quot;Claude Code Skill 소개&quot;가 &lt;code class=&quot;language-text&quot;&gt;$ARGUMENTS&lt;/code&gt;로 전달되어, 스킬에 정의된 규칙대로 포스팅이 만들어집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;SKILL.md 프론트매터 옵션 정리&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;슬래시 명령어 이름&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;blog-post&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;스킬 설명&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;블로그 포스팅 초안을 작성합니다&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;disable-model-invocation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt;면 수동 호출만 가능&lt;/td&gt;
&lt;td&gt;부작용 있는 작업에 권장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;allowed-tools&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;사용할 도구 제한&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Read, Grep, Glob&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;context&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;fork&lt;/code&gt; 시 서브에이전트로 분리 실행&lt;/td&gt;
&lt;td&gt;메인 대화 오염 방지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;agent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;context: fork&lt;/code&gt; 시 에이전트 타입&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Explore&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Plan&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;실전 예시 — 블로그 포스팅 자동화 Skill&lt;/h2&gt;
&lt;p&gt;실제로 사용 중인 스킬 전체를 공개합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blog&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;post
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 블로그 포스팅 초안을 작성합니다. 주제를 전달하면 구조화된 마크다운 포스팅을 생성합니다.
&lt;span class=&quot;token key atrule&quot;&gt;disable-model-invocation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;allowed-tools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Read&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Grep&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Glob&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WebSearch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WebFetch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Agent
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 블로그 포스팅 작성 스킬&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;## 기본 정보&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;블로그명&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; AI JAVAPARK
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;필명&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 자바파커
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;플랫폼&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 티스토리
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;주요 독자&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 개발자&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; AI/IT에 관심 있는 사람들

&lt;span class=&quot;token comment&quot;&gt;## 작성 규칙&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;### 톤 &amp;amp; 스타일&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 실전 경험 기반의 친근한 문체 (&quot;~합니다&quot; 체)
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 어려운 개념은 비유나 실제 사례로 설명
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 독자가 바로 따라할 수 있는 실용적 내용 중심
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 불필요한 서론 최소화&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 핵심부터 진입

&lt;span class=&quot;token comment&quot;&gt;### 구조&lt;/span&gt;
1. &lt;span class=&quot;token important&quot;&gt;**도입**&lt;/span&gt; — 왜 이 주제를 다루는지 (2~3문장)
2. &lt;span class=&quot;token important&quot;&gt;**본문**&lt;/span&gt; — 개념 설명 + 실전 예시 + 코드/설정 예시
3. &lt;span class=&quot;token important&quot;&gt;**정리**&lt;/span&gt; — 핵심 요약 또는 다음 단계 제안

&lt;span class=&quot;token comment&quot;&gt;### 포맷&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 마크다운 형식
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 코드 블록에는 언어 표기
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 적절한 소제목으로 스캔 가능하게 구성
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 긴 설명보다 표&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 목록&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 코드 예시 활용

&lt;span class=&quot;token comment&quot;&gt;## 작업 흐름&lt;/span&gt;
1. 주제($ARGUMENTS)를 받으면 먼저 포스팅 아웃라인을 잡는다
2. 필요하면 WebSearch로 최신 정보를 확인한다
3. 프로젝트 내 관련 코드/설정이 있으면 참조한다
4. 마크다운 초안을 작성한다
5. 초안을 프로젝트 루트에 posts/ 디렉토리 아래 저장한다&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 스킬 덕분에 &lt;code class=&quot;language-text&quot;&gt;/blog-post 주제&lt;/code&gt; 한 줄이면 블로그 톤, 구조, 포맷을 매번 설명하지 않아도 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Claude Code Skill 활용 예시 — 코드 리뷰, 이슈 처리&lt;/h2&gt;
&lt;h3&gt;코드 리뷰 스킬&lt;/h3&gt;
&lt;p&gt;PR을 서브에이전트로 분석합니다. &lt;code class=&quot;language-text&quot;&gt;!&lt;/code&gt;command`` 문법으로 쉘 명령어 결과를 동적으로 주입하는 게 포인트입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; review
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; PR 코드 리뷰를 수행합니다
&lt;span class=&quot;token key atrule&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fork
&lt;span class=&quot;token key atrule&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Explore
&lt;span class=&quot;token key atrule&quot;&gt;allowed-tools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Bash(gh &lt;span class=&quot;token important&quot;&gt;*)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Read&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Grep&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Glob
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;## PR 컨텍스트&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;PR diff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;!&lt;/span&gt;`gh pr diff`
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;변경 파일&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;!&lt;/span&gt;`gh pr diff &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;only`

&lt;span class=&quot;token comment&quot;&gt;## 리뷰 기준&lt;/span&gt;
1. 버그 가능성이 있는 코드
2. 성능 이슈
3. 보안 취약점
4. 컨벤션 위반&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;GitHub 이슈 처리 스킬&lt;/h3&gt;
&lt;p&gt;이슈 번호만 넘기면 분석부터 커밋까지 처리합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fix&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;issue
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; GitHub 이슈를 분석하고 수정합니다
&lt;span class=&quot;token key atrule&quot;&gt;disable-model-invocation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

GitHub 이슈 &lt;span class=&quot;token comment&quot;&gt;#$ARGUMENTS 를 처리합니다:&lt;/span&gt;

1. 이슈 내용을 읽고 요구사항 파악
2. 관련 코드 탐색
3. 수정 구현
4. 테스트 작성
5. 커밋 생성&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;Claude Code Skill 작성 팁 5가지&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;disable-model-invocation: true&lt;/code&gt;를 습관적으로 쓰세요.&lt;/strong&gt;
배포, 커밋, 메시지 전송 등 부작용이 있는 스킬에 설정하지 않으면, Claude가 대화 중 알아서 호출할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;description을 잘 쓰세요.&lt;/strong&gt;
Claude가 자동 호출 여부를 판단할 때 이 설명을 봅니다. 모호하면 엉뚱한 타이밍에 호출됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SKILL.md는 500줄 이내로.&lt;/strong&gt;
길어지면 별도 파일로 분리하고 SKILL.md에서 참조하세요. 스킬 디렉토리 안에 &lt;code class=&quot;language-text&quot;&gt;examples/&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;templates/&lt;/code&gt; 같은 하위 폴더를 두면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;$ARGUMENTS&lt;/code&gt;로 입력값을 받으세요.&lt;/strong&gt;
&lt;code class=&quot;language-text&quot;&gt;/skill-name 인자값&lt;/code&gt; 형태로 호출하면 &lt;code class=&quot;language-text&quot;&gt;$ARGUMENTS&lt;/code&gt;에 전달됩니다. &lt;code class=&quot;language-text&quot;&gt;$0&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;$1&lt;/code&gt;로 개별 인자도 접근 가능합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;context: fork&lt;/code&gt;로 대화를 깔끔하게.&lt;/strong&gt;
리서치나 분석처럼 긴 작업은 서브에이전트로 분리하면 메인 대화가 오염되지 않습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Skill과 프롬프트 템플릿은 뭐가 다른가요?&lt;/h3&gt;
&lt;p&gt;프롬프트 템플릿은 텍스트를 복사-붙여넣기 하는 방식입니다. Skill은 Claude Code가 직접 파일을 읽고 실행하기 때문에, 도구 사용 제한(&lt;code class=&quot;language-text&quot;&gt;allowed-tools&lt;/code&gt;), 자동 호출 제어(&lt;code class=&quot;language-text&quot;&gt;disable-model-invocation&lt;/code&gt;), 서브에이전트 분리(&lt;code class=&quot;language-text&quot;&gt;context: fork&lt;/code&gt;) 같은 세밀한 제어가 가능합니다.&lt;/p&gt;
&lt;h3&gt;Skill을 팀원과 공유할 수 있나요?&lt;/h3&gt;
&lt;p&gt;프로젝트 루트의 &lt;code class=&quot;language-text&quot;&gt;.claude/skills/&lt;/code&gt; 에 저장하면 Git으로 커밋할 수 있습니다. 팀원이 같은 저장소를 클론하면 동일한 슬래시 명령어를 사용할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;Skill이 너무 길어지면 어떻게 하나요?&lt;/h3&gt;
&lt;p&gt;SKILL.md는 500줄 이내로 유지하는 것이 좋습니다. 길어지면 스킬 디렉토리 안에 &lt;code class=&quot;language-text&quot;&gt;examples/&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;templates/&lt;/code&gt; 같은 하위 폴더를 만들고, SKILL.md에서 해당 파일을 참조하도록 작성하세요.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;Skill은 결국 **&quot;Claude에게 주는 업무 매뉴얼을 파일로 저장한 것&quot;**입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;SKILL.md&lt;/code&gt; 파일 하나 만들고&lt;/li&gt;
&lt;li&gt;프론트매터에 이름과 설명 적고&lt;/li&gt;
&lt;li&gt;본문에 작업 지시를 마크다운으로 작성하면&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;그때부터 &lt;code class=&quot;language-text&quot;&gt;/name&lt;/code&gt;으로 호출할 수 있습니다.&lt;/p&gt;
&lt;p&gt;반복하는 작업이 있다면, 오늘 바로 하나 만들어보세요. 한번 만들어두면 다시는 같은 설명을 반복하지 않아도 됩니다.&lt;/p&gt;
&lt;p&gt;여러분은 어떤 반복 업무를 스킬로 만들고 싶으신가요? 댓글로 알려주세요!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;참고 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/skills&quot;&gt;Claude Code 공식 문서 — Skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/memory&quot;&gt;Claude Code 공식 문서 — CLAUDE.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/hooks&quot;&gt;Claude Code 공식 문서 — Hooks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Gatsby 블로그 스킨 커스터마이징 — 나만의 디자인 만들기]]></title><description><![CDATA[안녕하세요, 자바파커입니다. 지난 포스팅에서 Gatsby 블로그를 설치하고 배포까지 마쳤습니다. 하지만 기본 테마 그대로 사용하기에는 아쉬운 부분이 있습니다. 이번 포스팅에서는 gatsby-starter-hoodie…]]></description><link>http://blog.javapark.kr/02-customizing-skin/</link><guid isPermaLink="false">http://blog.javapark.kr/02-customizing-skin/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;지난 포스팅에서 Gatsby 블로그를 설치하고 배포까지 마쳤습니다. 하지만 기본 테마 그대로 사용하기에는 아쉬운 부분이 있습니다. 이번 포스팅에서는 gatsby-starter-hoodie 테마를 기준으로 블로그 디자인을 나만의 스타일로 커스터마이징하는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;h2&gt;Gatsby 테마 구조 이해&lt;/h2&gt;
&lt;p&gt;커스터마이징을 시작하기 전에 테마의 폴더 구조를 이해하는 것이 중요합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;src/
├── assets/
│   └── theme/
│       └── index.js        # 테마 색상, 크기 등 핵심 설정
├── components/
│   ├── Article/            # 본문 영역 컴포넌트
│   ├── Bio/                # 프로필 영역
│   ├── Header/             # 상단 헤더
│   ├── Layout/             # 전체 레이아웃
│   ├── Sidebar/            # 사이드바
│   └── ...
├── pages/
│   └── index.js            # 메인 페이지
└── templates/
    └── Post.js             # 개별 포스트 템플릿&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;핵심 파일은 &lt;code class=&quot;language-text&quot;&gt;src/assets/theme/index.js&lt;/code&gt;입니다. 이 파일에서 색상, 크기, 폰트 등 대부분의 디자인 변수를 관리합니다.&lt;/p&gt;
&lt;h2&gt;콘텐츠 폭 조정&lt;/h2&gt;
&lt;p&gt;기본 테마의 콘텐츠 폭이 좁게 느껴진다면 조정할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;Layout/Body 컴포넌트 수정&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;src/components/Layout/Body/index.js&lt;/code&gt; 파일을 찾아 &lt;code class=&quot;language-text&quot;&gt;max-width&lt;/code&gt; 값을 변경합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/Layout/Body/index.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; styled &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;styled-components&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; styled&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;div&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  margin: 0 auto;
  padding-top: 80px;
  max-width: 680px;  /* 기본값 */

  @media (max-width: 768px) {
    padding: 80px 16px 0;
  }
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 값을 필요에 따라 조정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; styled&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;div&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  margin: 0 auto;
  padding-top: 80px;
  max-width: 760px;  /* 더 넓은 콘텐츠 영역 */

  @media (max-width: 768px) {
    padding: 80px 20px 0;
  }
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;팁&lt;/strong&gt;: 너무 넓으면 한 줄에 글자 수가 많아져 가독성이 떨어집니다. 일반적으로 680px~800px 사이가 적당합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;테마 변수로 관리하기&lt;/h3&gt;
&lt;p&gt;반복 사용되는 값은 테마 변수로 관리하면 유지보수가 편리합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/assets/theme/index.js 에 추가&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;maxWidth&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;760px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;mobileBreakpoint&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;768px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tabletBreakpoint&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1024px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; size &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;타이포그래피 변경&lt;/h2&gt;
&lt;p&gt;블로그의 분위기를 결정짓는 가장 큰 요소는 폰트입니다.&lt;/p&gt;
&lt;h3&gt;웹 폰트 추가&lt;/h3&gt;
&lt;p&gt;Google Fonts나 눈누(Noonnu)에서 원하는 폰트를 선택합니다. &lt;code class=&quot;language-text&quot;&gt;gatsby-browser.js&lt;/code&gt;에서 웹 폰트를 로드하는 방법이 가장 간단합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-browser.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./src/assets/fonts/fonts.css&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* src/assets/fonts/fonts.css */&lt;/span&gt;
&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&apos;https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&amp;amp;display=swap&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&apos;https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&amp;amp;display=swap&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;폰트 적용&lt;/h3&gt;
&lt;p&gt;전역 스타일 또는 테마 파일에서 폰트를 적용합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/assets/theme/index.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fonts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&apos;Noto Sans KR&apos;, -apple-system, BlinkMacSystemFont, &apos;Segoe UI&apos;, sans-serif&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&apos;JetBrains Mono&apos;, &apos;Fira Code&apos;, Consolas, monospace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fonts &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;styled-components에서 사용할 때는 다음과 같이 적용합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fonts &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../../assets/theme&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; styled&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;div&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  font-family: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
  font-size: 16px;
  line-height: 1.8;
  letter-spacing: -0.01em;
  word-break: keep-all;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;글꼴 크기와 행간 조정&lt;/h3&gt;
&lt;p&gt;가독성을 높이려면 &lt;strong&gt;line-height&lt;/strong&gt;(행간)와 &lt;strong&gt;letter-spacing&lt;/strong&gt;(자간) 조정이 중요합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* 추천 설정 */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 16px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;/* 본문 기본 크기 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.8&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;       &lt;span class=&quot;token comment&quot;&gt;/* 행간: 1.6~1.8 추천 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;letter-spacing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; -0.01em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* 한글은 약간 좁히면 자연스럽습니다 */&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;word-break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; keep-all&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* 한글 단어 단위 줄바꿈 */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 700&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 700&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;h3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.25rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 500&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;다크/라이트 테마 색상 커스터마이징&lt;/h2&gt;
&lt;p&gt;gatsby-starter-hoodie는 다크모드를 기본 지원합니다. 색상 설정은 테마 파일에서 관리합니다.&lt;/p&gt;
&lt;h3&gt;theme/index.js 수정&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/assets/theme/index.js&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; light &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// 배경 색상&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;bodyBackground&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#ffffff&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;cardBackground&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#f8f9fa&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 텍스트 색상&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#1a1a2e&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;textSecondary&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#6c757d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;textTertiary&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#adb5bd&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 강조 색상&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#0066cc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;primaryLight&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#e7f1ff&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 경계선&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#e9ecef&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;borderLight&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#f1f3f5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 인라인 코드&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;inlineCodeBackground&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#f1f3f5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;inlineCodeText&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#e74c3c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 헤더&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;headerBackground&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rgba(255, 255, 255, 0.85)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dark &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// 배경 색상&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;bodyBackground&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#1a1a2e&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;cardBackground&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#16213e&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 텍스트 색상&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#e0e0e0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;textSecondary&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#a0a0a0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;textTertiary&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#707070&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 강조 색상&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#4dabf7&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;primaryLight&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#1a2744&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 경계선&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#2c3e50&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;borderLight&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#233554&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 인라인 코드&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;inlineCodeBackground&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#2d2d2d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;inlineCodeText&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#ff6b6b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 헤더&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;headerBackground&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rgba(26, 26, 46, 0.85)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; light&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dark &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;색상 팔레트 선택 팁&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;배경색&lt;/strong&gt;: 순백(&lt;code class=&quot;language-text&quot;&gt;#fff&lt;/code&gt;)보다 살짝 톤을 줄인 &lt;code class=&quot;language-text&quot;&gt;#fafafa&lt;/code&gt;나 &lt;code class=&quot;language-text&quot;&gt;#f8f9fa&lt;/code&gt;가 눈에 편합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;다크모드 배경&lt;/strong&gt;: 순검정(&lt;code class=&quot;language-text&quot;&gt;#000&lt;/code&gt;)보다 짙은 남색(&lt;code class=&quot;language-text&quot;&gt;#1a1a2e&lt;/code&gt;)이나 짙은 회색(&lt;code class=&quot;language-text&quot;&gt;#1e1e1e&lt;/code&gt;)이 부드럽습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;강조색(primary)&lt;/strong&gt;: 블로그의 정체성을 나타내는 색상을 하나 정해서 일관되게 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;대비&lt;/strong&gt;: 텍스트와 배경의 명암비가 최소 4.5:1 이상이 되어야 가독성이 보장됩니다. &lt;a href=&quot;https://webaim.org/resources/contrastchecker/&quot;&gt;WebAIM Contrast Checker&lt;/a&gt;에서 확인할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;코드 블록 스타일링&lt;/h2&gt;
&lt;p&gt;기술 블로그에서 코드 블록은 매우 중요한 요소입니다. Gatsby는 기본적으로 &lt;strong&gt;Prism.js&lt;/strong&gt;를 사용합니다.&lt;/p&gt;
&lt;h3&gt;Prism.js 테마 변경&lt;/h3&gt;
&lt;p&gt;gatsby-starter-hoodie에서 사용하는 Prism 테마를 변경하려면 &lt;code class=&quot;language-text&quot;&gt;gatsby-browser.js&lt;/code&gt;에서 import를 수정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-browser.js&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 기본 테마 대신 원하는 테마를 import합니다&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// import &quot;prismjs/themes/prism.css&quot;           // 라이트&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// import &quot;prismjs/themes/prism-tomorrow.css&quot;  // 다크&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// import &quot;prismjs/themes/prism-okaidia.css&quot;   // Monokai 스타일&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;prismjs/themes/prism-vsc-dark-plus.css&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// VS Code 스타일&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;커스텀 코드 블록 스타일&lt;/h3&gt;
&lt;p&gt;Prism 테마를 직접 오버라이드하면 더 세밀하게 조정할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* src/assets/styles/code.css */&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* 코드 블록 컨테이너 */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.gatsby-highlight&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5em 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 8px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;overflow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hidden&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* 코드 블록 본문 */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.gatsby-highlight pre[class*=&quot;language-&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #1e1e2e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.2em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 8px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 14px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;line-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.6&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;overflow-x&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; auto&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;-webkit-overflow-scrolling&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; touch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* 인라인 코드 */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;:not(pre) &gt; code[class*=&quot;language-&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--inline-code-bg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #f1f3f5&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--inline-code-text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; #e74c3c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.15em 0.4em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0.9em&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* 코드 블록 언어 표시 */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.gatsby-highlight pre[class*=&quot;language-&quot;]::before&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;class&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px 8px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 11px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #999&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;text-transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; uppercase&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;코드 복사 버튼 추가&lt;/h3&gt;
&lt;p&gt;코드 블록에 복사 버튼을 추가하면 사용자 경험이 크게 향상됩니다. &lt;code class=&quot;language-text&quot;&gt;gatsby-remark-code-buttons&lt;/code&gt; 플러그인을 사용합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gatsby-remark-code-buttons&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;gatsby-config.js&lt;/code&gt;에 플러그인을 추가합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-config.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;gatsby-transformer-remark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;gatsby-remark-code-buttons&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;buttonText&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;복사&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;toasterText&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;복사되었습니다!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;token literal-property property&quot;&gt;toasterDuration&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// ... 기존 플러그인들&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;복사 버튼의 스타일도 추가합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* 코드 복사 버튼 스타일 */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.gatsby-code-button-container&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; relative&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.gatsby-code-button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; absolute&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 8px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 8px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1px solid &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 4px 10px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ccc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 12px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pointer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; all 0.2s ease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;z-index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.gatsby-code-button:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 255&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fff&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;헤더/푸터 커스터마이징&lt;/h2&gt;
&lt;h3&gt;헤더 수정&lt;/h3&gt;
&lt;p&gt;헤더는 블로그의 첫인상을 결정합니다. &lt;code class=&quot;language-text&quot;&gt;src/components/Header/index.js&lt;/code&gt;를 수정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/Header/index.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; styled &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;styled-components&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; HeaderWrapper &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; styled&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;header&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 56px;
  background: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headerBackground&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;border&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  transition: background 0.3s ease;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Logo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; styled&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  font-size: 1.2rem;
  font-weight: 700;
  color: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
  text-decoration: none;

  &amp;amp;:hover {
    color: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;primary&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
  }
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;팁&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;backdrop-filter: blur()&lt;/code&gt;를 사용하면 스크롤할 때 배경이 흐려지는 글래스모피즘 효과를 줄 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;푸터 추가&lt;/h3&gt;
&lt;p&gt;gatsby-starter-hoodie에는 기본 푸터가 간단하게 되어 있습니다. 커스텀 푸터를 추가해 봅시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/Footer/index.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; styled &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;styled-components&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; FooterWrapper &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; styled&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;footer&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  margin-top: 80px;
  padding: 40px 0;
  border-top: 1px solid &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;border&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
  text-align: center;
  font-size: 0.85rem;
  color: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textSecondary&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Footer&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;FooterWrapper&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;copy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFullYear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AI&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JAVAPARK&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; Built &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;a href&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://www.gatsbyjs.com/&quot;&lt;/span&gt; target&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;_blank&quot;&lt;/span&gt; rel&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;noreferrer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        Gatsby
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;FooterWrapper&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Footer&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;반응형 브레이크포인트 조정&lt;/h2&gt;
&lt;p&gt;다양한 디바이스에서 최적의 경험을 제공하기 위해 반응형 디자인을 조정합니다.&lt;/p&gt;
&lt;h3&gt;미디어 쿼리 정리&lt;/h3&gt;
&lt;p&gt;일관된 미디어 쿼리를 사용하기 위해 브레이크포인트를 정의합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/assets/theme/breakpoints.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; breakpoints &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;mobile&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;576px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tablet&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;768px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;desktop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1024px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;wide&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1200px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; media &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;mobile&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@media (max-width: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;breakpoints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mobile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;tablet&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@media (max-width: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;breakpoints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tablet&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;desktop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@media (max-width: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;breakpoints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;desktop&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;wide&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@media (min-width: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;breakpoints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wide&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; breakpoints&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; media &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;styled-components에서 활용&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; media &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../../assets/theme/breakpoints&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Container &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; styled&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;div&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
  max-width: 760px;
  margin: 0 auto;
  padding: 0 24px;

  &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;media&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tablet&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; {
    padding: 0 20px;
  }

  &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;media&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mobile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; {
    padding: 0 16px;
  }
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;모바일 최적화 체크리스트&lt;/h3&gt;
&lt;p&gt;반응형 커스터마이징 시 다음 항목들을 꼭 확인합니다.&lt;/p&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 모바일에서 텍스트가 잘리지 않는지 확인&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 코드 블록이 가로 스크롤로 처리되는지 확인&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 이미지가 컨테이너 폭을 넘지 않는지 확인&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 터치 타겟(버튼, 링크)이 최소 44px 이상인지 확인&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 헤더가 모바일에서 적절히 축소되는지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;크롬 개발자 도구(&lt;code class=&quot;language-text&quot;&gt;F12&lt;/code&gt;)의 디바이스 툴바를 활용하면 다양한 화면 크기를 쉽게 테스트할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;변경사항 적용 및 배포&lt;/h2&gt;
&lt;p&gt;모든 커스터마이징을 마쳤다면 개발 서버에서 결과를 확인하고 배포합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 개발 서버에서 확인&lt;/span&gt;
gatsby develop

&lt;span class=&quot;token comment&quot;&gt;# 문제가 없다면 배포&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;주의&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;gatsby develop&lt;/code&gt;에서는 보이지 않는 문제가 &lt;code class=&quot;language-text&quot;&gt;gatsby build&lt;/code&gt;에서 발생할 수 있습니다. 배포 전에 반드시 &lt;code class=&quot;language-text&quot;&gt;gatsby build&lt;/code&gt;로 프로덕션 빌드를 테스트하세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. styled-components를 몰라도 커스터마이징할 수 있나요?&lt;/h3&gt;
&lt;p&gt;네, 기본 CSS 문법만 알면 됩니다. styled-components는 JavaScript 파일 안에 CSS를 작성하는 방식일 뿐, 문법 자체는 CSS와 동일합니다. 백틱(&lt;code class=&quot;language-text&quot;&gt;`&lt;/code&gt;) 안에 일반 CSS를 그대로 작성하면 됩니다. 다만 &lt;code class=&quot;language-text&quot;&gt;${}&lt;/code&gt; 구문으로 JavaScript 변수를 활용할 수 있다는 점이 일반 CSS와 다릅니다.&lt;/p&gt;
&lt;h3&gt;Q2. 테마 수정 후 기존 글 스타일이 깨지는 경우 어떻게 하나요?&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;gatsby clean&lt;/code&gt; 명령어로 캐시를 초기화한 뒤 다시 빌드해 보세요. 대부분의 스타일 관련 이슈는 캐시 문제입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;gatsby clean &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; gatsby develop&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그래도 문제가 지속된다면 브라우저 개발자 도구에서 해당 요소를 검사하여 어떤 스타일이 적용되고 있는지 확인합니다.&lt;/p&gt;
&lt;h3&gt;Q3. 다크모드 전환이 깜빡이는 현상이 있습니다.&lt;/h3&gt;
&lt;p&gt;SSR(서버 사이드 렌더링) 시점과 클라이언트 사이드 렌더링 시점의 테마가 다르면 깜빡임이 발생합니다. &lt;code class=&quot;language-text&quot;&gt;gatsby-ssr.js&lt;/code&gt;에서 초기 테마를 설정하는 스크립트를 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;body&gt;&lt;/code&gt; 태그 앞에 삽입하면 해결됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-ssr.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;onRenderBody&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; setPreBodyComponents &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setPreBodyComponents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script
      key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;theme-script&quot;&lt;/span&gt;
      dangerouslySetInnerHTML&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;__html&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
          (function() {
            try {
              var mode = localStorage.getItem(&apos;theme&apos;);
              if (mode) {
                document.body.className = mode;
              }
            } catch (e) {}
          })();
        &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;다음 포스팅에서는 &lt;strong&gt;마크다운 글쓰기와 카테고리 관리&lt;/strong&gt; 방법을 다룹니다. frontmatter 작성법, 태그 전략, 시리즈 기능, 폴더 구조 설계까지 체계적인 블로그 운영법을 알아보겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[GitHub Actions로 블로그 자동 배포하기 — push만 하면 끝]]></title><description><![CDATA[안녕하세요, 자바파커입니다. "글 수정할 때마다 npm run build 하고 gh-pages 브랜치에 push…]]></description><link>http://blog.javapark.kr/05-github-actions-deploy/</link><guid isPermaLink="false">http://blog.javapark.kr/05-github-actions-deploy/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;글 수정할 때마다 npm run build 하고 gh-pages 브랜치에 push하고... 이걸 매번 해야 하나요?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;솔직히 말하면, 수동 배포를 계속하다 보면 글 쓰는 것보다 배포가 더 귀찮아지는 순간이 옵니다. 결론부터 말씀드리면 — GitHub Actions를 설정하면 &lt;code class=&quot;language-text&quot;&gt;git push&lt;/code&gt; 한 번으로 빌드부터 배포까지 전부 자동화할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이번 포스팅에서는 Gatsby 블로그를 GitHub Actions로 자동 배포하는 CI/CD 파이프라인을 처음부터 끝까지 구축해보겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;수동 배포의 문제점&lt;/h2&gt;
&lt;p&gt;수동으로 GitHub Pages에 배포하려면 보통 이런 과정을 거칩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 1. 빌드&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run build

&lt;span class=&quot;token comment&quot;&gt;# 2. gh-pages 브랜치에 배포&lt;/span&gt;
npx gh-pages &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; public

&lt;span class=&quot;token comment&quot;&gt;# 3. 또는 직접 public 폴더를 gh-pages 브랜치에 push&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 방식의 문제점은 명확합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;글을 수정할 때마다 수동으로 빌드해야 합니다&lt;/li&gt;
&lt;li&gt;빌드 명령어를 잊거나 실수하면 배포가 안 됩니다&lt;/li&gt;
&lt;li&gt;로컬 환경에 따라 빌드 결과가 달라질 수 있습니다&lt;/li&gt;
&lt;li&gt;시간이 오래 걸립니다 (특히 Gatsby 빌드는 느린 편)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;자동화의 핵심은 단순합니다. &lt;strong&gt;코드를 push하면 나머지는 서버가 알아서 하도록&lt;/strong&gt; 만드는 것입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;GitHub Actions 기본 개념&lt;/h2&gt;
&lt;p&gt;GitHub Actions는 GitHub에서 제공하는 CI/CD(지속적 통합/지속적 배포) 서비스입니다. 레포지토리에 특정 이벤트(push, PR 등)가 발생하면 정의된 작업을 자동으로 실행합니다.&lt;/p&gt;
&lt;h3&gt;핵심 용어 정리&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;용어&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;비유&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Workflow&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;자동화 작업의 전체 흐름&lt;/td&gt;
&lt;td&gt;레시피 전체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Event&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;워크플로우를 실행하는 트리거&lt;/td&gt;
&lt;td&gt;&quot;주문이 들어오면&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Job&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;워크플로우 안의 작업 단위&lt;/td&gt;
&lt;td&gt;레시피의 각 단계 (재료 준비, 조리, 플레이팅)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Step&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Job 안의 개별 명령어&lt;/td&gt;
&lt;td&gt;&quot;양파를 잘게 썬다&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Runner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;워크플로우가 실행되는 서버&lt;/td&gt;
&lt;td&gt;주방&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Action&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;재사용 가능한 Step 묶음&lt;/td&gt;
&lt;td&gt;밀키트 (미리 만들어진 것)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;워크플로우 파일은 &lt;code class=&quot;language-text&quot;&gt;.github/workflows/&lt;/code&gt; 디렉토리에 YAML 형식으로 작성합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;블로그 배포용 workflow 파일 작성&lt;/h2&gt;
&lt;p&gt;프로젝트 루트에 &lt;code class=&quot;language-text&quot;&gt;.github/workflows/deploy.yml&lt;/code&gt; 파일을 만들겠습니다.&lt;/p&gt;
&lt;h3&gt;전체 workflow 파일&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .github/workflows/deploy.yml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy Blog to GitHub Pages

&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; main  &lt;span class=&quot;token comment&quot;&gt;# main 브랜치에 push하면 실행&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;permissions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; write

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;build-and-deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;# 1. 레포지토리 코드 체크아웃&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Checkout repository
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v4

      &lt;span class=&quot;token comment&quot;&gt;# 2. Node.js 설정&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Setup Node.js
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@v4
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;20&quot;&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm&quot;&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;# 3. 의존성 설치&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install dependencies
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm ci

      &lt;span class=&quot;token comment&quot;&gt;# 4. Gatsby 빌드&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build Gatsby site
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm run build
        &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;PREFIX_PATHS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;# 5. GitHub Pages 배포&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy to GitHub Pages
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; peaceiris/actions&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages@v4
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;github_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.GITHUB_TOKEN &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;publish_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./public
          &lt;span class=&quot;token key atrule&quot;&gt;publish_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 파일 하나면 &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; 브랜치에 push할 때마다 자동으로 빌드 후 &lt;code class=&quot;language-text&quot;&gt;gh-pages&lt;/code&gt; 브랜치에 배포됩니다.&lt;/p&gt;
&lt;h3&gt;파일 생성 방법&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 디렉토리 생성&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; .github/workflows

&lt;span class=&quot;token comment&quot;&gt;# 파일 생성 (위 내용을 붙여넣기)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;nano&lt;/span&gt; .github/workflows/deploy.yml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;각 Step 상세 설명&lt;/h2&gt;
&lt;h3&gt;Step 1: actions/checkout&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Checkout repository
  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v4&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;GitHub Actions Runner(서버)에 레포지토리 코드를 가져옵니다. 모든 워크플로우의 첫 번째 단계입니다.&lt;/p&gt;
&lt;h3&gt;Step 2: actions/setup-node&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Setup Node.js
  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@v4
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;20&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Node.js를 설치합니다. &lt;code class=&quot;language-text&quot;&gt;node-version&lt;/code&gt;은 로컬에서 사용하는 버전과 맞추는 것이 좋습니다.&lt;/p&gt;
&lt;p&gt;로컬 Node.js 버전 확인 방법:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-v&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# v20.11.0 이런 식으로 출력됩니다&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Step 3: npm ci&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install dependencies
  &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm ci&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; 대신 &lt;code class=&quot;language-text&quot;&gt;npm ci&lt;/code&gt;를 사용합니다. &lt;code class=&quot;language-text&quot;&gt;npm ci&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt;을 기반으로 정확히 동일한 의존성을 설치하므로, 빌드 환경의 일관성을 보장합니다.&lt;/p&gt;
&lt;h3&gt;Step 4: Gatsby 빌드&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build Gatsby site
  &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm run build
  &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;PREFIX_PATHS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;gatsby build&lt;/code&gt; 명령어를 실행해 정적 파일을 생성합니다. 결과물은 &lt;code class=&quot;language-text&quot;&gt;public/&lt;/code&gt; 폴더에 저장됩니다.&lt;/p&gt;
&lt;h3&gt;Step 5: peaceiris/actions-gh-pages&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy to GitHub Pages
  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; peaceiris/actions&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages@v4
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;github_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.GITHUB_TOKEN &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;publish_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./public
    &lt;span class=&quot;token key atrule&quot;&gt;publish_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;public/&lt;/code&gt; 폴더의 내용을 &lt;code class=&quot;language-text&quot;&gt;gh-pages&lt;/code&gt; 브랜치에 자동으로 push합니다. &lt;code class=&quot;language-text&quot;&gt;GITHUB_TOKEN&lt;/code&gt;은 별도 설정 없이 GitHub Actions가 자동으로 제공합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;캐시 설정으로 빌드 속도 향상&lt;/h2&gt;
&lt;p&gt;Gatsby 빌드는 처음에는 시간이 꽤 걸립니다. 캐시를 설정하면 빌드 시간을 크게 줄일 수 있습니다.&lt;/p&gt;
&lt;h3&gt;npm 캐시 (이미 적용됨)&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;actions/setup-node&lt;/code&gt;의 &lt;code class=&quot;language-text&quot;&gt;cache: &quot;npm&quot;&lt;/code&gt; 옵션으로 npm 패키지 캐시는 이미 적용되어 있습니다.&lt;/p&gt;
&lt;h3&gt;Gatsby 캐시 추가&lt;/h3&gt;
&lt;p&gt;Gatsby는 &lt;code class=&quot;language-text&quot;&gt;.cache&lt;/code&gt; 폴더에 빌드 캐시를 저장합니다. 이것도 캐시하면 빌드 속도가 더 빨라집니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Step 2와 Step 3 사이에 추가&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Cache Gatsby build
  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/cache@v4
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
      .cache
      public&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gatsby&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;build&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hashFiles(&apos;package&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;lock.json&apos;) &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hashFiles(&apos;contents/&lt;span class=&quot;token important&quot;&gt;**&apos;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;restore-keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
      gatsby-build-${{ hashFiles(&apos;package-lock.json&apos;) }}-
      gatsby-build-&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;캐시 적용 전후 빌드 시간 비교&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;캐시 없음&lt;/th&gt;
&lt;th&gt;캐시 있음&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;npm install&lt;/td&gt;
&lt;td&gt;~60초&lt;/td&gt;
&lt;td&gt;~10초&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gatsby build&lt;/td&gt;
&lt;td&gt;~120초&lt;/td&gt;
&lt;td&gt;~30초&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;전체&lt;/td&gt;
&lt;td&gt;~3분&lt;/td&gt;
&lt;td&gt;~1분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;실제 시간은 블로그 규모에 따라 다르지만, 캐시만으로 2~3배 빨라지는 것을 체감할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;캐시 포함 완성 workflow&lt;/h2&gt;
&lt;p&gt;캐시까지 포함한 최종 workflow 파일입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# .github/workflows/deploy.yml&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy Blog to GitHub Pages

&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; main

&lt;span class=&quot;token key atrule&quot;&gt;permissions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; write

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;build-and-deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Checkout repository
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v4

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Setup Node.js
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@v4
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;node-version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;20&quot;&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm&quot;&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Cache Gatsby build
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/cache@v4
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
            .cache
            public&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gatsby&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;build&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hashFiles(&apos;package&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;lock.json&apos;) &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hashFiles(&apos;contents/&lt;span class=&quot;token important&quot;&gt;**&apos;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;restore-keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
            gatsby-build-${{ hashFiles(&apos;package-lock.json&apos;) }}-
            gatsby-build-&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install dependencies
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm ci

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build Gatsby site
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm run build
        &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;PREFIX_PATHS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;

      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy to GitHub Pages
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; peaceiris/actions&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages@v4
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;github_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.GITHUB_TOKEN &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;publish_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./public
          &lt;span class=&quot;token key atrule&quot;&gt;publish_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;커스텀 도메인 설정 (CNAME)&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;blog.javapark.kr&lt;/code&gt;처럼 커스텀 도메인을 사용하고 있다면, 배포할 때마다 CNAME 파일이 유지되어야 합니다.&lt;/p&gt;
&lt;h3&gt;방법 1: static 폴더에 CNAME 파일 추가&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;blog.javapark.kr&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; static/CNAME&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Gatsby 빌드 시 &lt;code class=&quot;language-text&quot;&gt;static/&lt;/code&gt; 폴더의 파일이 그대로 &lt;code class=&quot;language-text&quot;&gt;public/&lt;/code&gt;에 복사되므로, 배포 시 자동으로 포함됩니다.&lt;/p&gt;
&lt;h3&gt;방법 2: workflow에서 CNAME 옵션 사용&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy to GitHub Pages
  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; peaceiris/actions&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages@v4
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;github_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.GITHUB_TOKEN &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;publish_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./public
    &lt;span class=&quot;token key atrule&quot;&gt;publish_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gh&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages
    &lt;span class=&quot;token key atrule&quot;&gt;cname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; blog.javapark.kr&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;두 가지 방법 모두 동일한 결과를 만들지만, 저는 방법 1을 추천합니다. CNAME 파일이 프로젝트에 명시적으로 포함되어 있으면 관리가 더 편합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;GitHub Pages 설정 확인&lt;/h2&gt;
&lt;p&gt;workflow를 배포하기 전에 GitHub 레포지토리 설정을 확인해야 합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GitHub 레포지토리 &gt; &lt;strong&gt;Settings&lt;/strong&gt; 탭 클릭&lt;/li&gt;
&lt;li&gt;왼쪽 메뉴에서 &lt;strong&gt;Pages&lt;/strong&gt; 클릭&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source&lt;/strong&gt; 항목을 &lt;strong&gt;Deploy from a branch&lt;/strong&gt;로 설정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Branch&lt;/strong&gt;를 &lt;code class=&quot;language-text&quot;&gt;gh-pages&lt;/code&gt; / &lt;code class=&quot;language-text&quot;&gt;/ (root)&lt;/code&gt;로 설정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save&lt;/strong&gt; 클릭&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 설정이 되어 있어야 &lt;code class=&quot;language-text&quot;&gt;gh-pages&lt;/code&gt; 브랜치에 push된 파일이 실제로 웹에 배포됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;배포 상태 확인 및 디버깅&lt;/h2&gt;
&lt;h3&gt;Actions 탭에서 확인&lt;/h3&gt;
&lt;p&gt;push 후 GitHub 레포지토리의 &lt;strong&gt;Actions&lt;/strong&gt; 탭에 들어가면 워크플로우 실행 상태를 확인할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;초록색 체크: 성공&lt;/li&gt;
&lt;li&gt;빨간색 X: 실패&lt;/li&gt;
&lt;li&gt;노란색 원: 진행 중&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;빌드 실패 시 확인할 것&lt;/h3&gt;
&lt;p&gt;실패한 워크플로우를 클릭하면 각 Step의 로그를 볼 수 있습니다. 자주 발생하는 오류와 해결법을 정리했습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;오류&lt;/th&gt;
&lt;th&gt;원인&lt;/th&gt;
&lt;th&gt;해결법&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;npm ci&lt;/code&gt; 실패&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt; 불일치&lt;/td&gt;
&lt;td&gt;로컬에서 &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; 후 lock 파일 커밋&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;gatsby build&lt;/code&gt; 실패&lt;/td&gt;
&lt;td&gt;플러그인 설정 오류&lt;/td&gt;
&lt;td&gt;로컬에서 &lt;code class=&quot;language-text&quot;&gt;gatsby build&lt;/code&gt; 먼저 테스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;권한 오류&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;permissions&lt;/code&gt; 미설정&lt;/td&gt;
&lt;td&gt;workflow에 &lt;code class=&quot;language-text&quot;&gt;permissions: contents: write&lt;/code&gt; 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;gh-pages&lt;/code&gt; 배포 안 됨&lt;/td&gt;
&lt;td&gt;Pages 설정 미완료&lt;/td&gt;
&lt;td&gt;Settings &gt; Pages에서 브랜치 설정 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;로컬에서 빌드 테스트&lt;/h3&gt;
&lt;p&gt;GitHub Actions에 push하기 전에 로컬에서 빌드가 정상인지 확인하는 습관을 들이면 좋습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 캐시 정리 후 빌드 테스트&lt;/span&gt;
gatsby clean &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; gatsby build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;배포 프로세스 전체 흐름 정리&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;로컬에서 글 작성/수정
       |
       v
git add . &amp;amp;&amp;amp; git commit -m &quot;새 글 추가&quot;
       |
       v
git push origin main
       |
       v
GitHub Actions 자동 실행
  1. 코드 체크아웃
  2. Node.js 설정
  3. 캐시 복원
  4. npm ci
  5. gatsby build
  6. gh-pages 브랜치에 배포
       |
       v
GitHub Pages가 gh-pages 브랜치 감지
       |
       v
https://blog.javapark.kr 에 반영 완료&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제 글을 쓰고 push만 하면 됩니다. 나머지는 전부 자동입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q. GitHub Actions는 무료인가요?&lt;/h3&gt;
&lt;p&gt;네, 공개(public) 레포지토리에서는 완전 무료입니다. 비공개(private) 레포지토리에서는 월 2,000분의 무료 빌드 시간이 제공됩니다. 블로그 하나를 운영하기에는 충분한 양입니다.&lt;/p&gt;
&lt;h3&gt;Q. main 브랜치가 아닌 다른 브랜치에서 배포하고 싶어요&lt;/h3&gt;
&lt;p&gt;workflow 파일의 &lt;code class=&quot;language-text&quot;&gt;on.push.branches&lt;/code&gt; 값을 변경하면 됩니다. 예를 들어 &lt;code class=&quot;language-text&quot;&gt;develop&lt;/code&gt; 브랜치에서 배포하려면 다음과 같이 수정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; develop&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Q. 배포 후 사이트에 반영되기까지 얼마나 걸리나요?&lt;/h3&gt;
&lt;p&gt;보통 GitHub Actions 빌드에 1&lt;del&gt;3분, GitHub Pages 반영에 1&lt;/del&gt;2분 정도 걸립니다. 전체적으로 push 후 3~5분이면 사이트에 반영됩니다. 캐시가 따뜻한(warm) 상태라면 더 빨라집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;여러분은 블로그 배포를 어떻게 하고 계신가요? 댓글로 알려주세요.&lt;/p&gt;
&lt;p&gt;다음 포스팅에서는 &lt;strong&gt;블로그에 광고와 댓글 시스템을 다는 방법&lt;/strong&gt;을 다룹니다. AdSense, 쿠팡 파트너스로 수익화하고, Utterances로 댓글 기능을 구축하는 방법까지 알아보겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Gatsby로 GitHub 블로그 시작하기 — 설치부터 첫 배포까지]]></title><description><![CDATA[안녕하세요, 자바파커입니다. 개발자라면 한 번쯤 나만의 기술 블로그를 운영해보고 싶다는 생각을 해보셨을 겁니다. 네이버 블로그, 티스토리, 벨로그 등 다양한 플랫폼이 있지만, 저는 GitHub Pages + Gatsby…]]></description><link>http://blog.javapark.kr/01-getting-started/</link><guid isPermaLink="false">http://blog.javapark.kr/01-getting-started/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;개발자라면 한 번쯤 나만의 기술 블로그를 운영해보고 싶다는 생각을 해보셨을 겁니다. 네이버 블로그, 티스토리, 벨로그 등 다양한 플랫폼이 있지만, 저는 &lt;strong&gt;GitHub Pages + Gatsby&lt;/strong&gt; 조합을 강력히 추천합니다.&lt;/p&gt;
&lt;p&gt;이 포스팅에서는 Gatsby와 gatsby-starter-hoodie 테마를 활용해 GitHub 블로그를 처음부터 배포까지 완성하는 전 과정을 다룹니다.&lt;/p&gt;
&lt;h2&gt;왜 GitHub Pages 블로그인가?&lt;/h2&gt;
&lt;p&gt;GitHub Pages 블로그를 선택해야 하는 이유는 명확합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;비용 0원&lt;/strong&gt;: 호스팅 비용이 전혀 들지 않습니다. GitHub에서 무료로 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;개발자 친화적&lt;/strong&gt;: Git으로 버전 관리를 하고, 마크다운으로 글을 씁니다. 개발자에게 이보다 자연스러운 워크플로우는 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;마크다운 기반&lt;/strong&gt;: 코드 블록, 수식, 표 등을 편리하게 작성할 수 있습니다. 기술 블로그에 최적화된 형식입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;커스터마이징 자유&lt;/strong&gt;: HTML, CSS, JavaScript를 완전히 제어할 수 있습니다. 원하는 기능을 직접 추가하고, 디자인을 자유롭게 변경할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;커스텀 도메인 지원&lt;/strong&gt;: 무료 HTTPS와 함께 나만의 도메인을 연결할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO 유리&lt;/strong&gt;: 정적 사이트 생성(SSG) 방식이라 검색엔진 최적화에 유리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;다른 플랫폼과 비교&lt;/h2&gt;
&lt;p&gt;블로그 플랫폼을 선택할 때 가장 많이 고민하는 옵션들을 비교해 보겠습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;GitHub Pages&lt;/th&gt;
&lt;th&gt;티스토리&lt;/th&gt;
&lt;th&gt;벨로그&lt;/th&gt;
&lt;th&gt;Medium&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;비용&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;일부 유료&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;커스터마이징&lt;/td&gt;
&lt;td&gt;완전 자유&lt;/td&gt;
&lt;td&gt;스킨 수준&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;td&gt;거의 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;마크다운&lt;/td&gt;
&lt;td&gt;네이티브 지원&lt;/td&gt;
&lt;td&gt;부분 지원&lt;/td&gt;
&lt;td&gt;네이티브 지원&lt;/td&gt;
&lt;td&gt;부분 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;코드 블록&lt;/td&gt;
&lt;td&gt;커스텀 가능&lt;/td&gt;
&lt;td&gt;기본&lt;/td&gt;
&lt;td&gt;기본&lt;/td&gt;
&lt;td&gt;기본&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEO 제어&lt;/td&gt;
&lt;td&gt;완전 제어&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;td&gt;제한적&lt;/td&gt;
&lt;td&gt;불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;광고 수익&lt;/td&gt;
&lt;td&gt;직접 설정&lt;/td&gt;
&lt;td&gt;카카오 애드핏&lt;/td&gt;
&lt;td&gt;불가&lt;/td&gt;
&lt;td&gt;Partner Program&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;초기 설정 난이도&lt;/td&gt;
&lt;td&gt;높음&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;매우 낮음&lt;/td&gt;
&lt;td&gt;매우 낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;초기 설정이 다소 복잡하다는 단점이 있지만, 이 시리즈를 따라오시면 어렵지 않게 완성할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;사전 준비&lt;/h2&gt;
&lt;p&gt;Gatsby 블로그를 시작하기 전에 다음 도구들이 필요합니다.&lt;/p&gt;
&lt;h3&gt;Node.js 설치&lt;/h3&gt;
&lt;p&gt;Gatsby는 Node.js 기반 프레임워크입니다. &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js 공식 사이트&lt;/a&gt;에서 &lt;strong&gt;LTS 버전&lt;/strong&gt;을 설치합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 설치 확인&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# v20.x.x 이상 권장&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 10.x.x 이상&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;팁&lt;/strong&gt;: nvm(Node Version Manager)을 사용하면 Node.js 버전을 쉽게 관리할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Git 설치&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://git-scm.com/&quot;&gt;Git 공식 사이트&lt;/a&gt;에서 설치하거나, 아래 명령어로 확인합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# git version 2.x.x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;GitHub 계정 생성&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;에 계정이 없다면 가입합니다. GitHub Pages를 사용하려면 GitHub 계정이 필수입니다.&lt;/p&gt;
&lt;h2&gt;Gatsby 설치 및 프로젝트 생성&lt;/h2&gt;
&lt;h3&gt;Gatsby CLI 설치&lt;/h3&gt;
&lt;p&gt;먼저 Gatsby CLI를 전역으로 설치합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; gatsby-cli&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;gatsby-starter-hoodie로 프로젝트 생성&lt;/h3&gt;
&lt;p&gt;gatsby-starter-hoodie는 깔끔한 디자인과 다크모드, 시리즈 기능 등을 기본 제공하는 테마입니다. 이 블로그(AI JAVAPARK)에서도 사용하고 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 프로젝트 생성&lt;/span&gt;
npx gatsby new my-blog https://github.com/devHudi/gatsby-starter-hoodie

&lt;span class=&quot;token comment&quot;&gt;# 프로젝트 폴더로 이동&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; my-blog&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;프로젝트 생성이 완료되면 다음과 같은 폴더 구조가 생성됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;my-blog/
├── contents/
│   └── posts/          # 블로그 글 저장 폴더
├── src/
│   ├── assets/         # 테마, 이미지 등 정적 자원
│   ├── components/     # React 컴포넌트
│   ├── pages/          # 페이지 컴포넌트
│   └── templates/      # 템플릿 컴포넌트
├── static/             # 정적 파일 (favicon 등)
├── blog-config.js      # 블로그 설정 파일
├── gatsby-config.js    # Gatsby 설정 파일
├── gatsby-node.js      # Gatsby Node API
└── package.json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;blog-config.js 설정&lt;/h2&gt;
&lt;p&gt;프로젝트 루트에 있는 &lt;code class=&quot;language-text&quot;&gt;blog-config.js&lt;/code&gt; 파일을 열어 블로그 기본 정보를 설정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AI JAVAPARK&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;개발과 AI를 다루는 기술 블로그&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;자바파커&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;siteUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://blog.javapark.kr&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://github.com/javapark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 사용하지 않는 링크는 빈 문자열로 두면 됩니다&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;linkedIn&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;facebook&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;instagram&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mailto:your-email@example.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;utterances&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;javapark/blog-comments&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pathname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;각 항목을 설명하면 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;title&lt;/strong&gt;: 블로그 제목입니다. 브라우저 탭과 헤더에 표시됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;description&lt;/strong&gt;: 블로그 설명입니다. SEO 메타 태그에 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;author&lt;/strong&gt;: 작성자 이름입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;siteUrl&lt;/strong&gt;: 배포될 블로그 URL입니다. GitHub Pages 기본 URL(&lt;code class=&quot;language-text&quot;&gt;https://username.github.io&lt;/code&gt;) 또는 커스텀 도메인을 입력합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;links&lt;/strong&gt;: SNS 링크입니다. 프로필 영역에 아이콘으로 표시됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;utterances&lt;/strong&gt;: GitHub Issues 기반 댓글 시스템 설정입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;로컬 개발 서버 실행&lt;/h2&gt;
&lt;p&gt;설정을 마쳤다면 로컬에서 블로그를 확인해 봅시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 개발 서버 실행&lt;/span&gt;
gatsby develop&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;브라우저에서 &lt;code class=&quot;language-text&quot;&gt;http://localhost:8000&lt;/code&gt;으로 접속하면 블로그를 확인할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 만약 포트 충돌이 발생한다면 포트를 변경할 수 있습니다&lt;/span&gt;
gatsby develop &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;개발 서버는 &lt;strong&gt;핫 리로딩&lt;/strong&gt;을 지원하므로, 파일을 수정하면 브라우저가 자동으로 새로고침됩니다. 글을 쓰면서 실시간으로 결과를 확인할 수 있어 매우 편리합니다.&lt;/p&gt;
&lt;h3&gt;빌드 테스트&lt;/h3&gt;
&lt;p&gt;배포 전에 프로덕션 빌드가 정상적으로 되는지 확인하는 것이 좋습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 프로덕션 빌드&lt;/span&gt;
gatsby build

&lt;span class=&quot;token comment&quot;&gt;# 빌드 결과 로컬에서 확인&lt;/span&gt;
gatsby serve&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;gatsby serve&lt;/code&gt;를 실행하면 &lt;code class=&quot;language-text&quot;&gt;http://localhost:9000&lt;/code&gt;에서 빌드된 결과물을 확인할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;GitHub Pages 배포&lt;/h2&gt;
&lt;p&gt;이제 가장 중요한 단계인 배포를 진행합니다.&lt;/p&gt;
&lt;h3&gt;GitHub 리포지토리 생성&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;GitHub에서 &lt;strong&gt;New repository&lt;/strong&gt;를 클릭합니다.&lt;/li&gt;
&lt;li&gt;Repository name을 &lt;code class=&quot;language-text&quot;&gt;username.github.io&lt;/code&gt; 형식으로 입력합니다. (예: &lt;code class=&quot;language-text&quot;&gt;javapark.github.io&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Public&lt;/strong&gt;으로 설정합니다. (GitHub Pages 무료 플랜은 Public 리포지토리에서만 동작합니다.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create repository&lt;/strong&gt;를 클릭합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;원격 리포지토리 연결&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 기존 원격 저장소 제거 (starter 원본이 연결되어 있을 수 있습니다)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote remove origin

&lt;span class=&quot;token comment&quot;&gt;# 새 리포지토리 연결&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; remote &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; origin https://github.com/username/username.github.io.git

&lt;span class=&quot;token comment&quot;&gt;# 기본 브랜치를 main으로 설정&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; branch &lt;span class=&quot;token parameter variable&quot;&gt;-M&lt;/span&gt; main

&lt;span class=&quot;token comment&quot;&gt;# 첫 커밋 및 푸시&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Initial commit&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push &lt;span class=&quot;token parameter variable&quot;&gt;-u&lt;/span&gt; origin main&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;gh-pages 패키지로 배포&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;gh-pages&lt;/code&gt; 패키지를 사용하면 빌드 결과물만 별도 브랜치에 배포할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# gh-pages 패키지 설치&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gh-pages --save-dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;에 배포 스크립트를 추가합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;deploy&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;gatsby build &amp;amp;&amp;amp; gh-pages -d public -b gh-pages&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;배포를 실행합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;GitHub Pages 설정&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;GitHub 리포지토리 &gt; &lt;strong&gt;Settings&lt;/strong&gt; &gt; &lt;strong&gt;Pages&lt;/strong&gt;로 이동합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source&lt;/strong&gt;를 &lt;code class=&quot;language-text&quot;&gt;Deploy from a branch&lt;/code&gt;로 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Branch&lt;/strong&gt;를 &lt;code class=&quot;language-text&quot;&gt;gh-pages&lt;/code&gt;로 선택하고 폴더는 &lt;code class=&quot;language-text&quot;&gt;/ (root)&lt;/code&gt;로 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save&lt;/strong&gt;를 클릭합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;몇 분 뒤 &lt;code class=&quot;language-text&quot;&gt;https://username.github.io&lt;/code&gt;에 블로그가 배포됩니다.&lt;/p&gt;
&lt;h3&gt;배포 확인&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 배포 상태 확인 (GitHub CLI가 설치되어 있다면)&lt;/span&gt;
gh api repos/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;owner&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;repo&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;/pages &lt;span class=&quot;token parameter variable&quot;&gt;--jq&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.status&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;브라우저에서 &lt;code class=&quot;language-text&quot;&gt;https://username.github.io&lt;/code&gt;에 접속하여 블로그가 정상적으로 표시되는지 확인합니다.&lt;/p&gt;
&lt;h2&gt;첫 글 작성해보기&lt;/h2&gt;
&lt;p&gt;배포가 완료되었으니 첫 글을 작성해 봅시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 글 폴더 생성&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; contents/posts/my-first-post&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;contents/posts/my-first-post/index.md&lt;/code&gt; 파일을 만들고 다음과 같이 작성합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;나의 첫 블로그 포스팅&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GitHub 블로그에 첫 글을 작성했습니다.&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 블로그
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 시작&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 안녕하세요!&lt;/span&gt;

이것은 나의 첫 블로그 포스팅입니다.

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; 코드 블록도 됩니다&lt;/span&gt;

\```javascript
console.log(&quot;Hello, Blog!&quot;);
\```&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;글을 작성한 뒤 다시 배포합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. GitHub Pages는 정말 무료인가요?&lt;/h3&gt;
&lt;p&gt;네, 완전히 무료입니다. Public 리포지토리에서는 GitHub Pages를 무료로 사용할 수 있으며, 월 트래픽 제한은 약 100GB입니다. 일반적인 개인 블로그에서는 이 제한에 도달할 일이 거의 없습니다.&lt;/p&gt;
&lt;h3&gt;Q2. gatsby-starter-hoodie 대신 다른 테마를 써도 되나요?&lt;/h3&gt;
&lt;p&gt;물론입니다. &lt;a href=&quot;https://www.gatsbyjs.com/starters/&quot;&gt;Gatsby Starter Library&lt;/a&gt;에서 다양한 테마를 확인할 수 있습니다. 다만 이 시리즈에서는 gatsby-starter-hoodie를 기준으로 설명하므로, 다른 테마를 선택하면 설정 방법이 다를 수 있습니다.&lt;/p&gt;
&lt;h3&gt;Q3. 커스텀 도메인은 어떻게 연결하나요?&lt;/h3&gt;
&lt;p&gt;GitHub 리포지토리 Settings &gt; Pages에서 &lt;strong&gt;Custom domain&lt;/strong&gt; 항목에 원하는 도메인을 입력합니다. 그 전에 도메인 DNS 설정에서 CNAME 레코드를 &lt;code class=&quot;language-text&quot;&gt;username.github.io&lt;/code&gt;로 지정해야 합니다. 이 부분은 시리즈 후반부에서 자세히 다룰 예정입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;다음 포스팅에서는 &lt;strong&gt;Gatsby 블로그 스킨 커스터마이징&lt;/strong&gt; 방법을 다룹니다. 콘텐츠 폭, 폰트, 색상, 다크모드까지 나만의 블로그 디자인을 만들어 보겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[마크다운 글쓰기와 카테고리 관리 — 체계적인 블로그 운영법]]></title><description><![CDATA[안녕하세요, 자바파커입니다. 지금까지 Gatsby 블로그를 설치하고, 스킨을 커스터마이징하는 방법을 다뤘습니다. 이번 포스팅에서는 실제 글을 작성하고 콘텐츠를 체계적으로 관리하는 방법을 알아보겠습니다. 마크다운 문법부터 frontmatter…]]></description><link>http://blog.javapark.kr/03-markdown-and-categories/</link><guid isPermaLink="false">http://blog.javapark.kr/03-markdown-and-categories/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;지금까지 Gatsby 블로그를 설치하고, 스킨을 커스터마이징하는 방법을 다뤘습니다. 이번 포스팅에서는 실제 글을 작성하고 콘텐츠를 체계적으로 관리하는 방법을 알아보겠습니다. 마크다운 문법부터 frontmatter, 태그 전략, 시리즈 기능, 이미지 관리까지 블로그 운영에 필요한 모든 것을 다룹니다.&lt;/p&gt;
&lt;h2&gt;마크다운 기본 문법&lt;/h2&gt;
&lt;p&gt;마크다운은 텍스트 기반의 경량 마크업 언어입니다. 기술 블로그에서 가장 많이 사용되는 문법들을 정리합니다.&lt;/p&gt;
&lt;h3&gt;제목 (Heading)&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;#&lt;/code&gt; 기호의 개수로 제목 수준을 구분합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;#&lt;/span&gt; h1 — 포스트 제목 (frontmatter title과 중복되므로 본문에서는 사용하지 않습니다)&lt;/span&gt;
&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; h2 — 주요 섹션&lt;/span&gt;
&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; h3 — 하위 섹션&lt;/span&gt;
&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;####&lt;/span&gt; h4 — 세부 항목&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;팁&lt;/strong&gt;: 본문에서는 &lt;code class=&quot;language-text&quot;&gt;##&lt;/code&gt;(h2)부터 시작하는 것이 SEO와 문서 구조에 좋습니다. h1은 포스트 제목이 자동으로 사용합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;텍스트 서식&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;굵게&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt; 또는 &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;__&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;굵게&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;__&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token italic&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;기울임&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;*&lt;/span&gt;&lt;/span&gt; 또는 &lt;span class=&quot;token italic&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;기울임&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;_&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token strike&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;~~&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;취소선&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;~~&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token code-snippet code keyword&quot;&gt;`인라인 코드`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;결과:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;굵게&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;기울임&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;취소선&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;인라인 코드&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;목록&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;순서 없는 목록:
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 항목 1
&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 항목 2
  &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 중첩 항목 2-1
  &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; 중첩 항목 2-2

순서 있는 목록:
&lt;span class=&quot;token list punctuation&quot;&gt;1.&lt;/span&gt; 첫 번째
&lt;span class=&quot;token list punctuation&quot;&gt;2.&lt;/span&gt; 두 번째
&lt;span class=&quot;token list punctuation&quot;&gt;3.&lt;/span&gt; 세 번째&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;코드 블록&lt;/h3&gt;
&lt;p&gt;기술 블로그의 핵심 요소입니다. 백틱 세 개(&lt;code class=&quot;language-text&quot;&gt;```&lt;/code&gt;)로 감싸고 언어를 지정합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;javascript&lt;/span&gt;
&lt;span class=&quot;token code-block language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; greeting &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;안녕하세요!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;greeting&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;python&lt;/span&gt;
&lt;span class=&quot;token code-block language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;안녕하세요!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token code&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;span class=&quot;token code-language&quot;&gt;bash&lt;/span&gt;
&lt;span class=&quot;token code-block language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gatsby-cli &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;지원되는 주요 언어 키워드: &lt;code class=&quot;language-text&quot;&gt;javascript&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;typescript&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;python&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;java&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;bash&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;css&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;html&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;json&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;yaml&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;sql&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;go&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;rust&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;kotlin&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;swift&lt;/code&gt; 등&lt;/p&gt;
&lt;h3&gt;표 (Table)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token table&quot;&gt;&lt;span class=&quot;token table-header-row&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; 기능 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; 설명 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; 필수 여부 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token table-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;------&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;------&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;----------&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token table-data-rows&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; title &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 포스트 제목 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 필수 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; description &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 짧은 설명 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 권장 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; date &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 작성일 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 필수 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; tags &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 태그 목록 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; 권장 &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;결과:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;필수 여부&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;title&lt;/td&gt;
&lt;td&gt;포스트 제목&lt;/td&gt;
&lt;td&gt;필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;description&lt;/td&gt;
&lt;td&gt;짧은 설명&lt;/td&gt;
&lt;td&gt;권장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;date&lt;/td&gt;
&lt;td&gt;작성일&lt;/td&gt;
&lt;td&gt;필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tags&lt;/td&gt;
&lt;td&gt;태그 목록&lt;/td&gt;
&lt;td&gt;권장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;인용 (Blockquote)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; 이것은 인용문입니다.
&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; 여러 줄로 작성할 수 있습니다.

&lt;span class=&quot;token blockquote punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;참고&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;: 강조 표시와 함께 사용하면 주의사항이나 팁을 효과적으로 전달할 수 있습니다.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;참고&lt;/strong&gt;: 강조 표시와 함께 사용하면 주의사항이나 팁을 효과적으로 전달할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;링크와 이미지&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;링크 텍스트&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;https://example.com&lt;/span&gt;)&lt;/span&gt;
&lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;새 탭에서 열기&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;https://example.com&lt;/span&gt;)&lt;/span&gt;{:target=&quot;_blank&quot;}

&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;이미지 대체 텍스트&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;./images/example.png&lt;/span&gt;)&lt;/span&gt;
&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;외부 이미지&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;https://example.com/image.png&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;구분선&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token hr punctuation&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;세 개 이상의 하이픈(&lt;code class=&quot;language-text&quot;&gt;-&lt;/code&gt;), 별표(&lt;code class=&quot;language-text&quot;&gt;*&lt;/code&gt;), 밑줄(&lt;code class=&quot;language-text&quot;&gt;_&lt;/code&gt;)로 구분선을 만들 수 있습니다.&lt;/p&gt;
&lt;h2&gt;Frontmatter 구조&lt;/h2&gt;
&lt;p&gt;Frontmatter는 마크다운 파일 상단에 YAML 형식으로 작성하는 메타데이터입니다. gatsby-starter-hoodie에서 지원하는 필드를 자세히 알아봅시다.&lt;/p&gt;
&lt;h3&gt;기본 구조&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;포스트 제목&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;포스트에 대한 짧은 설명 (SEO 메타 설명에 사용됩니다)&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; gatsby
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; blog
&lt;span class=&quot;token key atrule&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;시리즈 이름&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;각 필드 상세 설명&lt;/h3&gt;
&lt;h4&gt;title (필수)&lt;/h4&gt;
&lt;p&gt;포스트의 제목입니다. HTML &lt;code class=&quot;language-text&quot;&gt;&amp;lt;title&gt;&lt;/code&gt; 태그와 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;h1&gt;&lt;/code&gt; 태그에 사용됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Gatsby로 GitHub 블로그 시작하기 — 설치부터 첫 배포까지&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;큰따옴표로 감싸는 것이 안전합니다. 특히 콜론(&lt;code class=&quot;language-text&quot;&gt;:&lt;/code&gt;)이 포함된 경우 반드시 따옴표가 필요합니다.&lt;/li&gt;
&lt;li&gt;SEO를 위해 핵심 키워드를 앞쪽에 배치합니다.&lt;/li&gt;
&lt;li&gt;50~60자 이내가 검색 결과에서 잘리지 않아 적절합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;description (권장)&lt;/h4&gt;
&lt;p&gt;포스트에 대한 짧은 설명으로, 검색엔진 결과와 블로그 목록에 표시됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Gatsby 설치부터 gatsby-starter-hoodie 테마 적용, GitHub Pages 배포까지 완전 가이드&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;120~160자 이내가 적절합니다.&lt;/li&gt;
&lt;li&gt;핵심 키워드를 자연스럽게 포함합니다.&lt;/li&gt;
&lt;li&gt;클릭을 유도하는 명확한 문장을 작성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;date / update&lt;/h4&gt;
&lt;p&gt;작성일과 수정일입니다. &lt;code class=&quot;language-text&quot;&gt;YYYY-MM-DD&lt;/code&gt; 형식으로 작성합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;date&lt;/code&gt;: 포스트 최초 작성일입니다. 목록 정렬에 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;update&lt;/code&gt;: 포스트 수정일입니다. 포스트를 업데이트했을 때 갱신합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;tags&lt;/h4&gt;
&lt;p&gt;포스트에 붙이는 태그 목록입니다. 배열 형식으로 작성합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; gatsby
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; github&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pages
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; blog&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;series&lt;/h4&gt;
&lt;p&gt;여러 포스트를 하나의 시리즈로 묶을 때 사용합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GitHub 블로그 A to Z&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;같은 &lt;code class=&quot;language-text&quot;&gt;series&lt;/code&gt; 값을 가진 포스트들이 자동으로 그룹핑되어 포스트 하단에 시리즈 네비게이션이 표시됩니다.&lt;/p&gt;
&lt;h2&gt;폴더 구조 설계&lt;/h2&gt;
&lt;p&gt;블로그가 커지면 폴더 구조가 매우 중요해집니다. 처음부터 체계적으로 설계하면 나중에 관리가 편합니다.&lt;/p&gt;
&lt;h3&gt;추천 폴더 구조&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;contents/
└── posts/
    ├── gatsby-blog/                     # 카테고리: Gatsby 블로그
    │   ├── 01-getting-started/
    │   │   ├── index.md
    │   │   └── images/
    │   │       ├── setup-screen.png
    │   │       └── deploy-result.png
    │   ├── 02-customizing-skin/
    │   │   └── index.md
    │   └── 03-markdown-and-categories/
    │       └── index.md
    ├── javascript/                      # 카테고리: JavaScript
    │   ├── closure-explained/
    │   │   └── index.md
    │   └── async-await-guide/
    │       └── index.md
    ├── devops/                          # 카테고리: DevOps
    │   ├── docker-basics/
    │   │   └── index.md
    │   └── github-actions-ci/
    │       └── index.md
    └── til/                             # 카테고리: Today I Learned
        ├── 2026-03-28-css-grid/
        │   └── index.md
        └── 2026-04-01-git-rebase/
            └── index.md&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;네이밍 규칙&lt;/h3&gt;
&lt;p&gt;폴더와 파일 이름에 일관된 규칙을 적용합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;카테고리 폴더&lt;/strong&gt;: 소문자 영문, 하이픈(&lt;code class=&quot;language-text&quot;&gt;-&lt;/code&gt;) 구분 (예: &lt;code class=&quot;language-text&quot;&gt;gatsby-blog&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;javascript&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;포스트 폴더&lt;/strong&gt;: 시리즈의 경우 번호 접두사 사용 (예: &lt;code class=&quot;language-text&quot;&gt;01-getting-started&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단독 포스트&lt;/strong&gt;: 핵심 키워드로 구성 (예: &lt;code class=&quot;language-text&quot;&gt;closure-explained&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TIL&lt;/strong&gt;: 날짜 접두사 사용 (예: &lt;code class=&quot;language-text&quot;&gt;2026-03-28-css-grid&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이미지 폴더&lt;/strong&gt;: 포스트 폴더 내 &lt;code class=&quot;language-text&quot;&gt;images/&lt;/code&gt; 하위에 관리&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;왜 index.md를 사용하는가?&lt;/h3&gt;
&lt;p&gt;포스트마다 폴더를 만들고 &lt;code class=&quot;language-text&quot;&gt;index.md&lt;/code&gt;를 사용하는 이유가 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# 이렇게 하면
posts/my-post.md          # 이미지를 어디에 둘지 애매합니다

# 이렇게 하면
posts/my-post/index.md    # 관련 이미지를 같은 폴더에 둘 수 있습니다
posts/my-post/images/screenshot.png&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이미지를 같은 폴더에 두면 상대 경로(&lt;code class=&quot;language-text&quot;&gt;./images/screenshot.png&lt;/code&gt;)로 참조할 수 있어 관리가 훨씬 편합니다.&lt;/p&gt;
&lt;h2&gt;태그 전략&lt;/h2&gt;
&lt;p&gt;태그를 잘 설계하면 독자가 관련 글을 쉽게 찾을 수 있고, SEO에도 도움이 됩니다.&lt;/p&gt;
&lt;h3&gt;태그 작성 규칙&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;소문자 통일&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;JavaScript&lt;/code&gt; 대신 &lt;code class=&quot;language-text&quot;&gt;javascript&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;React&lt;/code&gt; 대신 &lt;code class=&quot;language-text&quot;&gt;react&lt;/code&gt;를 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;하이픈 구분&lt;/strong&gt;: 두 단어 이상인 경우 하이픈으로 연결합니다. (예: &lt;code class=&quot;language-text&quot;&gt;github-pages&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;styled-components&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;복수형 지양&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;algorithms&lt;/code&gt; 대신 &lt;code class=&quot;language-text&quot;&gt;algorithm&lt;/code&gt;처럼 단수형을 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;의미 있는 태그&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;기타&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;잡담&lt;/code&gt; 같은 모호한 태그는 피합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;적정 개수&lt;/strong&gt;: 포스트당 3~5개가 적절합니다. 너무 많으면 태그의 의미가 희석됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;태그 분류 체계&lt;/h3&gt;
&lt;p&gt;태그를 기술/도구/개념/시리즈로 분류하면 체계적으로 관리할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 기술/언어 태그&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;javascript&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; typescript&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; python&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; java&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; go&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 프레임워크/도구 태그&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;gatsby&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; react&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next.js&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; docker&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; github&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;actions&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 개념 태그&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;algorithm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;structure&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; design&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pattern&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; clean&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 유형 태그&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tutorial&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; review&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; til&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;태그 관리 스프레드시트&lt;/h3&gt;
&lt;p&gt;블로그가 커지면 태그 목록을 별도로 관리하는 것이 좋습니다. 간단한 표를 만들어 사용 중인 태그와 포스트 수를 추적합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;태그&lt;/th&gt;
&lt;th&gt;포스트 수&lt;/th&gt;
&lt;th&gt;비고&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gatsby&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;블로그 시리즈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;javascript&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;주력 언어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;react&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;프론트엔드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;til&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;Today I Learned&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;시리즈 기능 활용&lt;/h2&gt;
&lt;p&gt;gatsby-starter-hoodie의 시리즈 기능은 연관된 포스트를 그룹으로 묶어주는 강력한 기능입니다.&lt;/p&gt;
&lt;h3&gt;시리즈 설정 방법&lt;/h3&gt;
&lt;p&gt;frontmatter에 같은 &lt;code class=&quot;language-text&quot;&gt;series&lt;/code&gt; 값을 지정하면 자동으로 시리즈가 생성됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 포스트 1&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Gatsby 블로그 시작하기&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GitHub 블로그 A to Z&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-01&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 포스트 2&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;블로그 스킨 커스터마이징&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GitHub 블로그 A to Z&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 포스트 3&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;마크다운 글쓰기와 카테고리 관리&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GitHub 블로그 A to Z&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-07&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이렇게 설정하면 각 포스트 하단에 시리즈 목록이 자동으로 표시되어, 독자가 이전/다음 포스트로 쉽게 이동할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;시리즈 네이밍 팁&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;시리즈 이름은 &lt;strong&gt;한국어&lt;/strong&gt;로 작성해도 됩니다. 태그와 달리 시리즈 이름은 URL에 직접 사용되지 않습니다.&lt;/li&gt;
&lt;li&gt;명확하고 구체적인 이름을 사용합니다. (예: &quot;GitHub 블로그 A to Z&quot;, &quot;React 핵심 개념 정리&quot;)&lt;/li&gt;
&lt;li&gt;시리즈 내 포스트 순서는 &lt;code class=&quot;language-text&quot;&gt;date&lt;/code&gt; 값으로 결정됩니다. 날짜를 순차적으로 설정하면 원하는 순서대로 표시됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;시리즈 활용 사례&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;시리즈 1: &quot;GitHub 블로그 A to Z&quot;
├── 01. Gatsby로 GitHub 블로그 시작하기
├── 02. 블로그 스킨 커스터마이징
├── 03. 마크다운 글쓰기와 카테고리 관리
├── 04. SEO 최적화
├── 05. GitHub Actions 자동 배포
└── 06. 광고 및 댓글 시스템

시리즈 2: &quot;JavaScript 핵심 개념&quot;
├── 01. 실행 컨텍스트와 호이스팅
├── 02. 클로저 완벽 이해
├── 03. 프로토타입과 상속
└── 04. 비동기 프로그래밍&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;이미지 관리&lt;/h2&gt;
&lt;p&gt;기술 블로그에서 이미지는 스크린샷, 다이어그램, 아키텍처 도표 등으로 자주 사용됩니다. 효율적인 이미지 관리 방법을 알아봅시다.&lt;/p&gt;
&lt;h3&gt;로컬 이미지&lt;/h3&gt;
&lt;p&gt;가장 간단한 방법은 포스트 폴더 내에 이미지를 함께 보관하는 것입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;posts/my-post/
├── index.md
└── images/
    ├── screenshot-01.png
    └── architecture-diagram.png&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;마크다운에서 상대 경로로 참조합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;스크린샷&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;./images/screenshot-01.png&lt;/span&gt;)&lt;/span&gt;
&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;아키텍처 다이어그램&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;./images/architecture-diagram.png&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;장점&lt;/strong&gt;: 포스트와 이미지가 함께 관리되어 직관적입니다.
&lt;strong&gt;단점&lt;/strong&gt;: 리포지토리 용량이 커질 수 있습니다. GitHub 리포지토리의 권장 용량은 1GB 이하입니다.&lt;/p&gt;
&lt;h3&gt;GitHub Release 활용&lt;/h3&gt;
&lt;p&gt;리포지토리 용량을 아끼면서 이미지를 관리하는 방법입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GitHub 리포지토리 &gt; &lt;strong&gt;Releases&lt;/strong&gt; &gt; &lt;strong&gt;Draft a new release&lt;/strong&gt;로 이동합니다.&lt;/li&gt;
&lt;li&gt;이미지 파일을 드래그 앤 드롭으로 업로드합니다.&lt;/li&gt;
&lt;li&gt;생성된 URL을 마크다운에서 사용합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;스크린샷&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;https://github.com/username/repo/releases/download/v1.0/screenshot.png&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;팁&lt;/strong&gt;: GitHub Issues에 이미지를 드래그 앤 드롭하면 자동으로 &lt;code class=&quot;language-text&quot;&gt;user-images.githubusercontent.com&lt;/code&gt; URL이 생성됩니다. 이 URL을 복사해서 사용할 수도 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;외부 CDN 활용&lt;/h3&gt;
&lt;p&gt;이미지가 많은 블로그라면 별도의 CDN 서비스를 사용하는 것이 효율적입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare Images&lt;/strong&gt;: 합리적인 가격, 이미지 리사이징 지원&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;imgbb&lt;/strong&gt;: 무료 이미지 호스팅&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub 자체 CDN&lt;/strong&gt;: Issues/PR에 이미지를 업로드하면 생성되는 URL 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;이미지 최적화&lt;/h3&gt;
&lt;p&gt;이미지 크기가 크면 페이지 로딩 속도에 영향을 줍니다. 다음 사항을 지키면 좋습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;포맷&lt;/strong&gt;: 스크린샷은 PNG, 사진은 WebP 또는 JPEG를 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;크기&lt;/strong&gt;: 콘텐츠 폭의 2배(Retina 대응) 정도가 적절합니다. 본문 폭이 760px이면 이미지 폭은 1520px 이하로 유지합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;압축&lt;/strong&gt;: &lt;a href=&quot;https://squoosh.app/&quot;&gt;Squoosh&lt;/a&gt;나 &lt;a href=&quot;https://tinypng.com/&quot;&gt;TinyPNG&lt;/a&gt;로 압축합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;alt 텍스트&lt;/strong&gt;: 접근성과 SEO를 위해 항상 의미 있는 대체 텍스트를 작성합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- 좋은 예 --&gt;&lt;/span&gt;
&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;Gatsby 프로젝트 폴더 구조&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;./images/folder-structure.png&lt;/span&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- 나쁜 예 --&gt;&lt;/span&gt;
![](./images/image1.png)
&lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;[&lt;span class=&quot;token content&quot;&gt;사진&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;./images/photo.png&lt;/span&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;글쓰기 워크플로우&lt;/h2&gt;
&lt;p&gt;마지막으로, 실제 글쓰기 워크플로우를 정리합니다.&lt;/p&gt;
&lt;h3&gt;새 포스트 작성 과정&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 1. 포스트 폴더 생성&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; contents/posts/category-name/post-title

&lt;span class=&quot;token comment&quot;&gt;# 2. index.md 파일 생성&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; contents/posts/category-name/post-title/index.md

&lt;span class=&quot;token comment&quot;&gt;# 3. frontmatter 작성&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 4. 본문 작성&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 5. 개발 서버에서 확인&lt;/span&gt;
gatsby develop

&lt;span class=&quot;token comment&quot;&gt;# 6. 문제가 없으면 커밋 및 배포&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;feat: add new post - 포스트 제목&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;포스트 템플릿&lt;/h3&gt;
&lt;p&gt;매번 frontmatter를 처음부터 작성하는 것은 번거롭습니다. 아래 템플릿을 복사해서 사용하세요.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;

안녕하세요, &lt;span class=&quot;token bold&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;token content&quot;&gt;자바파커&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;**&lt;/span&gt;&lt;/span&gt;입니다.

(도입부: 이 글에서 다루는 내용과 독자가 얻을 수 있는 것)

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 섹션 1&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; 하위 섹션&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 섹션 2&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt; 자주 묻는 질문 (FAQ)&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; Q1.&lt;/span&gt;

&lt;span class=&quot;token title important&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;###&lt;/span&gt; Q2.&lt;/span&gt;

&lt;span class=&quot;token hr punctuation&quot;&gt;---&lt;/span&gt;

다음 포스팅에서는 ~ 다룹니다.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. 마크다운 에디터는 무엇을 추천하나요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;VS Code&lt;/strong&gt;를 가장 추천합니다. 마크다운 프리뷰(&lt;code class=&quot;language-text&quot;&gt;Ctrl+Shift+V&lt;/code&gt;), 마크다운 린트, 이미지 붙여넣기 등 블로그 글쓰기에 필요한 확장 기능이 풍부합니다. 추천 확장 프로그램은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Markdown All in One&lt;/strong&gt;: 단축키, 목차 생성, 서식 지원&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Markdown Preview Enhanced&lt;/strong&gt;: 향상된 미리보기&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paste Image&lt;/strong&gt;: 클립보드 이미지를 바로 붙여넣기&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;markdownlint&lt;/strong&gt;: 마크다운 문법 검사&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Q2. 태그와 시리즈, 카테고리의 차이점은 무엇인가요?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;태그(tag)&lt;/strong&gt;: 포스트의 주제나 기술을 나타내는 키워드입니다. 하나의 포스트에 여러 태그를 붙일 수 있습니다. (예: &lt;code class=&quot;language-text&quot;&gt;javascript&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;react&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;tutorial&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;시리즈(series)&lt;/strong&gt;: 순서대로 읽어야 하는 연속 포스트를 그룹핑합니다. 하나의 포스트는 하나의 시리즈에만 속할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;카테고리&lt;/strong&gt;: gatsby-starter-hoodie에서는 폴더 구조로 카테고리를 대체합니다. 별도의 카테고리 frontmatter 필드는 없으며, 폴더 경로가 곧 카테고리 역할을 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Q3. 이전에 작성한 글을 수정하면 date도 바꿔야 하나요?&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;date&lt;/code&gt;는 최초 작성일이므로 변경하지 않습니다. 대신 &lt;code class=&quot;language-text&quot;&gt;update&lt;/code&gt; 필드를 수정일로 갱신합니다. 이렇게 하면 목록 정렬 순서는 유지되면서 독자에게 &quot;최근 업데이트 됨&quot;을 알릴 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-04&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# 최초 작성일 (변경하지 않음)&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2026-04-10&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# 수정일 (갱신)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;다음 포스팅에서는 &lt;strong&gt;SEO 최적화&lt;/strong&gt; 방법을 다룹니다. 검색엔진에 블로그가 잘 노출되도록 메타 태그, 사이트맵, 구글 서치 콘솔 등록까지 실전 가이드를 알아보겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[GitHub 블로그 SEO 최적화 — 검색에 노출되는 블로그 만들기]]></title><description><![CDATA[안녕하세요, 자바파커입니다. "블로그 글을 열심히 썼는데, 구글에 검색해도 안 나와요." GitHub Pages…]]></description><link>http://blog.javapark.kr/04-seo-optimization/</link><guid isPermaLink="false">http://blog.javapark.kr/04-seo-optimization/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;블로그 글을 열심히 썼는데, 구글에 검색해도 안 나와요.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub Pages로 블로그를 만들고 글까지 발행했는데, 정작 검색 엔진에서 내 글이 보이지 않는다면 정말 허무하겠죠. 결론부터 말씀드리면 — 블로그를 만드는 것과 검색에 노출되는 것은 완전히 다른 문제입니다. SEO(Search Engine Optimization) 설정 없이는 아무리 좋은 글을 써도 구글이 찾아오지 않습니다.&lt;/p&gt;
&lt;p&gt;이번 포스팅에서는 Gatsby 기반 GitHub 블로그의 SEO를 처음부터 끝까지 최적화하는 방법을 다룹니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;SEO가 블로그에 중요한 이유&lt;/h2&gt;
&lt;p&gt;SEO란 검색 엔진 최적화(Search Engine Optimization)의 약자로, 구글이나 네이버 같은 검색 엔진이 내 블로그를 잘 이해하고, 검색 결과에 잘 노출시킬 수 있도록 만드는 작업입니다.&lt;/p&gt;
&lt;p&gt;블로그에 SEO가 중요한 이유는 간단합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;SEO 미적용&lt;/th&gt;
&lt;th&gt;SEO 적용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;검색 노출&lt;/td&gt;
&lt;td&gt;거의 없음&lt;/td&gt;
&lt;td&gt;키워드별 상위 노출 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;유입 경로&lt;/td&gt;
&lt;td&gt;직접 공유만 가능&lt;/td&gt;
&lt;td&gt;구글 검색 유입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공유 시 미리보기&lt;/td&gt;
&lt;td&gt;제목만 표시&lt;/td&gt;
&lt;td&gt;이미지 + 설명 표시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;크롤링&lt;/td&gt;
&lt;td&gt;구조 파악 어려움&lt;/td&gt;
&lt;td&gt;사이트맵으로 효율적 크롤링&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;특히 GitHub Pages 블로그는 티스토리나 워드프레스와 달리 SEO 설정이 자동으로 되지 않기 때문에 직접 설정해줘야 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Gatsby SEO 컴포넌트 만들기 (React Helmet)&lt;/h2&gt;
&lt;p&gt;Gatsby에서 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;head&gt;&lt;/code&gt; 태그를 제어하려면 &lt;code class=&quot;language-text&quot;&gt;react-helmet&lt;/code&gt; 또는 Gatsby의 &lt;code class=&quot;language-text&quot;&gt;Head API&lt;/code&gt;를 사용합니다. gatsby-starter-hoodie 테마에는 이미 SEO 컴포넌트가 포함되어 있지만, 직접 만드는 방법도 알아두면 좋습니다.&lt;/p&gt;
&lt;h3&gt;react-helmet 설치&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gatsby-plugin-react-helmet react-helmet&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;gatsby-config.js&lt;/code&gt;에 플러그인을 추가합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-config.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;gatsby-plugin-react-helmet&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ... 기존 플러그인들&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;SEO 컴포넌트 기본 구조&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/SEO.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Helmet &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react-helmet&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useStaticQuery&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; graphql &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;gatsby&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;SEO&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; description&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; article &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; site &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useStaticQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;graphql&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
    query {
      site {
        siteMetadata {
          defaultTitle: title
          defaultDescription: description
          siteUrl
          defaultImage: image
        }
      }
    }
  &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    defaultTitle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    defaultDescription&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    siteUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    defaultImage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; site&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;siteMetadata

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; seo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; title &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; defaultTitle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; description &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; defaultDescription&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;siteUrl&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;image &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; defaultImage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;siteUrl&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Helmet&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;

      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* Open Graph */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:url&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:type&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;article &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;article&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;website&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;

      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* Twitter Card */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter:card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;summary_large_image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter:title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter:description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter:image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Helmet&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SEO&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 컴포넌트를 각 페이지나 템플릿에서 불러와 사용하면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;메타태그 최적화 — title, description, keywords&lt;/h2&gt;
&lt;p&gt;메타태그는 검색 엔진이 페이지의 내용을 파악하는 핵심 정보입니다.&lt;/p&gt;
&lt;h3&gt;title 태그 작성법&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;60자 이내로 작성합니다&lt;/li&gt;
&lt;li&gt;핵심 키워드를 앞쪽에 배치합니다&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;페이지 제목 | 사이트명&lt;/code&gt; 형식이 일반적입니다&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;GitHub 블로그 SEO 최적화 가이드 | AI JAVAPARK&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;description 메타태그&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;150자 내외로 작성합니다&lt;/li&gt;
&lt;li&gt;페이지 내용을 요약하되, 클릭을 유도하는 문장으로 구성합니다&lt;/li&gt;
&lt;li&gt;검색 결과에서 제목 아래에 표시되는 텍스트입니다&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;메타태그, sitemap, Open Graph 설정까지 — Gatsby 기반 GitHub 블로그의 검색 노출을 높이는 실전 SEO 가이드입니다.&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;gatsby-config.js의 siteMetadata 활용&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-config.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;siteMetadata&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;AI JAVAPARK&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;AI와 개발 이야기를 나누는 블로그&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;siteUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://blog.javapark.kr&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/og-default.png&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;자바파커&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;각 포스팅의 frontmatter에 작성한 &lt;code class=&quot;language-text&quot;&gt;title&lt;/code&gt;과 &lt;code class=&quot;language-text&quot;&gt;description&lt;/code&gt;이 메타태그로 자동 연결되도록 템플릿을 구성하는 것이 좋습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Open Graph와 Twitter Card 설정&lt;/h2&gt;
&lt;p&gt;Open Graph(OG)는 페이스북, 카카오톡 등에서 링크 공유 시 미리보기를 결정하는 프로토콜입니다. Twitter Card는 트위터(현 X)에서의 미리보기입니다.&lt;/p&gt;
&lt;h3&gt;Open Graph 필수 태그&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;GitHub 블로그 SEO 최적화&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;검색 노출을 높이는 실전 가이드&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://blog.javapark.kr/og-image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:url&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://blog.javapark.kr/github-blog/04-seo-optimization/&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:type&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;article&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;og:site_name&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;AI JAVAPARK&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Twitter Card 태그&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter:card&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;summary_large_image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter:title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;GitHub 블로그 SEO 최적화&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter:description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;검색 노출을 높이는 실전 가이드&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;twitter:image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://blog.javapark.kr/og-image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;OG 이미지 권장 사양&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;권장값&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;크기&lt;/td&gt;
&lt;td&gt;1200 x 630px&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;포맷&lt;/td&gt;
&lt;td&gt;PNG 또는 JPG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;파일 크기&lt;/td&gt;
&lt;td&gt;1MB 이하&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;위치&lt;/td&gt;
&lt;td&gt;static 폴더에 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;OG 이미지가 잘 적용됐는지 확인하려면 &lt;a href=&quot;https://developers.facebook.com/tools/debug/&quot;&gt;Facebook Sharing Debugger&lt;/a&gt;나 &lt;a href=&quot;https://cards-dev.twitter.com/validator&quot;&gt;Twitter Card Validator&lt;/a&gt;를 활용하세요.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;sitemap.xml 생성하기&lt;/h2&gt;
&lt;p&gt;사이트맵은 검색 엔진에게 &quot;내 블로그에는 이런 페이지들이 있습니다&quot;라고 알려주는 XML 파일입니다. 일종의 블로그 목차라고 생각하면 됩니다.&lt;/p&gt;
&lt;h3&gt;gatsby-plugin-sitemap 설치 및 설정&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gatsby-plugin-sitemap&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-config.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;siteMetadata&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;siteUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://blog.javapark.kr&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;gatsby-plugin-sitemap&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
          {
            allSitePage {
              nodes {
                path
              }
            }
          }
        &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;resolveSiteUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://blog.javapark.kr&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;serialize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; path &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;changefreq&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;weekly&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;빌드 후 &lt;code class=&quot;language-text&quot;&gt;public/sitemap-index.xml&lt;/code&gt;에 사이트맵이 생성됩니다. &lt;code class=&quot;language-text&quot;&gt;https://blog.javapark.kr/sitemap-index.xml&lt;/code&gt;로 접근해서 확인할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;robots.txt 설정하기&lt;/h2&gt;
&lt;p&gt;robots.txt는 검색 엔진 크롤러에게 &quot;이 페이지는 크롤링해도 됩니다 / 하지 마세요&quot;를 알려주는 파일입니다.&lt;/p&gt;
&lt;h3&gt;gatsby-plugin-robots-txt 설치 및 설정&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; gatsby-plugin-robots-txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-config.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;gatsby-plugin-robots-txt&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://blog.javapark.kr&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;sitemap&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://blog.javapark.kr/sitemap-index.xml&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;policy&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;userAgent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token literal-property property&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;빌드 후 생성되는 &lt;code class=&quot;language-text&quot;&gt;robots.txt&lt;/code&gt; 내용은 다음과 같습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;User-agent: *
Allow: /

Sitemap: https://blog.javapark.kr/sitemap-index.xml
Host: https://blog.javapark.kr&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;Google Search Console 등록&lt;/h2&gt;
&lt;p&gt;사이트맵과 robots.txt를 만들었으면, 이제 구글에 &quot;내 블로그가 여기 있습니다&quot;라고 직접 알려줘야 합니다.&lt;/p&gt;
&lt;h3&gt;등록 절차&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://search.google.com/search-console&quot;&gt;Google Search Console&lt;/a&gt;에 접속합니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;속성 추가&lt;/strong&gt; 버튼을 클릭합니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URL 접두어&lt;/strong&gt; 방식으로 &lt;code class=&quot;language-text&quot;&gt;https://blog.javapark.kr&lt;/code&gt;을 입력합니다&lt;/li&gt;
&lt;li&gt;소유권 확인 방법 중 &lt;strong&gt;HTML 태그&lt;/strong&gt; 방식을 선택합니다&lt;/li&gt;
&lt;li&gt;제공되는 메타태그를 SEO 컴포넌트에 추가합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// SEO 컴포넌트에 추가&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Helmet&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;google-site-verification&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;여기에_구글이_제공한_인증코드&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Helmet&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;빌드 후 배포하고, Search Console에서 &lt;strong&gt;확인&lt;/strong&gt; 버튼을 누릅니다&lt;/li&gt;
&lt;li&gt;소유권 확인이 완료되면 &lt;strong&gt;Sitemaps&lt;/strong&gt; 메뉴에서 사이트맵 URL을 제출합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;https://blog.javapark.kr/sitemap-index.xml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;네이버 서치어드바이저 등록&lt;/h3&gt;
&lt;p&gt;네이버 검색 노출도 원한다면 &lt;a href=&quot;https://searchadvisor.naver.com/&quot;&gt;네이버 서치어드바이저&lt;/a&gt;에도 동일하게 등록합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;naver-site-verification&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;네이버_인증코드&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;구조화 데이터 (JSON-LD) 추가하기&lt;/h2&gt;
&lt;p&gt;구조화 데이터(Structured Data)는 검색 엔진에게 페이지의 의미를 더 정확하게 알려주는 방법입니다. 구글 검색 결과에서 별점, 작성일, 작성자 같은 리치 스니펫(Rich Snippet)이 표시되는 게 바로 구조화 데이터 덕분입니다.&lt;/p&gt;
&lt;h3&gt;블로그 포스팅용 JSON-LD&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/SEO.js 에 추가&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; structuredData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;@context&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://schema.org&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;@type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;BlogPosting&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;headline&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;datePublished&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;dateModified&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; update &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;author&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;@type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Person&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;자바파커&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://blog.javapark.kr&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;publisher&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;@type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Organization&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AI JAVAPARK&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;logo&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&quot;@type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ImageObject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://blog.javapark.kr/logo.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;mainEntityOfPage&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;@type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;WebPage&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;@id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; seo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Helmet을 통해 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script&gt;&lt;/code&gt; 태그로 삽입합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Helmet&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;application/ld+json&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    {JSON.stringify(structuredData)}
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Helmet&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;구조화 데이터 테스트&lt;/h3&gt;
&lt;p&gt;구글의 &lt;a href=&quot;https://search.google.com/test/rich-results&quot;&gt;리치 결과 테스트&lt;/a&gt; 도구에서 URL을 입력하면 구조화 데이터가 제대로 적용됐는지 확인할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;GitHub 블로그 SEO 검색 노출 체크리스트&lt;/h2&gt;
&lt;p&gt;모든 설정을 마쳤다면, 아래 체크리스트로 빠진 항목이 없는지 확인해보세요.&lt;/p&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;code class=&quot;language-text&quot;&gt;gatsby-config.js&lt;/code&gt;의 &lt;code class=&quot;language-text&quot;&gt;siteMetadata&lt;/code&gt;에 title, description, siteUrl, image 설정&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; SEO 컴포넌트에 title, description 메타태그 포함&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Open Graph 태그 (og:title, og:description, og:image, og:url) 설정&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Twitter Card 태그 설정&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;code class=&quot;language-text&quot;&gt;gatsby-plugin-sitemap&lt;/code&gt;으로 sitemap.xml 생성&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; &lt;code class=&quot;language-text&quot;&gt;gatsby-plugin-robots-txt&lt;/code&gt;로 robots.txt 생성&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Google Search Console에 사이트 등록 및 사이트맵 제출&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 네이버 서치어드바이저 등록 (선택)&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 구조화 데이터 (JSON-LD) 추가&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; OG 이미지 (1200x630px) 준비&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; 각 포스팅의 frontmatter에 title, description 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q. SEO 설정 후 검색에 바로 노출되나요?&lt;/h3&gt;
&lt;p&gt;아닙니다. 구글이 크롤링하고 인덱싱하는 데에는 며칠에서 몇 주까지 걸릴 수 있습니다. Search Console에서 직접 URL 색인 요청을 하면 속도를 앞당길 수 있습니다. Search Console의 &lt;strong&gt;URL 검사&lt;/strong&gt; 메뉴에서 URL을 입력한 뒤 &lt;strong&gt;색인 생성 요청&lt;/strong&gt; 버튼을 누르면 됩니다.&lt;/p&gt;
&lt;h3&gt;Q. gatsby-starter-hoodie 테마에 이미 SEO가 적용되어 있나요?&lt;/h3&gt;
&lt;p&gt;네, 기본적인 메타태그와 OG 태그가 포함되어 있습니다. 다만 sitemap, robots.txt, 구조화 데이터, Search Console 등록은 직접 해야 합니다. 테마에 포함된 SEO 컴포넌트를 열어서 현재 어디까지 설정되어 있는지 확인해보시는 걸 추천합니다.&lt;/p&gt;
&lt;h3&gt;Q. OG 이미지를 포스팅마다 다르게 설정할 수 있나요?&lt;/h3&gt;
&lt;p&gt;네, frontmatter에 &lt;code class=&quot;language-text&quot;&gt;image&lt;/code&gt; 필드를 추가하고, SEO 컴포넌트에서 해당 값을 읽어오도록 구성하면 됩니다. 포스팅별로 고유한 OG 이미지를 설정하면 SNS 공유 시 클릭률이 높아집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;여러분은 블로그 SEO 어디까지 설정하고 계신가요? 댓글로 알려주세요.&lt;/p&gt;
&lt;p&gt;다음 포스팅에서는 &lt;strong&gt;GitHub Actions로 블로그를 자동 배포하는 방법&lt;/strong&gt;을 다룹니다. push만 하면 빌드부터 배포까지 알아서 되는 환경을 만들어보겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[블로그에 광고와 댓글 시스템 달기 — 수익화와 소통]]></title><description><![CDATA[안녕하세요, 자바파커입니다. "블로그에 글만 올리면 끝인가요? 수익도 낼 수 있고, 독자와 소통도 할 수 있다면 좋겠는데..." GitHub Pages…]]></description><link>http://blog.javapark.kr/06-ads-and-comments/</link><guid isPermaLink="false">http://blog.javapark.kr/06-ads-and-comments/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;블로그에 글만 올리면 끝인가요? 수익도 낼 수 있고, 독자와 소통도 할 수 있다면 좋겠는데...&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub Pages 블로그도 광고를 달아 수익을 만들 수 있고, 댓글 시스템을 붙여 독자와 소통할 수 있습니다. 결론부터 말씀드리면 — 정적 사이트라서 불가능할 것 같지만, 방법은 충분히 있습니다.&lt;/p&gt;
&lt;p&gt;이번 포스팅에서는 Google AdSense와 쿠팡 파트너스로 수익화하는 방법, 그리고 Utterances로 GitHub 기반 댓글 시스템을 구축하는 방법을 다룹니다. &quot;GitHub 블로그 A to Z&quot; 시리즈의 마지막 편입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;블로그 수익화 옵션 비교&lt;/h2&gt;
&lt;p&gt;GitHub Pages 블로그에 적용할 수 있는 수익화 방법은 크게 세 가지입니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;방법&lt;/th&gt;
&lt;th&gt;난이도&lt;/th&gt;
&lt;th&gt;승인 필요&lt;/th&gt;
&lt;th&gt;수익 구조&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Google AdSense&lt;/td&gt;
&lt;td&gt;중간&lt;/td&gt;
&lt;td&gt;승인 심사 있음&lt;/td&gt;
&lt;td&gt;CPC (클릭당 과금)&lt;/td&gt;
&lt;td&gt;가장 보편적, 심사 통과가 관건&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;쿠팡 파트너스&lt;/td&gt;
&lt;td&gt;쉬움&lt;/td&gt;
&lt;td&gt;가입 즉시 가능&lt;/td&gt;
&lt;td&gt;CPS (구매당 수수료)&lt;/td&gt;
&lt;td&gt;한국 사용자 대상으로 효과적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;제휴 마케팅&lt;/td&gt;
&lt;td&gt;중간&lt;/td&gt;
&lt;td&gt;업체별 다름&lt;/td&gt;
&lt;td&gt;건당 수수료&lt;/td&gt;
&lt;td&gt;특정 상품/서비스 추천&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;초보 블로거라면 &lt;strong&gt;쿠팡 파트너스를 먼저 시작&lt;/strong&gt;하고, 블로그가 어느 정도 성장한 뒤 &lt;strong&gt;AdSense 승인을 신청&lt;/strong&gt;하는 것을 추천합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Google AdSense 신청 및 설정&lt;/h2&gt;
&lt;h3&gt;AdSense 승인 조건&lt;/h3&gt;
&lt;p&gt;구글이 공식적으로 밝히지는 않지만, 경험적으로 알려진 조건들이 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;양질의 포스팅이 15개 이상&lt;/li&gt;
&lt;li&gt;각 포스팅이 1,000자 이상의 충실한 내용&lt;/li&gt;
&lt;li&gt;개인정보처리방침(Privacy Policy) 페이지 존재&lt;/li&gt;
&lt;li&gt;커스텀 도메인 사용 (github.io 도메인으로는 승인이 어려울 수 있음)&lt;/li&gt;
&lt;li&gt;저작권 문제가 없는 콘텐츠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;AdSense 신청 절차&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/adsense&quot;&gt;Google AdSense&lt;/a&gt;에 접속하여 가입합니다&lt;/li&gt;
&lt;li&gt;블로그 URL(&lt;code class=&quot;language-text&quot;&gt;https://blog.javapark.kr&lt;/code&gt;)을 등록합니다&lt;/li&gt;
&lt;li&gt;AdSense에서 제공하는 인증 코드를 블로그의 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;head&gt;&lt;/code&gt;에 추가합니다&lt;/li&gt;
&lt;li&gt;심사 결과를 기다립니다 (보통 1~2주)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Gatsby에 AdSense 코드 삽입하기&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;gatsby-ssr.js&lt;/code&gt; 파일을 사용해 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;head&gt;&lt;/code&gt;에 스크립트를 추가합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// gatsby-ssr.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;onRenderBody&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; setHeadComponents &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setHeadComponents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script
      key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;adsense&quot;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt;
      src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX&quot;&lt;/span&gt;
      crossOrigin&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;ca-pub-XXXXXXXXXXXXXXXX&lt;/code&gt; 부분은 AdSense에서 제공하는 본인의 퍼블리셔 ID로 교체합니다.&lt;/p&gt;
&lt;h3&gt;포스팅 내에 광고 배치하기&lt;/h3&gt;
&lt;p&gt;승인이 완료되면, 광고 컴포넌트를 만들어 원하는 위치에 삽입할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/AdSense.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useEffect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; AdSense &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; slot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; format &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;auto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; responsive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;adsbygoogle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;adsbygoogle &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;AdSense error:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;textAlign&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;20px 0&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ins&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;adsbygoogle&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;block&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;data-ad-client&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;ca-pub-XXXXXXXXXXXXXXXX&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;data-ad-slot&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;slot&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;data-ad-format&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;format&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;data-full-width-responsive&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;responsive&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; AdSense&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;포스팅 템플릿에서 사용할 때는 다음과 같이 합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 포스팅 본문 아래에 삽입&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AdSense&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;slot&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1234567890&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;쿠팡 파트너스 가입 및 광고 삽입&lt;/h2&gt;
&lt;p&gt;쿠팡 파트너스는 가입 후 바로 사용할 수 있어서 블로그 초기부터 적용하기 좋습니다. 방문자가 링크를 통해 24시간 내에 구매하면 수수료(보통 3~5%)를 받을 수 있습니다.&lt;/p&gt;
&lt;h3&gt;가입 절차&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://partners.coupang.com/&quot;&gt;쿠팡 파트너스&lt;/a&gt;에 접속하여 가입합니다&lt;/li&gt;
&lt;li&gt;미디어(블로그) 정보를 등록합니다&lt;/li&gt;
&lt;li&gt;승인 후 광고 소재를 생성할 수 있습니다&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;다이나믹 배너 삽입 (iframe 방식)&lt;/h3&gt;
&lt;p&gt;쿠팡 파트너스에서 제공하는 다이나믹 배너를 Gatsby 컴포넌트로 만들어봅시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/CoupangAd.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; CoupangAd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; src&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;100%&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;100&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;20px 0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;textAlign&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;center&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;iframe&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;frameBorder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;scrolling&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;no&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;referrerPolicy&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;unsafe-url&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;쿠팡 파트너스&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;maxWidth&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;100%&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;fontSize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;11px&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#888&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;marginTop&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;4px&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를
        제공받습니다.
      &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; CoupangAd&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;쿠팡 파트너스 사이트에서 생성한 다이나믹 배너의 &lt;code class=&quot;language-text&quot;&gt;src&lt;/code&gt; 값을 복사해서 사용합니다.&lt;/p&gt;
&lt;h3&gt;텍스트 링크 방식&lt;/h3&gt;
&lt;p&gt;배너 대신 본문에 자연스럽게 상품 링크를 넣는 방법도 있습니다. 리뷰 글이나 추천 글에 적합합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;markdown&quot;&gt;&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;개발에 사용 중인 키보드가 궁금하시다면, &lt;span class=&quot;token url&quot;&gt;[&lt;span class=&quot;token content&quot;&gt;제가 사용하는 키보드&lt;/span&gt;](&lt;span class=&quot;token url&quot;&gt;쿠팡_파트너스_링크&lt;/span&gt;)&lt;/span&gt;를 참고해보세요.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;광고 위치 전략&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;위치&lt;/th&gt;
&lt;th&gt;효과&lt;/th&gt;
&lt;th&gt;주의사항&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;포스팅 상단 (제목 아래)&lt;/td&gt;
&lt;td&gt;노출률 높음&lt;/td&gt;
&lt;td&gt;사용자 이탈 위험&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;포스팅 중간&lt;/td&gt;
&lt;td&gt;자연스러운 노출&lt;/td&gt;
&lt;td&gt;내용 흐름을 깨지 않도록 배치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;포스팅 하단 (본문 끝)&lt;/td&gt;
&lt;td&gt;글을 다 읽은 독자에게 노출&lt;/td&gt;
&lt;td&gt;가장 무난한 위치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사이드바&lt;/td&gt;
&lt;td&gt;지속적 노출&lt;/td&gt;
&lt;td&gt;모바일에서는 안 보일 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;저는 포스팅 하단에 하나, 긴 글의 경우 중간에 하나 정도 배치하는 것을 추천합니다. 솔직히 광고를 너무 많이 넣으면 독자가 떠납니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;댓글 시스템 비교&lt;/h2&gt;
&lt;p&gt;GitHub Pages는 서버가 없는 정적 사이트이기 때문에, 자체적으로 댓글 기능을 구현할 수 없습니다. 외부 서비스를 활용해야 합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;서비스&lt;/th&gt;
&lt;th&gt;기반&lt;/th&gt;
&lt;th&gt;로그인 방식&lt;/th&gt;
&lt;th&gt;비용&lt;/th&gt;
&lt;th&gt;장점&lt;/th&gt;
&lt;th&gt;단점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Disqus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;자체 플랫폼&lt;/td&gt;
&lt;td&gt;소셜 로그인&lt;/td&gt;
&lt;td&gt;무료 (광고 포함)&lt;/td&gt;
&lt;td&gt;설정 간편&lt;/td&gt;
&lt;td&gt;광고 삽입, 무거움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Utterances&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GitHub Issues&lt;/td&gt;
&lt;td&gt;GitHub 로그인&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;가볍고 깔끔&lt;/td&gt;
&lt;td&gt;GitHub 계정 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Giscus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GitHub Discussions&lt;/td&gt;
&lt;td&gt;GitHub 로그인&lt;/td&gt;
&lt;td&gt;무료&lt;/td&gt;
&lt;td&gt;스레드 지원, 리액션&lt;/td&gt;
&lt;td&gt;GitHub 계정 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;개발 블로그라면 &lt;strong&gt;Utterances&lt;/strong&gt; 또는 &lt;strong&gt;Giscus&lt;/strong&gt;를 추천합니다. 독자 대부분이 개발자이고 GitHub 계정을 가지고 있을 테니까요. 이번 글에서는 설정이 간단한 Utterances를 기준으로 설명하겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Utterances 설정하기&lt;/h2&gt;
&lt;p&gt;Utterances는 GitHub Issues를 댓글 저장소로 활용하는 오픈소스 위젯입니다. 누군가 댓글을 달면, 해당 포스팅에 대응하는 GitHub Issue가 자동으로 생성됩니다.&lt;/p&gt;
&lt;h3&gt;1단계: utterances 앱 설치&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/apps/utterances&quot;&gt;utterances 앱 페이지&lt;/a&gt;에 접속합니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install&lt;/strong&gt; 버튼을 클릭합니다&lt;/li&gt;
&lt;li&gt;블로그 레포지토리(예: &lt;code class=&quot;language-text&quot;&gt;javapark/javapark.github.io&lt;/code&gt;)를 선택합니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install&lt;/strong&gt; 을 확인합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2단계: Utterances 컴포넌트 만들기&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/Utterances.js&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useEffect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useRef &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Utterances &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; repo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; theme &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;github-light&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; containerRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;containerRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; script &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://utteranc.es/client.js&quot;&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;async &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;repo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; repo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;issue-term&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pathname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;crossorigin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 기존 스크립트가 있으면 제거&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existingScript &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; containerRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existingScript&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      existingScript&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    containerRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;repo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;containerRef&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Utterances&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;3단계: 포스팅 템플릿에 삽입&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/templates/blog-post.js (또는 해당 템플릿 파일)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Utterances &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../components/Utterances&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 본문 아래에 추가&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Utterances&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;javapark/javapark.github.io&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;github-light&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Utterances 설정 옵션&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;값&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;repo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;사용자명/레포명&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;댓글이 저장될 레포지토리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;issue-term&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;pathname&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Issue 매핑 기준 (URL 경로 기준)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;issue-term&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Issue 매핑 기준 (포스팅 제목 기준)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;theme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;github-light&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;라이트 테마&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;theme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;github-dark&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;다크 테마&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;theme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;preferred-color-scheme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OS 설정에 따라 자동 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;issue-term&lt;/code&gt;은 &lt;code class=&quot;language-text&quot;&gt;pathname&lt;/code&gt;을 추천합니다. URL이 바뀌지 않는 한 댓글이 유지되기 때문입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;다크모드 대응 댓글 시스템&lt;/h2&gt;
&lt;p&gt;gatsby-starter-hoodie 테마는 다크모드를 지원합니다. 블로그가 다크모드로 전환되면 댓글 위젯도 함께 변해야 자연스럽습니다.&lt;/p&gt;
&lt;h3&gt;테마 상태에 따라 Utterances 테마 변경&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// src/components/Utterances.js (다크모드 대응 버전)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useEffect&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useContext &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ThemeContext &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../contexts/ThemeContext&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Utterances&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; repo &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; containerRef &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; isDarkMode &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ThemeContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; theme &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; isDarkMode &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;github-dark&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;github-light&quot;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;containerRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 기존 iframe 제거&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; existingIframe &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; containerRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;.utterances&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existingIframe&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      existingIframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; script &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://utteranc.es/client.js&quot;&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;async &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;repo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; repo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;issue-term&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pathname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;crossorigin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    containerRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;script&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;repo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;containerRef&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Utterances&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;메시지 방식으로 테마 변경 (iframe 재생성 없이)&lt;/h3&gt;
&lt;p&gt;위 방법은 테마가 변경될 때마다 iframe을 다시 만들기 때문에 깜빡임이 발생합니다. &lt;code class=&quot;language-text&quot;&gt;postMessage&lt;/code&gt;를 활용하면 더 부드럽게 전환할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; iframe &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.utterances-frame&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iframe&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    iframe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contentWindow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;postMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;set-theme&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; theme &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;https://utteranc.es&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 코드를 기존 컴포넌트의 &lt;code class=&quot;language-text&quot;&gt;useEffect&lt;/code&gt;와 별도로 추가하면, 다크모드 전환 시 댓글 위젯이 부드럽게 테마를 변경합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;광고 배치 팁 — 사용자 경험과 수익의 균형&lt;/h2&gt;
&lt;p&gt;솔직히 말하면, 광고는 많이 넣을수록 수익이 올라갈 것 같지만 현실은 반대인 경우가 많습니다.&lt;/p&gt;
&lt;h3&gt;광고 배치 원칙&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;본문 내용을 방해하지 않기&lt;/strong&gt; — 독자가 글을 읽다가 광고에 가로막히면 이탈합니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;한 페이지에 3개 이하&lt;/strong&gt; — AdSense 정책상 제한은 없지만, 3개를 넘기면 사용자 경험이 급격히 나빠집니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;모바일 대응 필수&lt;/strong&gt; — 모바일에서 화면을 가득 채우는 광고는 최악입니다&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;관련성 있는 광고&lt;/strong&gt; — 쿠팡 파트너스 링크는 포스팅 주제와 관련된 상품으로 설정합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;추천 배치 패턴&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[포스팅 제목]
[본문 시작]
...
(본문의 40~50% 지점)
--- 쿠팡 파트너스 배너 ---
...
[본문 끝]
--- AdSense 광고 ---
--- 댓글 시스템 ---&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 패턴이면 독자가 글을 읽는 흐름을 크게 방해하지 않으면서도 광고 노출을 확보할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;시리즈 마무리 — GitHub 블로그 A to Z 정리&lt;/h2&gt;
&lt;p&gt;&quot;GitHub 블로그 A to Z&quot; 시리즈 6편을 통해 블로그의 생성부터 수익화까지 전 과정을 다뤘습니다. 지금까지의 여정을 정리해보겠습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;편&lt;/th&gt;
&lt;th&gt;주제&lt;/th&gt;
&lt;th&gt;핵심 내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1편&lt;/td&gt;
&lt;td&gt;시작하기&lt;/td&gt;
&lt;td&gt;Gatsby + gatsby-starter-hoodie로 블로그 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2편&lt;/td&gt;
&lt;td&gt;스킨 커스터마이징&lt;/td&gt;
&lt;td&gt;테마 색상, 폰트, 레이아웃 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3편&lt;/td&gt;
&lt;td&gt;마크다운과 카테고리&lt;/td&gt;
&lt;td&gt;포스팅 작성법, 시리즈/태그 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4편&lt;/td&gt;
&lt;td&gt;SEO 최적화&lt;/td&gt;
&lt;td&gt;메타태그, sitemap, 구조화 데이터, Search Console&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5편&lt;/td&gt;
&lt;td&gt;자동 배포&lt;/td&gt;
&lt;td&gt;GitHub Actions CI/CD 파이프라인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6편&lt;/td&gt;
&lt;td&gt;광고와 댓글&lt;/td&gt;
&lt;td&gt;AdSense, 쿠팡 파트너스, Utterances&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;블로그 운영을 시작하시는 분들께&lt;/h3&gt;
&lt;p&gt;블로그는 기술적 완성도보다 &lt;strong&gt;꾸준한 글쓰기&lt;/strong&gt;가 훨씬 중요합니다. 완벽한 디자인과 모든 기능이 갖춰져야 시작할 수 있는 게 아닙니다. 글 하나라도 먼저 쓰고, 나머지는 천천히 개선해 나가시면 됩니다.&lt;/p&gt;
&lt;p&gt;직접 조사하고 경험한 내용을 바탕으로 이 시리즈를 작성했는데, 여러분의 블로그 시작에 조금이라도 도움이 되었으면 좋겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q. AdSense 승인이 거절되면 어떻게 하나요?&lt;/h3&gt;
&lt;p&gt;거절 사유를 메일로 받게 됩니다. 가장 흔한 거절 사유는 &quot;콘텐츠 불충분&quot;입니다. 양질의 포스팅을 5~10개 더 작성한 뒤 재신청하면 됩니다. 재신청 횟수에는 제한이 없으니, 콘텐츠를 보강하면서 꾸준히 신청해보세요. 커스텀 도메인을 사용하는 것도 승인률을 높이는 데 도움이 됩니다.&lt;/p&gt;
&lt;h3&gt;Q. Utterances 대신 Giscus를 사용하는 것이 더 좋나요?&lt;/h3&gt;
&lt;p&gt;둘 다 좋은 선택입니다. Giscus는 GitHub Discussions 기반이라 댓글에 대한 답글(스레드)과 리액션을 지원하는 장점이 있습니다. 설정 방법도 Utterances와 거의 동일합니다. 만약 댓글 간 대화가 활발할 것 같다면 Giscus를, 단순 댓글이면 Utterances를 추천합니다.&lt;/p&gt;
&lt;h3&gt;Q. 쿠팡 파트너스 수익은 어느 정도 나오나요?&lt;/h3&gt;
&lt;p&gt;솔직히 일일 방문자가 100명 이하일 때는 월 수익이 커피 한 잔 값도 안 됩니다. 블로그 트래픽이 핵심이기 때문에, SEO 최적화(4편 참고)와 꾸준한 포스팅으로 방문자를 먼저 늘리는 데 집중하시는 게 좋습니다. 트래픽이 올라오면 자연스럽게 수익도 따라옵니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;여러분은 블로그 수익화를 어떻게 하고 계신가요? 또는 어떤 댓글 시스템을 사용하고 계신가요? 댓글로 알려주세요.&lt;/p&gt;
&lt;p&gt;&quot;GitHub 블로그 A to Z&quot; 시리즈를 끝까지 읽어주셔서 감사합니다. 앞으로도 블로그 운영에 도움이 되는 글을 꾸준히 올리겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[윈도우 단축키 완전 정복 — 매일 쓰는 핵심 단축키만 모았습니다]]></title><description><![CDATA[안녕하세요, 자바파커입니다. 마우스 없이도 컴퓨터를 자유자재로 다룰 수 있다면 어떨까요? 솔직히 말하면, 윈도우 단축키는 수백 개가 넘습니다. 하지만 실제로 매일 쓰는 건 20~3…]]></description><link>http://blog.javapark.kr/windows-keyboard-shortcuts/</link><guid isPermaLink="false">http://blog.javapark.kr/windows-keyboard-shortcuts/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;마우스 없이도 컴퓨터를 자유자재로 다룰 수 있다면 어떨까요?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;솔직히 말하면, 윈도우 단축키는 수백 개가 넘습니다. 하지만 &lt;strong&gt;실제로 매일 쓰는 건 20~30개 정도&lt;/strong&gt;면 충분합니다. 오늘은 &quot;진짜 쓰는 것만&quot; 카테고리별로 정리해봤습니다. 결론부터 말씀드리면 — 이 글에 나온 단축키만 1주일 연습하면, 작업 속도가 눈에 띄게 빨라집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;윈도우 기본 단축키 — 이것만은 반드시&lt;/h2&gt;
&lt;p&gt;가장 기본이면서도 가장 자주 쓰는 단축키입니다. 이미 아시는 것도 있겠지만, 한 번 더 정리해두면 좋습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;활용 팁&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;복사&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;잘라내기&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + V&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;붙여넣기&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;실행 취소&lt;/td&gt;
&lt;td&gt;실수했을 때 생명줄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;다시 실행&lt;/td&gt;
&lt;td&gt;취소한 걸 되돌릴 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;전체 선택&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;저장&lt;/td&gt;
&lt;td&gt;수시로 누르는 습관 필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;찾기&lt;/td&gt;
&lt;td&gt;문서, 브라우저, 탐색기 모두 동작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + P&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;인쇄&lt;/td&gt;
&lt;td&gt;PDF 저장에도 활용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;F2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이름 바꾸기&lt;/td&gt;
&lt;td&gt;파일/폴더 선택 후 바로 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Delete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;삭제&lt;/td&gt;
&lt;td&gt;휴지통으로 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Shift + Delete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;영구 삭제&lt;/td&gt;
&lt;td&gt;휴지통 거치지 않음 (주의!)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;윈도우 키 조합 단축키 — 생산성의 핵심&lt;/h2&gt;
&lt;p&gt;윈도우 키(⊞)를 활용한 단축키는 시스템 수준의 기능을 빠르게 실행할 수 있어서, 알아두면 가장 체감이 큽니다.&lt;/p&gt;
&lt;h3&gt;시스템 &amp;#x26; 앱 실행&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;한 줄 설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 탐색기 열기&lt;/td&gt;
&lt;td&gt;가장 자주 쓰는 단축키 중 하나&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + I&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;설정 열기&lt;/td&gt;
&lt;td&gt;제어판 찾을 필요 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;화면 잠금&lt;/td&gt;
&lt;td&gt;자리 비울 때 보안 필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;실행 창 열기&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;cmd&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;calc&lt;/code&gt; 등 빠른 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + S&lt;/code&gt; (또는 &lt;code class=&quot;language-text&quot;&gt;Win + Q&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;검색&lt;/td&gt;
&lt;td&gt;앱, 파일, 설정 통합 검색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;빠른 링크 메뉴&lt;/td&gt;
&lt;td&gt;장치 관리자, 터미널 등 고급 메뉴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + .&lt;/code&gt; (마침표)&lt;/td&gt;
&lt;td&gt;이모지 패널&lt;/td&gt;
&lt;td&gt;이모지, 특수문자, 가오모지 입력&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + 숫자(1~9)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;작업표시줄 앱 실행&lt;/td&gt;
&lt;td&gt;1번째~9번째 고정 앱 바로 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;창(Window) 관리 단축키&lt;/h3&gt;
&lt;p&gt;멀티태스킹의 핵심입니다. 이 단축키들을 익히면 마우스로 창을 드래그할 일이 거의 없어집니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + ←&lt;/code&gt; / &lt;code class=&quot;language-text&quot;&gt;Win + →&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;창을 화면 왼쪽/오른쪽 반으로 스냅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + ↑&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;창 최대화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + ↓&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;창 최소화 (최대화 상태면 원래 크기로)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;스냅 레이아웃 선택 (Windows 11)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;바탕화면 보기/복귀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;모든 창 최소화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Home&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 창 제외 모두 최소화 (설정에서 제목 표시줄 흔들기 활성화 필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Alt + Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;열린 창 간 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Alt + F4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 창/프로그램 닫기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;작업 보기 (가상 데스크톱 포함)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;가상 데스크톱 단축키 — 모니터 하나로도 충분합니다&lt;/h2&gt;
&lt;p&gt;윈도우 11의 가상 데스크톱 기능은 모니터가 하나뿐인 환경에서 특히 유용합니다. 업무용 데스크톱, 개인용 데스크톱을 분리해서 사용해보세요.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Ctrl + D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새 가상 데스크톱 만들기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Ctrl + ←&lt;/code&gt; / &lt;code class=&quot;language-text&quot;&gt;→&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;데스크톱 간 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Ctrl + F4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 가상 데스크톱 닫기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;전체 데스크톱 &amp;#x26; 창 보기&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;저는 데스크톱 1번에 업무(슬랙, 이메일), 2번에 개발(VS Code, 터미널), 3번에 참고자료(브라우저)를 배치합니다. &lt;code class=&quot;language-text&quot;&gt;Win + Ctrl + ←/→&lt;/code&gt;로 순식간에 전환하니까, 듀얼 모니터 부럽지 않습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;스크린샷 &amp;#x26; 클립보드 단축키 — 자료 정리의 필수 기능&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Shift + S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;화면 캡처 (영역 선택)&lt;/td&gt;
&lt;td&gt;가장 많이 쓰는 스크린샷 방법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;PrtScn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;전체 화면 캡처&lt;/td&gt;
&lt;td&gt;클립보드에 복사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + PrtScn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;전체 화면 캡처 후 자동 저장&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;사진/스크린샷&lt;/code&gt; 폴더에 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + V&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;클립보드 히스토리&lt;/td&gt;
&lt;td&gt;이전에 복사한 내용 목록에서 선택&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Win + V&lt;/code&gt;는 처음 사용 시 활성화가 필요합니다. 한 번 켜두면 복사 이력이 쌓이기 때문에, &quot;아까 복사한 거 어디 갔지?&quot; 하는 상황이 사라집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;브라우저 단축키 — 크롬, 엣지 공통&lt;/h2&gt;
&lt;p&gt;웹 브라우저에서의 단축키도 업무 속도에 큰 영향을 줍니다. 크롬과 엣지 모두 동일하게 작동합니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새 탭 열기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 탭 닫기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;닫은 탭 다시 열기 (최대 10개)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;다음 탭으로 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이전 탭으로 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;주소창 포커스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + 숫자(1~8)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;해당 번째 탭으로 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + 9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;마지막 탭으로 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;F5&lt;/code&gt; / &lt;code class=&quot;language-text&quot;&gt;Ctrl + R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새로고침&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + Delete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;인터넷 사용 기록 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;특히 &lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + T&lt;/code&gt;는 실수로 탭을 닫았을 때 정말 유용합니다. 직접 써보면 &quot;이걸 왜 이제 알았지?&quot; 하게 됩니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;파일 탐색기 단축키 — 파일 관리가 빨라집니다&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새 탐색기 창 열기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새 폴더 만들기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Alt + ←&lt;/code&gt; / &lt;code class=&quot;language-text&quot;&gt;→&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;뒤로/앞으로 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Alt + ↑&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;상위 폴더로 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Alt + D&lt;/code&gt; 또는 &lt;code class=&quot;language-text&quot;&gt;Ctrl + L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;경로 표시줄 포커스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Alt + Enter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;선택한 항목의 속성 보기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;F2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;이름 바꾸기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;F5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새로고침&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;팁:&lt;/strong&gt; 파일 탐색기 상단의 커맨드 바는 선택한 파일 유형에 따라 관련 작업(복사, 이동, 압축 해제 등) 아이콘이 자동으로 바뀝니다. &lt;code class=&quot;language-text&quot;&gt;Alt&lt;/code&gt; 키를 누르면 키보드로 각 메뉴에 접근할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;개발자를 위한 윈도우 단축키 추가 팁&lt;/h2&gt;
&lt;p&gt;개발자라면 아래 단축키도 함께 익혀두면 좋습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + `&lt;/code&gt; (백틱)&lt;/td&gt;
&lt;td&gt;Windows 터미널 Quake 모드 (터미널 앱 설치 필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + Esc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;작업 관리자 바로 열기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Pause&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;시스템 정보 (설정 &gt; 정보 페이지로 이동)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + G&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Xbox Game Bar (화면 녹화)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + V&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;서식 없이 붙여넣기 (브라우저, VS Code 등 지원 앱에서만 동작)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Win + `&lt;/code&gt;은 Windows 터미널의 &lt;strong&gt;Quake 모드&lt;/strong&gt;로, 화면 상단에 터미널이 슬라이드로 나타납니다. Windows 터미널이 설치되어 있어야 동작합니다. &lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + V&lt;/code&gt;는 OS 기본 단축키가 아니라 앱별 지원 기능이지만, 크롬·엣지·VS Code 등 개발자가 주로 쓰는 앱에서는 대부분 동작합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;윈도우 단축키 빠르게 익히는 3단계 방법&lt;/h2&gt;
&lt;p&gt;단축키를 한꺼번에 외우려고 하면 오히려 역효과입니다. 아래 방법을 추천합니다.&lt;/p&gt;
&lt;h3&gt;1단계: 5개만 먼저 (1주차)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Win + E&lt;/code&gt; (탐색기), &lt;code class=&quot;language-text&quot;&gt;Win + L&lt;/code&gt; (잠금), &lt;code class=&quot;language-text&quot;&gt;Win + D&lt;/code&gt; (바탕화면)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Shift + S&lt;/code&gt; (캡처), &lt;code class=&quot;language-text&quot;&gt;Win + V&lt;/code&gt; (클립보드)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2단계: 창 관리 추가 (2주차)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Win + ←/→&lt;/code&gt; (스냅), &lt;code class=&quot;language-text&quot;&gt;Alt + Tab&lt;/code&gt; (창 전환)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Tab&lt;/code&gt; (작업 보기), &lt;code class=&quot;language-text&quot;&gt;Win + Ctrl + D&lt;/code&gt; (가상 데스크톱)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3단계: 브라우저 &amp;#x26; 탐색기 (3주차)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + W/T/Shift+T&lt;/code&gt; (탭 관리)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + N&lt;/code&gt; (새 폴더), &lt;code class=&quot;language-text&quot;&gt;Alt + ←&lt;/code&gt; (뒤로)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;핵심은 &lt;strong&gt;한 번에 많이 외우는 것이 아니라, 매일 쓰는 동작부터 바꾸는 것&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;윈도우 단축키 한 장 요약표&lt;/h2&gt;
&lt;p&gt;가장 활용도 높은 단축키만 한 장으로 정리했습니다. 모니터 옆에 붙여두고 쓰세요.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;카테고리&lt;/th&gt;
&lt;th&gt;단축키&lt;/th&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;필수&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + C/X/V/Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;복사/잘라내기/붙여넣기/취소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시스템&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 탐색기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시스템&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + I&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시스템&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;화면 잠금&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;창 관리&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + ←/→&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;화면 분할&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;창 관리&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Alt + Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;창 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;창 관리&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;바탕화면&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;캡처&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Shift + S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;영역 캡처&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;클립보드&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + V&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;클립보드 히스토리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가상 데스크톱&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Ctrl + D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새 데스크톱&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가상 데스크톱&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Win + Ctrl + ←/→&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;데스크톱 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;브라우저&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + T/W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새 탭/탭 닫기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;브라우저&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Ctrl + Shift + T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;닫은 탭 복구&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q. 윈도우 단축키가 안 먹힐 때는 어떻게 하나요?&lt;/h3&gt;
&lt;p&gt;일부 단축키는 특정 앱이 포커스를 가로채면 동작하지 않을 수 있습니다. &lt;code class=&quot;language-text&quot;&gt;Win + D&lt;/code&gt;로 바탕화면으로 나간 뒤 다시 시도하거나, 게임 모드가 활성화되어 있다면 &lt;code class=&quot;language-text&quot;&gt;Win + G&lt;/code&gt;에서 게임 모드를 꺼보세요. 키보드 드라이버 문제일 수도 있으니, 설정 &gt; 접근성 &gt; 키보드에서 고정 키, 필터 키가 꺼져 있는지 확인하세요.&lt;/p&gt;
&lt;h3&gt;Q. 윈도우 10과 11의 단축키 차이가 있나요?&lt;/h3&gt;
&lt;p&gt;대부분의 단축키는 동일합니다. 윈도우 11에서 새로 추가된 주요 단축키는 &lt;code class=&quot;language-text&quot;&gt;Win + Z&lt;/code&gt;(스냅 레이아웃), &lt;code class=&quot;language-text&quot;&gt;Win + C&lt;/code&gt;(Copilot 실행), &lt;code class=&quot;language-text&quot;&gt;Win + W&lt;/code&gt;(위젯) 등이 있습니다.&lt;/p&gt;
&lt;h3&gt;Q. 자주 쓰는 프로그램에 나만의 단축키를 지정할 수 있나요?&lt;/h3&gt;
&lt;p&gt;네, 가능합니다. 프로그램의 바로가기 아이콘을 우클릭 → 속성 → &quot;바로 가기 키&quot; 항목에 원하는 키 조합을 입력하면 됩니다. &lt;code class=&quot;language-text&quot;&gt;Ctrl + Alt + 원하는 키&lt;/code&gt; 형태로 지정할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;오늘 소개한 단축키 중 &lt;strong&gt;하나만이라도 오늘부터 써보세요.&lt;/strong&gt; 1주일이면 손에 붙고, 한 달이면 마우스 없이도 대부분의 작업이 가능해집니다.&lt;/p&gt;
&lt;p&gt;더 자세한 전체 단축키 목록은 &lt;a href=&quot;https://support.microsoft.com/ko-kr/windows/keyboard-shortcuts-in-windows-dcc61a57-8ff0-cffe-9796-cb9706c75eec&quot;&gt;Microsoft 공식 키보드 단축키 문서&lt;/a&gt;에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;여러분이 가장 자주 쓰는 윈도우 단축키는 뭔가요? 댓글로 알려주세요!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[파이썬 프로젝트 관리의 혁신: pipenv 사용가이드]]></title><description><![CDATA[…]]></description><link>http://blog.javapark.kr/pipenv/</link><guid isPermaLink="false">http://blog.javapark.kr/pipenv/</guid><pubDate>Sun, 28 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;파이썬 프로젝트 관리의 혁신: &lt;code class=&quot;language-text&quot;&gt;pipenv&lt;/code&gt; 사용 가이드&lt;/h1&gt;
&lt;h2&gt;서론: 파이썬과 패키지 관리의 중요성&lt;/h2&gt;
&lt;p&gt;파이썬은 그 유연성과 강력한 라이브러리 덕분에 전 세계적으로 사랑받는 프로그래밍 언어입니다. 하지만, 프로젝트가 커지면서 다양한 패키지를 효율적으로 관리하는 것이 중요해집니다. 여기서 &lt;code class=&quot;language-text&quot;&gt;pipenv&lt;/code&gt;의 역할이 빛을 발합니다!&lt;/p&gt;
&lt;h2&gt;&lt;code class=&quot;language-text&quot;&gt;pipenv&lt;/code&gt;란 무엇인가?&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;pipenv&lt;/code&gt;는 파이썬의 공식 권장 패키지 관리 도구로, 패키지 의존성 관리와 가상 환경 설정을 하나의 도구로 통합합니다. 이를 통해 프로젝트별 종속성 관리가 더욱 쉬워집니다.&lt;/p&gt;
&lt;h2&gt;&lt;code class=&quot;language-text&quot;&gt;pipenv&lt;/code&gt;의 설치 및 기본 사용법&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;설치&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; pipenv&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 명령어로 &lt;code class=&quot;language-text&quot;&gt;pipenv&lt;/code&gt;를 설치할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;프로젝트 시작&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; myproject
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; myproject
pipenv shell&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이렇게 하면 &lt;code class=&quot;language-text&quot;&gt;myproject&lt;/code&gt; 폴더 안에 새로운 가상 환경이 생성됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;패키지 설치&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pipenv &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; requests&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;필요한 패키지를 설치하고, 이는 자동으로 &lt;code class=&quot;language-text&quot;&gt;Pipfile&lt;/code&gt;에 기록됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;고급 사용법과 팁&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;개발 의존성&lt;/strong&gt;: 개발 중에만 필요한 패키지는 &lt;code class=&quot;language-text&quot;&gt;pipenv install --dev [패키지명]&lt;/code&gt;을 통해 관리합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;스크립트 실행&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;pipenv run python script.py&lt;/code&gt; 명령어로 스크립트를 실행할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;실습 예제: 웹 스크래핑&lt;/h2&gt;
&lt;p&gt;간단한 웹 스크래핑 프로젝트를 예로 들어보겠습니다. &lt;code class=&quot;language-text&quot;&gt;requests&lt;/code&gt;와 &lt;code class=&quot;language-text&quot;&gt;beautifulsoup4&lt;/code&gt;를 설치하고, 간단한 스크래핑 스크립트를 실행해봅니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pipenv &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; requests beautifulsoup4
pipenv run python scraper.py&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아래는 간단한 웹 스크래핑을 위한 &lt;code class=&quot;language-text&quot;&gt;scraper.py&lt;/code&gt;의 예시 코드입니다. 이 예제에서는 &lt;code class=&quot;language-text&quot;&gt;requests&lt;/code&gt;와 &lt;code class=&quot;language-text&quot;&gt;beautifulsoup4&lt;/code&gt;를 사용하여 웹 페이지의 HTML을 가져오고, 특정 요소를 파싱합니다.&lt;/p&gt;
&lt;h3&gt;scraper.py 예시 코드&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; requests
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; bs4 &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; BeautifulSoup

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scrape_website&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# URL에서 HTML을 가져옵니다.&lt;/span&gt;
    response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requests&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# 요청이 성공했는지 확인합니다.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status_code &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Failed to retrieve the webpage&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;# HTML 내용을 파싱합니다.&lt;/span&gt;
    soup &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BeautifulSoup&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;html.parser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;# 원하는 데이터를 추출합니다. (예: 모든 h1 태그)&lt;/span&gt;
    headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; soup&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;find_all&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;h1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; header &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; headers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;header&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 스크래핑할 웹사이트 URL&lt;/span&gt;
url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;http://example.com&quot;&lt;/span&gt;
scrape_website&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 코드는 기본적인 웹 스크래핑 구조를 보여줍니다. &lt;code class=&quot;language-text&quot;&gt;scrape_website&lt;/code&gt; 함수는 주어진 URL에서 HTML을 가져와 &lt;code class=&quot;language-text&quot;&gt;BeautifulSoup&lt;/code&gt;으로 파싱합니다. 이 예제에서는 모든 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;h1&gt;&lt;/code&gt; 태그의 텍스트를 찾아 출력합니다. 실제 사용 시에는 원하는 웹사이트 URL과 추출하고자 하는 데이터에 맞게 코드를 수정해야 합니다.&lt;/p&gt;
&lt;p&gt;주의: 웹 스크래핑을 할 때는 해당 웹사이트의 이용 약관을 준수하고, 과도한 요청으로 서버에 부하를 주지 않도록 주의해야 합니다.&lt;/p&gt;
&lt;h2&gt;결론&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;pipenv&lt;/code&gt;는 파이썬 프로젝트의 패키지 관리와 가상 환경 관리를 간소화해줍니다. 이를 통해 개발자는 프로젝트의 의존성을 보다 쉽게 관리할 수 있습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Ruff를 이용한 python 코드 품질 관리]]></title><description><![CDATA[Ruff 소개 최근 Python 개발자들 사이에서 Ruff가 많은 주목을 받고 있습니다. Ruff는 Python…]]></description><link>http://blog.javapark.kr/ruff/</link><guid isPermaLink="false">http://blog.javapark.kr/ruff/</guid><pubDate>Sun, 28 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Ruff 소개&lt;/h2&gt;
&lt;p&gt;최근 Python 개발자들 사이에서 Ruff가 많은 주목을 받고 있습니다. Ruff는 Python 코드의 품질을 향상시키는 데 도움이 되는 강력한 린트 도구입니다. 린트는 코딩 스타일, 프로그래밍 오류, 버그, 복잡한 구조 등을 분석하여 개선 방향을 제시하는 소프트웨어 도구입니다. Ruff는 빠른 성능과 사용 편의성으로 인해 많은 Python 개발자들에게 선택받고 있습니다.&lt;/p&gt;
&lt;h2&gt;Ruff의 장점&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;빠른 성능&lt;/strong&gt;: Ruff는 다른 린트 도구보다 빠른 분석 속도를 제공합니다. 이는 대규모 프로젝트에서도 효율적으로 사용할 수 있음을 의미합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;사용 용이성&lt;/strong&gt;: 설치 및 구성이 간단하며, 쉽게 사용할 수 있는 명령어 인터페이스를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자동화&lt;/strong&gt;: Ruff는 코드 작성 과정에서 자동으로 문제를 탐지하고 수정 제안을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Ruff 설치 및 사용&lt;/h2&gt;
&lt;h3&gt;설치 방법&lt;/h3&gt;
&lt;p&gt;Ruff는 Python의 패키지 관리자인 pip를 통해 쉽게 설치할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; ruff&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;사용 방법&lt;/h3&gt;
&lt;p&gt;Ruff를 사용하여 프로젝트의 코드를 분석하는 것은 매우 간단합니다. 터미널에서 다음 명령을 실행하기만 하면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ruff path/to/your/code&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;VS Code에서의 Python 코딩&lt;/h2&gt;
&lt;p&gt;Visual Studio Code (VS Code)는 다양한 프로그래밍 언어를 지원하는 인기 있는 코드 편집기입니다. Python 개발에도 매우 적합하며, Ruff와 같은 도구를 통합하여 사용할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;VS Code 설정&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Python 확장 설치&lt;/strong&gt;: VS Code의 마켓플레이스에서 Python 확장을 설치합니다. 이 확장은 Python 개발에 필요한 다양한 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ruff 통합&lt;/strong&gt;: Ruff는 VS Code의 설정을 통해 Python 개발 환경에 쉽게 통합될 수 있습니다. 이를 통해 코드를 작성하는 동안 실시간으로 피드백을 받을 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Python 코딩 예제&lt;/h3&gt;
&lt;p&gt;다음은 VS Code에서 Python 코드를 작성하고 Ruff를 사용하여 코드 품질을 관리하는 간단한 예제입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 예제 코드&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;example_function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
    y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

example_function&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 코드를 VS Code에서 작성하고 Ruff를 실행하면, Ruff는 코드 스타일과 구조상의 문제를 지적해 줄 것입니다. 예를 들어, 함수 내의 변수와 연산자 사이의 공백, 함수 정의와 호출 사이의 공백 등을 조정할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;이러한 방식으로 Ruff와 VS Code를 활용하면 Python 개발 과정에서 코드 품질을 지속적으로 관리하고 개선할 수 있습니다. 더 나은 코드 품질로 안정적이고 효율적인 Python 애플리케이션 개발을 지향하는 개발자들에게 이러한 도구는 매우 유용합니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[pyenv 를 이용한 파이썬 버전관리]]></title><description><![CDATA[Python 버전 관리의 중요성 Python은 지속적으로 발전하고 있는 프로그래밍 언어입니다. 다양한 버전의 Python이 공존하며, 각 프로젝트나 라이브러리는 특정 Python…]]></description><link>http://blog.javapark.kr/pyenv/</link><guid isPermaLink="false">http://blog.javapark.kr/pyenv/</guid><pubDate>Sun, 28 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Python 버전 관리의 중요성&lt;/h3&gt;
&lt;p&gt;Python은 지속적으로 발전하고 있는 프로그래밍 언어입니다. 다양한 버전의 Python이 공존하며, 각 프로젝트나 라이브러리는 특정 Python 버전에 최적화되어 있습니다. 이 때문에 동일한 시스템에서 여러 버전의 Python을 효율적으로 관리하는 것이 중요합니다. Python 버전 관리는 호환성 문제를 해결하고, 프로젝트의 요구사항을 정확히 충족시키는 데 도움을 줍니다.&lt;/p&gt;
&lt;h3&gt;pyenv 소개&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;pyenv&lt;/code&gt;는 Python 버전을 관리하는 탁월한 도구입니다. 여러 버전의 Python을 설치하고, 각각의 프로젝트에 적합한 버전으로 쉽게 전환할 수 있게 해줍니다. &lt;code class=&quot;language-text&quot;&gt;pyenv&lt;/code&gt;는 사용자의 시스템에 여러 Python 버전을 설치하고, 필요에 따라 전환하는 것을 간단한 명령어로 가능하게 합니다.&lt;/p&gt;
&lt;h3&gt;pyenv 설치 및 설정&lt;/h3&gt;
&lt;h4&gt;설치&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: Homebrew를 사용하여 &lt;code class=&quot;language-text&quot;&gt;brew install pyenv&lt;/code&gt; 명령어로 설치할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Linux&lt;/strong&gt;: Git을 통해 클론하거나 패키지 매니저를 사용하여 설치합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;pyenv-win&lt;/code&gt;을 사용하여 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;기본 설정&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;설치 후, &lt;code class=&quot;language-text&quot;&gt;pyenv&lt;/code&gt;를 시스템 경로에 추가해야 합니다.&lt;/li&gt;
&lt;li&gt;쉘 설정 파일(&lt;code class=&quot;language-text&quot;&gt;.bashrc&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;.zshrc&lt;/code&gt; 등)에 초기화 스크립트를 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;pyenv를 사용한 Python 버전 관리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;버전 설치&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;pyenv install 3.8.1&lt;/code&gt;과 같은 명령어로 특정 Python 버전을 설치합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전 전환&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;pyenv global 3.8.1&lt;/code&gt; 명령어로 전역 Python 버전을 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전 확인&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;python --version&lt;/code&gt;을 사용하여 현재 사용 중인 Python 버전을 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;실제 사용 사례&lt;/h3&gt;
&lt;p&gt;예를 들어, 프로젝트 A는 Python 3.7을, 프로젝트 B는 Python 3.9를 사용한다고 가정해 봅시다. &lt;code class=&quot;language-text&quot;&gt;pyenv&lt;/code&gt;를 사용하면 각 프로젝트 디렉토리에서 다른 버전의 Python을 설정할 수 있습니다. 이를 통해 각 프로젝트의 요구사항을 정확히 충족시키면서도 개발 환경을 깔끔하게 유지할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;pyenv와 가상 환경&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;pyenv-virtualenv&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;pyenv&lt;/code&gt;와 함께 사용하여 각 Python 버전에 대한 독립적인 가상 환경을 생성할 수 있습니다. 이는 라이브러리 의존성 관리를 간편하게 만들어 줍니다.&lt;/p&gt;
&lt;h3&gt;고급 팁과 트러블슈팅&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;팁&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;pyenv&lt;/code&gt; 명령어 자동완성 기능을 설정하여 사용성을 높일 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;문제 해결&lt;/strong&gt;: 설치 중 발생하는 문제들은 주로 환경 변수 설정이나 의존성 문제에서 비롯됩니다. 문제 발생 시 공식 문서나 커뮤니티를 참조하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;pyenv&lt;/code&gt;를 사용하면 Python 개발 환경을 효율적으로 관리할 수 있습니다. 이를 통해 개발자는 다양한 프로젝트에 유연하게 대응할 수 있으며, Python 개발의 생산성과 효율성을 크게 향상시킬 수 있습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[개발자들에게 형상관리는 선택이 아닌 필수]]></title><description><![CDATA[안녕하세요, 자바파커입니다. "혼자 개발하는데 Git이 필요한가요?" 결론부터 말씀드리면 — 혼자 개발할 때야말로 Git…]]></description><link>http://blog.javapark.kr/git/</link><guid isPermaLink="false">http://blog.javapark.kr/git/</guid><pubDate>Wed, 22 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요, &lt;strong&gt;자바파커&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;혼자 개발하는데 Git이 필요한가요?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;결론부터 말씀드리면 — &lt;strong&gt;혼자 개발할 때야말로 Git이 더 필요합니다.&lt;/strong&gt; 코드를 잘못 수정해서 되돌리고 싶을 때, 어제 작업한 내용이 뭔지 확인하고 싶을 때, 로컬 컴퓨터가 고장났을 때 — Git 없이는 모든 게 수작업입니다.&lt;/p&gt;
&lt;p&gt;이 글에서는 형상관리가 왜 필수인지, Git의 핵심 개념부터 실전 워크플로우까지 정리합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;형상관리란 무엇인가&lt;/h2&gt;
&lt;p&gt;형상관리(SCM, Source Code Management)는 &lt;strong&gt;소스 코드의 변경 이력을 체계적으로 관리하는 것&lt;/strong&gt;입니다. 단순히 백업하는 게 아니라, 누가, 언제, 왜, 무엇을 변경했는지를 기록합니다.&lt;/p&gt;
&lt;h3&gt;형상관리 없이 개발하면 생기는 일&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;프로젝트_최종.zip&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;프로젝트_최종_진짜최종.zip&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;프로젝트_최종_v3_수정.zip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&quot;어제 고친 코드가 뭐였지?&quot; — 기억에 의존&lt;/li&gt;
&lt;li&gt;&quot;이 버그, 언제부터 있었지?&quot; — 추적 불가&lt;/li&gt;
&lt;li&gt;컴퓨터 포맷하면 모든 히스토리 소실&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;형상관리 도구 비교&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;도구&lt;/th&gt;
&lt;th&gt;방식&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;현재 상태&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Git&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;분산형&lt;/td&gt;
&lt;td&gt;로컬 저장소, 브랜치 강력, 업계 표준&lt;/td&gt;
&lt;td&gt;압도적 1위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subversion (SVN)&lt;/td&gt;
&lt;td&gt;중앙집중형&lt;/td&gt;
&lt;td&gt;단순한 구조, 레거시 프로젝트&lt;/td&gt;
&lt;td&gt;유지보수 모드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mercurial&lt;/td&gt;
&lt;td&gt;분산형&lt;/td&gt;
&lt;td&gt;Git과 유사, 더 단순&lt;/td&gt;
&lt;td&gt;거의 사용 안 함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;2026년 현재 &lt;strong&gt;Git이 사실상 유일한 선택지&lt;/strong&gt;입니다. GitHub, GitLab, Bitbucket 모두 Git 기반입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Git 핵심 개념 — 이것만 알면 시작할 수 있다&lt;/h2&gt;
&lt;h3&gt;저장소 (Repository)&lt;/h3&gt;
&lt;p&gt;프로젝트의 모든 파일과 변경 이력이 저장되는 공간입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 새 저장소 생성&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; init

&lt;span class=&quot;token comment&quot;&gt;# 기존 저장소 복제&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/username/repo.git&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;스테이징과 커밋&lt;/h3&gt;
&lt;p&gt;Git의 작업 흐름은 3단계입니다:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;작업 디렉토리 → 스테이징 영역 → 저장소
 (수정)        (git add)      (git commit)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 변경된 파일 확인&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; status

&lt;span class=&quot;token comment&quot;&gt;# 파일을 스테이징에 추가&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; src/main.js

&lt;span class=&quot;token comment&quot;&gt;# 커밋 (변경 이력 저장)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;로그인 기능 추가&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 변경 이력 확인&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; log &lt;span class=&quot;token parameter variable&quot;&gt;--oneline&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;브랜치 (Branch)&lt;/h3&gt;
&lt;p&gt;브랜치는 &lt;strong&gt;독립적인 작업 공간&lt;/strong&gt;입니다. 메인 코드에 영향 주지 않고 새 기능을 개발할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 브랜치 생성 및 이동&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout &lt;span class=&quot;token parameter variable&quot;&gt;-b&lt;/span&gt; feature/login

&lt;span class=&quot;token comment&quot;&gt;# 작업 완료 후 메인에 병합&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout main
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; merge feature/login

&lt;span class=&quot;token comment&quot;&gt;# 브랜치 삭제&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; branch &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; feature/login&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;원격 저장소 (Remote)&lt;/h3&gt;
&lt;p&gt;GitHub, GitLab 같은 원격 서버에 코드를 저장합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 원격 저장소에 푸시&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push origin main

&lt;span class=&quot;token comment&quot;&gt;# 원격 저장소에서 가져오기&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; pull origin main&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;커밋 메시지 컨벤션 — 잘 쓰는 것이 중요하다&lt;/h2&gt;
&lt;p&gt;나쁜 커밋 메시지:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;수정
fix
ㅋㅋ
asdf&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;좋은 커밋 메시지:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;feat: 소셜 로그인 기능 추가
fix: 비밀번호 유효성 검사 오류 수정
docs: README에 설치 가이드 추가
refactor: 인증 미들웨어 구조 개선&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Conventional Commits 규칙&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;접두사&lt;/th&gt;
&lt;th&gt;용도&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;feat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새 기능&lt;/td&gt;
&lt;td&gt;feat: 검색 필터 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;fix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;버그 수정&lt;/td&gt;
&lt;td&gt;fix: 날짜 포맷 오류 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;docs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;문서 변경&lt;/td&gt;
&lt;td&gt;docs: API 문서 업데이트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;style&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;코드 스타일 (동작 변경 없음)&lt;/td&gt;
&lt;td&gt;style: 들여쓰기 정리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;refactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;리팩토링&lt;/td&gt;
&lt;td&gt;refactor: 유저 서비스 분리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;테스트 추가/수정&lt;/td&gt;
&lt;td&gt;test: 로그인 단위 테스트 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;chore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;빌드, 설정 변경&lt;/td&gt;
&lt;td&gt;chore: eslint 설정 업데이트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이 규칙을 따르면 &lt;code class=&quot;language-text&quot;&gt;git log&lt;/code&gt;만 봐도 프로젝트 히스토리를 한눈에 파악할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;브랜치 전략 — 팀 규모에 맞게&lt;/h2&gt;
&lt;h3&gt;혼자 개발할 때 (1인)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;main ──●──●──●──●──●&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; 브랜치 하나로 충분합니다. 커밋을 자주 하고, 의미 있는 단위로 나누세요.&lt;/p&gt;
&lt;h3&gt;소규모 팀 (2~5명)&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;main    ──●────────●────────●──
             \      /  \      /
feature/a  ──●──●──    ──●──●──&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;GitHub Flow&lt;/strong&gt; — &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;feature&lt;/code&gt; 브랜치만 사용합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;에서 &lt;code class=&quot;language-text&quot;&gt;feature/기능명&lt;/code&gt; 브랜치 생성&lt;/li&gt;
&lt;li&gt;작업 후 Pull Request 생성&lt;/li&gt;
&lt;li&gt;코드 리뷰 후 &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;에 병합&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;중규모 이상 팀&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;main    ──●──────────────●──
           \            /
develop  ──●──●──●──●──●──
              \  /
feature   ──●──●&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Git Flow&lt;/strong&gt; — &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;develop&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;feature&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;release&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;hotfix&lt;/code&gt; 브랜치를 사용합니다. 릴리즈 주기가 있는 프로젝트에 적합합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;실전 Git 워크플로우 — 매일 하는 루틴&lt;/h2&gt;
&lt;h3&gt;아침에 시작할 때&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 최신 코드 받기&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; pull origin main

&lt;span class=&quot;token comment&quot;&gt;# 작업 브랜치 생성&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout &lt;span class=&quot;token parameter variable&quot;&gt;-b&lt;/span&gt; feature/user-profile&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;작업 중&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 자주 커밋하기 (의미 있는 단위로)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; src/components/Profile.jsx
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;feat: 프로필 페이지 UI 구현&quot;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; src/services/user.js
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;feat: 프로필 데이터 조회 API 연동&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;작업 완료 후&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 원격에 푸시&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push origin feature/user-profile

&lt;span class=&quot;token comment&quot;&gt;# GitHub에서 Pull Request 생성&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 리뷰 후 병합&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;자주 쓰는 Git 명령어 정리&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;명령어&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 상태 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git diff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경 내용 비교&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git log --oneline&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;커밋 히스토리 (한 줄)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git stash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;작업 임시 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git stash pop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;임시 저장 복원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git reset HEAD~1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;마지막 커밋 취소 (변경 유지)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git checkout -- 파일명&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;파일 변경 취소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git blame 파일명&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;각 줄의 마지막 수정자 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;git rebase -i HEAD~3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;최근 3개 커밋 정리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;AI 시대의 형상관리&lt;/h2&gt;
&lt;p&gt;2026년 현재, AI 코딩 도구(Claude Code, Cursor, GitHub Copilot)가 코드를 대량으로 생성합니다. 이럴 때 형상관리가 더 중요해집니다.&lt;/p&gt;
&lt;h3&gt;AI와 Git을 함께 쓰는 팁&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AI가 생성한 코드도 의미 있는 단위로 커밋하세요.&lt;/strong&gt; &quot;AI가 만든 코드&quot;라고 한 덩어리로 커밋하면 나중에 추적이 어렵습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 작업 전에 브랜치를 만드세요.&lt;/strong&gt; AI가 예상과 다른 결과를 만들면 브랜치를 버리면 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;커밋 메시지에 AI 사용 여부를 남기세요.&lt;/strong&gt; &lt;code class=&quot;language-text&quot;&gt;Co-Authored-By&lt;/code&gt; 태그를 활용하면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;feat: 대시보드 차트 구현

Co-Authored-By: Claude &amp;lt;noreply@anthropic.com&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;.gitignore — 불필요한 파일 제외하기&lt;/h2&gt;
&lt;p&gt;프로젝트에 포함하면 안 되는 파일들을 &lt;code class=&quot;language-text&quot;&gt;.gitignore&lt;/code&gt;에 등록합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;gitignore&quot;&gt;&lt;pre class=&quot;language-gitignore&quot;&gt;&lt;code class=&quot;language-gitignore&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 의존성&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;node_modules&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;__pycache__&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 환경변수 (비밀키!)&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;.env&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;.env.local&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 빌드 결과물&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;dist&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;build&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;.cache&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# OS 파일&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;.DS_Store&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;Thumbs.db&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# IDE 설정&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;.vscode&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token entry string&quot;&gt;.idea&lt;span class=&quot;token punctuation&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;특히 &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; 파일은 &lt;strong&gt;절대 커밋하면 안 됩니다.&lt;/strong&gt; API 키, 비밀번호 등이 GitHub에 공개되면 보안 사고로 이어집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;h3&gt;Q1. 혼자 개발하는데 Git이 정말 필요한가요?&lt;/h3&gt;
&lt;p&gt;네. 혼자일 때야말로 &quot;3시간 전 코드로 돌아가고 싶다&quot;는 상황이 자주 옵니다. Git 없이는 Ctrl+Z를 수십 번 누르거나, 백업 폴더를 뒤져야 합니다. &lt;code class=&quot;language-text&quot;&gt;git log&lt;/code&gt;와 &lt;code class=&quot;language-text&quot;&gt;git checkout&lt;/code&gt;이면 몇 초 만에 해결됩니다.&lt;/p&gt;
&lt;h3&gt;Q2. Git과 GitHub는 다른 건가요?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Git&lt;/strong&gt;은 로컬에서 동작하는 버전 관리 도구이고, &lt;strong&gt;GitHub&lt;/strong&gt;는 Git 저장소를 호스팅하는 웹 서비스입니다. Git은 도구, GitHub는 플랫폼입니다. GitLab, Bitbucket도 같은 역할을 합니다.&lt;/p&gt;
&lt;h3&gt;Q3. 커밋은 얼마나 자주 해야 하나요?&lt;/h3&gt;
&lt;p&gt;&quot;의미 있는 변경 단위&quot;마다 커밋하세요. 하루에 한 번 큰 커밋보다, 기능 단위로 작은 커밋 여러 개가 훨씬 낫습니다. &quot;로그인 폼 UI 구현&quot;, &quot;로그인 API 연동&quot;, &quot;로그인 에러 처리&quot; — 이렇게 나누면 나중에 문제가 생겨도 특정 커밋만 되돌릴 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;관련 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/doc&quot;&gt;Git 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://skills.github.com/&quot;&gt;GitHub Skills — Git 학습&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.conventionalcommits.org/ko/&quot;&gt;Conventional Commits 스펙&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;Git Flow 소개&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;여러분은 Git을 어떻게 활용하고 계신가요? 나만의 워크플로우가 있다면 댓글로 공유해주세요!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[SheetJS]]></title><description><![CDATA[SheetJS는 다양한 형식의 스프레드시트 파일, 예를 들면 Excel (XLSX 및 XLS), CSV 및 기타 스프레드시트 형식을 읽고 쓸 수 있는 JavaScript…]]></description><link>http://blog.javapark.kr/sheetjs/</link><guid isPermaLink="false">http://blog.javapark.kr/sheetjs/</guid><pubDate>Thu, 09 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;SheetJS는 다양한 형식의 스프레드시트 파일, 예를 들면 Excel (XLSX 및 XLS), CSV 및 기타 스프레드시트 형식을 읽고 쓸 수 있는 JavaScript 라이브러리입니다. 이 라이브러리를 사용하면 웹 애플리케이션에서 스프레드시트 데이터를 처리할 수 있는 강력한 API를 제공합니다.&lt;/p&gt;
&lt;p&gt;SheetJS를 사용하면 서버 측 처리 없이도 브라우저에서 스프레드시트 데이터를 직접 조작할 수 있습니다. 이 라이브러리는 주로 웹 애플리케이션에서 Excel 파일 업로드, 데이터 내보내기 및 기타 스프레드시트 관련 작업을 처리하는 데 사용됩니다.&lt;/p&gt;
&lt;p&gt;SheetJS를 사용하려면 스크립트 태그를 사용하거나 npm 또는 yarn과 같은 패키지 관리자를 사용하여 라이브러리를 프로젝트에 포함시킬 수 있습니다. 다음은 JavaScript에서 Excel 파일을 읽는 예제입니다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;먼저 SheetJS 라이브러리를 HTML 파일에 포함시킵니다:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.0/xlsx.full.min.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;파일 업로드를 처리할 HTML 입력 요소를 만듭니다:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;file-input&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;output&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;파일 업로드를 처리하고 Excel 데이터를 읽는 JavaScript 코드를 추가합니다:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;file-input&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;change&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleFile&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; reader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FileReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  reader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onload&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; workbook &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;XLSX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;binary&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 첫 번째 시트를 읽고자 한다고 가정합니다&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sheetName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; workbook&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SheetNames&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sheet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; workbook&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Sheets&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;sheetName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 시트 데이터를 객체 배열로 파싱합니다&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; jsonData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;XLSX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;utils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sheet_to_json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sheet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 파싱된 데이터를 사용합니다&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;displayData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;jsonData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  reader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readAsBinaryString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;displayData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; outputDiv &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;output&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  outputDiv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 예제에서는 사용자가 파일을 선택하면 Excel 데이터를 읽고 파싱하여 화면에 표시하는 기본적인 동작을 구현한 것입니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[🎇 Next.js 미들웨어 설정하기]]></title><description><![CDATA[next.js에서 미들웨어 사용하기 Next.js에서 미들웨어를 사용하려면 next.config.js 파일을 생성하고 next.config.js 파일에서 middleware…]]></description><link>http://blog.javapark.kr/middleware/</link><guid isPermaLink="false">http://blog.javapark.kr/middleware/</guid><pubDate>Thu, 14 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;next.js에서 미들웨어 사용하기&lt;/h1&gt;
&lt;p&gt;Next.js에서 미들웨어를 사용하려면 next.config.js 파일을 생성하고 next.config.js 파일에서 middleware를 설정해야 합니다. 미들웨어는 페이지의 요청을 처리하기 전에 실행되는 함수로, 요청을 가로채고 수정할 수 있는 기능을 제공합니다.&lt;/p&gt;
&lt;p&gt;다음은 Next.js에서 미들웨어를 사용하는 방법입니다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;next.config.js 파일 생성: 프로젝트 루트 디렉토리에 next.config.js 파일을 생성합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;미들웨어 함수 작성: 미들웨어 함수를 작성합니다. 미들웨어 함수는 요청(request), 응답(response), 그리고 next() 함수를 인자로 받습니다. 예를 들어, 간단한 로깅 미들웨어를 작성해보겠습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// middleware/logger.js&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Request received for: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 다음 미들웨어나 핸들러로 요청을 전달&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;next.config.js&lt;/code&gt;에서 미들웨어 설정: `next.config.js`` 파일에서 미들웨어를 설정합니다. 미들웨어를 적용할 페이지나 API 경로를 지정할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// next.config.js&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rewrites&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api/:path*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;destination&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/api-handler/:path*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;redirects&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/old-route&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;destination&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/new-route&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;permanent&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/(.*)&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; securityHeaders&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;middleware&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;~/middleware/logger.js&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 미들웨어 파일의 상대 경로나 모듈 경로를 지정&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 예제에서는 logger.js 미들웨어를 설정에 추가하였습니다. 또한, rewrites, redirects, headers 섹션을 사용하여 리라이트, 리다이렉트, 헤더를 조작하는 미들웨어를 설정할 수도 있습니다.&lt;/p&gt;
&lt;p&gt;이제 Next.js 애플리케이션에서 미들웨어를 사용할 수 있습니다. 만약 특정 페이지나 API 경로에만 미들웨어를 적용하고 싶다면, next.config.js에서 해당 경로에 대한 미들웨어를 설정할 수 있습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[🎇 Next.js 미들웨어 설정하기 - 로그]]></title><description><![CDATA[개요 SSR 에서 서버에서 공통 로그를 남기려고 하는데 어떻게 시작해야 하는지 Chat GPT 에게 물어보았다. 1. Next.js 를 이용한 React Application 샘플 다음은 Next.js를 사용하여 React…]]></description><link>http://blog.javapark.kr/middleware-log/</link><guid isPermaLink="false">http://blog.javapark.kr/middleware-log/</guid><pubDate>Fri, 10 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;개요&lt;/h1&gt;
&lt;p&gt;SSR 에서 서버에서 공통 로그를 남기려고 하는데 어떻게 시작해야 하는지 Chat GPT 에게 물어보았다.&lt;/p&gt;
&lt;h1&gt;1. Next.js 를 이용한 React Application 샘플&lt;/h1&gt;
&lt;p&gt;다음은 Next.js를 사용하여 React 애플리케이션을 만드는 간단한 예제입니다.&lt;/p&gt;
&lt;p&gt;먼저, Next.js를 설치해야합니다. **&lt;code class=&quot;language-text&quot;&gt;npm&lt;/code&gt;**을 사용하여 설치할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm install next react react-dom&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그리고 이제 다음과 같이 &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;pages&lt;/code&gt;&lt;/strong&gt; 폴더를 만들고 &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;index.js&lt;/code&gt;&lt;/strong&gt; 파일을 생성합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;// pages/index.js

function Home() {
  return &amp;lt;div&gt;Welcome to Next.js!&amp;lt;/div&gt;;
}

export default Home;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그리고 마지막으로 다음과 같이 &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;&lt;/strong&gt; 파일에 다음을 추가하여 애플리케이션을 실행합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;{
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;next dev&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제 터미널에서 &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;npm run dev&lt;/code&gt;&lt;/strong&gt; 명령을 실행하고 브라우저에서 **&lt;code class=&quot;language-text&quot;&gt;http://localhost:3000&lt;/code&gt;**으로 이동하면 &quot;Welcome to Next.js!&quot;라는 텍스트가 표시되는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;이것은 Next.js를 사용하여 생성된 매우 간단한 React 애플리케이션입니다. 이제 Next.js를 더 깊이 이해하고 컴포넌트, 라우팅, 데이터 가져오기 등을 추가하여 애플리케이션을 더 발전시킬 수 있습니다.&lt;/p&gt;
&lt;h1&gt;2. 라우팅 추가&lt;/h1&gt;
&lt;p&gt;다음은 Next.js에서 라우팅을 추가하는 방법입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;pages&lt;/code&gt;&lt;/strong&gt; 폴더 안에 새로운 파일을 생성하여 라우트를 추가합니다. 파일 이름은 라우트 경로와 일치해야합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;// pages/about.js

function About() {
  return &amp;lt;div&gt;About us&amp;lt;/div&gt;;
}

export default About;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;Link&lt;/code&gt;&lt;/strong&gt; 컴포넌트를 사용하여 라우트로 이동할 수 있는 링크를 만듭니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;// pages/index.js

import Link from &apos;next/link&apos;;

function Home() {
  return (
    &amp;lt;div&gt;
      &amp;lt;div&gt;Welcome to Next.js!&amp;lt;/div&gt;
      &amp;lt;Link href=&quot;/about&quot;&gt;
        About us
      &amp;lt;/Link&gt;
    &amp;lt;/div&gt;
  );
}

export default Home;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;next/router&lt;/code&gt;&lt;/strong&gt; 모듈을 사용하여 프로그래밍 방식으로 라우팅을 수행할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;jsxCopy code
// pages/index.js

import { useRouter } from &apos;next/router&apos;;

function Home() {
  const router = useRouter();

  const handleClick = (e) =&gt; {
    e.preventDefault();
    router.push(&apos;/about&apos;);
  };

  return (
    &amp;lt;div&gt;
      &amp;lt;div&gt;Welcome to Next.js!&amp;lt;/div&gt;
      &amp;lt;Link href=&quot;/about&quot;&gt;
        About us
      &amp;lt;/Link&gt;
      &amp;lt;button onClick={handleClick}&gt;Go to about page&amp;lt;/button&gt;
    &amp;lt;/div&gt;
  );
}

export default Home;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제 **&lt;code class=&quot;language-text&quot;&gt;http://localhost:3000&lt;/code&gt;**에서 클릭 가능한 링크와 버튼이 있으며, 클릭하면 &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;http://localhost:3000/about&lt;/code&gt;&lt;/strong&gt; 페이지로 이동합니다.&lt;/p&gt;
&lt;h1&gt;3. 요청 마다 로그를 남기려면?&lt;/h1&gt;
&lt;p&gt;Next.js에서 각 요청마다 로그를 남기려면 미들웨어 함수를 사용할 수 있습니다. 미들웨어 함수는 요청과 응답에 대한 핸들러 함수로, 이를 사용하여 로그를 남기고 다음 미들웨어로 요청을 전달할 수 있습니다.&lt;/p&gt;
&lt;p&gt;다음은 Next.js에서 미들웨어 함수를 사용하여 각 요청마다 로그를 남기는 방법입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;server.js&lt;/code&gt;&lt;/strong&gt; 파일을 생성합니다. 이 파일은 Next.js에서 서버 측 렌더링을 구성하는 데 사용됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;// server.js

const express = require(&apos;express&apos;);
const next = require(&apos;next&apos;);

const dev = process.env.NODE_ENV !== &apos;production&apos;;
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() =&gt; {
  const server = express();

  // 미들웨어 함수를 등록합니다.
  server.use((req, res, next) =&gt; {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    next();
  });

  server.get(&apos;*&apos;, (req, res) =&gt; {
    return handle(req, res);
  });

  server.listen(3000, (err) =&gt; {
    if (err) throw err;
    console.log(&apos;&gt; Ready on http://localhost:3000&apos;);
  });
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;server.js&lt;/code&gt;&lt;/strong&gt; 파일에서 등록한 미들웨어 함수는 각 요청마다 로그를 출력합니다. &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;console.log&lt;/code&gt;&lt;/strong&gt; 대신 파일에 로그를 기록하거나 로그 서버로 전송하는 등의 작업을 수행할 수도 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이제 Next.js 애플리케이션을 시작하면 각 요청에 대한 로그가 콘솔에 출력됩니다. 미들웨어 함수를 사용하면 요청을 가로채고 필요한 작업을 수행할 수 있으므로, 요청을 기록하는 것 외에도 인증, 권한 부여, 캐싱 등의 작업을 수행할 수 있습니다.&lt;/p&gt;
&lt;h1&gt;4. 실행방법&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;server.js&lt;/code&gt;&lt;/strong&gt; 파일을 만든 후에는 다음 명령어를 사용하여 Next.js 애플리케이션을 실행합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;node server.js&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 명령어는 Node.js로 &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;server.js&lt;/code&gt;&lt;/strong&gt; 파일을 실행합니다. &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;server.js&lt;/code&gt;&lt;/strong&gt; 파일은 Next.js에서 서버 측 렌더링을 구성하는 데 사용되므로, 이 파일을 실행하면 Next.js 애플리케이션이 서버에서 실행됩니다.&lt;/p&gt;
&lt;p&gt;애플리케이션이 실행되면 브라우저에서 **&lt;code class=&quot;language-text&quot;&gt;http://localhost:3000&lt;/code&gt;**에 접속하여 애플리케이션을 확인할 수 있습니다. 이때 &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;server.js&lt;/code&gt;&lt;/strong&gt; 파일에서 등록한 미들웨어 함수가 요청을 가로채고 로그를 남길 것입니다.&lt;/p&gt;
&lt;p&gt;서버에서 애플리케이션을 실행하려면 &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;server.js&lt;/code&gt;&lt;/strong&gt; 파일이 포함된 디렉토리에서 위 명령어를 실행해야 합니다.&lt;/p&gt;
&lt;h1&gt;결과&lt;/h1&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:00.827Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/webpack.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262580782
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:00.831Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/main.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262580782
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:00.834Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/react&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;refresh.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262580782       
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:00.837Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/pages/_app.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262580782
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:00.841Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/pages/index.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262580782
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:00.842Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/development/_buildManifest.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262580782 
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:00.848Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/development/_ssgManifest.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262580782
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:01.055Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/development/_devMiddlewareManifest.json
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.658Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.682Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/webpack.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262583664
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.683Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/main.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262583664
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.684Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/react&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;refresh.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262583664       
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.688Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/pages/_app.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262583664
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.689Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/pages/index.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262583664
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.690Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/development/_buildManifest.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262583664 
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.693Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/development/_ssgManifest.js&lt;span class=&quot;token punctuation&quot;&gt;?&lt;/span&gt;ts=1678262583664   
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:03.885Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/development/_devMiddlewareManifest.json
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:05.912Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/development/_devPagesManifest.json
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token datetime number&quot;&gt;2023-03-08T08:03:05.920Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; GET /_next/static/chunks/pages/about.js
wait  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; compiling /about&lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[🎇 1. VuePress 시작하기]]></title><description><![CDATA[VuePress 시작하기 VuePress 를 이용하여 TIL 을 작성하려고 한다. VuePress 를 이용하여 md 파일을 html 로 변환하고 이를 서비스 하려고 한다. 그럼 Vuepress 는 무엇인가? Vuepress 는 무엇? Vuepress…]]></description><link>http://blog.javapark.kr/getting-started/</link><guid isPermaLink="false">http://blog.javapark.kr/getting-started/</guid><pubDate>Wed, 26 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;VuePress 시작하기&lt;/h1&gt;
&lt;p&gt;VuePress 를 이용하여 TIL 을 작성하려고 한다. VuePress 를 이용하여 md 파일을 html 로 변환하고 이를 서비스 하려고 한다. 그럼 Vuepress 는 무엇인가?&lt;/p&gt;
&lt;h2&gt;Vuepress 는 무엇?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Vuepress 는 Vue.js 로 개발되어진 정적 사이트 생성기이다&lt;/li&gt;
&lt;li&gt;기술문서 작성을 위해 최적화된 기본테마를 제공해준다&lt;/li&gt;
&lt;li&gt;Plugin API를 제공해주어 플러그인을 제작하거나 적용할 수 있다. ( Google Analytics, PWA 를 손쉽게 적용가능함 )&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;기본 설치 및 빌드&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# global install&lt;/span&gt;
$ &lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; global &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; vuepress

&lt;span class=&quot;token comment&quot;&gt;# install as a local dependency&lt;/span&gt;
$ &lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; vuepress

$ &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; docs

&lt;span class=&quot;token comment&quot;&gt;# 마크다운 파일을 생성한다.&lt;/span&gt;
$ &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;# Hello VuePress&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; docs/README.md&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;package.json 에 scripts 추가&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;docs:dev&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vuepress dev docs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;docs:build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vuepress build docs&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Development Mode&lt;/span&gt;
$ &lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; docs:dev

&lt;span class=&quot;token comment&quot;&gt;# build to static files&lt;/span&gt;
$ &lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; docs:build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Directory Structure&lt;/h2&gt;
&lt;p&gt;VuePress 에서 권장되는 구조는 아래와 같다&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.
├── docs
│   ├── .vuepress (Optional)
│   │   ├── components (Optional)
│   │   ├── theme (Optional)
│   │   │   └── Layout.vue
│   │   ├── public (Optional)
│   │   ├── styles (Optional)
│   │   │   ├── index.styl
│   │   │   └── palette.styl
│   │   ├── templates (Optional, Danger Zone)
│   │   │   ├── dev.html
│   │   │   └── ssr.html
│   │   ├── config.js (Optional)
│   │   └── enhanceApp.js (Optional)
│   │ 
│   ├── README.md
│   ├── guide
│   │   └── README.md
│   └── config.md
│ 
└── package.json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;:::warning Note
자세한 사항은 &lt;a href=&quot;https://vuepress.vuejs.org/guide/directory-structure.html#default-page-routing&quot;&gt;VuePress 공식문서&lt;/a&gt; 를 참고하길 바란다
:::&lt;/p&gt;
&lt;h2&gt;Default Page Routing&lt;/h2&gt;
&lt;p&gt;타겟 디렉토리로 &lt;code class=&quot;language-text&quot;&gt;docs&lt;/code&gt; 를 사용한다. 아래의 모든 &apos;상대경로&apos;는 &lt;code class=&quot;language-text&quot;&gt;docs&lt;/code&gt; 디렉토리에 상대적이다.
기본 페이지 라우팅 경로는 다음과 같다&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;경로&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;페이지 라우팅&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/README.md&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/guide/README.md&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/guide/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/config.md&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/config.html&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Maekdown Extensions&lt;/h2&gt;
&lt;h3&gt;Syntax Highlighting in Code Blocks&lt;/h3&gt;
&lt;p&gt;input&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;
``` js
export default {
  name: &apos;MyComponent&apos;,
  // ...
}
```
&lt;/pre&gt;
&lt;p&gt;output&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;MyComponent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Line Numbers&lt;/h3&gt;
&lt;p&gt;You can enable line numbers for each code blocks via config:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;markdown&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;lineNumbers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Deploying&lt;/h2&gt;
&lt;h3&gt;GitHub Pages&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;docs/.vuepress/config.js&lt;/code&gt; 에 base 설정&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;https://github.com/&amp;lt;USERNAME&gt;/&amp;lt;REPO&gt;&lt;/code&gt; 의 경우 base 는 &quot;/&lt;REPO&gt;/&quot; 가 됨&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;프로젝트 내에 deploy.sh 설정&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/usr/bin/env sh&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# abort on errors&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# build&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run docs:build

&lt;span class=&quot;token comment&quot;&gt;# navigate into the build output directory&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; docs/.vuepress/dist

&lt;span class=&quot;token comment&quot;&gt;# if you are deploying to a custom domain&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# echo &apos;www.example.com&apos; &gt; CNAME&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; init
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-A&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;deploy&apos;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# if you are deploying to https://&amp;lt;USERNAME&gt;.github.io&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# git push -f git@github.com:&amp;lt;USERNAME&gt;/&amp;lt;USERNAME&gt;.github.io.git master&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# if you are deploying to https://&amp;lt;USERNAME&gt;.github.io/&amp;lt;REPO&gt;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; https://github.com/javapark/javapark.github.io.git master:gh-pages

&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; -&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;main.yaml&lt;/code&gt; 설정&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;name: Build and Deploy
on: [push]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@main

    - name: Vuepress deploy
      uses: jenkey2011/vuepress-deploy@1.0.1
      env:
        ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
        BUILD_SCRIPT: yarn &amp;amp;&amp;amp; yarn docs:build
        TARGET_BRANCH: gh-pages
        BUILD_DIR: docs/.vuepress/dist&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;&lt;a href=&quot;https://vuepress.vuejs.org/guide/deploy.html#netlify&quot;&gt;Netlify&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; , setup up a new project from GitHub with the following settings:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build Command:&lt;/strong&gt; vuepress build docs or yarn docs:build or npm run docs:build&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Publish directory:&lt;/strong&gt; docs/.vuepress/dist&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Hit the deploy button&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Ref&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://limdongjin.github.io/vuejs/vuepress/#table-of-contents&quot;&gt;Vuepress 로 기술문서 빠르게 만들어보자&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vuepress.vuejs.org/&quot;&gt;VuePress&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;Comment /&gt;</content:encoded></item></channel></rss>