<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>devNote</title>
    <link>https://sddev.tistory.com/</link>
    <description>노력형 영재의 개발 블로그입니다.
IT에 대한 생각, 개발 지식 등을 정리합니다.</description>
    <language>ko</language>
    <pubDate>Sat, 4 Jul 2026 20:41:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>sddev</managingEditor>
    <image>
      <title>devNote</title>
      <url>https://tistory1.daumcdn.net/tistory/4044297/attach/e92cce42109d4e9d80495784dcd9d917</url>
      <link>https://sddev.tistory.com</link>
    </image>
    <item>
      <title>[Docker] 실무에서 당장 써먹는 Docker Logs 핵심 명령어 5가지 요약</title>
      <link>https://sddev.tistory.com/479</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 컨테이너를 운영하다 보면 &quot;방금 찍힌 에러 로그가 뭐지?&quot;, &quot;어제 새벽 3시에 무슨 일이 있었지?&quot; 같은 상황을 직면하게 됩니다. 수백 만 줄의 로그 속에서 길을 잃지 않기 위해, 실무에서 가장 활용도가 높은 실용적인 명령어 패턴을 정리해 보았습니다. 이 5가지만 기억해도 로그 확인 시간이 절반으로 줄어듭니다.&lt;br /&gt;&lt;b&gt;1. 실시간 로그 모니터링: &lt;/b&gt;-f&lt;b&gt; (Follow)&lt;/b&gt;&lt;br /&gt;가장 기본적이면서도 가장 많이 쓰는 명령어입니다. 배포 직후 서버가 정상적으로 떴는지 확인하거나, 실시간으로 들어오는 요청을 모니터링할 때 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;apache&quot; style=&quot;background-color: #f5f5f5;&quot;&gt;&lt;code&gt;docker logs -f [컨테이너_이름]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Tip&lt;/b&gt;: 로그가 너무 빠르게 올라가서 멈추고 싶다면 Ctrl + C로 빠져나올 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 최근 N줄만 깔끔하게 보기: &lt;/b&gt;--tail&lt;br /&gt;컨테이너가 몇 달 동안 켜져 있었다면, docker logs를 그냥 쳤을 때 수 기가바이트(GB)의 과거 로그가 터미널을 덮어버려 렉이 걸릴 수 있습니다. 최근 쌓인 로그만 빠르게 확인하세요.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f5f5f5;&quot;&gt;&lt;code&gt;# 최근 100줄만 출력
docker logs --tail 100 [컨테이너_이름]

# 최근 50줄을 출력하면서, 앞으로 쌓일 로그도 실시간으로 보기 (가장 추천!)
docker logs -f --tail 50 [컨테이너_이름]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;3. 특정 시간대 범인 찾기: &lt;/b&gt;--since&lt;b&gt; &amp;amp; &lt;/b&gt;--until&lt;br /&gt;&quot;오늘 오후 3시 40분쯤에 API가 터졌다&quot;는 제보를 받았다면, 특정 시간대만 타임머신을 타고 돌아가듯 격리해서 봐야 합니다.&lt;/p&gt;
&lt;pre class=&quot;css&quot; style=&quot;background-color: #f5f5f5;&quot;&gt;&lt;code&gt;# 날짜와 정확한 시간 지정 (YYYY-MM-DDTHH:MM:SS)
docker logs --since &quot;2026-07-02T15:40:00&quot; --until &quot;2026-07-02T15:50:00&quot; [컨테이너_이름]

# 인간 친화적인 상대 시간 지정 (30분 전부터 10분 전까지)
docker logs --since 30m --until 10m [컨테이너_이름]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;m은 분(Minutes), h는 시간(Hours), d는 일(Days) 단위로 쓸 수 있어서 --since 3h 형태로도 자주 쓰입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 로그에 강제로 시간표시 하기: &lt;/b&gt;-t&lt;b&gt; (Timestamps)&lt;/b&gt;&lt;br /&gt;컨테이너 내부 애플리케이션 프레임워크 설정을 잘못해서 로그에 &quot;언제 이 로그가 찍혔는지&quot; 시간이 나오지 않을 때가 있습니다. 이때 도커 엔진이 기억하는 타임스탬프를 강제로 주입할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;apache&quot; style=&quot;background-color: #f5f5f5;&quot;&gt;&lt;code&gt;docker logs -t [컨테이너_이름]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;결과 비교&lt;/b&gt;:&lt;br /&gt;&amp;bull; 기본: [INFO] Connection accepted.&lt;br /&gt;&amp;bull; -t 적용: 2026-07-02T15:42:01.123456789Z [INFO] Connection accepted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 에러 로그만 필터링하거나 검색하기: &lt;/b&gt;grep&lt;b&gt; 조합&lt;/b&gt;&lt;br /&gt;특정 키워드(예: Exception, Error, 404)가 포함된 로그만 골라내고 싶을 때 리눅스의 grep과 조합합니다. 여기서 핵심 포인트는 2&amp;gt;&amp;amp;1 리다이렉션입니다. 도커의 표준 에러(stderr)까지 파이프로 넘겨주어야 놓치는 로그가 없습니다.&lt;/p&gt;
&lt;pre class=&quot;autoit&quot; style=&quot;background-color: #f5f5f5;&quot;&gt;&lt;code&gt;# 'Exception'이 포함된 로그 검색
docker logs [컨테이너_이름] 2&amp;gt;&amp;amp;1 | grep &quot;Exception&quot;

# 실시간으로 들어오는 로그 중 'ERROR'라는 단어만 실시간 감시
docker logs -f [컨테이너_이름] 2&amp;gt;&amp;amp;1 | grep &quot;ERROR&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;  한눈에 보는 요약 치트시트 (Cheat Sheet)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황명령어 조합&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;방금 배포하고 잘 돌아가는지 볼 때&lt;/td&gt;
&lt;td&gt;docker logs &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;-f --tail&lt;/b&gt; &lt;/span&gt;100 &amp;lt;name&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;어제 하루 동안 쌓인 에러 확인할 때&lt;/td&gt;
&lt;td&gt;docker logs &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;--since&lt;/span&gt;&lt;/b&gt; 24h &amp;lt;name&amp;gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; 2&amp;gt;&amp;amp;1 | grep&lt;/b&gt;&lt;/span&gt; &quot;ERROR&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;특정 장애 발생 시간 10분간을 분석할 때&lt;/td&gt;
&lt;td&gt;docker logs &lt;span style=&quot;color: #ee2323;&quot;&gt;--since&lt;/span&gt; &quot;시간&quot; --until &quot;시간&quot; -t &amp;lt;name&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/479</guid>
      <comments>https://sddev.tistory.com/479#entry479comment</comments>
      <pubDate>Thu, 2 Jul 2026 16:23:32 +0900</pubDate>
    </item>
    <item>
      <title>[AI] Claude Code 실용적 활용 팁 9가지 (소스코드 분석 기반)</title>
      <link>https://sddev.tistory.com/478</link>
      <description>&lt;blockquote data-pm-slice=&quot;2 1 []&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출처:&lt;/b&gt; &lt;a href=&quot;https://www.threads.com/@unclejobs.ai/post/DWjHEgOiT9U/%EC%9C%A0%EC%B6%9C%EB%90%9C-claude-code-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C%EB%A5%BC-%EB%9C%AF%EC%96%B4%EB%B3%B8-%EC%82%AC%EB%9E%8C%EC%9D%B4-%EC%A0%95%EB%A6%AC%EB%A5%BC-%ED%95%B4%EC%A4%AC%EC%8A%B5%EB%8B%88%EB%8B%A4%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-51%EB%A7%8C-%EC%A4%84%EC%9D%84-%EC%9D%BD%EA%B3%A0%EB%B3%B8%EC%9D%B4-%EB%A7%90%EB%A1%9C%EB%8A%94-%EB%82%B4%EA%B0%80-%EC%9D%BC%EC%97%88%EB%8B%A4%EA%B8%B0%EB%B3%B4%EB%8B%A4-claude-cod&quot;&gt;unclejobs.ai (Threads)&lt;/a&gt; &lt;b&gt;요약:&lt;/b&gt; Claude Code 소스코드 분석을 통해 밝혀진, 단순 채팅을 넘어 '에이전트 오케스트레이션 플랫폼'으로 활용하기 위한 구체적인 설정 및 사용법.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;span style=&quot;color: #ee2323;&quot;&gt;CLAUDE.md는 매 턴마다 다시 읽힙니다&lt;/span&gt;.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 시작 시 한 번만 읽는 것이 아니라, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;메시지를 보낼 때마다 다시 읽습니다&lt;/span&gt;.&lt;/b&gt; 이는 소스코드에서 확인된 동작으로, AI의 행동을 제어하는 가장 강력한 수단입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;4단계 계층 구조:&lt;/b&gt; 글로벌 (~/.claude/CLAUDE.md), 프로젝트 (./CLAUDE.md), 모듈별 규칙 (.claude/rules/*.md), 로컬 메모 (CLAUDE.local.md) 순으로 적용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활용법:&lt;/b&gt; 아키텍처 결정, 파일 규칙, 테스트 패턴, &quot;절대 하지 말아야 할&quot; 규칙 등을 명시해두면 매번 AI의 판단에 반영됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 서브에이전트 5개를 돌려도 비용은 1개와 거의 같습니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브에이전트를 생성(fork)하면 부모 컨텍스트의 바이트 단위 복사본을 만들고, API가 이 프롬프트를 캐시하기 때문에 비용이 거의 늘어나지 않습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;3가지 실행 모델:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fork: 부모 컨텍스트를 상속하여 캐시 효율을 극대화합니다.&lt;/li&gt;
&lt;li&gt;teammate: 별도 터미널 패널(tmux/iTerm)에서 파일 기반 메일박스로 통신합니다.&lt;/li&gt;
&lt;li&gt;worktree: 독립된 git 워크트리로 에이전트별 브랜치를 격리하여 안전하게 작업합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시사점:&lt;/b&gt; 보안 감사, 리팩토링, 테스트 작성, 문서 업데이트, 버그 수정을 &lt;b&gt;동시에 병렬로&lt;/b&gt; 처리할 수 있는 구조가 이미 내장되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 권한 팝업을 매번 클릭하는 것은 설정 실패입니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이 작업을 허용할까요?&quot; 팝업이 뜰 때마다 클릭하는 것은 정상적인 사용 경험이 아닙니다. settings.json에 glob 패턴으로 허용 범위를 미리 지정해두어야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;설정 예시:&lt;/b&gt; Bash(npm *), Bash(git *), Edit(src/**) 와 같이 허용할 명령어와 파일 범위를 명시할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Auto 모드:&lt;/b&gt; 새로 생긴 auto 모드는 LLM 분류기가 각 동작의 위험도를 판단하여 안전한 작업은 자동으로 승인해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 5가지 컨텍스트 압축 전략을 이해하고 활용해야 합니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Anthropic 엔지니어들이 컨텍스트 초과 문제 해결에 많은 노력을 기울였다는 증거입니다. 자동 압축을 기다리기보다, 필요할 때 수동으로 개입하는 것이 중요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;5가지 전략:&lt;/b&gt; microcompact(오래된 도구 결과 제거), context collapse(대화 구간 요약), session memory(핵심 맥락 파일 추출), full compact(전체 히스토리 요약), PTL truncation(가장 오래된 메시지 그룹 폐기)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 조언:&lt;/b&gt; /compact 명령어를 게임의 '수동 세이브'처럼 사용하세요. 중요한 맥락이 날아가기 전에 보존하고 불필요한 내용은 정리할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Hook 시스템이 진짜 확장 API입니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PreToolUse(도구 실행 전), PostToolUse(실행 후), UserPromptSubmit(메시지 전송 시) 등 25개 이상의 라이프사이클 이벤트에 사용자 정의 로직을 연결할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UserPromptSubmit 훅:&lt;/b&gt; 메시지를 보낼 때마다 자동으로 테스트 결과나 최신 git diff를 컨텍스트에 첨부할 수 있어 매우 강력합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;5가지 훅 종류:&lt;/b&gt; command(쉘 명령), prompt(LLM 맥락 주입), agent(에이전트 검증), HTTP(웹훅), function(JS 실행)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 세션을 매번 새로 시작하지 마세요.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 대화는 JSONL 파일로 저장되며, 세션을 이어가면 session memory가 축적되어 AI가 더 똑똑하게 행동합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;세션 명령어:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;--continue: 마지막 세션을 이어서 시작합니다.&lt;/li&gt;
&lt;li&gt;--resume: 특정 세션을 골라서 다시 엽니다.&lt;/li&gt;
&lt;li&gt;--fork-session: 과거 대화의 특정 지점에서 새로운 브랜치를 만듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비유:&lt;/b&gt; 매번 새 세션을 여는 것은 IDE를 1시간마다 껐다 켜는 것과 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 읽기는 병렬, 쓰기는 순차입니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code는 속도와 안정성을 모두 고려하여 도구를 실행합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;병렬 실행 (읽기):&lt;/b&gt; 파일 10개를 읽어야 하면 동시에 읽어 속도를 높입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순차 실행 (쓰기):&lt;/b&gt; 파일 3개를 수정해야 하면 충돌 방지를 위해 하나씩 순서대로 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 중간에 끊는 것을 두려워하지 마세요.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 파이프라인이 비동기 제너레이터 방식으로 동작하므로, Esc 키를 누르면 현재 스트리밍만 깔끔하게 중단되고 이전 맥락은 그대로 보존됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시사점:&lt;/b&gt; AI가 잘못된 방향으로 가고 있다면, 끝까지 기다리지 말고 즉시 중단하고 방향을 바로잡아주는 것이 효율적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. 결론: 설정하고, 병렬로 돌리고, 세션을 이어가세요.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code를 잘 쓰는 것은 프롬프트 엔지니어링의 영역이 아닙니다. 소스코드 분석 결과, 이 도구는 단순한 터미널 채팅이 아니라 **'에이전트 오케스트레이션 플랫폼'**에 가깝습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심:&lt;/b&gt; 설정을 통해 권한을 자동화하고, Hook으로 필요한 정보를 주입하며, 병렬 에이전트로 작업을 동시에 처리하고, 세션을 이어가며 컨텍스트를 축적하는 것이 핵심입니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능 ∕ AI</category>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/478</guid>
      <comments>https://sddev.tistory.com/478#entry478comment</comments>
      <pubDate>Thu, 2 Jul 2026 16:15:44 +0900</pubDate>
    </item>
    <item>
      <title>[AI] Claude Code 실용적 활용 팁 9가지 (소스코드 분석 기반)</title>
      <link>https://sddev.tistory.com/477</link>
      <description>&lt;blockquote data-pm-slice=&quot;2 1 []&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출처:&lt;/b&gt; &lt;a href=&quot;https://www.threads.com/@unclejobs.ai/post/DWjHEgOiT9U/%EC%9C%A0%EC%B6%9C%EB%90%9C-claude-code-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C%EB%A5%BC-%EB%9C%AF%EC%96%B4%EB%B3%B8-%EC%82%AC%EB%9E%8C%EC%9D%B4-%EC%A0%95%EB%A6%AC%EB%A5%BC-%ED%95%B4%EC%A4%AC%EC%8A%B5%EB%8B%88%EB%8B%A4%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-51%EB%A7%8C-%EC%A4%84%EC%9D%84-%EC%9D%BD%EA%B3%A0%EB%B3%B8%EC%9D%B4-%EB%A7%90%EB%A1%9C%EB%8A%94-%EB%82%B4%EA%B0%80-%EC%9D%BC%EC%97%88%EB%8B%A4%EA%B8%B0%EB%B3%B4%EB%8B%A4-claude-cod&quot;&gt;unclejobs.ai (Threads)&lt;/a&gt; &lt;b&gt;요약:&lt;/b&gt; Claude Code 소스코드 분석을 통해 밝혀진, 단순 채팅을 넘어 '에이전트 오케스트레이션 플랫폼'으로 활용하기 위한 구체적인 설정 및 사용법.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;span style=&quot;color: #ee2323;&quot;&gt;CLAUDE.md는 매 턴마다 다시 읽힙니다&lt;/span&gt;.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 시작 시 한 번만 읽는 것이 아니라, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;메시지를 보낼 때마다 다시 읽습니다&lt;/span&gt;.&lt;/b&gt; 이는 소스코드에서 확인된 동작으로, AI의 행동을 제어하는 가장 강력한 수단입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;4단계 계층 구조:&lt;/b&gt; 글로벌 (~/.claude/CLAUDE.md), 프로젝트 (./CLAUDE.md), 모듈별 규칙 (.claude/rules/*.md), 로컬 메모 (CLAUDE.local.md) 순으로 적용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활용법:&lt;/b&gt; 아키텍처 결정, 파일 규칙, 테스트 패턴, &quot;절대 하지 말아야 할&quot; 규칙 등을 명시해두면 매번 AI의 판단에 반영됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 서브에이전트 5개를 돌려도 비용은 1개와 거의 같습니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브에이전트를 생성(fork)하면 부모 컨텍스트의 바이트 단위 복사본을 만들고, API가 이 프롬프트를 캐시하기 때문에 비용이 거의 늘어나지 않습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;3가지 실행 모델:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fork: 부모 컨텍스트를 상속하여 캐시 효율을 극대화합니다.&lt;/li&gt;
&lt;li&gt;teammate: 별도 터미널 패널(tmux/iTerm)에서 파일 기반 메일박스로 통신합니다.&lt;/li&gt;
&lt;li&gt;worktree: 독립된 git 워크트리로 에이전트별 브랜치를 격리하여 안전하게 작업합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시사점:&lt;/b&gt; 보안 감사, 리팩토링, 테스트 작성, 문서 업데이트, 버그 수정을 &lt;b&gt;동시에 병렬로&lt;/b&gt; 처리할 수 있는 구조가 이미 내장되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 권한 팝업을 매번 클릭하는 것은 설정 실패입니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이 작업을 허용할까요?&quot; 팝업이 뜰 때마다 클릭하는 것은 정상적인 사용 경험이 아닙니다. settings.json에 glob 패턴으로 허용 범위를 미리 지정해두어야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;설정 예시:&lt;/b&gt; Bash(npm *), Bash(git *), Edit(src/**) 와 같이 허용할 명령어와 파일 범위를 명시할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Auto 모드:&lt;/b&gt; 새로 생긴 auto 모드는 LLM 분류기가 각 동작의 위험도를 판단하여 안전한 작업은 자동으로 승인해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 5가지 컨텍스트 압축 전략을 이해하고 활용해야 합니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Anthropic 엔지니어들이 컨텍스트 초과 문제 해결에 많은 노력을 기울였다는 증거입니다. 자동 압축을 기다리기보다, 필요할 때 수동으로 개입하는 것이 중요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;5가지 전략:&lt;/b&gt; microcompact(오래된 도구 결과 제거), context collapse(대화 구간 요약), session memory(핵심 맥락 파일 추출), full compact(전체 히스토리 요약), PTL truncation(가장 오래된 메시지 그룹 폐기)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 조언:&lt;/b&gt; /compact 명령어를 게임의 '수동 세이브'처럼 사용하세요. 중요한 맥락이 날아가기 전에 보존하고 불필요한 내용은 정리할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Hook 시스템이 진짜 확장 API입니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PreToolUse(도구 실행 전), PostToolUse(실행 후), UserPromptSubmit(메시지 전송 시) 등 25개 이상의 라이프사이클 이벤트에 사용자 정의 로직을 연결할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UserPromptSubmit 훅:&lt;/b&gt; 메시지를 보낼 때마다 자동으로 테스트 결과나 최신 git diff를 컨텍스트에 첨부할 수 있어 매우 강력합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;5가지 훅 종류:&lt;/b&gt; command(쉘 명령), prompt(LLM 맥락 주입), agent(에이전트 검증), HTTP(웹훅), function(JS 실행)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 세션을 매번 새로 시작하지 마세요.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 대화는 JSONL 파일로 저장되며, 세션을 이어가면 session memory가 축적되어 AI가 더 똑똑하게 행동합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;세션 명령어:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;--continue: 마지막 세션을 이어서 시작합니다.&lt;/li&gt;
&lt;li&gt;--resume: 특정 세션을 골라서 다시 엽니다.&lt;/li&gt;
&lt;li&gt;--fork-session: 과거 대화의 특정 지점에서 새로운 브랜치를 만듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비유:&lt;/b&gt; 매번 새 세션을 여는 것은 IDE를 1시간마다 껐다 켜는 것과 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 읽기는 병렬, 쓰기는 순차입니다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code는 속도와 안정성을 모두 고려하여 도구를 실행합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;병렬 실행 (읽기):&lt;/b&gt; 파일 10개를 읽어야 하면 동시에 읽어 속도를 높입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순차 실행 (쓰기):&lt;/b&gt; 파일 3개를 수정해야 하면 충돌 방지를 위해 하나씩 순서대로 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 중간에 끊는 것을 두려워하지 마세요.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 파이프라인이 비동기 제너레이터 방식으로 동작하므로, Esc 키를 누르면 현재 스트리밍만 깔끔하게 중단되고 이전 맥락은 그대로 보존됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시사점:&lt;/b&gt; AI가 잘못된 방향으로 가고 있다면, 끝까지 기다리지 말고 즉시 중단하고 방향을 바로잡아주는 것이 효율적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. 결론: 설정하고, 병렬로 돌리고, 세션을 이어가세요.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code를 잘 쓰는 것은 프롬프트 엔지니어링의 영역이 아닙니다. 소스코드 분석 결과, 이 도구는 단순한 터미널 채팅이 아니라 **'에이전트 오케스트레이션 플랫폼'**에 가깝습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심:&lt;/b&gt; 설정을 통해 권한을 자동화하고, Hook으로 필요한 정보를 주입하며, 병렬 에이전트로 작업을 동시에 처리하고, 세션을 이어가며 컨텍스트를 축적하는 것이 핵심입니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/477</guid>
      <comments>https://sddev.tistory.com/477#entry477comment</comments>
      <pubDate>Wed, 1 Jul 2026 16:10:46 +0900</pubDate>
    </item>
    <item>
      <title>[개발자 도구] 새 창/팝업 뜰 때 개발자 도구(F12) 자동으로 열고 네트워크 로그 잡는 방법</title>
      <link>https://sddev.tistory.com/476</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;웹 개발을 하거나 API 테스트를 하다 보면, 버튼을 눌렀을 때 새 창(팝업)이나 새 탭이 열리면서 데이터가 넘어가는 과정을 확인해야 할 때가 많습니다.&lt;br /&gt;하지만 새 창이 뜨는 속도가 너무 빨라 뒤늦게 F12를 누르면 이미 초기 네트워크 로그(Network Log)는 날아가고 없는 경우가 허다하죠.  &amp;zwj; &lt;br /&gt;오늘은 마이크로소프트 엣지(Edge) 브라우저에서 부모 창의 개발자 도구를 켜두면 새 창이 열릴 때 개발자 도구도 자동으로 함께 켜지게 만드는 전역 설정 방법을 소개해 드립니다. 이 방법을 쓰면 첫 요청부터 완벽하게 로그를 보존할 수 있습니다!&lt;br /&gt;&lt;b&gt; ️ Edge 새 창 뜰 때 개발자 도구 자동 연결하기 (30초 컷)&lt;/b&gt;&lt;br /&gt;방법은 아주 간단합니다. 부모 창(원래 창)에서 옵션 하나만 켜두면 됩니다.&lt;br /&gt;&lt;b&gt;1단계: 개발자 도구 설정 진입&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;현재 띄워져 있는 메인 브라우저 창에서 &lt;b&gt;F12&lt;/b&gt; 키를 눌러 개발자 도구를 엽니다.&lt;/li&gt;
&lt;li&gt;개발자 도구 창 우측 상단에 있는 **톱니바퀴 아이콘(설정 / Settings)**을 클릭합니다.&lt;br /&gt;(톱니바퀴가 안 보인다면 F1 키를 눌러도 바로 설정 화면으로 이동합니다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2단계: 자동 열기 옵션 체크&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;설정 왼쪽 메뉴에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Preferences (기본 설정)&lt;/b&gt; 탭&lt;/span&gt;을 선택합니다.&lt;/li&gt;
&lt;li&gt;스크롤을 아주 조금만 아래로 내려 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Global (전역)&lt;/b&gt; 섹션&lt;/span&gt;을 찾습니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;항목 중 &lt;b&gt;Auto-open DevTools for popups (팝업에 대해 자동으로 개발자 도구 열기)&lt;/b&gt; 찾아 체크박스에 체크(V)&lt;/span&gt;합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;설정 끝!&lt;/b&gt; 이제 설정 창을 닫고 테스트를 해보시면 됩니다.&lt;br /&gt;&lt;b&gt;  완벽한 로그 보존을 위한 마지막 한 걸음 (강력 추천)&lt;/b&gt;&lt;br /&gt;만약 새 창이 열리자마자 다른 주소로 **순식간에 리다이렉트(화면 전환)**가 일어나는 페이지라면, 자동 열기 설정만으로는 첫 로그가 덮어씌워져 안 보일 수 있습니다.&lt;br /&gt;이를 방지하기 위해 새 창이 열렸을 때 다음 설정까지 함께 켜주면 완벽합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;자동으로 열린 새 창의 개발자 도구에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Network (네트워크)&lt;/b&gt; 탭&lt;/span&gt;으로 이동합니다.&lt;/li&gt;
&lt;li&gt;상단 메뉴 바에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Preserve log (로그 보존)&lt;/b&gt; 체크박스에 체크&lt;/span&gt;합니다.&lt;br /&gt;(아이콘 모드일 경우, 깔대기 모양 옆에 화살표가 둥글게 감싸고 있는 모양입니다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Preserve log 기능까지 활성화해 두면, 페이지가 새로고침되거나 다른 URL로 넘어가도 이전 단계의 네트워크 요청 기록이 지워지지 않고 차곡차곡 누적됩니다.&lt;br /&gt;&lt;b&gt;✍️ 요약 및 정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;문제:&lt;/b&gt; 새 창이 뜨면 개발자 도구를 켜기도 전에 초기 네트워크 로그가 유실됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해결:&lt;/b&gt; F12 &amp;gt; 설정(F1) &amp;gt; 기본 설정 &amp;gt; &lt;b&gt;Auto-open DevTools for popups&lt;/b&gt; 체크!&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한 줄 팁:&lt;/b&gt; 리다이렉트가 심한 사이트라면 네트워크 탭의 **Preserve log**까지 켜둘 것!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 새 팝업창이 뜰 때마다 허둥지둥 F12 누르지 마시고, 이 전역 옵션 하나로 편안하게 디버깅하세요! 도움이 되셨다면 공감과 댓글 부탁드립니다.   &lt;/p&gt;</description>
      <category>웹 개발/백엔드 일반</category>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/476</guid>
      <comments>https://sddev.tistory.com/476#entry476comment</comments>
      <pubDate>Thu, 25 Jun 2026 11:24:27 +0900</pubDate>
    </item>
    <item>
      <title>[AI] 프롬프트 캐싱, 서킷 브레이커, 그리고 Ralph Loop 한눈에 이해하기</title>
      <link>https://sddev.tistory.com/475</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 프롬프트 캐싱 (Prompt Caching)&lt;/b&gt;&lt;br /&gt;개념: &lt;span style=&quot;color: #ee2323;&quot;&gt;고정된 컨텍스트(API 문서, 시스템 가이드, 긴 코드베이스 등)의 연산 비용과 응답 시간을 아끼기 위해 메모리에 적재해두는 기술&lt;/span&gt;입니다.&lt;br /&gt;&lt;b&gt;  의사코드 구현 모델&lt;/b&gt;&lt;br /&gt;개발자가 &lt;span style=&quot;color: #ee2323;&quot;&gt;매번 긴 시스템 지침을 모델에 전달하는 대신&lt;/span&gt;, &lt;b&gt;&lt;u&gt;백엔드나 프레임워크 단&lt;/u&gt;에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;내부적으로 매칭되는 해시(Hash)가 있는지 확인&lt;/span&gt;&lt;/b&gt;하고 이를&lt;span style=&quot;color: #ee2323;&quot;&gt; 재사용하는 논리 구조&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; LLM.compute_with_cached_state 핵심이다.(캐시 key값을 같이 넘겨준다. 나머지는 변경된 user_query만)&lt;/p&gt;
&lt;pre class=&quot;ruby&quot; style=&quot;background-color: #f5f5f5;&quot;&gt;&lt;code&gt;import hashlib

class PromptCacheManager:
    def __init__(self):
        # 실제 환경에서는 Redis나 클라우드 제공업체의 내장 KV Cache 메모리 레이어입니다.
        self.cache_storage = {}

    def get_completion(self, system_instruction, user_prompt):
        # 1. 고정된 대형 프롬프트의 해시값을 생성
        instruction_hash = hashlib.sha256(system_instruction.encode()).hexdigest()
        
        # 2. 캐시 스토리지 확인 (Hit or Miss)
        if instruction_hash in self.cache_storage:
            print(&quot;✨ Prompt Cache HIT! (비용 절감, 빠른 응답)&quot;)
            cached_tokens_state = self.cache_storage[instruction_hash]
            # 이미 계산된 KV Cache 상태를 모델에 전달하여 user_prompt만 이어서 연산
            response = LLM.compute_with_cached_state(cached_tokens_state, user_prompt)
        else:
            print(&quot;  Prompt Cache MISS. (전체 연산 후 캐싱 진행)&quot;)
            # 처음부터 전체 연산 수행
            cached_tokens_state, response = LLM.compute_full(system_instruction, user_prompt)
            # 다음 요청을 위해 저장
            self.cache_storage[instruction_hash] = cached_tokens_state
            
        return response
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;2. 서킷 브레이커 (Circuit Breaker)&lt;/b&gt;&lt;br /&gt;개념: &lt;span style=&quot;color: #ee2323;&quot;&gt;외부 API나 &lt;u&gt;하위 서비스가 망가졌을 때&lt;/u&gt;&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;무한정 대기하거나 연쇄 장애를 일으키지 않고&lt;/u&gt;, &lt;u&gt;즉시 차단(Fail-Fast)&lt;/u&gt;했다가&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;정상화되면 다시 연결&lt;/u&gt;하는 패턴&lt;/span&gt;입니다.&lt;br /&gt;&lt;b&gt;  의사코드 구현 모델&lt;/b&gt;&lt;br /&gt;Closed, Open, Half-Open 상태를 &lt;span style=&quot;color: #ee2323;&quot;&gt;상태 패턴(State Pattern)&lt;/span&gt;이나 &lt;span style=&quot;color: #ee2323;&quot;&gt;조건문으로 관리하는&lt;u&gt; 백엔드 단의 구현&lt;/u&gt; 형태&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;CircuitBreaker 기능&lt;/span&gt;(&lt;u&gt;실패 횟수에 따른 비활성화&lt;/u&gt;, &lt;u&gt;일정 시간 이후에 정상화 검증&lt;/u&gt;, &lt;u&gt;정상화 후 활성화 상태로 복구&lt;/u&gt;)을 하는 구현체를 Agent가 사용하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;API, 도구 등에 적용하는 방식&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre class=&quot;pf&quot; style=&quot;background-color: #f5f5f5;&quot;&gt;&lt;code&gt;import time

class CircuitBreaker:
    def __init__(self, failure_threshold=3, recovery_time=10):
        self.state = &quot;CLOSED&quot;           # 초기 상태: 정상
        self.failure_count = 0          # 실패 횟수 카운트
        self.failure_threshold = failure_threshold # 차단 기준치
        self.recovery_time = recovery_time         # 격리 시간(초)
        self.last_state_changed = time.time()

    def call_external_api(self, request_data):
        current_time = time.time()

        # 1. OPEN 상태일 때: 격리 시간이 지났으면 테스트 모드(HALF-OPEN)로 전환
        if self.state == &quot;OPEN&quot;:
            if current_time - self.last_state_changed &amp;gt; self.recovery_time:
                self.state = &quot;HALF-OPEN&quot;
                print(&quot;⚡ [HALF-OPEN] 서비스 회복 여부를 확인하기 위해 요청을 하나 흘려보냅니다.&quot;)
            else:
                # 격리 기간 중에는 바로 에러를 뱉거나 대체 데이터(Fallback)를 리턴 (Fail-Fast)
                return &quot;Fallback Data: 외부 서버 장애로 임시 데이터를 반환합니다.&quot;

        # 2. 실제 API 호출 시도
        try:
            response = ExternalService.request(request_data)
            
            # 호출 성공 시 처리
            if self.state == &quot;HALF-OPEN&quot;:
                print(&quot;  [CLOSED] 서비스가 정상 복구되었습니다! 서킷을 닫습니다.&quot;)
                self.state = &quot;CLOSED&quot;
                self.failure_count = 0
            return response

        except Exception as e:
            # 호출 실패 시 처리
            self.failure_count += 1
            print(f&quot;❌ 호출 실패 (누적: {self.failure_count}/{self.failure_threshold})&quot;)

            if self.failure_count &amp;gt;= self.failure_threshold or self.state == &quot;HALF-OPEN&quot;:
                self.state = &quot;OPEN&quot;
                self.last_state_changed = time.time()
                print(&quot;  [OPEN] 장애율 초과! 서킷이 열렸습니다. 외부 호출을 차단합니다.&quot;)
                
            return &quot;Fallback Data: 서비스 장애 감지로 우회 처리되었습니다.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;3. Ralph Loop (Agent Harness Engineering)&lt;/b&gt;&lt;br /&gt;개념: 코딩 에이전트(Claude Code, Cursor CLI 등)가 &lt;span style=&quot;color: #ee2323;&quot;&gt;긴 작업을 할 때 대화가 길어질수록 환각(Hallucination)이 심해지고 성능이 떨어지는 문제를 해결하기 위한 루프&lt;/span&gt;입니다. **&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;매 반복마다 컨텍스트 창을 완전히 초기화(Fresh Context)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;**하되, &lt;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;파일 시스템&lt;/b&gt;(TODO 파일, &lt;b&gt;Git 커밋&lt;/b&gt;)을 &lt;b&gt;영속성 메모리로 활용&lt;/b&gt;&lt;/span&gt;&lt;/u&gt;하여 &lt;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;끈질기게 작업을 완수하게&lt;/span&gt;&lt;/u&gt; 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;모든 것을 LLM에 던지는 것이 아니라&lt;/b&gt;&lt;/span&gt;&lt;/u&gt;, 여러 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;영속적 메모리를 활용&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;하여, 그 때 그 때 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;필요한 항목들만 조회해와서 LLM에 context로 넘기면서 단계적으로 수행하여 전체 작업을 성공적으로 수행&lt;/span&gt;&lt;/b&gt;해내는 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 한번에 모든 할일을 LLM에 context로 다 넘기고 작업을 수행하게 할 수도 있지만, 정확도가 떨어진다. 먼저 &lt;span style=&quot;color: #ee2323;&quot;&gt;task 단위로 여러개를 나누고, task와 관련된 내용들을 파일로 만들고, task들을 순회하면서 새로운 LLM context에서 개별 작업들을 통해, 원하는 전체작업을 완성도 있게 수행해나가는 방식&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;  의사코드 구현 모델&lt;/b&gt;&lt;br /&gt;주로 에이전트를 감싸고 실행하는 인프라/스크립트(Harness)단인 **Shell Script(Bash)**나 이를 &lt;u&gt;&lt;b&gt;오케스트레이션하는 도구 형태로 구현&lt;/b&gt;&lt;/u&gt;됩니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f5f5f5;&quot;&gt;&lt;code&gt;#!/bin/bash
# ralph-loop.sh: 자율 코딩 에이전트를 실행하는 하네스(Harness) 스크립트

MAX_ITERATIONS=10
ITERATION=1
COMPLETED=false

echo &quot;  Ralph Loop를 시작합니다. 목표: 모든 개발 태스크 완료&quot;

# 루프가 돌 때마다 에이전트는 완전히 '새 프로세스'로 실행되어 대화 히스토리(컨텍스트 오염)가 초기화됩니다.
while [ $ITERATION -le $MAX_ITERATIONS ] &amp;amp;&amp;amp; [ &quot;$COMPLETED&quot; = false ]
do
    echo &quot;--------------------------------------------------&quot;
    echo &quot;  Iteration $ITERATION/$MAX_ITERATIONS - Fresh Context로 에이전트 구동&quot;
    echo &quot;--------------------------------------------------&quot;

    # 1. 파일 시스템에 적힌 현재 할 일(Task) 확인하기
    CURRENT_TASK=$(node -e &quot;
        const tasks = require('./.agent/tasks.json');
        const next = tasks.find(t =&amp;gt; t.status === 'PENDING');
        console.log(next ? next.id : 'NONE');
    &quot;)

    if [ &quot;$CURRENT_TASK&quot; = &quot;NONE&quot; ]; then
        echo &quot;  모든 태스크가 성공적으로 끝났습니다!&quot;
        COMPLETED=true
        break
    fi

    # 2. AI 에이전트를 완전 독립된 세션으로 실행 (Harness 가 프롬프트를 주입)
    # 에이전트는 이 실행 파일 안에서 코드를 수정하고 테스트를 돌립니다.
    claude-code --non-interactive --prompt &quot;
        너는 지금 Ralph Loop 모드로 작동 중이야. 
        ./.agent/tasks/TASK-${CURRENT_TASK}.json 에 적힌 요구사항을 구현해줘.
        작업이 끝나면 반드시 'npm test'를 돌려 검증하고, 
        성공하면 해당 태스크 상태를 'COMPLETED'로 바꾸고 종료해.
    &quot;

    # 3. 에이전트가 종료된 후, 하네스(Harness) 단에서 자동 검증 및 Git 커밋
    if npm run test:critical; then
        echo &quot;✅ 검증 성공: Git 커밋을 생성하고 다음 태스크로 넘어갑니다.&quot;
        git add .
        git commit -m &quot;feat(agent): completed task $CURRENT_TASK&quot;
    else
        echo &quot;⚠️ 검증 실패: 코드가 깨졌습니다. 다음 루프에서 에이전트가 이어서 디버깅하도록 컨텍스트를 유지합니다.&quot;
        # 실패 정보를 다음 루프의 에이전트가 읽을 수 있게 파일로 기록
        echo &quot;Test failed on task $CURRENT_TASK&quot; &amp;gt; ./.agent/error_log.txt
    fi

    ITERATION=$((ITERATION + 1))
done

if [ &quot;$COMPLETED&quot; = false ]; then
    echo &quot;  지정된 최대 반복 횟수에 도달하여 루프를 안전하게 탈출합니다.&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;  한눈에 정리하는 아키텍처적 차이점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;프롬프트 캐싱&lt;/b&gt;은&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;b&gt;LLM 엔진 내부&lt;/b&gt;에서 똑같은 입력을 빠르게 처리하기 위한 '성능 최적화 스크립트'&lt;/span&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서킷 브레이커&lt;/b&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;백엔드 인프라&lt;/b&gt;에서 불완전한 외부 시스템으로부터 내 앱을 보호하는 '방어벽 인터셉터'&lt;/span&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ralph Loop&lt;/b&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;**에이전트 실행 환경(Harness)**에서 LLM의 기억력 한계를 극복하고 장기적인 자동화를 가능케 하는 '무한 궤도 오케스트레이터'&lt;/span&gt;입니다. &lt;/li&gt;
&lt;/ul&gt;</description>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/475</guid>
      <comments>https://sddev.tistory.com/475#entry475comment</comments>
      <pubDate>Tue, 23 Jun 2026 14:49:08 +0900</pubDate>
    </item>
    <item>
      <title>[SSO] Single Sign On의 본질: 한 번 로그인으로 여러 시스템에 접근하기</title>
      <link>https://sddev.tistory.com/474</link>
      <description>&lt;blockquote data-pm-slice=&quot;2 4 []&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔터프라이즈 환경에서 SSO가 왜 다양한 형태로 구현되는지, 그리고 &amp;ldquo;표준 OIDC&amp;rdquo;와 &amp;ldquo;포털 연동형 SSO&amp;rdquo;의 차이를 이해하기 위한 핵심 정리&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. SSO란 무엇인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SSO(Single Sign-On)&lt;/b&gt; 는 &lt;span style=&quot;color: #ee2323;&quot;&gt;사용자가 &lt;b&gt;한 번 인증&lt;/b&gt;하면, 연결된 여러 애플리케이션에 &lt;b&gt;다시 로그인하지 않고&lt;/b&gt; 접근할 수 있게 하는 방식&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 두 가지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;인증(&lt;span style=&quot;color: #ee2323;&quot;&gt;Authentication&lt;/span&gt;)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&amp;ldquo;&lt;span style=&quot;color: #ee2323;&quot;&gt;이 사람이 누구&lt;/span&gt;인가?&amp;rdquo; &amp;mdash; 신원 확인&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;인가(Authorization)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&amp;ldquo;이 사람이 무엇을 할 수 있는가?&amp;rdquo; &amp;mdash; 권한 부여&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSO는 &lt;b&gt;인증을 중앙(또는 게이트웨이)에 맡기고&lt;/b&gt;, &lt;span style=&quot;color: #ee2323;&quot;&gt;각 앱은 그 결과를 받아 &lt;b&gt;자체 세션&amp;middot;토큰&lt;/b&gt;을 만드는 구조가 일반적&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre class=&quot;inform7&quot;&gt;&lt;code&gt;[사용자] &amp;rarr; [SSO / IdP / 게이트웨이] &amp;rarr; 인증 완료
                &amp;darr;
         [앱 A, 앱 B, 앱 C] &amp;larr; 각자 세션/토큰 발급&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. SSO를 구현하는 네 가지 대표 패턴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 자주 만나는 방식만 골라 정리한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 OIDC / OAuth2 (클라우드&amp;middot;SaaS의 표준)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가장 널리 쓰이는 현대적 방식.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;사용자 &amp;rarr; IdP 로그인 페이지
     &amp;rarr; redirect (?code=...)
     &amp;rarr; 앱이 code를 access_token으로 교환
     &amp;rarr; JWT(id_token) 서명 검증 후 로그인 완료&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점단점&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;표준 스펙, 라이브러리 풍부&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;IdP 등록&amp;middot;설정 필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;토큰 검증&amp;middot;만료&amp;middot;갱신이 명확&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;레거시 포털과 직접 연동 어려움&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표 IdP: Azure AD, Okta, Google, Keycloak&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 SAML 2.0 (대기업 레거시)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML 기반 Assertion을 IdP가 앱( SP )으로 POST한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;금융&amp;middot;대기업에서 여전히 많이 사용&lt;/li&gt;
&lt;li&gt;OIDC보다 설정이 무겁고 XML 서명 검증이 필요&lt;/li&gt;
&lt;li&gt;신규 프로젝트는 OIDC를 더 선호하는 추세&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 헤더 기반 SSO (Reverse Proxy / 게이트웨이 신뢰)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자는 &lt;b&gt;SSO 게이트웨이 앞&lt;/b&gt;에서만 로그인하고, 게이트웨이가 인증된 요청에 &lt;b&gt;HTTP 헤더&lt;/b&gt;를 붙여 앱으로 전달한다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;[사용자] &amp;rarr; [SSO Gateway] &amp;rarr; iv-user: hong.gildong
                        &amp;rarr; [내부 앱]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특징&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;대표 헤더&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;iv-user, REMOTE_USER, X-Forwarded-User&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;전제 조건&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;앱은 &lt;b&gt;게이트웨이 뒤&lt;/b&gt;에 있어야 하고, 헤더 위조를 막을 수 있어야&lt;/span&gt; 함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;흔한 환경&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;사내망, IBM WebSEAL, SiteMinder 등&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iv-user 는 IBM Tivoli / WebSEAL 계열에서 흔히 쓰이는 헤더 이름이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4 암호화 페이로드 + 포털 브릿지 (B2B&amp;middot;내부 포털 연동)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포털(예: 구매 시스템)이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;공유 비밀키로 암호화한 사용자 정보&lt;/b&gt;를 앱에 넘긴다&lt;/span&gt;.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;포털 &amp;rarr; POST app1_user_info=AES(env|사번|user_id)
앱  &amp;rarr; 복호화 &amp;rarr; 사용자 식별 &amp;rarr; 자체 토큰 발급&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점 단점&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;기존 포털 규격에 맞추기 쉬움&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;표준이 아니라 앱마다 포맷이 다름&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;IdP 없이 빠르게 연동 가능&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;키 관리&amp;middot;검증 로직을 앱이 직접 책임져야 함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 패턴 비교 한눈에&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방식신뢰 근거흔한 환경표준성&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;OIDC/OAuth2&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;IdP 서명 JWT, code 교환&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;SaaS, 클라우드&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;★★★★★&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;SAML&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;XML Assertion 서명&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;대기업 레거시 IdP&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;★★★★☆&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;헤더 SSO&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;게이트웨이가 헤더 주입&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;사내망, WebSEAL&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;★★☆☆☆ (관례)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;암호화 페이로드&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;공유키 복호화&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;내부 포털, B2B&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;★☆☆☆☆ (자체 규격)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;SSO = OIDC&amp;rdquo;가 아니다.&lt;/b&gt;&lt;br /&gt;환경에 따라 위 방식이 &lt;b&gt;단독&lt;/b&gt;으로 쓰이거나 &lt;b&gt;조합&lt;/b&gt;된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 하이브리드 SSO: 현실에서 가장 흔한 형태&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대기업 내부 연동에서는 아래가 자주 한 세트로 묶인다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;[포털] ── 암호화 페이로드(app1_user_info) ──&amp;rarr; [앱]
[게이트웨이] ── iv-user 헤더 ─────────────&amp;rarr; [앱]
[앱] ── 임시 토큰(session_id) ──────────&amp;rarr; [프론트]
[프론트] ── session_id 교환 ─────────────&amp;rarr; [앱] &amp;rarr; access_token&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 이렇게 복잡한가?&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;포털&lt;/b&gt;은 이미 자체 암호화 규격을 가지고 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;게이트웨이&lt;/b&gt;는 네트워크 경계에서 SSO를 처리한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;앱&lt;/b&gt;은 브라우저에 바로 내부 토큰을 주지 않고, &lt;b&gt;1회용 브릿지 토큰&lt;/b&gt;으로 한 번 더 교환한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 교과서 OIDC는 아니지만, &lt;b&gt;레거시 인프라 제약 안에서의 실무적 브릿지 패턴&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 2단계 토큰 교환이란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 포털 연동 SSO가 다음 두 단계를 거친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단계토큰역할수명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;1&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;session_id (임시)&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;포털 &amp;rarr; 프론트 브릿지&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;짧음 (Redis TTL)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;access_token (정식)&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;API 호출&amp;middot;세션 유지&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;상대적으로 김&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;POST /sso (서버 간&amp;middot;리다이렉트)
  &amp;rarr; session_id 발급
  &amp;rarr; redirect: https://app/?session_id=xxx

GET 프론트
  &amp;rarr; POST /auth/sso-login { session_id }
  &amp;rarr; access_token 발급&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 &lt;span style=&quot;color: #ee2323;&quot;&gt;URL에 session_id&lt;/span&gt;를 쓰는가?&lt;/b&gt;&lt;br /&gt;포털이 브라우저를 앱으로 보낼 때 가장 단순한 방법이 query string이기 때문이다.&lt;br /&gt;대신 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;짧은 TTL&lt;/b&gt;, &lt;b&gt;1회 사용&lt;/b&gt;, &lt;b&gt;HTTPS&lt;/b&gt;가 전제&lt;/span&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준 OAuth의 authorization code와 &lt;b&gt;역할은 비슷&lt;/b&gt;하지만, 스펙은 다르다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 검증 로직을 이해하는 열쇠&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하이브리드 SSO를 읽을 때 확인할 질문 세 가지.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q1. 누를 신뢰하는가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 헤더 (iv-user)&lt;/li&gt;
&lt;li&gt;암호화 본문 (app1_user_info)&lt;/li&gt;
&lt;li&gt;둘 다 있을 때 &lt;b&gt;교차 검증&lt;/b&gt;하는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q2. prod와 dev 규칙이 다른가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;prod: 헤더 필수&lt;/li&gt;
&lt;li&gt;dev: 암호문만으로도 허용&lt;/li&gt;
&lt;li&gt;특정 domain: prod에서도 헤더 생략 허용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;환경&amp;middot;도메인별 예외&lt;/b&gt;는 운영 요구에서 자주 생긴다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Q3. 최종 세션은 어디에 저장되는가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redis (서버 세션)&lt;/li&gt;
&lt;li&gt;HttpOnly Cookie&lt;/li&gt;
&lt;li&gt;프론트 메모리 / localStorage (보안상 덜 권장)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 보안 체크리스트 (핵심만)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목권장&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;전송&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;HTTPS 필수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;임시 토큰&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;짧은 TTL, 가능하면 1회성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;URL 토큰&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;히스토리&amp;middot;Referer 노출 인지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;헤더 SSO&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;게이트웨이 뒤에서만 신뢰, 직접 인터넷 노출 금지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;공유키&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;로그에 전체 노출 금지, 주기적 로테이션&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;prod 예외&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;domain 화이트리스트 등으로 최소화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. &amp;ldquo;우리 앱 SSO&amp;rdquo;를 읽는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드나 흐름도를 볼 때 이 순서로 따라가면 된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;진입점&lt;/b&gt; &amp;mdash; /sso, /callback, middleware 예외 분기?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;입력&lt;/b&gt; &amp;mdash; 헤더? form body? query?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검증&lt;/b&gt; &amp;mdash; 복호화, 헤더 일치, env/domain 예외&lt;/li&gt;
&lt;li&gt;&lt;b&gt;브릿지 토큰&lt;/b&gt; &amp;mdash; session_id 생성&amp;middot;저장 위치&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프론트&lt;/b&gt; &amp;mdash; URL에서 토큰 추출 &amp;rarr; API 교환&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최종 로그인&lt;/b&gt; &amp;mdash; access_token 발급, 사용자&amp;middot;역할 조회&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이후 요청&lt;/b&gt; &amp;mdash; Bearer / Cookie로 인증&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오해사실&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;SSO는 항상 OAuth다&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;OIDC가 표준이지만, 레거시&amp;middot;포털 연동은 다른 형태가 많다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;헤더만 있으면 된다&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;게이트웨이 신뢰 + 네트워크 격리가 전제다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;암호문만 있으면 된다&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;키 유출 시 위조 가능 &amp;mdash; 헤더와 교차 검증이 안전하다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;session_id in URL은 항상 위험하다&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;짧은 TTL&amp;middot;1회성이면 실무 타협으로 쓰이기도 한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SSO의 본질&lt;/b&gt;은 &amp;ldquo;표준 프로토콜을 쓰느냐&amp;rdquo;가 아니라,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;신원을 누가&amp;middot;어떤 근거로 확인했고, 앱이 그 결과를 어떻게 자기 세션으로 바꾸는가&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 이해하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 신규 서비스라면 &lt;b&gt;OIDC&lt;/b&gt;를 우선 검토하고,&lt;br /&gt;기존 포털&amp;middot;게이트웨이&amp;middot;App1 같은 &lt;b&gt;내부 시스템과 붙는다면 하이브리드 브릿지&lt;/b&gt;가 현실적인 선택이 될 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고: 용어 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용어설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IdP&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Identity Provider &amp;mdash; 신원을 증명해 주는 주체&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;SP&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Service Provider &amp;mdash; 서비스를 제공하는 앱&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;iv-user&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;IBM SSO 게이트웨이 등에서 쓰는 사용자 ID 헤더&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;app1_user_info&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;공유키로 암호화된 사용자 정보 페이로드 (프로젝트별 규격)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;session_id&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;SSO 브릿지용 임시 토큰&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;access_token&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;API 인증용 정식 토큰&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/474</guid>
      <comments>https://sddev.tistory.com/474#entry474comment</comments>
      <pubDate>Mon, 22 Jun 2026 16:52:09 +0900</pubDate>
    </item>
    <item>
      <title>[SSL] 운영환경 HTTPS 적용기 : Nginx + Docker + 사내 와일드카드 인증서</title>
      <link>https://sddev.tistory.com/473</link>
      <description>&lt;h1 data-pm-slice=&quot;1 1 []&quot;&gt;AOF Frontend HTTPS 설정 가이드&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문서는 AOF 프로젝트에서 &lt;b&gt;Nginx frontend 컨테이너에 HTTPS를 적용&lt;/b&gt;하기 위해 수행한 작업을 정리한 참고 자료입니다.&lt;br /&gt;인증서 발급부터 배포, CI/CD, 트러블슈팅까지 한 번에 파악할 수 있도록 구성했습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 전체 아키텍처 한눈에 보기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1809&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brIDcf/dJMcadWFQBJ/Kai9tUnh6kDKlBzdkYLkB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brIDcf/dJMcadWFQBJ/Kai9tUnh6kDKlBzdkYLkB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brIDcf/dJMcadWFQBJ/Kai9tUnh6kDKlBzdkYLkB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrIDcf%2FdJMcadWFQBJ%2FKai9tUnh6kDKlBzdkYLkB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1809&quot; height=&quot;410&quot; data-origin-width=&quot;1809&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심 원칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원칙설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;SSL 종료 지점&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;frontend Nginx 컨테이너 (443)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;Backend SSL&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;불필요 &amp;mdash; Nginx 뒤에서 HTTP(8001/8002)로 프록시&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;인증서 저장&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Git ❌ &amp;rarr; 호스트 고정 경로 /data001/config/dev/ssl/&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;자동 전환&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;entrypoint.sh가 인증서 유무로 HTTP/HTTPS 설정 선택&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 프로젝트에서 SSL이 처리되는 위치&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 관련 파일 맵&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일역할&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;cicd/container/entrypoint.sh&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;server.crt + server.key 존재 시 HTTPS 템플릿 적용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;cicd/container/default.conf.ssl.template&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;80(HTTP) + 443(HTTPS) Nginx 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;cicd/container/default.conf.template&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;인증서 없을 때 HTTP만&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;cicd/container/docker-compose-prd.yml&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;포트 80/443 노출, SSL 볼륨 마운트&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;cicd/container/ssl-setup/setup-ssl.sh&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;보안팀 원본 &amp;rarr; server.crt/server.key 변환&amp;middot;배포&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;cicd/container/Dockerfile&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Nginx 이미지 + 템플릿/entrypoint 포함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 entrypoint 자동 전환&lt;/h3&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;# cicd/container/entrypoint.sh (요약)
if [ -f /etc/nginx/ssl/server.crt ] &amp;amp;&amp;amp; [ -f /etc/nginx/ssl/server.key ]; then
    # &amp;rarr; default.conf.ssl.template 사용 (HTTP + HTTPS)
else
    # &amp;rarr; default.conf.template 사용 (HTTP만)
fi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 시작 시점에 판단하므로, &lt;b&gt;인증서만 배치하고 frontend를 재시작&lt;/b&gt;하면 HTTPS가 활성화됩니다. 이미지 재빌드는 필요 없습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예외:&lt;/b&gt; default.conf.ssl.template 내용을 바꾼 경우(리다이렉트, HSTS 등)에는 frontend &lt;b&gt;이미지 재빌드&lt;/b&gt;가 필요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 docker-compose 볼륨 마운트&lt;/h3&gt;
&lt;pre class=&quot;elixir&quot;&gt;&lt;code&gt;# cicd/container/docker-compose-prd.yml
frontend:
  ports:
    - &quot;80:80&quot;
    - &quot;443:443&quot;
  volumes:
    - /data001/config/dev/ssl:/etc/nginx/ssl:ro&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너 내부 경로: /etc/nginx/ssl/server.crt, /etc/nginx/ssl/server.key&lt;/li&gt;
&lt;li&gt;호스트 경로: /data001/config/dev/ssl/ (GitLab clone 경로와 &lt;b&gt;무관&lt;/b&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Backend .env와 동일한 패턴으로, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;비밀/인증서는 repo 밖 고정 경로&lt;/b&gt;&lt;/span&gt;에 둡니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 보안팀 인증서 파일 이해하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객사 등에서 받는 파일 구성 예시:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일의미Nginx 배포에 사용&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;File_Wildcard.xxx.com_crt.crt&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;서버(리프) 인증서 (*.xxx.com)&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;✅ server.crt의 &lt;b&gt;첫 번째&lt;/b&gt; 블록&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;KeyFile_Wildcard.xxx.com_crt.key&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;개인키 (암호화된 경우 password.txt 필요)&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;✅ server.key&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;ChainFile_ChainBundle.crt&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;중간 CA 체인&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;✅ server.crt에 &lt;b&gt;이어 붙임&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;CA_GLOBALSIGN.crt&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;루트 CA&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;❌ 배포 불필요 (검증&amp;middot;참고용)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;password.txt&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;개인키 복호화 비밀번호&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;❌ 배포 불필요 (작업 시에만 사용)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 PEM 파일에 BEGIN CERTIFICATE가 여러 개?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정상입니다.&lt;/b&gt; 하나의 .crt에 서버 인증서 + 중간 CA가 함께 들어 있는 경우가 많습니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;-----BEGIN CERTIFICATE-----   &amp;larr; 1번: 서버(리프) 인증서
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----   &amp;larr; 2번: 중간 CA
...
-----END CERTIFICATE-----&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;openssl x509 -in file.crt &amp;rarr; &lt;b&gt;첫 번째&lt;/b&gt; 인증서만 읽음&lt;/li&gt;
&lt;li&gt;Nginx ssl_certificate &amp;rarr; &lt;b&gt;모든 PEM 블록&lt;/b&gt; 사용 (fullchain)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 최종 산출물&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx가 기대하는 형태는 딱 2개입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일내용&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;server.crt&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;서버 인증서 + 중간 CA 체인 (fullchain PEM)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;server.key&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;복호화된 개인키 (평문 PEM)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CA_GLOBALSIGN.crt(루트)는 Nginx 설정에 넣지 않습니다. 브라우저/OS에 내장된 루트 CA로 검증합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. setup-ssl.sh 워크플로우&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 디렉토리 구조&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;cicd/container/ssl-setup/
├── setup-ssl.sh                              &amp;larr; 실행 스크립트 (Git 포함)
├── .gitignore                                &amp;larr; *.crt, *.key, password.txt 제외
├── File_Wildcard.xxx.com_crt.crt      &amp;larr; 보안팀 파일 (Git 제외)
├── ChainFile_ChainBundle.crt
├── CA_GLOBALSIGN.crt
├── KeyFile_Wildcard.xxx.com_crt.key
├── password.txt
└── .work/                                    &amp;larr; 중간 산출물 (실패 시 디버깅용, 성공 시 삭제)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 실행&lt;/h3&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 1. 보안팀 파일 5개를 ssl-setup/ 에 복사
# 2. 스크립트 실행
./cicd/container/ssl-setup/setup-ssl.sh

# 3. frontend 재시작 (인증서 반영)
docker compose -f cicd/container/docker-compose-prd.yml restart frontend&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3 스크립트가 하는 일&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;원본 파일 존재&amp;middot;크기(0바이트) 검사&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;password.txt로 암호화된 개인키 복호화 &amp;rarr; server.key&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;서버 인증서 + 체인 번들 결합 &amp;rarr; server.crt&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;인증서&amp;middot;키 쌍 일치(modulus) 및 체인 검증&lt;/li&gt;
&lt;li&gt;/data001/config/dev/ssl/에 배포 (기존 파일 백업 후 교체)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4 상단 변수 (재활용 시 수정)&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;SERVER_CERT_FILE=&quot;File_Wildcard.xxx.com_crt.crt&quot;
CHAIN_BUNDLE_FILE=&quot;ChainFile_ChainBundle.crt&quot;
ROOT_CA_FILE=&quot;CA_GLOBALSIGN.crt&quot;
PRIVATE_KEY_FILE=&quot;KeyFile_Wildcard.xxx.com_crt.key&quot;
PASSWORD_FILE=&quot;password.txt&quot;
SSL_DEPLOY_DIR=&quot;/data001/config/dev/ssl&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 트러블슈팅: 반드시 알아둘 PEM 이슈&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 파일 끝 줄바꿈 누락 (cat 합칠 때 PEM 깨짐)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안팀에서 받은 .crt 끝에 \n(개행)이 없는 경우가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;증상:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원본 File_Wildcard...crt 단독 &amp;rarr; openssl x509 성공 ✅&lt;/li&gt;
&lt;li&gt;합본 .work/server.crt &amp;rarr; Could not read certificate ❌&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;원인:&lt;/b&gt; cat으로 체인을 붙일 때 마지막 base64 줄과 -----BEGIN CERTIFICATE-----가 한 줄에 붙음&lt;/p&gt;
&lt;pre class=&quot;brainfuck&quot;&gt;&lt;code&gt;...abc123-----BEGIN CERTIFICATE-----&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt; setup-ssl.sh의 append_pem_file이 합칠 때 끝 개행을 자동 보정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;직접 확인:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;tail -c 5 File_Wildcard.lgdisplay.com_crt.crt | xxd
# 끝이 0a (LF)가 아니면 개행 없음&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 빈 server.crt&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 파일이 0바이트이거나 placeholder인 경우. 스크립트가 사전에 ! -s 검사로 차단합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3 적용 확인&lt;/h3&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;# 로그
docker logs frontend 2&amp;gt;&amp;amp;1 | head -5
# &quot;SSL 인증서가 발견되었습니다. HTTPS 설정을 적용합니다.&quot;

# 컨테이너 내부
docker exec frontend ls -la /etc/nginx/ssl/
docker exec frontend nginx -t

# 연결 테스트
curl -vk https://&amp;lt;도메인&amp;gt;/
curl -I http://&amp;lt;도메인&amp;gt;/&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. GitLab Runner / CI/CD와의 관계&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1 &lt;span style=&quot;color: #ee2323;&quot;&gt;왜 Git에 인증서를 넣지 않는가&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;개인키 유출 위험&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;보안 정책 위반&lt;/li&gt;
&lt;li&gt;GitLab Runner는 매 파이프라인마다 &lt;b&gt;새 clone&lt;/b&gt; &amp;rarr; clone 경로에 인증서를 두면 불안정&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.2 현재 CI/CD 구조 (요약)&lt;/h3&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;prd 브랜치 push
  &amp;rarr; GitLab Runner (shell executor)
  &amp;rarr; docker compose build/up (호스트 Docker)
  &amp;rarr; frontend 컨테이너 교체&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.gitlab-ci.yml의 HOST_PROJECT_DIR 변환은 소스 clone 경로용이며, &lt;b&gt;SSL은 /data001/config/dev/ssl 고정 경로&lt;/b&gt;를 사용합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.3 Backend와 동일한 패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종류호스트 경로Git&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Backend .env&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;/data001/config/dev/.env.*&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;❌&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;SSL 인증서&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;/data001/config/dev/ssl/&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;❌&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;애플리케이션 코드&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;GitLab clone&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;✅&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.4 인증서 갱신 시&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. ssl-setup/ 에 새 원본 파일 배치
# 2. setup-ssl.sh 실행
# 3. frontend만 재시작 (CI/CD 불필요)
docker compose -f cicd/container/docker-compose-prd.yml restart frontend&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. HTTP / HTTPS 병행 정책&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 default.conf.ssl.template은 &lt;b&gt;HTTP(80)와 HTTPS(443)를 동시에 제공&lt;/b&gt;하고, 강제 리다이렉트는 하지 않습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 변경 내용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목이전현재&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;80 포트&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;301 &amp;rarr; https:// 리다이렉트&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;HTTP 서비스 제공 (template과 동일)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;HSTS&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;활성화&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;&lt;b&gt;주석 처리&lt;/b&gt; (HTTP 병행과 충돌 방지)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;443 포트&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;HTTPS 서비스&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;동일&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리다이렉트/HSTS 설정은 템플릿에 &lt;b&gt;주석으로 보존&lt;/b&gt;되어 있어, 나중에 HTTPS 강제 전환 시 주석 해제만 하면 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 HTTP vs HTTPS 블록 관계&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;default.conf.ssl.template
├── server { listen 80;  ... }  &amp;larr; default.conf.template 과 동일
└── server { listen 443 ssl; ... + SSL 설정 }  &amp;larr; 추가&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증서 없을 때(default.conf.template)의 HTTP 동작과, 인증서 있을 때의 HTTP 동작은 &lt;b&gt;동일&lt;/b&gt;합니다. HTTPS가 추가되는 것뿐입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.3 애플리케이션 영향&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목영향&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Frontend API (/management)&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;상대 경로 &amp;rarr; 프로토콜 자동 맞춤, 재빌드 불필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;X-Forwarded-Proto&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;Nginx가 $scheme으로 전달 &amp;rarr; backend가 HTTP/HTTPS 구분 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;인증 쿠키&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;현재 secure=False &amp;rarr; HTTP/HTTPS 모두 동작&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;보안&lt;/span&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&lt;span&gt;HTTP 구간은 평문 통신 &amp;mdash; 사내 정책&amp;middot;노출 범위 확인 필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 운영 체크리스트&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최초 HTTPS 적용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-type=&quot;taskList&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안팀 인증서 5개 파일을 ssl-setup/에 배치&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;./cicd/container/ssl-setup/setup-ssl.sh 실행&amp;middot;검증 통과&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/data001/config/dev/ssl/server.crt, server.key 존재 확인&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;default.conf.ssl.template 변경 사항 반영 시 frontend &lt;b&gt;재빌드&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker compose restart frontend 또는 CI/CD 배포&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker logs frontend에서 HTTPS 적용 메시지 확인&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;curl -vk https://&amp;lt;도메인&amp;gt;/ 및 curl -I http://&amp;lt;도메인&amp;gt;/ 테스트&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방화벽/LB에서 80, 443 포트 개방 확인&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인증서 갱신&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-type=&quot;taskList&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ssl-setup/에 새 원본 파일 교체&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setup-ssl.sh 재실행 (기존 인증서 자동 백업)&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;frontend 재시작&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HTTPS 강제 전환 시 (향후)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-type=&quot;taskList&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;default.conf.ssl.template에서 80 포트 리다이렉트 블록 주석 해제&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 서비스 블록 주석 처리 (선택)&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HSTS 주석 해제 검토&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;backend 쿠키 secure=True 검토&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li data-type=&quot;taskItem&quot; data-checked=&quot;false&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;frontend 재빌드&amp;middot;배포&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 자주 묻는 질문 (FAQ)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. ssl/ (프로젝트 루트)와 cicd/container/ssl-setup/ 차이는?&lt;/b&gt;&lt;br /&gt;A. ssl/은 xxx 사내 CA 등 &lt;b&gt;빌드용&lt;/b&gt; 참고 자료. 운영 HTTPS 배포는 ssl-setup/ + /data001/config/dev/ssl/을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. &lt;span style=&quot;color: #ee2323;&quot;&gt;와일드카드 *.xxx.com이면 어떤 도메인까지&lt;/span&gt; 되나?&lt;/b&gt;&lt;br /&gt;A. &lt;span style=&quot;color: #ee2323;&quot;&gt;1단계 서브도메인 (aof.xxx.com)&lt;/span&gt; ✅. 2단계 (x.aof.xxx.com)는 와일드카드로 커버되지 않을 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. 인증서 변경만 했는데 frontend 재빌드가 필요한가?&lt;/b&gt;&lt;br /&gt;A. 아니요. &lt;span style=&quot;color: #ee2323;&quot;&gt;볼륨 마운트이므로 &lt;b&gt;재시작만&lt;/b&gt;&lt;/span&gt; 하면 됩니다. &lt;span style=&quot;color: #ee2323;&quot;&gt;Nginx 템플릿을 수정한 경우에만 재빌드가 필요&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. server_name localhost는 문제 없나?&lt;/b&gt;&lt;br /&gt;A. 실제 도메인 접속 시 리다이렉트 URL에 영향을 줄 수 있습니다. HTTPS 강제 리다이렉트를 켤 때는 운영 도메인으로 server_name 수정을 검토하세요. 현재는 리다이렉트를 사용하지 않으므로 영향이 적습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. &lt;span style=&quot;color: #ee2323;&quot;&gt;.gitignore를 폴더마다 둬도 되나&lt;/span&gt;?&lt;/b&gt;&lt;br /&gt;A. 네. ssl-setup/.gitignore는 해당 폴더의 인증서만 제외하고, 다른 경로의 .crt(예: ssl/xxx_CA_v3.crt)에는 영향을 주지 않습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 참고: OpenSSL 명령어 모음&lt;/h2&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 인증서 정보
openssl x509 -in server.crt -noout -subject -dates

# 개인키 검증
openssl rsa -in server.key -check -noout

# 인증서&amp;middot;키 쌍 일치 (MD5 해시가 같아야 함)
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5

# 체인 검증
openssl verify -CAfile CA_GLOBALSIGN.crt \
  -untrusted ChainFile_ChainBundle.crt \
  File_Wildcard.xxx.com_crt.crt

# 암호화된 키 복호화
openssl rsa -in KeyFile_Wildcard.xxx.com_crt.key \
  -out server.key -passin file:password.txt

# fullchain 수동 생성 (스크립트 없이)
cat File_Wildcard.xxx.com_crt.crt ChainFile_ChainBundle.crt &amp;gt; server.crt
# ⚠️ 파일 끝 개행 없으면 빈 줄 삽입 필요&lt;/code&gt;&lt;/pre&gt;</description>
      <category>웹 개발/백엔드 일반</category>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/473</guid>
      <comments>https://sddev.tistory.com/473#entry473comment</comments>
      <pubDate>Tue, 16 Jun 2026 11:12:10 +0900</pubDate>
    </item>
    <item>
      <title>[AI] AI 디자인의 한계, 'DESIGN.md' 파일 2,000개로 돌파하기 (ft. Refero Styles)</title>
      <link>https://sddev.tistory.com/471</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 오늘은 AI를 활용해 디자인을 하시는 분들에게 그야말로 '보물창고'가 될 만한 소식을 가져왔습니다.&lt;br /&gt;AI에게 디자인을 맡기면 어딘가 모르게 뻔하고, 결과물이 비슷비슷해서 아쉬웠던 적 없으신가요? 이제 세계적인 수준의 디자인 데이터를 직접 AI에게 학습시켜 보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;  AI 디자인의 치트키, DESIGN.md&lt;/b&gt;&lt;br /&gt;해외 디자인 씬에서 화제가 되고 있는 세계 최고 제품 2,000개의 디자인 데이터가 담긴 .md 파일들을 소개합니다. 이 파일들은 단순한 이미지 모음이 아닙니다. AI가 즉시 이해하고 적용할 수 있는 디자인 명세서에 가깝습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;포함된 핵심 요소:&lt;/b&gt; 색상(Color), 타이포그래피(Typography), 간격(Spacing), 레이아웃(Layout) 등&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활용 방법:&lt;/b&gt; 해당 .md 파일을 AI(Claude, ChatGPT 등)에게 업로드하거나 텍스트를 복사해 넘겨주기만 하면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  &quot;AI로 뻔하게 디자인하지 마세요&quot;&lt;/b&gt;&lt;br /&gt;범용적인 데이터만 학습한 AI는 평범한 결과물만 내놓습니다. 하지만 애플, 에어비앤비 같은 글로벌 제품들의 디자인 가이드가 담긴 데이터를 참고한다면 이야기가 달라집니다.&lt;br /&gt;세계적인 수준의 디자인 감각을 내 작업물에 이식해 보세요. 단순히 따라 하는 것을 넘어, 이 데이터들을 조합해 나만의 독창적인 DESIGN.md를 구축하는 것이 핵심입니다.&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  참고 링크&lt;/b&gt;&lt;br /&gt;아래 사이트에서 전 세계 디자인 트렌드와 핵심 요소들을 확인하고 직접 활용해 보실 수 있습니다.&lt;br /&gt;  &lt;a href=&quot;https://styles.refero.design/&quot;&gt;&lt;u&gt;Refero Styles 바로가기&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  한 줄 요약&lt;br /&gt;&quot;AI에게 '예쁘게 해줘'라고 말하는 대신, 세계 최고의 디자인 데이터를 건네주세요. 결과물의 디테일이 180도 달라집니다.&quot;&lt;br /&gt;여러분의 프로젝트에 세계적인 디자인 감각을 더해 보시기 바랍니다! &lt;/p&gt;</description>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/471</guid>
      <comments>https://sddev.tistory.com/471#entry471comment</comments>
      <pubDate>Wed, 27 May 2026 14:12:03 +0900</pubDate>
    </item>
    <item>
      <title>[AI] AI가 과대해석하거나 자주 실수하는 부분을 잘 잡아주는 CLAUDE.md &amp;amp; .cursor</title>
      <link>https://sddev.tistory.com/470</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md&quot;&gt;https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779858287563&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;andrej-karpathy-skills/CLAUDE.md at main &amp;middot; multica-ai/andrej-karpathy-skills&quot; data-og-description=&quot;A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls. - multica-ai/andrej-karpathy-skills&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md&quot; data-og-url=&quot;https://github.com/multica-ai/andrej-karpathy-skills/blob/main/CLAUDE.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Hnp3N/dJMb81G3TKQ/leRd1YyhJIMJqKH177ko4k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Hnp3N/dJMb81G3TKQ/leRd1YyhJIMJqKH177ko4k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;andrej-karpathy-skills/CLAUDE.md at main &amp;middot; multica-ai/andrej-karpathy-skills&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls. - multica-ai/andrej-karpathy-skills&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/multica-ai/andrej-karpathy-skills/blob/main/.cursor/rules/karpathy-guidelines.mdc&quot;&gt;andrej-karpathy-skills/.cursor/rules/karpathy-guidelines.mdc at main &amp;middot; multica-ai/andrej-karpathy-skills &amp;middot; GitHub&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1779858312524&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;andrej-karpathy-skills/.cursor/rules/karpathy-guidelines.mdc at main &amp;middot; multica-ai/andrej-karpathy-skills&quot; data-og-description=&quot;A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls. - multica-ai/andrej-karpathy-skills&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/multica-ai/andrej-karpathy-skills/blob/main/.cursor/rules/karpathy-guidelines.mdc&quot; data-og-url=&quot;https://github.com/multica-ai/andrej-karpathy-skills/blob/main/.cursor/rules/karpathy-guidelines.mdc&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Fhl8S/dJMb9jOtl9W/Kpa0tTWz1aafGJi3k5yMTk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/boz1Gg/dJMb8RRYper/my6NejYRAfcOp36rOK7Ca1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/multica-ai/andrej-karpathy-skills/blob/main/.cursor/rules/karpathy-guidelines.mdc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/multica-ai/andrej-karpathy-skills/blob/main/.cursor/rules/karpathy-guidelines.mdc&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Fhl8S/dJMb9jOtl9W/Kpa0tTWz1aafGJi3k5yMTk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/boz1Gg/dJMb8RRYper/my6NejYRAfcOp36rOK7Ca1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;andrej-karpathy-skills/.cursor/rules/karpathy-guidelines.mdc at main &amp;middot; multica-ai/andrej-karpathy-skills&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls. - multica-ai/andrej-karpathy-skills&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/470</guid>
      <comments>https://sddev.tistory.com/470#entry470comment</comments>
      <pubDate>Wed, 27 May 2026 14:05:19 +0900</pubDate>
    </item>
    <item>
      <title>[AI] Claude Code 분석 모음</title>
      <link>https://sddev.tistory.com/469</link>
      <description>&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/clqTjf/dJMcahxJ3Sk/XDvtFExijMUgxqZhrOK3G0/ai-study.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;ai-study.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.55MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>sddev</author>
      <guid isPermaLink="true">https://sddev.tistory.com/469</guid>
      <comments>https://sddev.tistory.com/469#entry469comment</comments>
      <pubDate>Thu, 21 May 2026 00:09:10 +0900</pubDate>
    </item>
  </channel>
</rss>