<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>lova-clover.log</title>
        <link>https://velog.io/</link>
        <description>프로젝트 및 해커톤 활동하는 오리</description>
        <lastBuildDate>Mon, 08 Jun 2026 22:38:22 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>lova-clover.log</title>
            <url>https://velog.velcdn.com/images/lova-clover/profile/08d20bbe-ef14-4699-ba93-313eaaa6cceb/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. lova-clover.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lova-clover" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[AI Agent는 챗봇이 아니다: 프롬프트의 시대에서 구조의 시대로]]></title>
            <link>https://velog.io/@lova-clover/AI-Agent%EB%8A%94-%EC%B1%97%EB%B4%87%EC%9D%B4-%EC%95%84%EB%8B%88%EB%8B%A4-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8%EC%9D%98-%EC%8B%9C%EB%8C%80%EC%97%90%EC%84%9C-%EA%B5%AC%EC%A1%B0%EC%9D%98-%EC%8B%9C%EB%8C%80%EB%A1%9C</link>
            <guid>https://velog.io/@lova-clover/AI-Agent%EB%8A%94-%EC%B1%97%EB%B4%87%EC%9D%B4-%EC%95%84%EB%8B%88%EB%8B%A4-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8%EC%9D%98-%EC%8B%9C%EB%8C%80%EC%97%90%EC%84%9C-%EA%B5%AC%EC%A1%B0%EC%9D%98-%EC%8B%9C%EB%8C%80%EB%A1%9C</guid>
            <pubDate>Mon, 08 Jun 2026 22:38:22 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요, Lova-clover입니다.</p>
<p>이번 글은 Antonio Gulli의 <code>Agentic Design Patterns: A Hands-On Guide to Building Intelligent Systems</code>를 읽고 정리한 글입니다.</p>
<p>처음에는 제목만 보고 “AI Agent 디자인 패턴을 모아둔 책인가?” 정도로 생각했습니다. Prompt Chaining, RAG, Tool Use, Multi-Agent 같은 익숙한 키워드가 나열되어 있어서, 그냥 요즘 유행하는 AI Agent 패턴 모음집처럼 보였습니다.</p>
<p>그런데 읽다 보니 느낌이 조금 달랐습니다.</p>
<p>이 책은 단순히 “이런 패턴이 있다”를 설명하는 책이라기보다, <strong>LLM을 어떻게 실제 시스템으로 만들 것인가</strong>에 대한 설계 노트에 가까웠습니다.</p>
<p>요즘 AI Agent라는 말은 정말 많이 보입니다.
챗봇에도 Agent라는 이름을 붙이고, 자동화 스크립트에도 Agent라고 부르고, RAG 하나 붙인 서비스도 Agent라고 말합니다.</p>
<p>그런데 이 책을 읽으면서 기준이 조금 선명해졌습니다.</p>
<blockquote>
<p>AI Agent는 답변을 잘하는 챗봇이 아니라, 목표를 향해 움직이는 시스템이다.</p>
</blockquote>
<p>이 한 문장이 이번 글의 핵심입니다.</p>
<hr>
<h2 id="한눈에-정리하면">한눈에 정리하면</h2>
<p>이 책을 읽고 제가 이해한 핵심은 이렇습니다.</p>
<pre><code class="language-text">LLM은 엔진이다.
Agent는 그 엔진을 움직이게 하는 시스템이다.

프롬프트는 출발점이다.
하지만 Agentic System은 프롬프트, 상태, 도구, 메모리, 계획, 검증, 안전장치가 함께 있어야 한다.</code></pre>
<p><code>Agentic Design Patterns</code>는 총 21개의 패턴을 다룹니다. 책에는 Prompt Chaining, Routing, Parallelization, Reflection, Tool Use, Planning, Multi-Agent, Memory Management, Learning and Adaptation, MCP, Goal Setting and Monitoring, Exception Handling, Human-in-the-Loop, RAG, A2A, Resource-Aware Optimization, Reasoning Techniques, Guardrails, Evaluation and Monitoring, Prioritization, Exploration and Discovery 등이 포함되어 있습니다. </p>
<p>제가 느낀 이 책의 핵심은 다음과 같습니다.</p>
<pre><code class="language-text">1. AI Agent는 프롬프트 하나로 만들어지지 않는다.
2. 복잡한 작업은 반드시 쪼개야 한다.
3. Agent는 외부 도구와 연결되어야 실제 일을 할 수 있다.
4. RAG는 끝이 아니라 Agentic RAG로 진화하고 있다.
5. 앞으로는 MCP, A2A 같은 연결 표준이 중요해진다.
6. 실서비스 Agent는 Guardrails, Evaluation, Monitoring 없이는 위험하다.
7. 결국 중요한 건 패턴 하나가 아니라 패턴 조합이다.</code></pre>
<p>개인적으로 가장 크게 남은 문장은 이겁니다.</p>
<blockquote>
<p>이제 AI 개발은 “모델을 잘 부르는 것”보다 “모델이 일할 수 있는 구조를 설계하는 것”에 가까워지고 있다.</p>
</blockquote>
<hr>
<h2 id="ai-agent란-무엇인가">AI Agent란 무엇인가?</h2>
<p>일반적인 챗봇은 보통 이런 식으로 동작합니다.</p>
<pre><code class="language-text">사용자 질문
-&gt; LLM 답변
-&gt; 끝</code></pre>
<p>물론 이것만으로도 충분히 유용합니다.
하지만 Agent는 여기서 한 단계 더 갑니다.</p>
<p>책에서는 AI Agent를 “환경을 인식하고, 특정 목표를 달성하기 위해 행동하는 시스템”으로 설명합니다. 그리고 Agentic AI의 동작 흐름을 다음 5단계로 정리합니다. </p>
<pre><code class="language-text">1. Get the Mission
2. Scan the Scene
3. Think It Through
4. Take Action
5. Learn and Get Better</code></pre>
<p>이걸 제 식으로 바꾸면 이렇게 볼 수 있습니다.</p>
<pre><code class="language-text">목표를 받는다.
필요한 정보를 모은다.
계획을 세운다.
도구를 사용해 행동한다.
결과를 보고 다음에 더 잘하도록 개선한다.</code></pre>
<p>즉, Agent는 단순히 “대답하는 AI”가 아닙니다.
Agent는 <strong>목표를 수행하기 위해 생각하고, 도구를 쓰고, 상태를 유지하고, 결과를 검토하는 시스템</strong>입니다.</p>
<p>OpenAI의 <a href="https://developers.openai.com/api/docs/guides/agents" title="Agents SDK | OpenAI API">Agents SDK 문서</a>에서도 Agent를 “계획하고, 도구를 호출하고, 여러 specialist와 협업하며, multi-step 작업을 완료하기 위해 충분한 상태를 유지하는 애플리케이션”으로 설명합니다.</p>
<p>여기서 중요한 차이가 생깁니다.</p>
<pre><code class="language-text">챗봇: 질문에 답한다.
Agent: 목표를 달성한다.</code></pre>
<p>이 차이를 이해하지 못하면, 아무리 GPT API를 많이 붙여도 Agent가 아니라 “조금 똑똑한 챗봇”에서 끝날 수 있습니다.</p>
<hr>
<h2 id="이-책을-읽으며-가장-크게-바뀐-생각">이 책을 읽으며 가장 크게 바뀐 생각</h2>
<p>저는 이 책을 읽기 전에는 AI Agent를 조금 기능 중심으로 봤습니다.</p>
<pre><code class="language-text">RAG 붙이면 좋다.
Tool Use 붙이면 좋다.
Multi-Agent로 나누면 멋있다.
LangGraph 쓰면 Agent 같다.</code></pre>
<p>그런데 책을 읽고 나니 생각이 조금 바뀌었습니다.</p>
<p>기능을 붙이는 것보다 중요한 건 <strong>흐름을 설계하는 것</strong>이었습니다.</p>
<p>예를 들어, “AI가 보고서를 작성한다”는 기능을 만든다고 해보겠습니다.
겉으로 보면 그냥 LLM에게 보고서를 써달라고 하면 될 것 같습니다.</p>
<p>하지만 제대로 만들려면 이런 질문을 해야 합니다.</p>
<pre><code class="language-text">사용자의 목표는 무엇인가?
필요한 자료는 어디서 가져오는가?
자료가 최신인지 어떻게 확인하는가?
여러 자료가 충돌하면 어떻게 판단하는가?
보고서 초안은 누가 작성하는가?
초안의 오류는 누가 검토하는가?
최종 결과는 어떤 기준으로 평가하는가?
실패하면 어떻게 복구하는가?
사람 승인은 어디에 들어가는가?</code></pre>
<p>이 질문에 답하는 과정이 Agentic Design에 가깝습니다.</p>
<p>책에서도 강력한 LLM만으로는 복잡한 목표를 안정적으로 달성하기 어렵고, 상태 관리, 커뮤니케이션, 도구 접근, 로직 흐름을 다루는 구조가 필요하다고 설명합니다. </p>
<p>읽으면서 조금 찔렸던 부분도 있습니다.</p>
<p>AI를 쓰다 보면 “생성은 됐으니까 된 거 아닌가?”라는 착각을 하기 쉽습니다.
하지만 이 책은 계속 묻습니다.</p>
<pre><code class="language-text">그 결과는 검증됐는가?
그 과정은 재현 가능한가?
그 Agent는 실패했을 때 멈출 수 있는가?
그 도구 호출은 안전한가?
그 출력은 사람이 승인할 수 있는 형태인가?
그 비용과 지연시간은 감당 가능한가?</code></pre>
<p>이 질문들이 좋았습니다.</p>
<p>왜냐하면 이 질문들이 있어야 AI 프로젝트가 장난감에서 벗어나 실제 서비스에 가까워지기 때문입니다.</p>
<hr>
<h2 id="21개-패턴을-크게-나누면">21개 패턴을 크게 나누면</h2>
<p>책에는 21개 패턴이 나오지만,
저는 이 패턴들을 크게 5개 그룹으로 나눠서 보는 게 이해하기 좋았습니다.</p>
<pre><code class="language-text">1. 작업 흐름을 만드는 패턴
2. 외부 세계와 연결하고 협업하는 패턴
3. 기억하고 개선하는 패턴
4. 안전하게 운영하는 패턴
5. 더 깊게 추론하고 탐색하는 패턴</code></pre>
<p>하나씩 보면 이렇습니다.</p>
<hr>
<h2 id="1-작업-흐름을-만드는-패턴">1. 작업 흐름을 만드는 패턴</h2>
<p>여기에 들어가는 대표 패턴은 다음과 같습니다.</p>
<pre><code class="language-text">Prompt Chaining
Routing
Parallelization
Planning
Prioritization</code></pre>
<p>이 그룹은 Agent가 일을 “어떤 순서로 처리할지”를 다룹니다.</p>
<p>Prompt Chaining은 복잡한 작업을 한 번에 처리하지 않고 여러 단계로 나누는 방식입니다. 책에서는 하나의 큰 프롬프트가 여러 제약과 추론 단계를 동시에 처리하려 하면 지시 누락, 문맥 이탈, 오류 증가가 생길 수 있다고 설명합니다. 그래서 복잡한 작업을 작은 단계로 나누고, 이전 단계의 출력을 다음 단계의 입력으로 넘기는 구조가 필요합니다. </p>
<p>예를 들어 시장 조사 보고서를 만든다면 이렇게 나눌 수 있습니다.</p>
<pre><code class="language-text">자료 수집
-&gt; 핵심 내용 요약
-&gt; 주요 트렌드 추출
-&gt; 근거 데이터 정리
-&gt; 보고서 초안 작성
-&gt; 최종 검토</code></pre>
<p>Routing은 입력에 따라 다른 경로로 보내는 패턴입니다.</p>
<pre><code class="language-text">결제 문의 -&gt; 결제 Agent
기술 문의 -&gt; 기술지원 Agent
환불 문의 -&gt; 환불 정책 Tool
모호한 질문 -&gt; 추가 질문</code></pre>
<p>Parallelization은 독립적인 작업을 동시에 처리하는 방식입니다.</p>
<pre><code class="language-text">뉴스 검색
논문 검색
공식 문서 검색
커뮤니티 반응 검색</code></pre>
<p>이런 작업들은 서로 기다릴 필요가 없으니 병렬로 처리할 수 있습니다.</p>
<p>Planning은 목표를 여러 하위 단계로 쪼개는 능력입니다.</p>
<pre><code class="language-text">&quot;AI Agent 트렌드 보고서 작성해줘&quot;
-&gt; Agent 정의 정리
-&gt; 주요 패턴 조사
-&gt; MCP/A2A 동향 확인
-&gt; 실무 적용 사례 정리
-&gt; 결론 작성</code></pre>
<p>이제 중요한 건 “LLM이 글을 잘 쓰냐”가 아니라, <strong>LLM이 어떤 순서로 일을 하게 만들 것인가</strong>입니다.</p>
<hr>
<h2 id="2-외부-세계와-연결하고-협업하는-패턴">2. 외부 세계와 연결하고 협업하는 패턴</h2>
<p>여기에 들어가는 대표 패턴은 다음과 같습니다.</p>
<pre><code class="language-text">Tool Use
RAG
MCP
A2A
Multi-Agent</code></pre>
<p>LLM은 기본적으로 텍스트를 생성하는 모델입니다.
하지만 실제 업무에서는 텍스트 생성만으로는 부족합니다.</p>
<pre><code class="language-text">최신 정보를 검색해야 한다.
DB를 조회해야 한다.
계산을 해야 한다.
파일을 읽어야 한다.
API를 호출해야 한다.
다른 Agent에게 일을 넘겨야 한다.</code></pre>
<p>이때 Tool Use가 필요합니다.</p>
<p>Tool Use는 Agent가 외부 API, 데이터베이스, 검색 도구, 계산기, 코드 실행기 등을 사용하는 패턴입니다. 책에서는 Tool Use가 LLM을 정적인 텍스트 생성기에서 외부 시스템과 상호작용하는 Agent로 바꾸는 핵심 패턴이라고 설명합니다. </p>
<p>RAG는 외부 문서나 지식 기반을 검색해서 LLM의 답변에 근거를 넣는 방식입니다.
하지만 요즘은 단순 RAG에서 한 단계 더 나아가 <strong>Agentic RAG</strong>가 중요해지고 있습니다.</p>
<p>일반 RAG가 이런 구조라면,</p>
<pre><code class="language-text">질문
-&gt; 관련 문서 검색
-&gt; LLM 답변</code></pre>
<p>Agentic RAG는 이렇게 움직입니다.</p>
<pre><code class="language-text">질문 분석
-&gt; 필요한 정보 판단
-&gt; 여러 소스 검색
-&gt; 출처 신뢰도 확인
-&gt; 충돌 정보 비교
-&gt; 부족한 정보 추가 검색
-&gt; 최종 답변 생성</code></pre>
<p>책에서는 Agentic RAG가 단순히 검색 결과를 받아들이는 구조가 아니라, 검색된 정보의 품질, 관련성, 완전성을 Agent가 능동적으로 점검하는 구조라고 설명합니다. 오래된 문서와 최신 정책 문서가 함께 검색되면 최신 공식 문서를 우선하고, 서로 다른 예산 수치가 검색되면 더 신뢰할 수 있는 최종 보고서를 선택하는 식입니다. </p>
<p>여기서 MCP와 A2A도 중요해집니다.</p>
<p>MCP는 AI 애플리케이션이 외부 데이터, 도구, 워크플로우에 연결될 수 있도록 돕는 오픈 표준입니다. <a href="https://modelcontextprotocol.io/docs/getting-started/intro" title="What is the Model Context Protocol (MCP)?">MCP 공식 문서</a>에서는 MCP를 AI 애플리케이션을 위한 “USB-C 포트”처럼 설명합니다.</p>
<p>책에서도 MCP는 단순 function calling과 다르다고 설명합니다. Function Calling이 정해진 함수 몇 개를 직접 호출하는 방식에 가깝다면, MCP는 LLM이 외부 도구와 리소스를 발견하고 사용할 수 있도록 하는 표준화된 연결 방식에 가깝습니다. </p>
<p>A2A는 Agent와 Agent가 서로 통신하기 위한 프로토콜입니다. Google은 <a href="https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/" title="Announcing the Agent2Agent Protocol (A2A)">A2A 발표 글</a>에서 A2A가 서로 다른 프레임워크나 공급자의 Agent들이 안전하게 정보를 교환하고 작업을 조정할 수 있게 한다고 설명합니다.</p>
<p>Multi-Agent는 하나의 Agent가 모든 일을 처리하는 대신, 여러 전문 Agent가 역할을 나눠 협업하는 구조입니다. A2A가 Agent와 Agent가 서로 통신하기 위한 연결 표준에 가깝다면, Multi-Agent는 그 안에서 어떤 Agent가 어떤 역할을 맡을지 설계하는 패턴에 가깝습니다.</p>
<p>쉽게 정리하면 이렇습니다.</p>
<pre><code class="language-text">Function Calling = 정해진 함수 호출
MCP = Agent와 도구/데이터를 연결하는 표준
A2A = Agent와 Agent를 연결하는 표준
Multi-Agent = Agent들의 역할 분담 구조</code></pre>
<p>이 흐름은 앞으로 꽤 중요해질 것 같습니다.</p>
<p>지금까지는 “내 앱 안에서 GPT를 어떻게 쓸까?”가 중요했다면, 앞으로는 “여러 Agent와 도구가 어떻게 연결될까?”가 더 중요해질 수 있기 때문입니다.</p>
<hr>
<h2 id="3-기억하고-개선하는-패턴">3. 기억하고 개선하는 패턴</h2>
<p>여기에 들어가는 대표 패턴은 다음과 같습니다.</p>
<pre><code class="language-text">Memory Management
Reflection
Learning and Adaptation
Goal Setting and Monitoring</code></pre>
<p>Agent가 단발성 답변만 한다면 메모리가 없어도 됩니다.
하지만 실제 작업은 보통 한 번에 끝나지 않습니다.</p>
<pre><code class="language-text">사용자의 이전 요청을 기억해야 한다.
작업 진행 상태를 알아야 한다.
이전에 실패한 방법을 피해야 한다.
사용자의 선호를 반영해야 한다.
초안을 만들고 다시 고쳐야 한다.</code></pre>
<p>이때 Memory와 Reflection이 중요해집니다.</p>
<p>Reflection은 Agent가 자신의 결과물을 다시 검토하고 개선하는 패턴입니다.
책에서는 Producer-Critic 구조를 설명합니다. 하나의 Agent가 결과를 만들고, 다른 Critic Agent가 오류, 누락, 품질 문제를 검토하는 방식입니다. </p>
<p>예를 들어 글쓰기 Agent라면 이렇게 만들 수 있습니다.</p>
<pre><code class="language-text">Writer Agent: 초안 작성
Critic Agent: 논리, 근거, 흐름 검토
Editor Agent: 문장 정리
Final Agent: 최종 출력</code></pre>
<p>코드 생성이라면 이렇게 볼 수 있습니다.</p>
<pre><code class="language-text">Implementer Agent: 코드 작성
Reviewer Agent: 버그와 구조 검토
Test Writer Agent: 테스트 작성
Refactor Agent: 수정</code></pre>
<p>이 구조가 중요한 이유는 단순합니다.</p>
<p>LLM의 첫 답변은 자주 그럴듯하지만 완벽하지 않습니다.
그래서 “한 번에 맞히기”보다 “만들고, 검토하고, 고치는 구조”가 훨씬 현실적입니다.</p>
<p>Goal Setting and Monitoring도 좋았습니다.</p>
<p>Agent에게 그냥 “잘해줘”라고 하면 안 됩니다.
목표와 성공 기준이 있어야 합니다.</p>
<pre><code class="language-text">목표: 고객 문의를 해결한다.
성공 기준: 답변 정확도, 처리 시간, 고객 만족도, 에스컬레이션 여부
모니터링: 어떤 도구를 썼는지, 어디서 실패했는지, 비용은 얼마인지</code></pre>
<p>즉, 좋은 Agent는 그냥 실행하는 게 아니라 <strong>자신이 목표에 가까워지고 있는지 추적해야 합니다.</strong></p>
<hr>
<h2 id="4-안전하게-운영하는-패턴">4. 안전하게 운영하는 패턴</h2>
<p>여기에 들어가는 대표 패턴은 다음과 같습니다.</p>
<pre><code class="language-text">Exception Handling
Human-in-the-Loop
Guardrails
Evaluation and Monitoring
Resource-Aware Optimization</code></pre>
<p>이 부분이 진짜 중요했습니다.</p>
<p>요즘은 AI Agent 데모가 정말 많습니다.
그런데 데모와 운영은 완전히 다릅니다.</p>
<p>데모에서는 한두 번 잘 돌아가면 괜찮아 보입니다.
하지만 실제 서비스에서는 계속 물어봐야 합니다.</p>
<pre><code class="language-text">도구 호출이 실패하면?
검색 결과가 틀리면?
비용이 너무 많이 나오면?
모델이 위험한 행동을 하려 하면?
사용자 데이터가 민감하면?
최종 결정을 AI가 해도 되는가?
누가 책임지는가?</code></pre>
<p>책은 Guardrails를 Agent가 위험하거나 원하지 않는 행동을 하지 않도록 막는 안전 패턴으로 설명합니다. 입력 검증, 출력 필터링, 도구 사용 제한, 외부 moderation, Human-in-the-Loop 등이 여기에 포함됩니다. </p>
<p>OpenAI의 <a href="https://developers.openai.com/api/docs/guides/agents" title="Agents SDK | OpenAI API">Agents SDK 문서</a>에서도 Agents SDK를 사용할 때 validation 또는 human review가 필요한 경우 Guardrails and human review를 추가하고, 실행을 추적하고 개선하기 위해 traces와 evaluation loop를 활용하는 흐름을 안내합니다.</p>
<p>이 부분을 보면서 든 생각은 이것입니다.</p>
<blockquote>
<p>실서비스 Agent는 똑똑해야 하는 것보다 먼저 안전해야 한다.</p>
</blockquote>
<p>특히 금융, 의료, 법률, 공공, 제조 같은 영역에서는 AI가 “알아서 결정”하면 위험할 수 있습니다.</p>
<p>현실적인 구조는 보통 이런 쪽에 가깝습니다.</p>
<pre><code class="language-text">AI가 후보를 만든다.
AI가 근거를 정리한다.
AI가 위험도를 표시한다.
사람이 승인한다.
시스템이 로그를 남긴다.
나중에 평가한다.</code></pre>
<p>이게 훨씬 안전하고 설득력 있습니다.</p>
<p>최근 Gartner는 <a href="https://www.gartner.com/en/newsroom/press-releases/2025-06-25-gartner-predicts-over-40-percent-of-agentic-ai-projects-will-be-canceled-by-end-of-2027" title="Gartner: Over 40% of Agentic AI Projects Will Be Canceled ...">Agentic AI 프로젝트 전망 발표</a>에서 Agentic AI 프로젝트 중 상당수가 비용 증가, 불명확한 비즈니스 가치, 부족한 리스크 관리 때문에 취소될 수 있다고 전망했습니다. 동시에 “Agent Washing”, 즉 기존 챗봇이나 자동화 도구를 진짜 Agent처럼 포장하는 문제도 지적했습니다.</p>
<p>그래서 앞으로는 “Agent를 만들었다”보다 이 질문이 더 중요해질 것 같습니다.</p>
<pre><code class="language-text">이 Agent는 어떤 목표를 달성하는가?
실패했을 때 어떻게 멈추는가?
사람 승인은 어디에 있는가?
비용과 지연시간은 관리되는가?
로그와 평가 지표는 남는가?</code></pre>
<p>이 질문에 답하지 못하면, 그건 아직 서비스라기보다는 실험에 가깝다고 생각합니다.</p>
<hr>
<h2 id="5-더-깊게-추론하고-탐색하는-패턴">5. 더 깊게 추론하고 탐색하는 패턴</h2>
<p>여기에 들어가는 대표 패턴은 다음과 같습니다.</p>
<pre><code class="language-text">Reasoning Techniques
Exploration and Discovery</code></pre>
<p>Reasoning Techniques에는 Chain-of-Thought, Tree-of-Thought, ReAct, Self-Correction 같은 방식이 포함됩니다.</p>
<p>책에서는 복잡한 문제를 해결하기 위해 Agent가 단순히 답을 내는 것이 아니라, 문제를 분해하고, 여러 경로를 탐색하고, 도구를 사용하고, 관찰 결과를 바탕으로 다음 행동을 정하는 구조를 설명합니다. </p>
<p>특히 ReAct 흐름은 Agent를 이해하는 데 도움이 됩니다.</p>
<pre><code class="language-text">Thought
-&gt; Action
-&gt; Observation
-&gt; Thought
-&gt; Action
-&gt; Observation
-&gt; Final Answer</code></pre>
<p>즉, Agent는 머릿속으로만 추론하는 것이 아니라, 생각한 뒤 행동하고, 행동 결과를 보고 다시 생각합니다.</p>
<p>이 구조가 들어가면 LLM은 단순 답변기가 아니라 문제 해결 루프를 가진 시스템에 가까워집니다.</p>
<hr>
<h2 id="최근-ai-agent-트렌드를-이-책으로-다시-보면">최근 AI Agent 트렌드를 이 책으로 다시 보면</h2>
<p>이 책을 읽고 나니 최근 AI 트렌드가 조금 다르게 보였습니다.</p>
<p>예전에는 이런 흐름이었습니다.</p>
<pre><code class="language-text">프롬프트 잘 쓰기
-&gt; RAG 붙이기
-&gt; Function Calling 붙이기</code></pre>
<p>지금은 흐름이 조금 바뀌고 있습니다.</p>
<pre><code class="language-text">Prompt Engineering
-&gt; Context Engineering

RAG
-&gt; Agentic RAG

Function Calling
-&gt; MCP

Single Agent
-&gt; Multi-Agent / A2A

데모
-&gt; 평가, 모니터링, 가드레일이 있는 운영 시스템</code></pre>
<p>하나씩 보면 이렇습니다.</p>
<hr>
<h2 id="트렌드-1-prompt-engineering에서-context-engineering으로">트렌드 1. Prompt Engineering에서 Context Engineering으로</h2>
<p>예전에는 프롬프트 문장을 얼마나 잘 쓰는지가 중요했습니다.</p>
<p>물론 지금도 중요합니다.
하지만 Agent 시대에는 프롬프트 한 줄보다, 모델에게 어떤 정보를 언제, 어떤 형태로 제공할지가 더 중요해지고 있습니다.</p>
<p>책에서는 Context Engineering을 모델이 토큰을 생성하기 전에 필요한 정보 환경을 설계하고 구성하는 과정으로 설명합니다. 여기에는 시스템 프롬프트, 검색된 문서, 도구 출력, 사용자 히스토리, 환경 상태 같은 정보가 포함됩니다. </p>
<p>이걸 쉽게 말하면 이렇습니다.</p>
<pre><code class="language-text">Prompt Engineering:
질문을 잘 쓰는 것

Context Engineering:
모델이 제대로 판단할 수 있도록 필요한 상황판을 만들어주는 것</code></pre>
<p>요즘 좋은 AI 서비스는 단순히 프롬프트가 좋은 게 아니라, 모델 앞에 놓이는 정보의 품질이 좋습니다.</p>
<hr>
<h2 id="트렌드-2-rag에서-agentic-rag로">트렌드 2. RAG에서 Agentic RAG로</h2>
<p>RAG는 이미 많은 사람들이 알고 있습니다.</p>
<p>하지만 단순 RAG만으로는 부족한 경우가 많습니다.</p>
<pre><code class="language-text">검색 결과가 오래됐으면?
서로 충돌하는 문서가 있으면?
질문이 복잡해서 여러 번 검색해야 하면?
내부 문서에 답이 없고 외부 검색이 필요하면?</code></pre>
<p>이때 Agentic RAG가 필요합니다.</p>
<p>Agentic RAG는 검색된 자료를 그냥 LLM에게 넘기지 않습니다.
Agent가 자료의 신뢰도, 최신성, 충돌 여부, 부족한 정보를 판단합니다. </p>
<p>그래서 앞으로 RAG 프로젝트를 할 때는 이렇게 말하면 약합니다.</p>
<pre><code class="language-text">문서를 검색해서 답변합니다.</code></pre>
<p>조금 더 강한 설명은 이렇습니다.</p>
<pre><code class="language-text">질문을 분석하고,
필요한 정보를 여러 소스에서 검색하고,
출처의 신뢰도와 최신성을 검토하고,
충돌하는 정보를 조정한 뒤,
근거 기반 답변을 생성합니다.</code></pre>
<p>이 차이가 큽니다.</p>
<p>전자는 검색 기능이고,
후자는 Agentic Workflow입니다.</p>
<hr>
<h2 id="트렌드-3-function-calling에서-mcp로">트렌드 3. Function Calling에서 MCP로</h2>
<p>Function Calling은 특정 함수를 LLM이 호출할 수 있게 만드는 방식입니다.
간단한 서비스에는 충분히 좋습니다.</p>
<p>하지만 도구가 많아지고, 여러 시스템과 연결해야 하고, 다른 Agent나 앱에서도 재사용해야 한다면 표준화가 중요해집니다.</p>
<p>MCP는 바로 이 지점에서 중요해집니다. 
<a href="https://modelcontextprotocol.io/docs/getting-started/intro" title="What is the Model Context Protocol (MCP)?">MCP 공식 문서</a>에서는 MCP를 AI 애플리케이션이 데이터 소스, 도구, 워크플로우에 연결되도록 하는 오픈소스 표준이라고 설명합니다.</p>
<p>책에서도 MCP는 단순히 도구를 하나 호출하는 구조가 아니라, LLM이 외부 리소스와 도구를 발견하고 사용할 수 있게 하는 표준 인터페이스에 가깝다고 설명합니다. </p>
<p>앞으로는 “어떤 API를 붙였는가?”뿐 아니라 이런 질문이 중요해질 것 같습니다.</p>
<pre><code class="language-text">이 도구는 다른 Agent도 재사용할 수 있는가?
권한 관리는 되는가?
도구 설명은 명확한가?
입출력 스키마는 안정적인가?
실패했을 때 Agent가 이해할 수 있는 오류를 반환하는가?</code></pre>
<p>이제 AI 개발은 API 연결을 넘어, <strong>Agent가 사용할 수 있는 도구 생태계를 설계하는 일</strong>이 되고 있습니다.</p>
<hr>
<h2 id="트렌드-4-single-agent에서-multi-agent--a2a로">트렌드 4. Single Agent에서 Multi-Agent / A2A로</h2>
<p>처음 Agent를 만들 때는 하나의 Agent가 모든 일을 하게 만들고 싶어집니다.</p>
<p>하지만 복잡한 문제는 보통 한 명의 만능 Agent보다 여러 전문 Agent가 나눠서 처리하는 편이 자연스럽습니다.</p>
<p>예를 들어 리서치 보고서를 만든다면 이렇게 나눌 수 있습니다.</p>
<pre><code class="language-text">Planner Agent: 조사 계획 수립
Researcher Agent: 자료 검색
Analyst Agent: 핵심 분석
Writer Agent: 초안 작성
Critic Agent: 오류 검토
Editor Agent: 최종 정리</code></pre>
<p>책도 복잡한 문제는 하나의 generalist Agent보다 여러 specialist Agent가 협업하는 구조가 더 적합할 수 있다고 설명합니다. </p>
<p>Google의 A2A 프로토콜은 이런 Agent 간 협업을 표준화하려는 흐름입니다. Google은 <a href="https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/" title="Announcing the Agent2Agent Protocol (A2A)">A2A 발표 글</a>에서 Agent들이 서로 정보를 교환하고 작업을 조정할 수 있다고 설명합니다. 또한 <a href="https://developers.googleblog.com/developers-guide-to-ai-agent-protocols/" title="Developer&#39;s Guide to AI Agent Protocols">AI Agent Protocols 개발자 가이드</a>에서는 A2A Agent가 Agent Card를 통해 이름, 기능, endpoint 같은 정보를 제공하고, 다른 Agent가 이를 바탕으로 기능을 발견하고 호출하는 구조를 설명합니다.</p>
<p>정리하면 앞으로의 방향은 이쪽에 가까워 보입니다.</p>
<pre><code class="language-text">하나의 거대한 Agent
-&gt; 역할이 나뉜 Agent 팀
-&gt; Agent끼리 표준 프로토콜로 연결되는 생태계</code></pre>
<hr>
<h2 id="트렌드-5-데모-agent에서-운영-가능한-agent로">트렌드 5. 데모 Agent에서 운영 가능한 Agent로</h2>
<p>가장 현실적인 트렌드는 이것이라고 생각합니다.</p>
<blockquote>
<p>앞으로는 “된다”보다 “운영 가능하다”가 중요해진다.</p>
</blockquote>
<p>AI Agent 데모는 이제 어렵지 않게 만들 수 있습니다.
하지만 운영 가능한 Agent는 훨씬 어렵습니다.</p>
<p>운영 가능한 Agent는 적어도 이런 것들이 필요합니다.</p>
<pre><code class="language-text">로그
평가 지표
비용 관리
지연시간 관리
오류 복구
권한 관리
도구 사용 제한
사람 승인
모니터링</code></pre>
<p>OpenAI의 <a href="https://developers.openai.com/api/docs/guides/agents" title="Agents SDK | OpenAI API">Agents SDK 문서</a>에서도 애플리케이션이 orchestration, tool execution, approvals, state를 직접 소유해야 할 때 Agents SDK가 적합하다고 설명합니다. 또한 복잡한 workflow에서는 handoffs, guardrails, human review, tracing, evaluation loop가 중요해집니다.</p>
<p>결국 Agent 개발은 “신기한 데모 만들기”에서 “안정적인 업무 시스템 만들기”로 넘어가야 합니다.</p>
<hr>
<h2 id="이-책이-좋았던-이유">이 책이 좋았던 이유</h2>
<p>제가 이 책에서 좋았던 점은 세 가지였습니다.</p>
<p>첫 번째는, 키워드가 아니라 구조를 보게 해준다는 점입니다.</p>
<p>요즘은 AI 키워드가 너무 빨리 바뀝니다.</p>
<pre><code class="language-text">RAG
GraphRAG
Agentic RAG
MCP
A2A
Multi-Agent
Deep Research
Context Engineering</code></pre>
<p>하나하나 따라가다 보면 끝이 없습니다.</p>
<p>그런데 이 책은 “지금 유행하는 기술명”보다 그 아래에 있는 반복되는 구조를 보게 해줍니다.</p>
<pre><code class="language-text">작업을 쪼갠다.
적절한 경로로 보낸다.
필요한 도구를 쓴다.
상태를 기억한다.
결과를 검토한다.
위험하면 멈춘다.
사람에게 넘긴다.
평가하고 개선한다.</code></pre>
<p>이건 모델이 바뀌어도 오래 갈 가능성이 높은 원리라고 느꼈습니다.</p>
<p>두 번째로 좋았던 점은, 이 책이 Agent를 마법처럼 포장하지 않는다는 점입니다.</p>
<p>요즘 AI Agent 이야기를 보면, 마치 목표만 던지면 AI가 알아서 계획하고, 실행하고, 검토하고, 결과까지 완벽하게 가져오는 것처럼 느껴질 때가 많습니다. 저도 처음에는 Agent라는 단어에서 그런 이미지를 떠올렸습니다.</p>
<p>하지만 이 책은 그 기대감을 적당히 눌러줍니다. Agent는 분명 강력하지만, 실제 시스템 안에 넣는 순간 훨씬 현실적인 문제들과 마주합니다.</p>
<pre><code class="language-text">모델 호출 비용은 계속 쌓인다.
작업 단계가 늘수록 응답은 느려진다.
도구 호출은 실패할 수 있다.
검색 결과는 틀리거나 오래됐을 수 있다.
메모리는 누락되거나 꼬일 수 있다.
Agent가 잘못된 판단을 할 수도 있다.
그래서 로그, 검증, 안전장치, 사람의 승인 과정이 필요하다.</code></pre>
<p>이 부분이 오히려 좋았습니다.</p>
<p>이 책은 “이제 AI가 다 해준다”는 식으로 독자를 들뜨게 만들지 않습니다. 대신 실제로 Agent를 만들고 운영할 때 어디서 깨질 수 있는지, 왜 깨지는지, 그리고 그 문제를 어떤 구조로 막아야 하는지를 보여줍니다.</p>
<p>그래서 더 실용적으로 느껴졌습니다.</p>
<p>Agent를 멋진 데모가 아니라, 운영 가능한 시스템으로 보게 만들기 때문입니다.</p>
<p>읽으면서 든 생각은 단순했습니다.</p>
<blockquote>
<p>좋은 AI Agent는 똑똑한 모델 하나 위에 세워지는 게 아니라, 실패를 전제로 한 구조 위에 세워진다.</p>
</blockquote>
<p>세 번째는, 개발자의 역할을 다시 생각하게 만든다는 점입니다.</p>
<p>AI가 코드를 쓰고, 글을 쓰고, 검색을 하고, 보고서를 만드는 시대가 오면 개발자는 뭘 해야 할까?</p>
<p>이 책을 읽고 나서 제 답은 조금 선명해졌습니다.</p>
<pre><code class="language-text">개발자는 AI에게 일을 시키는 사람이 아니라,
AI가 안전하게 일할 수 있는 구조를 설계하는 사람이어야 한다.</code></pre>
<p>이게 핵심이라고 생각합니다.</p>
<hr>
<h2 id="내가-앞으로-ai-프로젝트를-만들-때-체크할-것들">내가 앞으로 AI 프로젝트를 만들 때 체크할 것들</h2>
<p>이 책을 읽고 나서, 앞으로 AI 프로젝트를 만들 때는 기능 목록보다 먼저 아래 체크리스트를 봐야겠다고 느꼈습니다.</p>
<pre><code class="language-text">1. 이 Agent의 목표는 무엇인가?
2. 사용자의 입력을 어떻게 분류할 것인가?
3. 어떤 작업을 순차 처리하고, 어떤 작업을 병렬 처리할 것인가?
4. 어떤 외부 도구/API/DB를 사용할 것인가?
5. 검색 결과나 도구 결과를 어떻게 검증할 것인가?
6. 중간 상태는 어디에 저장할 것인가?
7. 이전 대화나 사용자 선호를 기억해야 하는가?
8. 결과물을 누가 검토할 것인가?
9. 위험한 행동은 어떻게 막을 것인가?
10. 사람 승인은 어디에 들어가는가?
11. 실패하면 retry, fallback, escalation 중 무엇을 할 것인가?
12. 비용과 지연시간은 어떻게 관리할 것인가?
13. 최종 결과의 품질은 어떤 지표로 평가할 것인가?</code></pre>
<p>이 질문에 답할 수 있으면 프로젝트 설명도 훨씬 강해질 것 같습니다.</p>
<p>예전에는 이렇게 말했을 수 있습니다.</p>
<pre><code class="language-text">GPT API와 RAG를 활용한 자동화 서비스를 만들었습니다.</code></pre>
<p>이제는 이렇게 말해야 할 것 같습니다.</p>
<pre><code class="language-text">사용자 요청을 분류하고,
작업을 단계별로 분해한 뒤,
필요한 문서와 도구를 호출하고,
검색 결과를 검증하고,
생성 결과를 Critic Agent로 검토하며,
사람 승인과 로그를 남기는 Agentic Workflow를 설계했습니다.</code></pre>
<p>전자와 후자의 차이가 꽤나 크다고 느꼈습니다.</p>
<p>전자는 AI 기능을 붙인 느낌이고,
후자는 AI 시스템을 설계한 느낌입니다.</p>
<hr>
<h2 id="그래서-뭘-먼저-공부하면-좋을까">그래서 뭘 먼저 공부하면 좋을까?</h2>
<p>이 책을 다 읽고 바로 모든 패턴을 구현하려고 하면 오히려 막힐 것 같습니다.</p>
<p>저라면 우선순위를 이렇게 잡을 것 같습니다.</p>
<pre><code class="language-text">1. Prompt Chaining
2. Routing
3. Tool Use / Function Calling
4. RAG
5. Reflection
6. Memory
7. Evaluation / Monitoring
8. Guardrails
9. MCP
10. Multi-Agent / A2A</code></pre>
<p>처음부터 거대한 Multi-Agent 시스템을 만들 필요는 없습니다.</p>
<p>오히려 가장 좋은 시작은 작은 workflow 하나를 제대로 만드는 것이라고 생각합니다.</p>
<p>예를 들면 이런 구조입니다.</p>
<pre><code class="language-text">사용자 질문 입력
-&gt; 질문 유형 분류
-&gt; 필요한 경우 문서 검색
-&gt; 답변 생성
-&gt; Critic Agent가 검토
-&gt; 부족하면 재검색 또는 수정
-&gt; 최종 답변
-&gt; 로그 저장</code></pre>
<p>이 정도만 제대로 만들어도 Agentic Design의 핵심을 많이 배울 수 있습니다.</p>
<p>여기서 중요한 건 화려한 이름이 아닙니다.</p>
<pre><code class="language-text">상태가 있는가?
흐름이 있는가?
도구가 있는가?
검증이 있는가?
실패 처리가 있는가?
평가 지표가 있는가?</code></pre>
<p>이 질문이 더 중요합니다.</p>
<hr>
<h2 id="결론-ai-agent는-프롬프트가-아니라-설계다">결론: AI Agent는 프롬프트가 아니라 설계다</h2>
<p><code>Agentic Design Patterns</code>를 읽고 가장 크게 남은 생각은 하나입니다.</p>
<blockquote>
<p>AI Agent는 챗봇의 확장판이 아니라, 소프트웨어 아키텍처에 가깝다.</p>
</blockquote>
<p>LLM은 강력합니다.
하지만 LLM 하나만으로는 실제 서비스를 만들기 어렵습니다.</p>
<p>실제 서비스가 되려면 목표가 있어야 하고, 작업 흐름이 있어야 하고, 도구를 써야 하고, 상태를 기억해야 하고, 결과를 검증해야 하고, 실패를 복구해야 하고, 안전장치가 있어야 합니다.</p>
<p>정리하면 이렇습니다.</p>
<pre><code class="language-text">Prompt Chaining으로 작업을 나눈다.
Routing으로 적절한 경로를 선택한다.
Tool Use로 외부 세계와 연결한다.
RAG로 근거를 가져온다.
Memory로 맥락을 유지한다.
Reflection으로 결과를 개선한다.
Guardrails로 위험을 막는다.
Evaluation으로 품질을 측정한다.
MCP와 A2A로 도구와 Agent 생태계에 연결한다.</code></pre>
<p>앞으로 AI 개발자는 단순히 “AI를 잘 쓰는 사람”에서 끝나면 안 될 것 같습니다.</p>
<p>더 중요한 역할은 따로 있습니다.</p>
<blockquote>
<p>AI가 일할 수 있는 구조를 설계하는 사람.</p>
</blockquote>
<p>이 책은 그 방향을 꽤 선명하게 보여줬습니다.</p>
<p>저도 앞으로 AI 프로젝트를 만들 때 “GPT API를 붙였다”에서 멈추지 않고,
<strong>어떤 Agentic Workflow를 설계했는지</strong>까지 설명할 수 있는 방향으로 가야겠다고 느꼈습니다.</p>
<p>AI Agent라는 말이 유행처럼 지나갈 수도 있습니다.
하지만 작업을 쪼개고, 도구를 연결하고, 상태를 관리하고, 결과를 검증하고, 안전하게 운영하는 설계 감각은 쉽게 사라지지 않을 것 같습니다.</p>
<p>그래서 이 책은 단순히 Agent 책이라기보다, 앞으로 AI 개발자가 가져야 할 사고방식을 정리한 책에 가깝다고 느꼈습니다.</p>
<hr>
<h2 id="참고">참고</h2>
<ul>
<li>Antonio Gulli, <code>Agentic Design Patterns: A Hands-On Guide to Building Intelligent Systems</code></li>
<li><a href="https://developers.openai.com/api/docs/guides/agents" title="Agents SDK | OpenAI API">OpenAI Agents SDK 문서</a></li>
<li><a href="https://modelcontextprotocol.io/docs/getting-started/intro" title="What is the Model Context Protocol (MCP)?">Model Context Protocol 공식 문서</a></li>
<li><a href="https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/" title="Announcing the Agent2Agent Protocol (A2A)">Google A2A 발표 글</a></li>
<li><a href="https://www.gartner.com/en/newsroom/press-releases/2025-06-25-gartner-predicts-over-40-percent-of-agentic-ai-projects-will-be-canceled-by-end-of-2027" title="Gartner: Over 40% of Agentic AI Projects Will Be Canceled ...">Gartner Agentic AI 프로젝트 전망</a></li>
<li><a href="https://developers.googleblog.com/developers-guide-to-ai-agent-protocols/" title="Developer&#39;s Guide to AI Agent Protocols">Google AI Agent Protocols 개발자 가이드</a></li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[2026 스마트 공장 MVP 해커톤, LossTwin AI 회고]]></title>
            <link>https://velog.io/@lova-clover/2026-%EC%8A%A4%EB%A7%88%ED%8A%B8-%EA%B3%B5%EC%9E%A5-MVP-%ED%95%B4%EC%BB%A4%ED%86%A4-LossTwin-AI-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@lova-clover/2026-%EC%8A%A4%EB%A7%88%ED%8A%B8-%EA%B3%B5%EC%9E%A5-MVP-%ED%95%B4%EC%BB%A4%ED%86%A4-LossTwin-AI-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sat, 23 May 2026 13:43:28 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요, Lova-clover입니다.</p>
<p>이번 글은 2026년 5월 22일에 열린 <code>2026 스마트 공장 운영 시스템 MVP 개발 해커톤</code> 본선에 참가하며 만들었던 <strong>LossTwin AI</strong> 회고입니다. 예선은 56팀 중 16팀이 통과했고, 그중 하나로 본선에 올라갔습니다. 본선에서는 발표자료·MVP 기준으로 2등을 받았고, 최종 결과는 발표까지 포함해서 3등이었습니다.</p>
<p>결과만 놓고 보면 충분히 감사한 기록입니다. 본선까지 올라갔고, 발표자료와 MVP도 좋게 봐주셨고, 최종 3등이라는 결과도 얻었습니다. 그런데 대회가 끝나고 나서 계속 생각난 건 순위보다 발표였습니다.</p>
<p>발표자료도 열심히 만들었고, MVP도 계속 다듬었습니다. 본선 전날부터 당일까지 잠도 별로 못 자면서 화면을 고치고, 슬라이드를 정리하고, 시각화를 더 잘 보이게 만들려고 했습니다. 그런데 막상 발표를 하고 나니, 제가 만든 걸 제가 생각한 만큼 자연스럽게 전달하지 못했다는 아쉬움이 남았습니다.</p>
<p>컨디션 영향도 있었을 겁니다. 잠을 거의 못 잔 상태였으니까요. 그래도 결국 돌아보면 제일 큰 이유는 발표 연습이 부족했다는 점이었습니다. 좋은 기획과 MVP가 있어도, 그걸 듣는 사람이 바로 이해할 수 있게 말하지 못하면 힘이 줄어든다는 걸 이번에 꽤 크게 느꼈습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/21c975a5-e454-49a9-a6e5-2f3a3d94794c/image.jpg" alt=""></p>
<blockquote>
<p>본선이 끝나고 나오는 길에 찍은 대회 배너
하루 종일 붙잡고 있던 대회가 이 사진 한 장으로 남았다.</p>
</blockquote>
<hr>
<h2 id="한눈에-정리하면">한눈에 정리하면</h2>
<ul>
<li>대회: 2026 스마트 공장 운영 시스템 MVP 개발 본선 해커톤</li>
<li>프로젝트명: LossTwin AI (<a href="https://github.com/Lova-clover/LossTwin-AI">GitHub</a>)</li>
<li>주제: 손실금액 기반 스마트공장 조치 의사결정 플랫폼</li>
<li>결과: 예선 통과, 본선 발표자료·MVP 2등, 발표 포함 최종 3등</li>
<li>핵심 메시지: 알람을 더 띄우는 AI가 아니라, 어떤 조치를 승인해야 손실을 줄일 수 있는지 알려주는 AI</li>
<li>MVP 범위: 로컬 React 앱, CSV 기반 샘플 데이터, 손실 분석, 시뮬레이션, ROI 비교, 작업지시, 리포트</li>
<li>잘했다고 생각하는 점: 스마트공장 문제를 <code>손실금액 -&gt; 조치 ROI -&gt; 작업지시</code> 흐름으로 좁힌 것</li>
<li>가장 크게 배운 점: 좋은 결과물도 결국 말로 자연스럽게 연결해야 한다는 것</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/a7364935-71b5-4890-acff-bea00781e1c3/image.png" alt=""></p>
<blockquote>
<p>최종 발표자료 표지
예선을 통과해 본선에서 발표했던 LossTwin AI</p>
</blockquote>
<hr>
<h2 id="처음에는-그냥-큰-스마트공장-대시보드였다">처음에는 그냥 큰 스마트공장 대시보드였다</h2>
<p>LossTwin AI는 처음부터 지금의 모습이었던 것은 아닙니다. 초반에는 <code>FactoryPulse AI</code>라는 이름에 가까웠고, 방향도 훨씬 넓었습니다. 공장 대시보드, 라인 모니터링, AI 모델 카드, Agent 루프, 작업지시서, What-if 의사결정, 리포트까지 전부 넣고 싶었습니다.</p>
<p>스마트공장 운영 시스템이라는 주제를 보면 품질, 설비, 생산, 안전을 모두 보여주고 싶어집니다. 저도 처음에는 그렇게 접근했습니다. 기능을 많이 넣으면 더 완성도 있어 보일 거라고 생각했습니다.</p>
<p>초기 흐름은 대략 이랬습니다.</p>
<pre><code class="language-text">센서 / MES / 품질검사 / 정비이력
-&gt; 위험 설비 탐지
-&gt; 원인 분석
-&gt; SOP 근거
-&gt; 작업지시서
-&gt; What-if 개선
-&gt; 리포트</code></pre>
<p>기능만 보면 나쁘지 않았습니다. 실제로 구현할 수 있는 화면도 많았고, 해커톤 MVP치고는 꽤 풍성한 구성이었습니다. 그런데 기획을 계속 들여다보다 보니 한 가지 질문이 남았습니다.</p>
<blockquote>
<p>그래서 현장 사람은 이걸 보고 무엇을 먼저 해야 하지?</p>
</blockquote>
<p>공장에는 이미 알람도 많고, 지표도 많고, 대시보드도 많습니다. 중요한 건 데이터를 더 많이 보여주는 것이 아니라, 그 데이터를 보고 어떤 결정을 내려야 하는지였습니다.</p>
<p>현장에서는 이런 질문이 더 중요하다고 생각했습니다.</p>
<pre><code class="language-text">지금 멈춰야 하나?
다음 교대조까지 기다려도 되나?
어떤 알람부터 처리해야 돈을 덜 잃나?
이 조치를 하면 얼마나 아낄 수 있나?</code></pre>
<p>이 질문을 기준으로 다시 보니 프로젝트의 중심이 조금씩 바뀌었습니다. 스마트공장 데이터를 잘 보여주는 대시보드가 아니라, <strong>손실을 줄이는 의사결정 시스템</strong>이어야 했습니다.</p>
<h2 id="factorypulse에서-losstwin-ai로">FactoryPulse에서 LossTwin AI로</h2>
<p>최종적으로 프로젝트 이름은 <strong>LossTwin AI</strong>로 바꿨습니다. 이름을 바꾼 이유도 있었습니다. <code>FactoryPulse</code>라는 이름은 이미 비슷한 제조/운영 제품명으로 쓰이는 사례가 있었고, 본선에서는 그런 유사한 인상 자체가 리스크가 될 수 있다고 판단했습니다.</p>
<p>이름을 바꾸면서 프로젝트의 문장도 더 선명해졌습니다.</p>
<pre><code class="language-text">LossTwin AI
손실금액 기반 스마트공장 조치 의사결정 플랫폼</code></pre>
<p>제가 가장 중요하게 잡은 문장은 이거였습니다.</p>
<blockquote>
<p>우리는 고장을 맞히는 AI가 아니라, 지금 어떤 조치를 승인해야 공장이 가장 적은 돈을 잃는지 알려주는 AI를 만들었습니다.</p>
</blockquote>
<p>이 문장이 프로젝트 전체를 잡아줬습니다. 단순히 위험 점수를 보여주는 것이 아니라, 이상 신호를 손실금액으로 바꾸고, 그 손실을 줄일 수 있는 조치를 비교하고, 사람이 승인할 수 있는 작업지시로 연결하는 흐름을 만들고 싶었습니다.</p>
<p>LossTwin AI의 핵심 흐름은 이렇게 정리했습니다.</p>
<pre><code class="language-text">센서/MES/QC/정비/SOP 데이터
-&gt; 이상징후 탐지
-&gt; Loss Event 생성
-&gt; 예상 손실금액 계산
-&gt; 원인 후보와 근거 제시
-&gt; 조치별 ROI 비교
-&gt; Guardian Gate 통과
-&gt; 작업지시 생성
-&gt; 조치 전후 절감액 검증</code></pre>
<p>여기서 중요한 건 &quot;AI가 분석했다&quot;에서 끝나지 않는 것이었습니다. AI가 분석한 결과가 현장 사람이 승인할 수 있는 작업 단위로 내려와야 했습니다. 그 흐름이 LossTwin AI의 핵심이었습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/cb1f09a8-d082-41af-bd84-27c6d5c42d43/image.png" alt=""></p>
<blockquote>
<p>Loss-to-Action Flow
이상 감지에서 손실 계산, ROI 비교, 작업지시까지 이어지는 최종 구조</p>
</blockquote>
<hr>
<h2 id="예선을-통과하고-본선으로">예선을 통과하고 본선으로</h2>
<p>예선을 통과했을 때는 기분이 좋았습니다. 기획서 단계에서 제가 잡은 방향이 어느 정도 설득력이 있었다는 뜻이라고 생각했기 때문입니다.</p>
<p>예선에서 통했던 지점은 아마 세 가지였던 것 같습니다.</p>
<p>첫 번째는 문제 정의가 구체적이었다는 점입니다. &quot;스마트공장을 효율화하겠다&quot;가 아니라, &quot;알람은 많은데 무엇부터 처리해야 손실을 줄일지 모른다&quot;는 문제로 좁혔습니다.</p>
<p>두 번째는 AI가 모델 점수에서 끝나지 않았다는 점입니다. 이상탐지, 품질위험, 원인 후보, SOP 근거, RUL, What-if를 전부 작업지시로 연결했습니다. AI가 결과를 내고 끝나는 게 아니라, 사람이 실행할 수 있는 형태로 바꾸는 구조를 보여주려고 했습니다.</p>
<p>세 번째는 로컬 MVP로 재현 가능하다는 점입니다. 대회에서 별도 GPU나 클라우드 리소스가 주어지는 구조가 아니었기 때문에, 인터넷 없이 노트북에서 돌아가는 MVP가 중요했습니다. 그래서 React, TypeScript, Vite 기반으로 로컬 앱을 만들고, 샘플 CSV와 규칙 기반/경량 추론 엔진으로 전체 흐름을 재현했습니다.</p>
<p>여기까지는 꽤 잘 흘러갔습니다. 예선 통과는 본선 준비를 더 진지하게 하게 만든 계기이기도 했습니다.</p>
<h2 id="본선-준비-자료와-mvp에-많이-신경-썼다">본선 준비, 자료와 MVP에 많이 신경 썼다</h2>
<p>본선 전까지 만든 화면은 꽤 많았습니다. 운영 대시보드, 라인 모니터링, 손실 분석, 시뮬레이션, ROI 비교, 작업지시, 알람 관리, 리포트, 설정 화면까지 들어갔습니다.</p>
<p>기술적으로는 React 19, TypeScript, Vite 기반 SPA로 만들었고, <code>src/factoryEngine.ts</code>에 로컬 위험 추론 엔진을 넣었습니다. 샘플 CSV 업로드, 예상 손실금액 계산, 조치별 ROI 비교, 손실 추이 차트, 원인 후보 Pareto, Guardian Gate 승인 흐름, 작업지시서 자동 생성, 리포트/CSV 내보내기까지 구현했습니다.</p>
<p>모델 근거도 비워두고 싶지 않았습니다. 그래서 모델 카드에는 2,560행 시간축 로그 기반의 성능 지표를 넣었습니다.</p>
<pre><code class="language-text">AUC 0.947
F1 0.741
Top Precision 0.628
Lead 38h</code></pre>
<p>물론 이 MVP가 실제 공장에 바로 들어갈 수 있는 완제품은 아닙니다. 합성/샘플 데이터와 로컬 추론 구조를 기반으로 한 데모였습니다. 그래서 발표에서도 &quot;실제 데이터가 들어오면 같은 스키마로 교체 가능한 구조&quot;라는 점을 강조하려고 했습니다.</p>
<p>돌아보면 발표자료와 MVP는 정말 많이 신경 썼습니다. 화면을 더 예쁘게 만들고 싶었고, 시연 흐름도 더 설득력 있게 보이게 만들고 싶었습니다. 그래서 본선 직전까지 계속 고쳤습니다. 다만 본선 당일에는 &quot;준비한 자료가 많다&quot;는 것과 &quot;그 자료가 자연스럽게 전달된다&quot;는 것이 완전히 다른 문제라는 걸 느꼈습니다.</p>
<h2 id="본선-데모는-cnc-07-하나로-좁혔다">본선 데모는 CNC-07 하나로 좁혔다</h2>
<p>본선 시연은 하나의 사건으로 좁혔습니다. <code>CNC-07</code> 설비에서 토크, 온도, 사이클타임, 불량률이 함께 상승하고, LossTwin AI가 이를 하나의 Loss Event로 묶어 90분 내 예상 손실을 계산하는 흐름이었습니다.</p>
<p>데모의 한 줄은 이랬습니다.</p>
<pre><code class="language-text">CNC-07 이상 발생
-&gt; 90분 내 손실 예측
-&gt; 조치 ROI 비교
-&gt; Guardian Gate 통과
-&gt; 작업지시 승인
-&gt; Before/After 절감액 확인</code></pre>
<p>원래는 <code>Paint Booth 05</code> 시나리오도 있었습니다. 초기 README와 전략 문서에는 그 흔적이 남아 있습니다. 하지만 본선 발표자료와 최종 MVP에서는 <code>CNC-07</code> 중심으로 바꿨습니다.</p>
<p>이 선택은 지금도 맞았다고 생각합니다. 많은 설비를 얕게 보여주는 것보다, 하나의 사건을 끝까지 밀고 가는 편이 더 강했습니다. 다만 하나의 사건을 끝까지 보여주려면 화면이 단순해야 했는데, 저는 막판까지 화면에 설명을 계속 더하고 있었습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/e3ff4ccc-09c1-4422-9161-ebb28c9ec31b/image.png" alt=""></p>
<blockquote>
<p>CNC-07 하나로 좁힌 본선 시연 시나리오</p>
</blockquote>
<hr>
<h2 id="시각화는-계속-바꾸다-보면-흐려진다">시각화는 계속 바꾸다 보면 흐려진다</h2>
<p>이번 본선에서 가장 많이 배운 부분 중 하나는 시각화였습니다.</p>
<blockquote>
<p>시각화는 장식이 아니라, 심사위원이 MVP를 이해하는 첫 번째 언어다.</p>
</blockquote>
<p>그래서 마지막까지 시각화를 계속 고쳤습니다. 실시간 신호 차트에 이상 구간을 넣고, 단계별 마커가 움직이게 만들고, 손실 비용 구조를 막대로 나누고, 조치안 비교 카드를 정리하고, 승인 게이트를 오른쪽 패널에 붙였습니다. 센서 값이 시뮬레이션 단계에 따라 변하게 만들고, 모바일 대응도 넣었습니다.</p>
<p>처음에는 분명히 좋아지는 것처럼 보였습니다. <code>감지 -&gt; 손실 예측 -&gt; 근거 -&gt; ROI 순위 -&gt; 승인 게이트 -&gt; 작업지시 -&gt; 절감 검증</code> 흐름이 화면 안에서 보이기 시작했기 때문입니다.</p>
<p>그런데 계속 바꾸다 보니 어느 순간부터 화면이 복잡해졌습니다. 설명 텍스트를 하나 더 넣으면 차트가 좁아지고, 차트를 줄이면 숫자가 덜 살아나고, 버튼을 정렬하면 카드 안의 텍스트가 밀렸습니다. ROI 카드를 보기 좋게 만들면 작업지시 미리보기가 답답해졌고, 모바일 대응을 넣으면 데스크톱 배치가 흔들렸습니다.</p>
<p>마지막에는 기능을 추가한다기보다, 이미 만든 화면이 무너지지 않게 붙잡는 시간이 더 길어졌습니다. 개발 로그에도 그 흔적이 남아 있습니다.</p>
<pre><code class="language-text">Stepper is not defined
alertStats is not defined
liveTime is not defined
Cannot read properties of undefined</code></pre>
<p>최종 화면은 돌아갔고, 빌드도 됐고, 캡처도 남겼습니다. 하지만 제가 머릿속으로 그렸던 만큼 깔끔하지는 않았습니다. 특히 시뮬레이션 화면은 보여주고 싶은 정보가 많다 보니, 오히려 한눈에 들어오는 힘이 약해진 부분이 있었습니다.</p>
<p>이건 아쉬웠습니다. 못 만들었다기보다는, 더 잘 보여줄 수 있었는데 그러지 못했다는 느낌이 남았습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/8cbf8c3c-f062-4a34-956f-1c23a174c636/image.png" alt=""></p>
<blockquote>
<p>막판까지 고친 시뮬레이션 화면. 
감지, 손실 예측, ROI, 승인 게이트를 한 화면에 담으려다 복잡해졌다.</p>
</blockquote>
<hr>
<h2 id="발표까지가-mvp였다">발표까지가 MVP였다</h2>
<p>기술적으로 힘들었던 것보다 더 크게 남은 건 발표였습니다.</p>
<p>준비한 문장은 있었습니다.</p>
<pre><code class="language-text">공장 알람은 많은데, 현장 반장은 무엇부터 처리해야 돈을 덜 잃는지 모릅니다.
LossTwin AI는 이상신호를 원화 손실과 조치 ROI로 바꿔 승인 가능한 작업지시까지 만듭니다.</code></pre>
<p>이 문장 자체는 괜찮았다고 생각합니다. 문제는 본선장에서 이 문장을 중심으로 끝까지 밀고 가지 못했다는 점입니다. 화면을 넘기면서 설명이 길어졌고, 어떤 장면에서는 핵심을 먼저 말해야 했는데 숫자나 기능 설명으로 빠졌습니다. 시연 흐름을 보여줘야 하는데, 어느 순간 제가 화면을 따라가고 있었습니다.</p>
<p>발표는 화면을 설명하는 시간이 아니라, 심사위원의 머릿속에 프로젝트를 한 줄로 꽂는 시간에 가까웠습니다. 이걸 이번에 제대로 느꼈습니다.</p>
<p>발표 흐름을 충분히 이어가지 못한 채 어느새 PPT 마지막 장까지 넘어갔고, 바로 이어진 Q&amp;A에서는 멘탈이 흔들려 답변을 차분하게 이어가지 못했습니다. 그 순간이 끝나고 나서도 꽤 오래 머릿속에 남았습니다.</p>
<p>솔직히 발표가 끝나고 나서는 15분 발표가 계속 머릿속에 남았습니다. 발표자료와 MVP는 어느 정도 준비했다고 생각했는데, 정작 발표에서는 제가 만든 흐름을 충분히 자연스럽게 전달하지 못했습니다. 화면은 있었지만, 그 화면들을 하나의 이야기로 묶어 말하는 연습이 부족했습니다.</p>
<p>처음에는 컨디션 탓도 떠올랐습니다. 본선 전날부터 발표자료와 MVP를 계속 다듬느라 잠을 거의 못 잤고, 그래서 말이 더 꼬인 것도 있었을 겁니다. 하지만 시간이 조금 지나고 나니 결국 핵심은 분명했습니다. 발표도 개발의 일부였고, 저는 그 부분을 충분히 준비하지 못했습니다.</p>
<p>그래서 이번 결과가 더 오래 남았습니다. 본선 발표자료와 MVP는 2등권 평가를 받았지만, 최종 결과는 발표까지 포함해 3등이었습니다. 이 차이가 저에게는 꽤 선명한 피드백처럼 느껴졌습니다. 다음에는 좋은 결과물을 만드는 것뿐 아니라, 그 결과물을 15분 안에 설득력 있게 전달하고 Q&amp;A까지 차분하게 이어가는 연습까지 가져가야겠다고 생각했습니다.</p>
<p>그래서 이번 대회 이후 가장 크게 든 생각은 이것입니다.</p>
<blockquote>
<p>발표 연습도 개발의 일부다.</p>
</blockquote>
<p>다음에는 코드와 화면만큼 발표도 몸에 붙여야겠다고 생각했습니다. 좋은 아이디어와 좋은 MVP가 있어도, 그것을 듣는 사람이 자연스럽게 이해하지 못하면 힘이 줄어듭니다.</p>
<h2 id="결과를-어떻게-받아들였나">결과를 어떻게 받아들였나</h2>
<p>결과는 예선 통과, 본선 발표자료·MVP 2등, 발표 이후 최종 3등이었습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/cf6cdf17-303e-47a4-ba96-1401efc3ab9d/image.jpeg" alt=""></p>
<blockquote>
<p>본선 1~3등 최종 리더보드</p>
</blockquote>
<p>감사한 결과입니다. 동시에 꽤 배울 게 많은 결과였습니다. 발표자료와 MVP는 좋게 봐주셨지만, 최종 순위에서는 발표가 포함되면서 3등이 되었습니다. 이건 저에게 좋은 신호이기도 했습니다. 프로젝트의 방향과 결과물은 통했지만, 전달 방식은 더 좋아질 여지가 있다는 뜻이니까요.</p>
<p>정리하면 이런 느낌입니다.</p>
<pre><code class="language-text">기획: 방향은 괜찮았다.
발표자료·MVP: 2등권이었다.
시각화: 욕심이 조금 과했다.
발표: 더 연습해야 한다.
최종 결과: 3등이었다.
회고: 다음에는 말로 설득하는 힘까지 가져가고 싶다.</code></pre>
<p>예전 같았으면 &quot;아 발표 때문에 아쉽다&quot;에서 멈췄을 것 같습니다. 그런데 이번에는 조금 다르게 느꼈습니다. 이건 부족함을 확인한 경험이기도 하지만, 동시에 다음에 어디를 키워야 하는지 알려준 경험이었습니다.</p>
<p>발표를 더 잘하고 싶어졌습니다. 그냥 말을 유창하게 하고 싶다는 뜻이 아니라, 내가 만든 것을 상대가 자연스럽게 이해할 수 있도록 연결하는 능력을 키우고 싶어졌습니다.</p>
<hr>
<h2 id="그래도-잘했다고-생각하는-것들">그래도 잘했다고 생각하는 것들</h2>
<p>아쉬움이 남지만, 이번 프로젝트에서 잘했다고 생각하는 결정도 있습니다.</p>
<p>첫 번째는 문제를 손실금액으로 바꾼 것입니다. 스마트공장 대시보드는 자칫하면 OEE, 불량률, 가동률, 계획 달성률, 설비 위험도 같은 숫자의 모음이 되기 쉽습니다. 전부 중요한 숫자지만, 동시에 보여주면 오히려 아무것도 결정하지 못합니다.</p>
<p>LossTwin AI는 이 숫자들을 예상 손실로 묶었습니다.</p>
<pre><code class="language-text">이상 신호
-&gt; 예상 손실금액
-&gt; 조치별 절감액
-&gt; ROI
-&gt; 작업지시</code></pre>
<p>이 구조는 앞으로도 괜찮은 방향이라고 생각합니다.</p>
<p>두 번째는 AI가 최종 결정을 내리지 않게 한 것입니다. 프로젝트 안에는 <code>Guardian Gate</code>라는 개념을 넣었습니다. AI가 조치를 추천하더라도 바로 실행하지 않고, 데이터 신뢰도, SOP 근거, 안전 조건, 관리자 승인 여부를 확인한 뒤 작업지시로 넘어갑니다.</p>
<p>&quot;AI가 알아서 공장을 운영합니다&quot;라는 말은 멋있어 보이지만, 실제 현장에서는 위험할 수 있습니다. 현장 시스템에서는 AI가 결정을 대신하는 것보다, 사람이 승인할 수 있는 근거를 정리해주는 쪽이 더 현실적이라고 생각했습니다.</p>
<p>세 번째는 데모를 하나의 사건으로 좁힌 것입니다. 처음에는 품질, 설비, 생산, 안전을 모두 보여주고 싶었지만, 본선에서 중요한 것은 많은 기능이 아니라 짧은 시간 안에 따라올 수 있는 흐름이었습니다.</p>
<pre><code class="language-text">CNC-07 이상 발생
-&gt; 손실 예측
-&gt; 조치 ROI 비교
-&gt; 승인
-&gt; 작업지시
-&gt; 절감 검증</code></pre>
<p>이 한 줄은 끝까지 가져갈 만했습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/577530c4-1206-4209-98a0-6ef0b7ae137f/image.png" alt=""></p>
<blockquote>
<p>조치 ROI 비교 화면. 
LossTwin AI에서 가장 중요한 장면은 &quot;어떤 조치가 가장 이득인가&quot;였다.</p>
</blockquote>
<hr>
<h2 id="다음에-다시-한다면">다음에 다시 한다면</h2>
<p>다음에 비슷한 본선을 다시 나간다면 제일 먼저 첫 30초 발표문부터 완성할 것 같습니다. 화면을 다 만든 뒤 발표를 붙이는 방식이 아니라, 처음부터 &quot;이 프로젝트는 무엇이고 왜 필요한가&quot;를 말로 정리한 뒤 그 문장에 맞게 화면을 배치해야겠다고 느꼈습니다.</p>
<p>데모도 하나의 사건만 끝까지 보여줄 것 같습니다. 이번에도 CNC-07 하나로 좁힌 건 잘한 선택이었지만, 화면 안에 너무 많은 설명을 넣으면서 그 장점이 조금 흐려졌습니다. 다음에는 핵심 화면은 본선 전날 고정하고, 본선 당일에는 UI를 거의 건드리지 않을 것 같습니다.</p>
<p>그리고 발표 연습을 정말 해야겠다고 생각했습니다. 클릭 순서, 화면 전환, 브라우저 확대 비율, 스크롤 위치, 첫 화면에서 보이는 영역까지 전부 발표의 일부였습니다. 기능이 있어도 발표자가 그 흐름을 자연스럽게 못 보여주면 힘이 줄어듭니다.</p>
<p>다음에는 이렇게 준비하고 싶습니다.</p>
<ol>
<li>첫 30초 발표문을 먼저 완성한다.</li>
<li>발표 중 반복할 문장을 하나만 정한다.</li>
<li>데모는 하나의 사건만 끝까지 보여준다.</li>
<li>핵심 화면은 본선 전날 고정한다.</li>
<li>본선 당일에는 UI를 거의 건드리지 않는다.</li>
<li>&quot;기능 설명&quot;보다 &quot;판단 흐름&quot;을 먼저 보여준다.</li>
<li>결과 화면보다 Before/After를 더 크게 만든다.</li>
</ol>
<p>이번에는 발표자료와 MVP를 잘 만들고 싶다는 마음이 컸습니다. 다음에는 거기에 더해서, 그것을 말로 잘 전달하는 연습까지 같이 가져가고 싶습니다.</p>
<hr>
<h2 id="가장-크게-배운-것">가장 크게 배운 것</h2>
<p>이번 본선을 통해 MVP에 대한 생각이 조금 바뀌었습니다.</p>
<p>예전에는 MVP를 &quot;핵심 기능이 돌아가는 최소 제품&quot; 정도로 생각했습니다. 그런데 본선장에서 느낀 MVP는 조금 달랐습니다.</p>
<blockquote>
<p>MVP는 기능의 최소 단위가 아니라, 납득의 최소 단위다.</p>
</blockquote>
<p>기능이 많아도 납득이 안 되면 약합니다. 반대로 기능이 적어도 문제, 판단, 실행, 결과가 한 줄로 이어지면 강합니다.</p>
<p>LossTwin AI에서 제가 가장 좋아한 흐름도 결국 이 한 줄이었습니다.</p>
<pre><code class="language-text">알람
-&gt; 손실금액
-&gt; 조치 ROI
-&gt; 승인 가능한 작업지시
-&gt; 절감액 검증</code></pre>
<p>이 흐름은 앞으로도 계속 가져가고 싶습니다. 그리고 다음에는 이 흐름을 화면뿐 아니라 말로도 더 잘 전달하고 싶습니다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>이번 본선은 좋은 기록이었고, 동시에 더 발전하고 싶다는 마음을 많이 남긴 경험이었습니다.</p>
<p>예선을 통과한 것도 기뻤고, 본선 발표자료와 MVP가 2등권이었다는 것도 감사한 기록입니다. 최종 3등이라는 결과도 충분히 감사했습니다. 다만 그 과정에서 발표의 중요성을 확실히 느꼈습니다.</p>
<p>발표자료와 MVP에 신경을 많이 쓰고, 잠도 별로 못 자고, 본선 직전까지 시각화를 계속 만졌습니다. 그만큼 결과물을 더 좋게 만들고 싶은 마음이 컸습니다. 하지만 본선장에서 평가받는 것은 &quot;내가 얼마나 많이 만들었는가&quot;가 아니라 &quot;상대가 얼마나 잘 이해했는가&quot;였습니다.</p>
<p>그래서 다음에는 발표 연습을 코드 수정만큼 해야겠다고 생각했습니다.</p>
<p>AI는 이상을 찾는 데서 끝나면 약합니다. AI가 현장의 언어로 번역될 때 강해집니다. LossTwin AI에서 그 언어는 손실금액, ROI, 작업지시, 승인, 검증이었습니다.</p>
<p>다음에는 더 적게 만들고, 더 선명하게 보여주고 싶습니다. 그리고 15분 발표와 Q&amp;A까지 포함해서, 제가 만든 것을 끝까지 설득력 있게 전달할 수 있는 사람이 되고 싶습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/457ea89c-5580-4f95-a277-70e425fc30f5/image.jpg" alt=""></p>
<blockquote>
<p>본선이 끝나고 받은 3등 결과 
기쁜 기록이었지만, 다음에는 발표와 Q&amp;A까지 더 잘해보고 싶다는 마음이 더 크게 남았다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[투자 데이터 대시보드를 만들며 배운 것 - RuleVest 회고]]></title>
            <link>https://velog.io/@lova-clover/%ED%88%AC%EC%9E%90-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C%EB%A5%BC-%EB%A7%8C%EB%93%A4%EB%A9%B0-%EB%B0%B0%EC%9A%B4-%EA%B2%83-RuleVest-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@lova-clover/%ED%88%AC%EC%9E%90-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C%EB%A5%BC-%EB%A7%8C%EB%93%A4%EB%A9%B0-%EB%B0%B0%EC%9A%B4-%EA%B2%83-RuleVest-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 05 May 2026 14:07:30 GMT</pubDate>
            <description><![CDATA[<p>이번 Daker 투자 데이터 Skills 해커톤에서
<code>RuleVest</code>라는 투자 데이터 분석 대시보드를 만들었다.</p>
<p>RuleVest는 투자 데이터를 업로드하면
브라우저 안에서 데이터 구조를 파악하고,
지표와 차트, 분석 요약을 자동으로 구성하는 웹 대시보드다.</p>
<p>결과부터 말하면,
<strong>1차 투표에서는 7위를 기록했지만, 2차 심사위원 평가에서는 탈락했다.</strong></p>
<p>처음에는 아쉬움이 컸다.</p>
<p>투표에서 어느 정도 반응이 있었기 때문에
심사위원 평가까지 통과할 수 있지 않을까 기대했다.</p>
<p>하지만 다시 돌아보니,
이번 프로젝트는 “보이는 완성도”와 “심사위원이 점수를 줄 수 있는 설득력”이 다르다는 걸 분명하게 보여준 경험이었다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/4e7e8dfa-6ce6-430c-aac7-4fd935ba191a/image.png" alt=""></p>
<blockquote>
<p>RuleVest 메인 화면</p>
</blockquote>
<hr>
<h2 id="한눈에-요약">한눈에 요약</h2>
<blockquote>
<p>RuleVest는 사용자에게는 보기 쉬운 자동 대시보드였지만,
심사위원에게 투자 도메인의 문제를 깊게 해결하는 서비스로 보이기에는 부족했다.</p>
</blockquote>
<ul>
<li>대회: <a href="https://daker.ai/public/hackathons/hackathon-investment-data-skills-dashboard">월간 해커톤 : 투자 데이터를 시각화하라- Skills 기반 대시보드 설계</a></li>
<li>프로젝트명: <a href="https://lova-clover.github.io/RuleVest/">RuleVest</a></li>
<li>주제: 투자 데이터 Skills 기반 대시보드</li>
<li>결과: 1차 투표 7위, 2차 심사위원 평가 탈락</li>
<li>구현: 투자 데이터 업로드 기반 자동 분석 대시보드</li>
<li>잘한 점: 웹 접근성, 화면 구성, 자동 분석 흐름</li>
<li>부족했던 점: 투자 도메인 이해, 차별점, 심사위원 설득 구조</li>
<li>배운 점: 대회에서는 구현물뿐 아니라 문제 정의와 평가 기준 대응이 중요하다</li>
</ul>
<hr>
<h2 id="rulevest가-뭔데">RuleVest가 뭔데?</h2>
<p>RuleVest는 투자 데이터를 업로드하면
데이터 구조를 자동으로 파악하고,
투자 지표와 차트, 분석 요약을 만들어주는 대시보드다.</p>
<p>CSV, JSON, TSV, XLSX 같은 파일을 넣으면
날짜 컬럼, 주요 지표, 벤치마크, 거래량처럼
분석에 필요한 역할을 추론하고
그 결과를 바탕으로 화면을 구성한다.</p>
<p>처음에는 단순하게 생각했다.</p>
<blockquote>
<p>CSV 올리면 차트 몇 개 보여주는 서비스면 되지 않을까?</p>
</blockquote>
<p>하지만 만들다 보니 중요한 건 차트 개수가 아니었다.</p>
<p>어떤 데이터를 어떤 기준으로 읽을 것인지,
그 기준을 어떻게 문서화할 것인지,
그리고 그 결과를 사용자가 납득할 수 있게 보여줄 수 있는지가 훨씬 중요했다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/da5725d9-35bd-4d90-ad33-bd42e2cb02b1/image.png" alt=""></p>
<blockquote>
<p>RuleVest 주요 기능</p>
</blockquote>
<hr>
<h2 id="skillsmd를-기준으로-만들었다">Skills.md를 기준으로 만들었다</h2>
<p>이번 대회에서 중요했던 건 단순히 웹사이트를 만드는 게 아니었다.</p>
<p><code>Skills.md</code>에
데이터 분석 규칙, 시각화 선택 기준, 인사이트 생성 방식, 검토 기준을 정의하고
그 문서를 바탕으로 실제 대시보드를 구현해야 했다.</p>
<p>그래서 RuleVest는 화면을 먼저 만든 뒤 억지로 문서를 붙인 게 아니라,
분석 규칙을 먼저 정리하고 그 규칙이 화면에 드러나도록 구성하려고 했다.</p>
<p>예를 들면 다음과 같은 기준을 세웠다.</p>
<ul>
<li>날짜 컬럼이 있으면 시계열 분석 모드로 본다</li>
<li>대표 지표와 벤치마크가 있으면 비교 분석을 수행한다</li>
<li>변동성과 최대 낙폭을 함께 보여준다</li>
<li>데이터 품질과 역할 매핑 결과를 사용자가 확인할 수 있게 한다</li>
<li>차트는 데이터 구조에 맞춰 자동으로 선택한다</li>
<li>원본 데이터 일부를 함께 보여줘 검토 가능하게 한다</li>
</ul>
<p>즉, RuleVest에서 대시보드는 단순한 장식이 아니라
<code>Skills.md</code>에 정의한 분석 규칙의 결과물에 가까웠다.</p>
<h3 id="skillsmd-핵심-설계-요약">Skills.md 핵심 설계 요약</h3>
<p>위 기준을 실제 구현 흐름으로 정리하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>단계</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td>File Intake</td>
<td>CSV, JSON, XLSX 파일을 브라우저에서 읽는다</td>
</tr>
<tr>
<td>Schema Intelligence</td>
<td>날짜, 자산, 수익률, 벤치마크, 거래량 역할을 추론한다</td>
</tr>
<tr>
<td>Mode Routing</td>
<td>데이터 구조에 따라 분석 모드를 선택한다</td>
</tr>
<tr>
<td>Metric Engine</td>
<td>KPI와 보조 지표를 계산한다</td>
</tr>
<tr>
<td>Visualization Selection</td>
<td>데이터 구조에 맞는 차트를 고른다</td>
</tr>
<tr>
<td>Insight Generation</td>
<td>수치 근거가 있는 분석 요약을 만든다</td>
</tr>
<tr>
<td>Validation Gate</td>
<td>품질, 근거 부족, 차트 부적합 여부를 점검한다</td>
</tr>
</tbody></table>
<p>전체 Skills.md는 GitHub에서 볼 수 있다.<br>👉 <a href="https://github.com/Lova-clover/RuleVest/blob/main/Skills.md">RuleVest Skills.md 보기</a></p>
<hr>
<h2 id="데이터는-생각보다-제멋대로였다">데이터는 생각보다 제멋대로였다</h2>
<p>투자 데이터라고 해서 항상 같은 형태로 들어오지는 않는다.</p>
<p>어떤 데이터는 <code>date</code>라는 컬럼을 쓰고,
어떤 데이터는 <code>timestamp</code>, <code>일자</code>, <code>기준일</code>처럼 다른 이름을 쓴다.</p>
<p>수익률이나 가격 데이터도 마찬가지다.</p>
<p><code>portfolio_nav</code>, <code>close</code>, <code>price</code>, <code>value</code>처럼
비슷한 의미를 가진 컬럼이 서로 다른 이름으로 들어올 수 있다.</p>
<p>그래서 RuleVest는 업로드된 데이터를
고정된 템플릿에 그대로 끼워 넣는 방식으로 만들지 않았다.</p>
<p>대신 컬럼 이름과 값의 형태를 보고
각 컬럼이 어떤 역할을 하는지 추론하도록 만들었다.</p>
<p>이 부분이 이번 프로젝트에서 가장 대회 취지에 가까웠던 부분이라고 생각한다.</p>
<p>단순히 “파일을 올리면 차트가 나온다”가 아니라,
업로드된 데이터의 구조를 먼저 해석하고
그 해석 결과를 바탕으로 대시보드를 구성하려고 했기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/1acd607e-9336-433a-bbb0-416213f32817/image.png" alt=""></p>
<blockquote>
<p>RuleVest 데이터 업로드 화면</p>
</blockquote>
<hr>
<h2 id="대시보드는-예쁘기만-하면-안-됐다">대시보드는 예쁘기만 하면 안 됐다</h2>
<p>처음 만든 화면은 정보가 많았다.</p>
<p>하지만 다시 보니 문제가 있었다.</p>
<p>정보는 많은데, 처음 보는 사람이
“그래서 뭘 먼저 봐야 하지?”라고 느낄 수 있었다.</p>
<p>해커톤 제출물에서 이건 치명적이다.</p>
<p>심사위원은 서비스를 오래 붙잡고 분석해주지 않는다.
처음 몇 초 안에 이 서비스가 무엇을 하는지,
어디를 보면 되는지 이해할 수 있어야 한다.</p>
<p>그래서 UI를 다시 정리했다.</p>
<p>RuleVest의 화면 흐름은 다음처럼 잡았다.</p>
<ol>
<li>업로드된 데이터의 구조를 확인한다</li>
<li>핵심 지표를 먼저 본다</li>
<li>차트로 추세를 확인한다</li>
<li>규칙 기반 분석 요약을 확인한다</li>
<li>원본 데이터 일부와 검토 정보를 확인한다</li>
</ol>
<p>이 흐름이 잡히면서
단순히 차트가 나열된 화면이 아니라
데이터를 읽고 판단하는 화면에 조금 더 가까워졌다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/94ceffc1-f57b-4ec4-83e7-d79e331f98f6/image.png" alt=""></p>
<blockquote>
<p>RuleVest 대시보드 전체 화면</p>
</blockquote>
<hr>
<h2 id="캐릭터도-넣어봤다">캐릭터도 넣어봤다</h2>
<p>중간에 고민했던 부분은 캐릭터였다.</p>
<p>투자 데이터 대시보드에 캐릭터를 넣으면
서비스가 가벼워 보일 수 있다.</p>
<p>반대로, 너무 딱딱한 데이터 분석 서비스를
조금 더 기억에 남게 만들 수도 있다.</p>
<p>결론적으로는 기능을 방해하지 않는 선에서
작게 사용하는 방향을 선택했다.</p>
<p>메인 화면과 안내 영역에서는
캐릭터가 RuleVest의 분위기를 만들어주도록 했고,
분석 화면에서는 너무 튀지 않게 보조 요소로만 사용했다.</p>
<p>투자 데이터라는 주제가 딱딱할 수 있는데,
캐릭터 덕분에 첫인상은 조금 더 부드러워졌다고 생각한다.</p>
   <table>
     <tr>
       <td align="center">
         <img src="https://velog.velcdn.com/images/lova-clover/post/e164af8b-efdf-4819-884a-fe0164f62152/image.png" width="200"/><br/>
         <sub>홈 캐릭터</sub>
       </td>
       <td align="center">
         <img src="https://velog.velcdn.com/images/lova-clover/post/8817323b-e3c6-46c3-9688-0dbf8103bdae/image.png" width="200"/><br/>
         <sub>인사이트 안내 캐릭터</sub>
       </td>
       <td align="center">
         <img src="https://velog.velcdn.com/images/lova-clover/post/e6328791-8ed3-4091-af97-853cdb90a23e/image.png" width="200"/><br/>
         <sub>대시보드 보조 캐릭터</sub>
       </td>
     </tr>
   </table>

<hr>
<h2 id="백엔드-없이-동작하게-만들었다">백엔드 없이 동작하게 만들었다</h2>
<p>배포는 GitHub Pages를 사용했다.</p>
<p>그래서 별도의 서버나 API 키 없이도
심사위원이 링크를 열고 바로 테스트할 수 있어야 했다.</p>
<p>RuleVest는 브라우저 안에서 데이터를 읽고 분석하는 구조로 만들었다.</p>
<p>파일을 업로드하면
브라우저에서 파싱하고,
컬럼 역할을 추론하고,
지표를 계산하고,
차트를 생성한다.</p>
<p>정적 사이트에서도 동작하기 때문에
심사 기간 동안 서버 문제나 API 키 문제 없이
링크만으로 확인할 수 있다는 점은 장점이었다.</p>
<p>해커톤 제출물에서는 이 부분도 중요하다고 느꼈다.</p>
<p>멋진 기능이 있어도
심사위원이 실행하기 어렵거나,
환경 설정이 필요하거나,
API 키 문제로 막히면 좋은 평가를 받기 어렵다고 생각했다.</p>
<hr>
<h2 id="1차-투표에서는-왜-통했을까">1차 투표에서는 왜 통했을까?</h2>
<p>RuleVest는 1차 투표에서 7위를 기록했다.</p>
<p>이 결과는 적어도 첫인상과 접근성 측면에서는
어느 정도 통했다는 의미라고 생각한다.</p>
<p>웹에서 바로 접속할 수 있었고,
데이터를 업로드하면 화면이 구성되는 흐름도 직관적이었다.</p>
<p>또한 투자 데이터라는 주제를
너무 복잡한 전문 용어로만 풀지 않고
대시보드 형태로 보여준 점도 긍정적으로 작용했을 것 같다.</p>
<p>즉, 대중 투표 관점에서는
“무엇을 하는 서비스인지 빠르게 이해되는가”와
“한 번 눌러보고 싶은가”가 중요했는데,
RuleVest는 이 부분에서는 어느 정도 역할을 했다고 본다.</p>
<p>하지만 여기서 통했다고 해서
심사위원 평가까지 통과할 수 있는 것은 아니었다.</p>
<hr>
<h2 id="2차-심사위원-평가에서는-왜-떨어졌을까">2차 심사위원 평가에서는 왜 떨어졌을까?</h2>
<p>가장 크게 느낀 한계는
RuleVest가 투자 도메인의 문제를 충분히 깊게 정의하지 못했다는 점이다.</p>
<p>나는 투자 데이터를
“시각화할 수 있는 데이터”로 바라봤다.</p>
<p>하지만 심사위원 입장에서는
단순히 차트를 보여주는 것보다
이 대시보드가 투자 판단을 어떻게 개선하는지가 더 중요했을 가능성이 높다.</p>
<p>예를 들어 투자 데이터 대시보드라면
다음과 같은 질문에 더 강하게 답했어야 했다.</p>
<ul>
<li>사용자가 어떤 투자 판단 실수를 줄일 수 있는가?</li>
<li>수익률 외에 어떤 위험 지표를 봐야 하는가?</li>
<li>변동성, 최대 낙폭, 자산 편중을 어떻게 해석하게 만들 것인가?</li>
<li>단순 차트와 RuleVest의 차별점은 무엇인가?</li>
<li>Skills.md의 규칙이 실제 화면에서 어떻게 작동하는가?</li>
</ul>
<p>돌아보면 RuleVest는
“투자 데이터를 올리면 대시보드가 자동으로 만들어진다”는 경험은 만들었지만,
“투자 판단을 더 잘하게 만드는 서비스”로 설득하기에는 부족했다.</p>
<p>이 차이가 2차 심사위원 평가에서 드러났다고 생각한다.</p>
<hr>
<h2 id="부족했던-점">부족했던 점</h2>
<h3 id="1-투자-도메인-문제-정의가-충분히-깊지-못했다">1. 투자 도메인 문제 정의가 충분히 깊지 못했다</h3>
<p>투자 도메인에 충분히 깊게 들어간 프로젝트는 아니었다.</p>
<p>그러다 보니
투자자가 실제로 어떤 지표를 중요하게 보는지,
어떤 상황에서 잘못된 판단을 하는지,
어떤 위험 신호를 먼저 봐야 하는지를 충분히 반영하지 못했다.</p>
<p>수익률, 변동성, 최대 낙폭, 벤치마크 대비 성과, 자산 편중 같은 개념을
더 명확한 사용자 문제와 연결했어야 했다.</p>
<p>단순히 차트를 보여주는 것이 아니라
“이 차트를 보고 어떤 판단을 바꿀 수 있는가”까지 설계했어야 했다.</p>
<h3 id="2-skills-기반-구조를-더-강하게-보여주지-못했다">2. Skills 기반 구조를 더 강하게 보여주지 못했다</h3>
<p>Skills.md를 작성하고 구현에 반영하긴 했지만,
심사위원이 봤을 때 그 구조가 한눈에 드러났는지는 아쉽다.</p>
<p>다시 만든다면
RuleVest의 내부 분석 흐름을 Skill 단위로 더 명확히 보여줬을 것 같다.</p>
<p>예를 들면 다음과 같은 식이다.</p>
<ul>
<li>Schema Detection Skill: 데이터 구조와 컬럼 역할 추론</li>
<li>Risk Metric Skill: 변동성, 최대 낙폭, 손실 구간 계산</li>
<li>Benchmark Skill: 기준 지표 대비 초과 성과 분석</li>
<li>Visualization Skill: 데이터 구조에 맞는 차트 선택</li>
<li>Insight Skill: 분석 결과를 검토 가능한 문장으로 요약</li>
</ul>
<p>이렇게 보여줬다면
단순한 웹 대시보드가 아니라
대회 주제에 맞춘 Skills 기반 분석 시스템으로 더 잘 전달됐을 것이다.</p>
<h3 id="3-차별점이-한-문장으로-정리되지-않았다">3. 차별점이 한 문장으로 정리되지 않았다</h3>
<p>RuleVest의 가장 큰 약점은
차별점이 한 문장으로 날카롭게 정리되지 않았다는 점이다.</p>
<p>“투자 데이터를 올리면 차트가 나온다”는 설명은 쉽지만, 강하지 않다.</p>
<p>다음처럼 더 날카롭게 정의했어야 했다.</p>
<blockquote>
<p>RuleVest는 투자 데이터의 위험 패턴을 자동으로 읽고,
사용자가 수익률 뒤에 숨은 리스크를 확인할 수 있게 돕는 Skills 기반 대시보드다.</p>
</blockquote>
<p>이 정도로 정의했다면
서비스의 방향이 더 분명해졌을 것이다.</p>
<hr>
<h2 id="다시-만든다면-어떻게-바꿀까">다시 만든다면 어떻게 바꿀까?</h2>
<p>다시 만든다면 RuleVest를
단순 자동 시각화 대시보드가 아니라
<strong>투자 리스크 해석 대시보드</strong>로 재정의할 것 같다.</p>
<p>기능도 다음 방향으로 바꿨을 것이다.</p>
<ul>
<li>최대 낙폭(MDD) 시각화</li>
<li>변동성 대비 수익률 분석</li>
<li>벤치마크 대비 초과 성과 분석</li>
<li>월별 손익 히트맵</li>
<li>특정 자산 또는 종목 편중 경고</li>
<li>손실 구간에서의 거래 패턴 분석</li>
<li>위험 패턴 기반 코멘트 생성</li>
<li>다음에 확인해야 할 투자 질문 추천</li>
</ul>
<p>이렇게 만들었다면
RuleVest는 단순히 데이터를 예쁘게 보여주는 도구가 아니라
투자 판단 전에 위험 구조를 점검하는 도구로 보였을 것이다.</p>
<hr>
<h2 id="만들면서-배운-것">만들면서 배운 것</h2>
<p>이번 프로젝트를 하면서 가장 크게 느낀 건
“화면을 만드는 것”과 “심사위원이 점수를 줄 수 있는 서비스를 만드는 것”은 다르다는 점이었다.</p>
<p>보기 좋은 화면은 중요하다.</p>
<p>하지만 대회에서는 그것만으로 부족하다.</p>
<p>심사위원은 다음을 본다.</p>
<ul>
<li>문제를 정확히 정의했는가?</li>
<li>대회 주제와 구현물이 잘 연결되는가?</li>
<li>단순 기능이 아니라 판단 흐름을 만들었는가?</li>
<li>차별점이 명확한가?</li>
<li>결과물을 직접 실행하고 이해할 수 있는가?</li>
</ul>
<p>RuleVest는 실행 가능한 웹서비스로 만들었다는 점에서는 의미가 있었다.</p>
<p>하지만 투자 도메인의 문제를 깊게 파고들고,
그 문제를 Skills 기반 구조로 설득하는 데에는 부족함이 있었다.</p>
<p>이 부분이 이번 프로젝트에서 가장 큰 배움이었다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>RuleVest는 투자 데이터를 업로드하면
데이터 구조를 파악하고,
차트와 지표, 분석 요약을 자동으로 구성하는 대시보드다.</p>
<p>1차 투표에서 7위를 기록했다는 점은
화면 구성과 접근성은 어느 정도 통했다는 신호였다.</p>
<p>하지만 2차 심사위원 평가에서 탈락한 것은
도메인 이해와 문제 해결 구조가 부족했다는 신호이기도 했다.</p>
<p>결국 좋은 대시보드는
차트를 많이 넣는다고 만들어지는 게 아니었다.</p>
<p>사용자가 어떤 판단을 해야 하는지,
그 판단을 위해 어떤 데이터를 먼저 봐야 하는지,
그리고 그 흐름을 어떤 기준으로 설계했는지가 더 중요했다.</p>
<p>이번 프로젝트는 아쉬움이 남지만,
그만큼 배운 것도 분명했다.</p>
<p>다음에는 단순히 “만든 결과물”이 아니라
문제 정의, 도메인 이해, 평가 기준에 맞는 구조까지 함께 설계해야겠다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/6bf02ce0-9a63-411f-b68e-0b64bc204085/image.png" alt=""></p>
<blockquote>
<p>아쉬움과 배움이 함께 남은 1차 투표 7위 기록</p>
</blockquote>
<hr>
<h2 id="링크">링크</h2>
<ul>
<li>Live Demo: <a href="https://lova-clover.github.io/RuleVest/">https://lova-clover.github.io/RuleVest/</a></li>
<li>GitHub: <a href="https://github.com/Lova-clover/RuleVest">https://github.com/Lova-clover/RuleVest</a></li>
<li>Daker Hackathon: <a href="https://daker.ai/public/hackathons/hackathon-investment-data-skills-dashboard">https://daker.ai/public/hackathons/hackathon-investment-data-skills-dashboard</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ChatGPT 이미지로 뽑은 UI, 실제 웹사이트로 구현해봤다]]></title>
            <link>https://velog.io/@lova-clover/ChatGPT-%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A1%9C-%EB%BD%91%EC%9D%80-UI-%EC%8B%A4%EC%A0%9C-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8%EB%A1%9C-%EA%B5%AC%ED%98%84%ED%95%B4%EB%B4%A4%EB%8B%A4</link>
            <guid>https://velog.io/@lova-clover/ChatGPT-%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A1%9C-%EB%BD%91%EC%9D%80-UI-%EC%8B%A4%EC%A0%9C-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8%EB%A1%9C-%EA%B5%AC%ED%98%84%ED%95%B4%EB%B4%A4%EB%8B%A4</guid>
            <pubDate>Mon, 27 Apr 2026 12:48:16 GMT</pubDate>
            <description><![CDATA[<p>최근에 ChatGPT 이미지 생성 결과물이 꽤 좋아졌다는 얘기를 들었다.</p>
<p>처음에는 그냥 가볍게 만져볼 생각이었다.</p>
<p>&quot;요즘 이미지 생성이 좋아졌다던데 진짜 쓸 만한가?&quot;<br>&quot;PPT 같은 것도 만들 수 있나?&quot;<br>&quot;웹 UI나 캐릭터, 로고까지 뽑으면 실제 프로젝트에 쓸 수 있을까?&quot;</p>
<p>딱 이 정도의 호기심이었다.</p>
<p>그래서 이것저것 해봤다.<br>PPT도 만들어보고, 웹페이지 시안도 뽑아보고, 캐릭터도 만들어보고, 로고도 만들어보고, 배지 아이콘이나 배경 이미지도 만들어봤다.</p>
<p>근데 생각보다 결과가 좋았다.</p>
<p>그냥 &quot;오 신기하다&quot; 정도가 아니라,</p>
<blockquote>
<p>어? 이거 잘 정리하면 진짜 프로젝트 하나 나오겠는데?</p>
</blockquote>
<p>라는 생각이 들었다.</p>
<p>그래서 한 번 가볍게 웹페이지까지 만들어보기로 했다.</p>
<p>그렇게 만든 프로젝트가 <strong>Leveli</strong>다.</p>
<ul>
<li>Live Demo: <a href="https://leveli.vercel.app">https://leveli.vercel.app</a></li>
<li>GitHub: <a href="https://github.com/Lova-clover/Leveli">https://github.com/Lova-clover/Leveli</a></li>
</ul>
<hr>
<h2 id="leveli가-뭔데">Leveli가 뭔데?</h2>
<p>Leveli는 AI 성장 코치 콘셉트의 반응형 프론트엔드 프로젝트다.</p>
<p>챌린지, 배지, 커뮤니티, 내 정보 같은 기능을 하나의 성장 플랫폼 흐름으로 묶어봤다.</p>
<p>정확히 말하면 실제 AI API가 붙은 서비스는 아니다.<br>이번 프로젝트의 핵심은 기능 구현보다 이거였다.</p>
<blockquote>
<p>ChatGPT로 만든 UI 시안을 실제 웹페이지 구조로 다시 해석하고 구현할 수 있을까?</p>
</blockquote>
<p>이 질문을 확인해보고 싶었다.</p>
<p>완성된 결과물은 이런 느낌이다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/4cb050e5-a1bf-44d0-a1b8-e9f317e99f41/image.png" alt="Leveli 메인 화면"></p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/ce681eab-74b4-4750-936f-e1300008d998/image.png" alt="Leveli 로그인 화면"></p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/12d99d67-3711-4900-ad21-2289b3004a8b/image.png" alt="Leveli 모바일 화면"></p>
<hr>
<h2 id="시작은-진짜-단순했다">시작은 진짜 단순했다</h2>
<p>처음부터 &quot;서비스 하나 만들어야지&quot; 이런 건 아니었다.</p>
<p>그냥 ChatGPT 이미지 생성이 얼마나 쓸 만해졌는지 궁금했다.</p>
<p>나는 개인 프로젝트를 만들 때 항상 비슷한 지점에서 막힌다.</p>
<ul>
<li>기능은 만들었는데 화면이 밋밋함</li>
<li>로고가 없어서 프로젝트가 가벼워 보임</li>
<li>캐릭터나 배지 같은 시각 요소를 직접 만들기 어려움</li>
<li>Figma를 처음부터 잡자니 부담스러움</li>
<li>결국 결과물이 &quot;기능 구현 연습&quot;처럼만 보임</li>
</ul>
<p>그래서 이번에는 순서를 바꿔봤다.</p>
<p>기능부터 만들지 않고, 먼저 이미지 생성으로 서비스 분위기를 잡았다.</p>
<p>대략 이런 방향이었다.</p>
<pre><code class="language-text">한국 Z세대를 타겟으로 한 성장 플랫폼
블랙과 네온 라임 컬러
강한 캐릭터성
모바일 앱 같은 리듬
챌린지, 배지, 커뮤니티가 있는 서비스형 UI</code></pre>
<p>이 방향으로 이미지를 여러 장 뽑아봤다.</p>
<p>처음부터 완벽하진 않았다.<br>텍스트가 이상하게 나오기도 했고, 캐릭터가 화면마다 조금씩 달라지기도 했고, 예쁜데 실제 웹으로 만들기에는 애매한 구성도 많았다.</p>
<p>그래도 방향성은 충분히 잡혔다.</p>
<p>&quot;이 느낌으로 웹사이트 만들면 꽤 괜찮겠다.&quot;</p>
<p>여기까지는 생각보다 빠르게 왔다.</p>
<hr>
<h2 id="근데-이미지는-웹페이지가-아니었다">근데 이미지는 웹페이지가 아니었다</h2>
<p>AI가 만든 UI 이미지를 보면 처음엔 착각하기 쉽다.</p>
<blockquote>
<p>오, 이대로 만들면 되겠네?</p>
</blockquote>
<p>근데 실제로 HTML/CSS로 옮기려고 하면 바로 깨진다.</p>
<p>이미지는 한 장이다.<br>하지만 웹페이지는 한 장이 아니다.</p>
<p>웹페이지에는 로고, 캐릭터, 버튼, 카드, 입력창, 배지, 배경, 텍스트, 상태 변화, 반응형 레이아웃, 페이지 이동이 다 따로 존재한다.</p>
<p>이미지에서는 이 모든 게 하나로 붙어 있다.<br>웹에서는 전부 나눠야 한다.</p>
<p>처음에는 AI 시안을 최대한 그대로 따라 만들려고 했다.</p>
<p>그런데 그렇게 하니까 화면이 이상해졌다.<br>이미지에서는 자연스러웠던 배치가 웹에서는 답답하게 보였다.</p>
<p>특히 데스크톱 화면에서 그랬다.<br>가로폭을 제대로 쓰지 못하면 사이트라기보다 카드 목업처럼 보였다.</p>
<p>그래서 방향을 바꿨다.</p>
<p>이미지를 따라 그리는 게 아니라,<br>이미지를 웹 구조로 다시 해석하기로 했다.</p>
<p>이게 이번 프로젝트에서 제일 중요한 지점이었다.</p>
<hr>
<h2 id="에셋으로-쪼개기">에셋으로 쪼개기</h2>
<p>가장 먼저 한 일은 에셋 분리였다.</p>
<p>AI가 만들어준 전체 이미지를 그대로 쓰면 그냥 큰 이미지를 붙인 페이지가 된다.<br>그건 웹사이트라기보다 포스터에 가깝다.</p>
<p>실제 웹에서 쓰려면 필요한 요소를 따로 분리해야 했다.</p>
<p>이번 프로젝트에서는 이런 것들이 필요했다.</p>
<pre><code class="language-text">로고
캐릭터
배지
아이콘
배경 효과
그래피티 요소
모바일용 비주얼
로그인/회원가입용 장식 이미지</code></pre>
<p>처음에는 캐릭터랑 로고만 있으면 될 줄 알았다.</p>
<p>근데 만들다 보니 계속 필요해졌다.<br>배지 카드 배경도 필요하고, 모바일 배경 효과도 필요하고, 하단 배너 이미지도 필요하고, 아이콘도 있어야 했다.</p>
<p>이때 느꼈다.</p>
<p>AI 이미지 생성에서 중요한 건 예쁜 최종 이미지 하나를 뽑는 게 아니었다.</p>
<blockquote>
<p>나중에 웹에서 재사용할 수 있는 단위로 뽑을 수 있는가?</p>
</blockquote>
<p>이게 훨씬 중요했다.</p>
<p>이미지를 잘 뽑는 것도 중요하지만,<br>그걸 나중에 쪼개서 쓸 수 있게 만드는 게 진짜 작업이었다.</p>
<hr>
<h2 id="htmlcssjavascript로-다시-만들기">HTML/CSS/JavaScript로 다시 만들기</h2>
<p>에셋을 정리한 뒤 실제 웹페이지를 만들었다.</p>
<p>기술 스택은 일부러 단순하게 잡았다.</p>
<pre><code class="language-text">HTML
CSS
Vanilla JavaScript
LocalStorage</code></pre>
<p>React나 Next.js를 쓸 수도 있었지만, 이번 실험의 핵심은 프레임워크가 아니었다.</p>
<p>이번에 보고 싶었던 건 하나였다.</p>
<blockquote>
<p>AI 이미지 시안을 정적 웹 구조로 어디까지 자연스럽게 옮길 수 있는가?</p>
</blockquote>
<p>그래서 빌드 도구 없이 정적 HTML/CSS/JS로 만들었다.</p>
<p>페이지는 메인, 로그인, 회원가입, 배지, 챌린지, 커뮤니티, 가격 안내, 내 정보까지 만들었다.</p>
<p>처음에는 메인만 만들 생각이었는데, 하다 보니 욕심이 생겼다.</p>
<p>로그인 화면도 뽑아봤고, 회원가입 화면도 뽑아봤는데 생각보다 괜찮았다.<br>그걸 안 쓰기엔 아까웠다.</p>
<p>그래서 인증 페이지까지 붙였다.</p>
<hr>
<h2 id="반응형은-그냥-줄이는-게-아니었다">반응형은 그냥 줄이는 게 아니었다</h2>
<p>이번에 제일 많이 고친 부분은 반응형이었다.</p>
<p>처음에는 데스크톱 화면을 만들고, 모바일에서는 줄이면 될 줄 알았다.</p>
<p>근데 아니었다.</p>
<p>데스크톱에서 괜찮은 구성은 모바일에서 너무 복잡해 보였고,<br>모바일에서 예쁜 구성은 데스크톱에서 너무 좁아 보였다.</p>
<p>결국 모바일과 데스크톱은 화면 크기만 다른 게 아니었다.</p>
<p>보는 방식이 달랐다.</p>
<p>데스크톱에서는 넓은 화면을 써서 브랜드 느낌, 캐릭터, 통계, 배지를 한 번에 보여주는 게 자연스러웠다.<br>모바일에서는 앱처럼 단일 컬럼으로 흐르고, 하단 탭바가 있는 편이 더 자연스러웠다.</p>
<p>그래서 구조를 이렇게 잡았다.</p>
<pre><code class="language-text">데스크톱: 넓은 랜딩 페이지 중심
모바일: 앱형 UI + 단일 컬럼 + 하단 탭바</code></pre>
<p>중간에 진짜 거슬렸던 것도 있었다.</p>
<p>첫 화면 문구에서 <code>레벨업!</code>만 따로 떨어져 보이는 문제였다.</p>
<p>사소해 보이지만 첫 화면에서는 사소하지 않다.<br>첫 문구가 어색하면 전체 사이트가 덜 만든 것처럼 보인다.</p>
<p>결국 줄바꿈 단위를 직접 잡았다.</p>
<pre><code class="language-text">오늘의 나를 넘어서,
내일의 나를 레벨업!</code></pre>
<p>이렇게 맞추고 나니까 첫인상이 훨씬 나아졌다.</p>
<hr>
<h2 id="로그인-상태를-넣으니-서비스처럼-보였다">로그인 상태를 넣으니 서비스처럼 보였다</h2>
<p>정적 웹 프로젝트라 실제 백엔드는 없다.</p>
<p>그래도 사용자 흐름은 보여주고 싶었다.</p>
<p>그래서 <code>LocalStorage</code>로 로그인 상태를 간단하게 흉내 냈다.</p>
<p>로그인하면 버튼이 사용자 이름으로 바뀌고,<br>로그인 상태일 때만 <code>내 정보</code>가 보이게 했다.</p>
<p>나중에는 로그아웃도 간단하게 추가했다.</p>
<p>물론 진짜 인증은 아니다.</p>
<p>하지만 이 작은 상태 변화가 들어가니까 느낌이 꽤 달라졌다.</p>
<p>그냥 예쁜 화면 모음이 아니라,<br>페이지들이 하나의 서비스 흐름처럼 이어지기 시작했다.</p>
<p>이런 게 생각보다 중요했다.</p>
<p>기능 자체는 작아도, 사용자가 &quot;아 이 사이트는 흐름이 있구나&quot;라고 느끼게 만든다.</p>
<hr>
<h2 id="프로젝트를-설명하기-위한-발표-자료도-만들었다">프로젝트를 설명하기 위한 발표 자료도 만들었다</h2>
<p>웹사이트만 만든 건 아니었다.</p>
<p>이번에 ChatGPT 이미지 생성을 만져보면서 PPT도 같이 만들어봤다.</p>
<p>사실 PPT는 큰 기대를 안 했다.<br>웹 시안이나 캐릭터는 그렇다 쳐도, 발표 자료까지 괜찮게 나올까 싶었다.</p>
<p>결과물은 단순한 장식용 이미지라기보다, Leveli의 서비스 콘셉트를 설명하는 시각 자료로 사용할 수 있을 정도였다.</p>
<p>디자인 톤도 웹사이트랑 어느 정도 맞고,<br>라임 컬러나 캐릭터 분위기도 잘 이어졌다.</p>
<p>그래서 프로젝트 발표 자료도 같이 정리했다.</p>
<ul>
<li>PDF: <a href="https://github.com/Lova-clover/leveli/blob/main/docs/ppt/leveli.pdf">leveli.pdf</a></li>
<li>PPTX: <a href="https://github.com/Lova-clover/leveli/blob/main/docs/ppt/leveli.pptx">leveli.pptx</a></li>
</ul>
<p>대표 슬라이드는 이런 느낌이다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/e40be68c-ef9c-4b66-ae25-1eb83b9b80e5/image.png" alt="Leveli 발표자료 1 - 브랜드 소개"></p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/ca0d59ca-da57-46df-af5f-02412eac73d6/image.png" alt="Leveli 발표자료 3 - 해결 방식"></p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/b892ffc4-cb9d-4327-80ee-54a28af97c0f/image.png" alt="Leveli 발표자료 6 - 서비스 화면"></p>
<hr>
<h2 id="ai가-한-것과-내가-한-것">AI가 한 것과 내가 한 것</h2>
<p>AI를 활용한 프로젝트를 올릴 때 제일 조심해야 하는 부분이 있다.</p>
<blockquote>
<p>이거 AI가 다 만든 거 아닌가?</p>
</blockquote>
<p>그래서 이 프로젝트에서는 역할을 명확히 나눠서 생각했다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>AI가 도와준 것</td>
<td>초기 UI 시안, 캐릭터, 로고, 배지, 배경 이미지 생성</td>
</tr>
<tr>
<td>내가 한 것</td>
<td>서비스 콘셉트 정의, 화면 흐름 구성, 에셋 분리, HTML/CSS/JavaScript 구현, 반응형 조정, 로그인 상태 처리, README/PPT 정리</td>
</tr>
<tr>
<td>최종 결과</td>
<td>생성된 이미지를 그대로 붙인 것이 아니라 실제 웹 UI로 재구성한 결과물</td>
</tr>
</tbody></table>
<p>AI는 완성된 웹사이트를 만들어준 게 아니었다.</p>
<p>AI는 시각적 출발점을 만들어줬다.</p>
<p>그 출발점을 보고 무엇을 살릴지, 무엇을 버릴지, 어떤 요소를 이미지로 쓰고 어떤 요소를 HTML/CSS로 구현할지 판단해야 했다.</p>
<p>결국 중요한 건 이미지를 뽑는 것 자체가 아니었다.</p>
<p>중요한 건 그 이미지를 구현 가능한 구조로 다시 해석하는 일이었다.</p>
<hr>
<h2 id="그래도-한계는-있었다">그래도 한계는 있었다</h2>
<p>이번 작업을 하면서 ChatGPT 이미지 생성이 꽤 강력하다는 걸 느꼈다.</p>
<p>하지만 그대로 실무에 바로 쓰기에는 한계도 분명했다.</p>
<p>첫 번째는 텍스트다.</p>
<p>이미지 안의 한글 텍스트는 아직 믿기 어렵다.<br>큰 제목은 그럴듯해도 작은 문구나 라벨은 어색한 경우가 있었다.</p>
<p>그래서 최종 웹에서는 이미지 안 텍스트를 그대로 쓰기보다 HTML 텍스트로 다시 구성했다.</p>
<p>두 번째는 일관성이다.</p>
<p>비슷한 분위기의 캐릭터는 계속 만들 수 있지만, 완전히 같은 캐릭터를 여러 화면에서 안정적으로 유지하는 건 쉽지 않았다.</p>
<p>중요한 캐릭터는 따로 에셋으로 분리해서 재사용하는 방식이 필요했다.</p>
<p>세 번째는 상태다.</p>
<p>이미지는 정적이다.<br>하지만 웹은 상태가 있다.</p>
<p>로그인 전과 후가 다르고, 버튼을 누르면 반응해야 하고, 모바일과 데스크톱에서 레이아웃도 달라져야 한다.</p>
<p>이 부분은 결국 직접 구현해야 했다.</p>
<hr>
<h2 id="이번에-느낀-것">이번에 느낀 것</h2>
<p>이번 프로젝트를 하면서 제일 크게 느낀 건 이거다.</p>
<blockquote>
<p>AI 이미지는 결과물이 아니라 출발점이다.</p>
</blockquote>
<p>이미지 생성은 확실히 빨라졌다.</p>
<p>이제는 웹 시안, 캐릭터, 로고, 배지, PPT 스타일 이미지까지 꽤 그럴듯하게 만들 수 있다.</p>
<p>하지만 그것이 곧 웹사이트가 되는 건 아니다.</p>
<p>예쁜 이미지를 얻는 것은 쉬워졌지만,<br>좋은 웹페이지를 만들려면 여전히 판단이 필요하다.</p>
<ul>
<li>어떤 요소를 분리할 것인가</li>
<li>어떤 요소를 CSS로 구현할 것인가</li>
<li>어떤 텍스트를 HTML로 다시 작성할 것인가</li>
<li>모바일과 데스크톱에서 정보를 어떻게 배치할 것인가</li>
<li>상태 변화는 어떻게 표현할 것인가</li>
<li>결과물을 어떻게 설명해야 오해가 없을 것인가</li>
</ul>
<p>이 판단은 여전히 사람이 해야 한다.</p>
<p>AI가 만들어주는 것은 가능성에 가깝다.<br>그 가능성을 실제 웹 구조로 바꾸는 과정에서 개발자의 역할은 사라지지 않았다.</p>
<p>오히려 더 선명해졌다고 느꼈다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>이번 Leveli 프로젝트를 한 문장으로 정리하면 이렇다.</p>
<blockquote>
<p>AI 기반 UI 시안을 실제 반응형 프론트엔드로 재구성한 실험 프로젝트</p>
</blockquote>
<p>처음에는 단순히 ChatGPT 이미지 생성이 좋아졌는지 확인하려고 시작했다.</p>
<p>그런데 하다 보니 이미지 생성에서 끝나지 않았다.</p>
<p>에셋을 분리하고,<br>레이아웃을 다시 짜고,<br>반응형을 조정하고,<br>로그인 상태를 흉내 내고,<br>Vercel에 배포하고,<br>README와 발표 자료까지 정리했다.</p>
<p>완벽한 서비스는 아니다.</p>
<p>하지만 이번 실험으로 하나는 확실히 느꼈다.</p>
<p>AI 이미지 생성은 UI/UX가 막막한 개인 프로젝트에서 꽤 큰 도움이 된다.</p>
<p>특히 나처럼 처음부터 로고, 캐릭터, 배지, 전체 디자인 톤을 잡는 것이 부담스러운 사람에게는<br>막연한 아이디어를 빠르게 시각화해주는 좋은 출발점이 될 수 있었다.</p>
<p>물론 이미지를 뽑는 것만으로 웹사이트가 완성되지는 않는다.</p>
<p>그 이미지를 실제 웹페이지로 바꾸려면<br>무엇을 에셋으로 분리할지,<br>무엇을 HTML/CSS로 다시 만들지,<br>모바일과 데스크톱에서 정보를 어떻게 배치할지 계속 판단해야 했다.</p>
<p>그래도 이번 작업을 통해 느낀 건 긍정적이었다.</p>
<p>AI는 내 디자인을 대신해준 것이 아니라,<br>내가 구현하고 싶은 방향을 더 빠르게 보고 판단할 수 있게 도와줬다.</p>
<p>결국 중요한 건 단순히 결과물을 빠르게 뽑는 능력이 아니라,<br>그 결과물을 실제로 동작하는 구조로 바꾸는 능력이었다.</p>
<p>그리고 이번 프로젝트에서 AI 이미지 생성은<br>그 출발점을 만드는 데 확실히 큰 도움이 됐다.</p>
<p>이번 작업을 통해 느낀 건 명확했다.</p>
<p>앞으로는 예쁜 UI를 만드는 데 드는 시간은 점점 줄어들 것이다.<br>그래서 중요한 건 UI 자체의 완성도가 아니라,<br>그 UI를 기반으로 어떤 문제를 해결하고<br>얼마나 완성도 있는 기능과 흐름을 만들 수 있는지가 될 것 같다.</p>
<p>다음에는 UI를 빠르게 확보한 뒤,<br>실제 문제 정의와 기능 완성도에 더 많은 시간을 써보려고 한다.</p>
<hr>
<h2 id="관련-링크">관련 링크</h2>
<ul>
<li>Live Demo: <a href="https://leveli.vercel.app">https://leveli.vercel.app</a></li>
<li>GitHub: <a href="https://github.com/Lova-clover/Leveli">https://github.com/Lova-clover/Leveli</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] 구조물 안정성 AI 경진대회: OOF는 좋았는데 왜 Public은 틀렸을까]]></title>
            <link>https://velog.io/@lova-clover/%ED%9A%8C%EA%B3%A0-%EA%B5%AC%EC%A1%B0%EB%AC%BC-%EC%95%88%EC%A0%95%EC%84%B1-AI-%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C-OOF%EB%8A%94-%EC%A2%8B%EC%95%98%EB%8A%94%EB%8D%B0-%EC%99%9C-Public%EC%9D%80-%ED%8B%80%EB%A0%B8%EC%9D%84%EA%B9%8C</link>
            <guid>https://velog.io/@lova-clover/%ED%9A%8C%EA%B3%A0-%EA%B5%AC%EC%A1%B0%EB%AC%BC-%EC%95%88%EC%A0%95%EC%84%B1-AI-%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C-OOF%EB%8A%94-%EC%A2%8B%EC%95%98%EB%8A%94%EB%8D%B0-%EC%99%9C-Public%EC%9D%80-%ED%8B%80%EB%A0%B8%EC%9D%84%EA%B9%8C</guid>
            <pubDate>Mon, 13 Apr 2026 03:53:17 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>🔗 <strong>대회 링크:</strong> <a href="https://dacon.io/competitions/official/236686/overview/description">대회 페이지 바로가기</a>
💻 <strong>GitHub:</strong> <a href="https://github.com/Lova-clover/dacon-structural-stability">프로젝트 소스코드</a>
🏆 <strong>최종 결과:</strong> <strong>Public 21위</strong> (0.0145427) ➡️ <strong>Private 12위</strong> (0.01703)</p>
</blockquote>
<p>아주 잘한 것도 아니고, 그렇다고 가볍게 넘길 결과도 아니었다.
특히 더 아쉬웠던 건, 대회 막판까지도 <em>“조금만 더 다듬으면 올라갈 것 같은데?”</em> 라는 감각이 계속 남았다는 점이다. 실제로 몇 번은 진짜 될 것처럼 보였다. </p>
<p>그런데 끝까지 돌아보면, 이번 대회는 점수보다 더 중요한 걸 남겼다.</p>
<p><strong>OOF가 좋다고 Public도 좋은 건 아니다.</strong>
그리고 생각보다 훨씬 자주, <strong>좋아 보이는 아이디어가 모델을 망친다.</strong></p>
<p>이번 글은 그 얘기다.
어떤 모델이 제일 셌는지보다, <strong>왜 어떤 실험은 OOF에서만 좋았고 Public에서는 무너졌는지</strong>, 그리고 왜 결국 “더 복잡한 방법”보다 “덜 망가뜨리는 방법”이 더 중요했는지를 정리해보려고 한다.</p>
<hr>
<h2 id="🏗️-이-대회는-생각보다-단순하지-않았다">🏗️ 이 대회는 생각보다 단순하지 않았다</h2>
<p>문제 자체는 얼핏 보면 익숙하다.</p>
<ul>
<li><strong>Input:</strong> <code>front.png</code>와 <code>top.png</code> 두 장의 이미지</li>
<li><strong>Output:</strong> 구조물이 안정한지, 불안정한지에 대한 확률</li>
<li><strong>Metric:</strong> <code>LogLoss</code></li>
</ul>
<p>여기까지만 보면 “이미지 두 장짜리 이진 분류”다. 그런데 실제로 해보면 얘기가 완전히 달라진다. 이 대회가 어려웠던 이유는 크게 세 가지였다.</p>
<ol>
<li><code>front</code>와 <code>top</code>이라는 서로 다른 시점을 같이 해석해야 한다.</li>
<li>정답을 맞히는 것보다 <strong>확률을 얼마나 잘 내느냐</strong>가 더 중요하다.</li>
<li><code>train</code>과 <code>dev/test</code>의 분포(분위기)가 꽤 다르다.</li>
</ol>
<p>특히 세 번째가 컸다. 초반에는 OOF가 오르면 그냥 좋은 줄 알았다. 당연히 그게 맞을 거라고 생각했다. 그런데 실제로는 OOF가 좋아진 실험이 Public에서 깨지는 경우가 계속 나왔다. </p>
<p>그때부터 이 프로젝트는 <em>“좋은 모델 찾기”</em> 보다 <strong>“어떤 검증이 진짜 믿을 만한가”</strong>를 따지는 프로젝트가 됐다.</p>
<hr>
<h2 id="🧩-처음엔-백본을-바꾸면-될-줄-알았다">🧩 처음엔 백본을 바꾸면 될 줄 알았다</h2>
<p>대회 초반에는 <code>ConvNeXt</code>, <code>EfficientNetV2</code>, <code>Swin</code> 같은 전형적인 이미지 백본을 돌렸다. 이건 사실 대부분의 이미지 대회에서 자연스러운 시작이다. 일단 강한 모델들을 올려보고, 어느 축이 맞는지 보는 것.</p>
<p>초기에는 ConvNeXt도 썼고, EfficientNetV2도 썼다. Swin도 시도했다.
그런데 시간이 지날수록 분명해진 게 있다.</p>
<blockquote>
<p><strong>이 문제는 “더 센 백본”이 바로 정답이 아니었다.</strong></p>
</blockquote>
<p>오히려 더 중요했던 건 다음과 같았다.</p>
<ul>
<li>두 뷰(View)를 어떻게 안정적으로 결합하는지</li>
<li><code>LogLoss</code> 기준으로 확률이 얼마나 정돈되는지</li>
<li><code>train</code> 쪽에 맞춘 모델이 아니라 <code>dev/test</code>에서도 안 무너지는지</li>
</ul>
<p>결국 주력은 <code>EfficientNetV2-S</code> 계열로 정리됐다. 
이유는 화려해서가 아니라, 가장 <strong>안정적으로 버텼기 때문</strong>이다. 이 지점에서 배운 첫 번째 교훈은 명확했다.</p>
<p><strong>백본 다양성은 필요할 수 있어도, 충분조건은 아니다.</strong></p>
<hr>
<h2 id="🔄-전환점은-모델-추가가-아니라-검증-방식이었다">🔄 전환점은 모델 추가가 아니라 &#39;검증 방식&#39;이었다</h2>
<p>초반에는 여러 모델을 섞고, 블렌딩 가중치를 만지고, 이것저것 붙여보는 식으로 갔다. 그런데 어느 순간부터 점수가 오르는 방식이 바뀌기 시작했다.</p>
<p>전환점은 “새 모델 하나 더”가 아니었다. 
오히려 <strong>강한 단일 모델을 얼마나 잘 다듬느냐</strong>였다. 특히 크게 작용한 건 세 가지였다.</p>
<h3 id="1-devfocus">1. devfocus</h3>
<p>이 대회에서는 <code>train</code>을 잘 맞히는 것보다, <code>dev/test</code>에 가까운 분포를 얼마나 잘 따라가느냐가 중요했다. 그래서 <code>dev</code> 쪽에 더 무게를 둔 <code>devfocus</code> 전략이 실제로 꽤 잘 맞았다.</p>
<p>처음엔 약간 우회적인 트릭처럼 느껴졌는데, 나중에 돌아보면 오히려 이게 문제를 제대로 본 접근이었다. 이 대회는 그냥 “데이터를 많이 잘 외우는 문제”가 아니라, <strong>분포 차이를 버티는 문제</strong>에 더 가까웠다.</p>
<h3 id="2-calibration">2. calibration</h3>
<p><code>LogLoss</code>에서는 확률 모양이 중요하다. 이건 너무 당연한 말 같지만, 실제로 대회에서는 자주 잊힌다.</p>
<p>Accuracy 관점에서는 비슷해 보여도, 확률이 조금만 과하면 <code>LogLoss</code>는 크게 흔들린다. 그래서 calibration은 생각보다 훨씬 중요했다. 단순히 <em>“예측을 더 잘하자”</em> 가 아니라, <em><strong>“예측을 덜 이상하게 만들자”</strong></em> 에 가까웠다.</p>
<h3 id="3-oof-기반-stacking">3. OOF 기반 stacking</h3>
<p>가장 의미 있었던 개선은 결국 여기서 나왔다. 같은 계열 모델을 seed만 조금 다르게 학습하고, OOF를 기준으로 stacking하는 방식이다.</p>
<p>처음엔 “이게 정말 그렇게 큰 차이를 만들까?” 싶었는데, 실제로는 꽤 달랐다. 완전히 다른 백본을 무리하게 섞는 것보다, <strong>같은 라인 안에서 약간 다른 결정 경계를 가진 모델을 안정적으로 조합하는 방식</strong>이 더 잘 버텼다.</p>
<hr>
<h2 id="🔬-exp-006과-exp-020-잘된-개선은-왜-잘됐나">🔬 EXP-006과 EXP-020: 잘된 개선은 왜 잘됐나</h2>
<h3 id="exp-006"><code>EXP-006</code></h3>
<p>이 프로젝트의 첫 번째 기준점이었다. 이때부터 단순 단일 제출이 아니라, <code>EfficientNetV2-S devfocus</code> 메인 런에 seed 다양성과 calibration, stacking을 얹는 방식이 자리를 잡았다.</p>
<p>중요했던 건 이 실험이 “크게 새롭다”는 데 있지 않았다. 오히려 반대였다.</p>
<ul>
<li>backbone은 크게 바꾸지 않았다.</li>
<li>검증 가능한 범위 안에서만 확장했다.</li>
<li>OOF 기준으로만 후처리를 붙였다.</li>
</ul>
<p>즉, <strong>좋은 체인을 더 세게 밀었다기보다, 좋은 체인을 덜 망가뜨리면서 다듬었다</strong>는 쪽이 맞다. 이후 여러 실험이 실패했음에도 다시 이 라인으로 돌아오게 된 이유도 여기에 있다. 특별히 기발한 아이디어는 아니었어도, 결과적으로 가장 단단한 파이프라인이었다.</p>
<h3 id="exp-020"><code>EXP-020</code></h3>
<p>두 번째 전환점이었다. 이 시점에는 이미 “그냥 좋은 설정을 다시 돌리면 된다”는 단계는 지났다. 핵심은 <strong>같은 계열 안에서도 어떤 seed pair가 진짜로 먹히는가</strong>였다.</p>
<p>여기서 <code>s2026 + s2029</code> 조합이 의미 있는 결과를 만들었다. 이 결과가 보여준 건 단순히 “seed 두 개 섞으면 좋아진다”가 아니었기 때문이다. 핵심은 이거였다.</p>
<ul>
<li>모든 passing seed가 같은 값어치를 하지 않는다.</li>
<li>fit mode보다 seed pair 자체가 더 중요할 수 있다.</li>
<li>local refinement는 넓게 하지 말고, <strong>이긴 조합 주변만 아주 좁게</strong> 봐야 한다.</li>
</ul>
<p>이때부터 실험 전략은 많이 달라졌다. 새 branch를 계속 열기보다는, <strong>이미 이긴 체인을 어떻게 안전하게 재현할지</strong>가 더 중요해졌다.</p>
<hr>
<h2 id="📉-oof는-왜-좋았고-public은-왜-틀렸을까">📉 OOF는 왜 좋았고, Public은 왜 틀렸을까</h2>
<p>이 프로젝트를 한 문장으로 요약하면 사실 이 질문이다.
<em>왜 어떤 실험은 OOF가 그렇게 좋아 보였는데, Public에서는 처참하게 깨졌을까?</em></p>
<h3 id="1-dev-최적화가-test-일반화는-아니었다">1. dev 최적화가 test 일반화는 아니었다</h3>
<p>OOF는 결국 내부 validation이다. 문제는 이 validation이 곧바로 실제 test를 대표하진 않는다는 데 있다.
이 대회에서는 <code>train</code>과 <code>dev/test</code>의 도메인 차이가 계속 발목을 잡았다. 그래서 dev에서 좋아 보이는 threshold, blend weight, fold 선택, calibration 파라미터가 Public에서는 오히려 독이 되는 경우가 많았다. 특히 meta blend나 fold pruning은 실제로는 dev의 노이즈까지 함께 학습해버리는 경우가 많았다.</p>
<h3 id="2-logloss는-확률의-작은-왜곡도-크게-벌린다">2. LogLoss는 확률의 작은 왜곡도 크게 벌린다</h3>
<p>confidence가 조금만 과해도 크게 손해 본다. 같은 backbone, 같은 fold 조합이라도 calibration 방식이나 stacker fit mode가 달라지면 결과가 꽤 크게 흔들렸다.
그래서 OOF가 아주 조금 좋아졌다는 사실만으로는 안심할 수 없었다. 그 개선이 정말 더 좋은 분류인지, 아니면 dev 분포에만 더 잘 맞는 확률 모양인지를 구분하기가 어려웠기 때문이다.</p>
<h3 id="3-공격적인-후처리는-거의-항상-위험했다">3. 공격적인 후처리는 거의 항상 위험했다</h3>
<p>대회 후반에는 <code>top-k fold 선택</code>, <code>pruning</code>, <code>meta blend</code>, <code>stage2 fine-tuning</code>, <code>anchor refinement</code> 등 별별 걸 다 붙였다.</p>
<p>하나하나 보면 다 논리는 있었다. 문제는, <strong>논리가 있다고 해서 점수가 오르지는 않았다</strong>는 거다. 실제로는 대부분의 공격적인 후처리가 메인 체인을 망가뜨렸다. 좋은 체인을 조금 더 좋게 만드는 게 아니라, 불안정하게 만드는 경우가 더 많았다.</p>
<blockquote>
<p><strong>잘 되는 체인을 더 좋게 만드는 것보다, 잘 되는 체인을 덜 망가뜨리는 게 더 중요하다.</strong></p>
</blockquote>
<hr>
<h2 id="🗑️-실패한-시도들은-왜-의미가-있었나">🗑️ 실패한 시도들은 왜 의미가 있었나</h2>
<p>실패한 실험은 점수로는 남지 않는다. 하지만 프로젝트에는 오히려 더 강하게 남는다.</p>
<ul>
<li><strong>ConvNeXt</strong>: 초기 검증용으로는 꽤 유용했다. 파이프라인 확인용으로 좋았지만, 성능 상한과 안정성 모두에서 EfficientNetV2 계열이 더 나았다.</li>
<li><strong>Swin</strong>: 구조적으로 더 강할 것 같았지만 의미 있는 개선을 보여주지 못했다. “더 무거운 구조”보다 이미 잘 맞는 모델의 확률 품질을 다듬는 것이 먼저였다.</li>
<li><strong>Distillation</strong>: <code>video teacher -&gt; image student</code> 구조는 끝까지 놓기 아쉬웠다. <code>simulation.mp4</code>를 teacher로 학습하는 아이디어는 좋았고 내부 결과도 괜찮았지만, Public에서 안정적으로 서주지 못했다. 여기서도 <strong>&#39;새로운 신호를 얼마나 조심해서 넣느냐&#39;</strong>가 중요하다는 걸 배웠다.</li>
<li><strong>Stage2 fine-tuning</strong>: 이건 진짜 함정이었다. 겉으로는 정교해 보이는데 실전에서는 이상할 정도로 자주 무너졌다. 오히려 다양성을 줄이고 과적합만 키우는 경우가 많았다.</li>
</ul>
<hr>
<h2 id="💡-이번-대회에서-남은-것">💡 이번 대회에서 남은 것</h2>
<p>최종 결과는 <strong>Public 21위, Private 12위</strong>. 아쉽게도 탑10에는 들지 못했다.</p>
<p>하지만 이번 대회에서 가장 뼈아픈 부분은 따로 있었다.</p>
<p>수상 검증 단계에 필요한 “Private Score 복구 가능한 코드”를 끝내 제출하지 못했다.
정확히는, 종료 시점에 final submission을 exact reproduction할 수 있도록 seed pair, OOF, intermediate artifact, 실행 기록을 검증 가능한 형태로 보존하지 못했다.
그 결과, 끝까지 검증 가능한 형태로 정리할 수만 있었다면 실제로 2등까지도 바라볼 수 있었지만, 그 가능성을 제출 가능한 결과물로 연결하지는 못했다.</p>
<p>이번 프로젝트의 가장 큰 실패는 모델이 아니라 재현성 관리였다.
그리고 이 교훈은, 이번 대회에서 얻은 어떤 모델링 기법보다 더 중요했다.</p>
<p>그래도 후회만 남은 건 아니다. 단순한 등수를 넘어, 이번 프로젝트는 내게 꽤 묵직한 레슨들을 남겼다.</p>
<ol>
<li><strong>검증 지표(OOF)를 맹신하지 말 것</strong></li>
<li><strong>LogLoss 환경에선 모델 크기보다 &#39;확률의 디테일&#39;이 먼저다</strong></li>
<li><strong>수많은 실패가 오히려 뚫고 갈 길을 알려줬다</strong></li>
<li><strong>재현 불가능한 점수는 내 점수가 아니다</strong></li>
</ol>
<p>특히 마지막 교훈, 대회 막판으로 갈수록 <em>&quot;어떤 세팅에서 점수가 제일 높게 튀었나&quot;</em> 보다 <em><strong>&quot;내가 이 결과를 다시 안정적으로 만들어낼 수 있는가&quot;</strong></em> 가 훨씬 중요하다는 것은 앞으로의 개발에서도 절대 잊지 말아야 할 기준이다.</p>
<hr>
<h2 id="🏁-마무리">🏁 마무리</h2>
<p>이 프로젝트를 한 문장으로 줄이면 이렇다.</p>
<blockquote>
<p><strong>큰 아이디어보다, 확률 품질과 검증 체계를 끝까지 붙잡는 쪽이 더 강했다.</strong></p>
</blockquote>
<p>초반에는 백본과 branch를 넓게 탐색했지만, 후반으로 갈수록 전략은 완전히 바뀌었다. 가장 강한 라인을 보수적으로 재현하고, 그 주변에서만 작게 움직이는 방식이 더 낫다는 걸 배웠다.</p>
<p>실무에서도 비슷하다고 생각한다. 모델을 바꾸는 건 눈에 잘 띈다. 하지만 실제 품질을 좌우하는 건 calibration, validation 신뢰도, 재현성 같은 덜 화려한 것들이다.</p>
<p>이번 프로젝트에서 얻은 가장 큰 수확도 그거다. 
무엇이 잘 됐는지보다, <strong>무엇이 왜 안 됐는지</strong>를 꽤 명확하게 이해하게 됐다. 다음 프로젝트에서는 그 차이가 훨씬 크게 작용할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] KIT 바이브코딩 공모전에서 ClassCue를 끝까지 제출하며 배운 것들]]></title>
            <link>https://velog.io/@lova-clover/%ED%9A%8C%EA%B3%A0-KIT-%EB%B0%94%EC%9D%B4%EB%B8%8C%EC%BD%94%EB%94%A9-%EA%B3%B5%EB%AA%A8%EC%A0%84%EC%97%90%EC%84%9C-ClassCue%EB%A5%BC-%EB%81%9D%EA%B9%8C%EC%A7%80-%EC%A0%9C%EC%B6%9C%ED%95%98%EB%A9%B0-%EB%B0%B0%EC%9A%B4-%EA%B2%83%EB%93%A4</link>
            <guid>https://velog.io/@lova-clover/%ED%9A%8C%EA%B3%A0-KIT-%EB%B0%94%EC%9D%B4%EB%B8%8C%EC%BD%94%EB%94%A9-%EA%B3%B5%EB%AA%A8%EC%A0%84%EC%97%90%EC%84%9C-ClassCue%EB%A5%BC-%EB%81%9D%EA%B9%8C%EC%A7%80-%EC%A0%9C%EC%B6%9C%ED%95%98%EB%A9%B0-%EB%B0%B0%EC%9A%B4-%EA%B2%83%EB%93%A4</guid>
            <pubDate>Sun, 12 Apr 2026 08:58:29 GMT</pubDate>
            <description><![CDATA[<p>처음엔 그냥 “한 번 해볼까?”였다.</p>
<p>바이브코딩 대회를 봤을 때도,
처음부터 확신이 있었던 건 아니었다.
요즘 AI 관련 공모전은 정말 많고,
겉보기에 그럴듯한 서비스도 넘쳐난다.
그래서 오히려 더 애매했다.</p>
<p>내가 여기서 뭘 만들 수 있을까.
그리고 더 중요한 건,
내가 만드는 게 정말 의미가 있을까.</p>
<p>마음을 먹고 한번 참가해보았다.</p>
<p>참가하고 나온 주제는 바로</p>
<p><strong>AI 활용 차세대 교육 솔루션</strong></p>
<p>이 문장을 처음 봤을 땐 조금 막막했다.
너무 넓었기 때문이다.
교육, AI, 솔루션.
셋 다 좋은 말인데, 동시에 너무 많은 가능성을 열어두는 말이기도 했다.</p>
<p>온라인 강의 플랫폼도 될 수 있고,
튜터링 앱도 될 수 있고,
문제 추천 서비스도 될 수 있고,
챗봇도 될 수 있었다.</p>
<p>그런데 공모전 설명을 조금 더 읽어보니 방향이 달라졌다.</p>
<p>이 대회가 원하는 건
그냥 “교육용 서비스 하나”가 아니라,
교강사, 수강생, 교육 운영자 같은 실제 현장 구성원들이 겪는 불편을
AI로 날카롭게 해결하는 서비스였다.</p>
<p>그때부터 생각이 조금 정리되기 시작했다.</p>
<p>나는 넓은 교육 문제를 풀고 싶은 게 아니라,
<strong>실제로 현장에서 반복되는데 늘 애매하게 남는 문제 하나를 제대로 잡고 싶었다.</strong></p>
<hr>
<h2 id="수업은-끝났는데-정작-중요한-판단은-그때부터-시작된다">수업은 끝났는데, 정작 중요한 판단은 그때부터 시작된다</h2>
<p>교육 현장에서 수업이 끝났다고 해서 일이 끝나는 건 아니다.</p>
<p>오히려 그다음이 더 중요할 때가 많다.</p>
<p>교강사는 수업이 끝난 뒤 이런 것들을 마주한다.</p>
<ul>
<li>강의자료</li>
<li>학생들이 남긴 질문</li>
<li>과제나 활동에서 보인 반응</li>
<li>수업 중 따로 적어둔 메모</li>
<li>“이 부분에서 많이 막히던데” 같은 감각적인 판단</li>
</ul>
<p>문제는 이 정보들이 없다는 게 아니었다.
문제는 <strong>이 정보들이 판단 가능한 형태로 정리되어 있지 않다</strong>는 것이었다.</p>
<p>어떤 질문이 단순 질문이고,
어떤 질문이 핵심 오개념인지,
다음 시간에 무엇을 먼저 다시 설명해야 하는지,
누구에게 어떤 방식으로 개입해야 하는지,
운영 차원에서는 어떤 수업이 반복적으로 막히고 있는지.</p>
<p>이건 생각보다 쉽게 정리되지 않는다.</p>
<p>수강생 입장에서도 비슷하다.
내가 무엇을 모르고 있는지,
무엇부터 복습해야 하는지,
질문을 남겼는데 그게 어떻게 반영됐는지
명확하게 보이지 않는 경우가 많다.</p>
<p>운영자는 더 멀리서 본다.
여러 수업에서 반복되는 오개념,
교강사 승인 지연,
피드백 답변 지연,
기관 단위 운영 병목은 보이는데
그걸 빠르게 읽고 정리하는 건 또 다른 문제다.</p>
<p>그렇게 정리한 문제의 이름이
ClassCue의 출발점이 됐다.</p>
<p><strong>“수업이 끝난 직후, 무엇을 다시 가르쳐야 하는지 빠르게 결정하기 어렵다.”</strong></p>
<hr>
<h2 id="그렇게-classcue가-만들어졌다">그렇게 ClassCue가 만들어졌다</h2>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/c35edd61-af33-4aa9-b0f1-2ec237c808aa/image.png" alt=""></p>
<p>ClassCue는 이 문제를 해결하기 위해 만든 AI 교육 서비스다.</p>
<p>한 줄로 말하면,</p>
<p><strong>흩어진 질문과 수업 기록을 다음 수업 개입안으로 바꾸는 도구</strong></p>
<p>다.</p>
<p>조금 더 구체적으로 설명하면,
ClassCue는 강의자료, 학생 질문, 교강사 메모를 하나의 세션으로 묶는다.
그다음 AI가 이 세션을 읽고 다음과 같은 결과를 구조화한다.</p>
<ul>
<li>어떤 오개념이 반복적으로 나타났는지</li>
<li>그 오개념을 뒷받침하는 근거 문장이 무엇인지</li>
<li>위험도가 높은 지점은 어디인지</li>
<li>다음 수업에서 어떤 개입을 해야 하는지</li>
<li>학습자에게는 어떤 복습 가이드와 미니 퀴즈를 주는 게 좋은지</li>
<li>운영자에게는 무엇을 브리프로 전달해야 하는지</li>
</ul>
<p>중요한 건,
이 결과가 자동으로 바로 배포되지 않는다는 점이었다.</p>
<p>나는 이 서비스를 “AI가 대신 판단하는 도구”로 만들고 싶지 않았다.
교육 현장에서는 특히 더 그렇다고 생각했다.</p>
<p>그래서 ClassCue 안에는
<strong>교강사가 반드시 검토하고 승인하는 단계(Human-in-the-loop)</strong> 를 넣었다.</p>
<p>AI는 분석하고 제안한다.
하지만 최종 판단은 사람이 한다.</p>
<p>이 구조는 단순한 기능 하나가 아니라,
이 서비스가 어떤 태도를 갖고 있는지 보여주는 핵심이기도 했다.</p>
<hr>
<h2 id="만들면서-제일-먼저-했던-건-기능을-늘리는-게-아니라-문제를-좁히는-일이었다">만들면서 제일 먼저 했던 건, 기능을 늘리는 게 아니라 문제를 좁히는 일이었다</h2>
<p>처음부터 ClassCue가 지금처럼 또렷했던 건 아니다.</p>
<p>오히려 초반에는 너무 많은 방향이 있었다.</p>
<ul>
<li>운영 대시보드를 더 크게 보이고 싶었다</li>
<li>학습자 화면을 더 풍부하게 만들고 싶었다</li>
<li>리포트도 더 화려하게 만들고 싶었다</li>
<li>AI Assistant도 붙이고 싶었다</li>
<li>플레이북, proof, ops, inbox까지 다 중요해 보였다</li>
</ul>
<p>문제는 그럴수록
정작 “이 서비스가 정확히 무엇을 해결하는가”가 흐려졌다는 점이다.</p>
<p>기능은 많아지는데,
핵심은 흐려졌다.</p>
<p>결국 중간부터는 기준을 완전히 바꿨다.</p>
<p>이 프로젝트는 LMS가 아니다.
올인원 교육 플랫폼도 아니다.
질문 챗봇도 아니다.</p>
<p><strong>수업 직후 재수업 의사결정을 돕는 도구</strong>여야 한다.</p>
<p>이 문장으로 계속 되돌아가면서
기능과 문장을 많이 덜어냈다.
설명도 줄였고,
화면도 줄였고,
주인공이 아닌 요소는 뒤로 밀었다.</p>
<p>만들수록 커지는 서비스가 아니라,
만들수록 더 선명해지는 서비스가 되도록 방향을 바꿨다.</p>
<hr>
<h2 id="ai를-썼다는-것보다-ai와-어떻게-일했는지가-더-중요했다-🧠">AI를 썼다는 것보다, AI와 어떻게 일했는지가 더 중요했다 🧠</h2>
<p>이번 공모전은 AI 활용 능력도 심사 항목이었다.
그런데 하다 보니 느낀 건,
AI를 잘 쓴다는 게 단순히 빠르게 결과를 뽑는 일이 아니라는 점이었다.</p>
<p>오히려 더 중요했던 건
<strong>각 도구에 어떤 역할을 맡길 것인가</strong>였다.</p>
<p>이번 작업에서는 크게 세 가지 층위로 AI를 활용했다.</p>
<h3 id="1-codex-54">1. Codex 5.4</h3>
<p>Codex 5.4는 가장 오랫동안 붙어 있던 개발 파트너였다.</p>
<ul>
<li>기획 정리</li>
<li>문제 정의 압축</li>
<li>구조 설계</li>
<li>실제 코드 구현</li>
<li>디버깅</li>
<li>코드 리뷰</li>
<li>제출 문서 정리</li>
</ul>
<p>까지 거의 전체 흐름을 함께 갔다.</p>
<p>이번 프로젝트는 “이 코드가 예쁘냐”보다
“이 서비스가 끝까지 닫히느냐”가 중요했기 때문에,
기능 하나 고치는 걸 넘어서
배포, 검증, 문서, 제출 상태까지 같이 점검할 수 있다는 점이 컸다.</p>
<h3 id="2-gemini-31-pro">2. Gemini 3.1 Pro</h3>
<p>Gemini 3.1 Pro는 UI/UX 방향 탐색에서 많이 활용했다.</p>
<ul>
<li>화면 위계를 어떻게 잡을지</li>
<li>설명을 어디까지 줄일지</li>
<li>어떤 문장이 더 빨리 읽히는지</li>
<li>카드와 섹션을 어떻게 덜어낼지</li>
<li>더 실제 서비스처럼 보이려면 무엇을 빼야 하는지</li>
</ul>
<p>이런 부분에서 꽤 도움을 받았다.</p>
<p>특히 “뭘 더 넣을까?”보다
“지금 이 화면에서 무엇이 불필요한가?”를 보는 데 유용했다.</p>
<h3 id="3-서비스-내부-ai-런타임">3. 서비스 내부 AI 런타임</h3>
<p>이건 사용자가 실제로 만나게 되는 AI다.</p>
<p>ClassCue의 내부 AI는 단순히 질문을 대답하는 챗봇이 아니라,
문서와 질문과 메모를 받아서
오개념, 근거, 개입안, 복습 흐름을 구조화하는 역할을 맡는다.</p>
<p>그리고 여기서 가장 중요하게 본 건 두 가지였다.</p>
<p>첫째,
AI 결과는 가능한 한 근거를 남길 것.</p>
<p>둘째,
AI 결과는 교강사 승인 전 외부로 그대로 나가지 않을 것.</p>
<p>이 태도는 결국 서비스의 신뢰와 연결됐다.
교육에서는 “AI가 말했다”보다
“왜 이런 판단이 나왔는가”가 훨씬 중요하다고 생각했기 때문이다.</p>
<hr>
<h2 id="개발보다-더-오래-붙들었던-건-서비스처럼-보이게-만드는-일이었다">개발보다 더 오래 붙들었던 건, ‘서비스처럼 보이게 만드는 일’이었다</h2>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/bf35b0f1-083e-43d3-94f0-dc15570a4ea5/image.png" alt=""></p>
<p>이번에 꽤 오래 씨름했던 부분은
의외로 기능이 아니라 화면이었다.</p>
<p>AI 서비스는 조금만 잘못 만들면
그럴듯한 카드 몇 개와
과한 설명 몇 줄로 채워진
“데모 느낌”이 강하게 난다.</p>
<p>나도 그 함정에 몇 번 들어갔다.</p>
<p>너무 절제하면 답답해졌고,
너무 힘을 주면 제품보다 연출이 먼저 보였다.
공간을 좁게 쓰면 문서처럼 보였고,
텍스트가 많아지면 설명 페이지처럼 보였다.</p>
<p>그래서 후반부에는 이런 기준을 계속 붙들었다.</p>
<ul>
<li>이 화면이 실제 서비스처럼 느껴지는가</li>
<li>사용자가 생각하지 않고도 다음 행동을 알 수 있는가</li>
<li>AI가 주인공이 아니라 사용자의 판단이 주인공으로 남는가</li>
</ul>
<p>이 기준으로 홈, 워크스페이스, 대시보드, 사례 증명, 인박스, 운영 화면을 계속 다시 정리했다.</p>
<p>특히 사례 증명 화면은
처음엔 너무 “심사용 증빙”처럼 보여서 많이 고쳤다.
나중에는 심사자보다도
실제로 이 서비스를 쓰는 교강사가
“질문이 이렇게 정리되고, 승인되고, 다음 수업으로 이어지는구나”를 이해할 수 있는 화면으로 바꾸려고 했다.</p>
<p>결국 좋은 UI라는 건 예쁜 장식이 아니라,
서비스의 의도를 더 빨리 읽히게 만드는 구조라는 걸 이번에 많이 체감했다.</p>
<hr>
<h2 id="이번-프로젝트를-진짜-서비스처럼-만들기-위해-했던-것들">이번 프로젝트를 진짜 서비스처럼 만들기 위해 했던 것들</h2>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/f68eddbe-b7c5-469b-873f-938204fc5ed7/image.png" alt=""></p>
<p>후반부에는 기능 추가보다
“이게 정말 돌아가느냐”를 더 많이 봤다.</p>
<p>그래서 실제로 챙긴 것들은 꽤 현실적이었다.</p>
<ul>
<li>Vercel 배포</li>
<li>Supabase 실연결</li>
<li>OpenAI API 연결</li>
<li>/api/health, /api/ready 체크</li>
<li>실제 세션 저장</li>
<li>실제 분석 반영</li>
<li>AI Assistant 응답</li>
<li>proof와 export 흐름 확인</li>
<li>public GitHub 정리</li>
<li>AI 협업 문서 정리</li>
</ul>
<p>이 과정에서 느낀 건,
서비스는 결국 “그럴듯한 화면”보다
<strong>끝까지 끊기지 않는 흐름</strong>으로 신뢰를 얻는다는 점이었다.</p>
<p>홈에서 시작해서,
세션을 만들고,
분석이 돌아가고,
결과를 확인하고,
승인하고,
다음 액션으로 이어지는 그 흐름이 실제로 닫혀야 했다.</p>
<p>그때서야 비로소 이게 단순한 데모가 아니라
“제출 가능한 상태”라는 말을 할 수 있게 됐다.</p>
<hr>
<h2 id="문서도-최대한-남기려고-했던-이유">문서도 최대한 남기려고 했던 이유</h2>
<p>이번 공모전은 AI와 효율적으로 협업한 흔적을 남기는 것도 중요했다.</p>
<p>그래서 결과물만 만들고 끝내지 않으려고 했다.</p>
<ul>
<li>어떤 문제 정의를 선택했는지</li>
<li>어떤 기능을 넣고 어떤 기능을 덜어냈는지</li>
<li>어떤 AI 도구를 어디에 썼는지</li>
<li>어떤 기준으로 구조를 정리했는지</li>
<li>무엇을 검증했고 무엇이 남았는지</li>
</ul>
<p>이런 것들을 문서로 최대한 남기려고 했다.</p>
<p>솔직히 개발만 해도 시간이 부족한데
문서까지 정리하는 건 꽤 번거로웠다.
하지만 지나고 보니,
이 과정이 단순히 심사용이 아니라
내가 지금 무엇을 만들고 있는지 계속 돌아보게 해주는 장치이기도 했다.</p>
<p>문서를 쓴다는 건 결국
생각을 정리하는 일이기도 했다.</p>
<p>그리고 그 덕분에
ClassCue는 기능이 많은 프로젝트라기보다
문제의식이 남아 있는 프로젝트가 될 수 있었다고 생각한다.</p>
<hr>
<h2 id="결국-제출까지-갔다-🚀">결국 제출까지 갔다 🚀</h2>
<p>완벽한 확신이 있었던 건 아니다.
중간중간 이게 정말 맞는지 흔들릴 때도 많았다.</p>
<p>아이디어가 약해 보이는 날도 있었고,
디자인이 마음에 안 드는 날도 있었고,
배포에서 막히는 순간도 있었고,
문서까지 정리하다 보면 “여기까지 해야 하나” 싶기도 했다.</p>
<p>그런데도 끝까지 제출까지 왔다.</p>
<p>그건 꽤 큰 차이였다.</p>
<p>이번 프로젝트는 적어도
아이디어만 말하다 끝나지 않았고,
AI를 붙였다고 설명만 하다 끝나지 않았고,
실제로 배포하고, 연결하고, 동작하는 상태까지 가져갔다.</p>
<p>그건 결과와 별개로 꽤 중요한 경험이었다.</p>
<hr>
<h2 id="이번-공모전이-남긴-것">이번 공모전이 남긴 것</h2>
<p>이번 공모전을 통해 제일 크게 배운 건 두 가지다.</p>
<p>첫째,
좋은 프로젝트는 처음부터 완벽한 아이디어로 시작하지 않아도 된다는 것.
오히려 끝까지 붙들고 좁히고 다듬는 과정에서 더 분명해질 수 있다는 것.</p>
<p>둘째,
AI 시대의 개발은 “무엇을 자동으로 만들 수 있느냐”보다
“무엇을 사람의 판단으로 남길 것이냐”가 더 중요할 수 있다는 것.</p>
<p>ClassCue는 아직 완성형 서비스는 아니다.
더 단단한 인증,
더 현실적인 운영,
더 정교한 권한 구조,
더 많은 실제 사용 데이터가 필요하다.</p>
<p>그래도 분명한 건 있다.</p>
<p>이번 프로젝트는 적어도
교육 현장에서 실제로 존재하는 문제를 향해
AI를 어디에, 어떻게 붙여야 하는지
끝까지 진지하게 고민하며 만든 결과물이었다.</p>
<p>그 점은 오래 남을 것 같다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>이번 공모전은 나에게
기능을 많이 만드는 경험보다
무엇이 정말 중요한지를 끝까지 가려내는 경험에 더 가까웠다.</p>
<p>좋은 서비스는 화려한 기능보다
문제를 더 정확히 붙들고,
사용자를 덜 헷갈리게 만들고,
실제로 한 번 더 쓰게 만드는 서비스라는 걸
이번에 다시 배웠다.</p>
<p>ClassCue가 완벽하다고 생각하진 않는다.
하지만 적어도
수업이 끝난 뒤 남는 질문들과 혼란을
다음 수업의 개입안으로 바꿔보려는 시도만큼은 진심이었다.</p>
<p>이번엔 끝까지 제출했다.
그걸로도 충분히 의미 있었다.</p>
<hr>
<h2 id="프로젝트-링크">프로젝트 링크</h2>
<p>이번에 제출한 ClassCue는 아래에서 확인할 수 있습니다.</p>
<ul>
<li>GitHub: <a href="https://github.com/Lova-clover/ClassCue">https://github.com/Lova-clover/ClassCue</a></li>
<li>Demo: <a href="https://class-cue-ruddy.vercel.app/">https://class-cue-ruddy.vercel.app/</a></li>
<li>대회주소: <a href="http://koreaitac.com/2025/landing/vibe_coding.asp">http://koreaitac.com/2025/landing/vibe_coding.asp</a></li>
</ul>
<p>읽어주셔서 감사합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[날짜 밀릴 때마다 다시 고치기 귀찮아서, 나만의 D-DAY 메모 앱을 만들었다]]></title>
            <link>https://velog.io/@lova-clover/%EB%82%A0%EC%A7%9C-%EB%B0%80%EB%A6%B4-%EB%95%8C%EB%A7%88%EB%8B%A4-%EB%8B%A4%EC%8B%9C-%EA%B3%A0%EC%B9%98%EA%B8%B0-%EA%B7%80%EC%B0%AE%EC%95%84%EC%84%9C-%EB%82%98%EB%A7%8C%EC%9D%98-D-DAY-%EB%A9%94%EB%AA%A8-%EC%95%B1%EC%9D%84-%EB%A7%8C%EB%93%A4%EC%97%88%EB%8B%A4</link>
            <guid>https://velog.io/@lova-clover/%EB%82%A0%EC%A7%9C-%EB%B0%80%EB%A6%B4-%EB%95%8C%EB%A7%88%EB%8B%A4-%EB%8B%A4%EC%8B%9C-%EA%B3%A0%EC%B9%98%EA%B8%B0-%EA%B7%80%EC%B0%AE%EC%95%84%EC%84%9C-%EB%82%98%EB%A7%8C%EC%9D%98-D-DAY-%EB%A9%94%EB%AA%A8-%EC%95%B1%EC%9D%84-%EB%A7%8C%EB%93%A4%EC%97%88%EB%8B%A4</guid>
            <pubDate>Fri, 20 Mar 2026 21:30:14 GMT</pubDate>
            <description><![CDATA[<p>해야 할 일을 적어두는 건 어렵지 않다.<br>문제는 그다음이었다.</p>
<p>“이번 주 안에 해야지” 하고 날짜까지 적어둔 일이 꼭 그 안에 끝나는 건 아니었다.<br>하루 밀리고, 이틀 밀리고, 그러다 보면 그 항목은 금방 지난 일정이 되어버린다.</p>
<p>그러면 또 날짜를 다시 고쳐야 한다.<br>한두 번이면 괜찮지만, 반복되면 점점 번거로워진다.</p>
<p>정작 해야 할 일은 그대로인데,<br>나는 앱에서 <strong>날짜 수정만 계속 하고 있었다.</strong></p>
<p>이게 생각보다 꽤 귀찮았다.</p>
<p>그래서 어느 순간 이런 생각을 했다.</p>
<p><strong>모든 메모에 억지로 날짜를 붙이지 말고,<br>평소 적어두는 메모와 날짜가 있는 일정만 분리해서 같이 다루면 되는 거 아닌가?</strong></p>
<p>이번 프로젝트는 그 생각에서 시작했다.</p>
<hr>
<h2 id="내가-원했던-건-예쁜-d-day-앱이-아니라-덜-귀찮은-정리-방식이었다">내가 원했던 건 “예쁜 D-DAY 앱”이 아니라, 덜 귀찮은 정리 방식이었다</h2>
<p>처음에는 그냥 감성 있는 D-DAY 메모 앱을 떠올렸다.<br>귀엽고, 가볍고, 휴대폰에서도 자주 열게 되는 그런 것.</p>
<p>그런데 만들다 보니 내가 정말 원했던 건 조금 달랐다.</p>
<p>내가 필요했던 건 이런 구조였다.</p>
<ul>
<li>날짜가 없는 평소 메모는 위에 계속 남아 있을 것</li>
<li>특정 날짜가 있는 일정은 따로 관리할 것</li>
<li>날짜가 된 일정은 그날 눈에 잘 띄게 올라올 것</li>
<li>일이 밀려도 전체 흐름이 덜 귀찮을 것</li>
</ul>
<p>그러니까 이건 흔한 기념일 앱이나 일정 앱이라기보다,<br><strong>메모와 일정 관리 사이 어딘가에 있는 도구</strong>에 가까웠다.</p>
<p>보통 메모 앱은 자유롭지만 날짜 흐름이 약하고,<br>할 일 앱은 날짜 관리는 되는데 자유 메모가 답답하다.</p>
<p>나는 그 중간이 필요했다.</p>
<hr>
<h2 id="그래서-제일-가벼운-방식으로-시작했다">그래서 제일 가벼운 방식으로 시작했다</h2>
<p>이 프로젝트를 처음부터 크게 만들 생각은 없었다.</p>
<p>로그인 붙이고, DB 만들고, 서버 세우고, 동기화까지 넣으면 물론 더 그럴듯해진다.<br>그런데 솔직히 말하면 이 프로젝트에는 그게 좀 과했다.<br>혼자 오래 쓰는 도구인데, 시작부터 무겁게 갈 이유가 없었다.</p>
<p>그래서 가장 단순한 방식으로 시작했다.</p>
<p><strong>단일 HTML 파일 + 바닐라 JavaScript + LocalStorage</strong></p>
<p>이 조합의 장점은 분명했다.</p>
<ul>
<li>만들기 빠르다</li>
<li>수정하기 쉽다</li>
<li>배포가 간단하다</li>
<li>개인용 도구로 쓰기에 충분하다</li>
</ul>
<p>생각보다 이런 조합이 주는 속도가 크다.<br>토이 프로젝트는 괜히 덩치를 키우는 순간 재미도 같이 사라진다.</p>
<p>처음 만든 버전은 솔직히 조금 투박했다.<br>그래도 필요한 로직은 이미 들어 있었다.</p>
<ul>
<li>메모 생성 / 수정 / 삭제</li>
<li>날짜 없는 메모와 날짜 있는 일정 분리</li>
<li>D-DAY 계산</li>
<li>오늘이 된 일정 상단 노출</li>
<li>로컬 저장</li>
</ul>
<p>한마디로 하면,<br><strong>예쁘진 않아도 쓸 수는 있는 상태</strong>였다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/bc92cbe0-bf22-4a3a-a00b-4ac867a757b7/image.jpeg" alt="모바일 메인 화면"></p>
<p>최종적으로는 이런 모바일 화면으로 정리했다. 날짜 없는 메모와 날짜 있는 일정을 함께 다루는 흐름이 이 화면에 담겨 있다.</p>
<hr>
<h2 id="그런데-쓸-수-있음과-계속-쓰고-싶음은-다르더라">그런데 “쓸 수 있음”과 “계속 쓰고 싶음”은 다르더라</h2>
<p>기능은 돌아갔다.<br>하지만 화면을 오래 보고 있으면 자꾸 마음에 걸렸다.</p>
<p>분명 필요한 건 다 들어 있는데,<br>완성된 도구라기보다는 <strong>만들다 만 실험작</strong>처럼 보였기 때문이다.</p>
<p>대표적으로 이런 문제가 있었다.</p>
<ul>
<li>모바일에서 쓰기엔 hover 중심 요소가 많았다</li>
<li>버튼 동작이 직관적이지 않은 곳이 있었다</li>
<li>귀여운 분위기를 내고 싶어 했지만 마감이 약했다</li>
<li>폰트와 여백, 위계가 전체적으로 정리되지 않았다</li>
<li>결과적으로 “제품”보다 “프로토타입”처럼 보였다</li>
</ul>
<p>딱 그 상태였다.<br>하려는 말은 알겠는데, 아직 설득력이 없는 화면.</p>
<p>그래서 한 번 크게 갈아엎었다.</p>
<hr>
<h2 id="한-번은-더-그럴듯하게-만들었는데-오히려-별로였다">한 번은 더 그럴듯하게 만들었는데, 오히려 별로였다</h2>
<p>중간에는 더 “제품처럼” 보이게 만들고 싶어서 구조를 크게 바꾼 적이 있었다.</p>
<ul>
<li>데스크톱 중심 보드</li>
<li>검색과 필터</li>
<li>카드 섹션</li>
<li>요약 패널</li>
<li>더 정돈된 UI 구조</li>
</ul>
<p>기술적으로는 분명 더 나아졌다.<br>코드 구조도 정리됐고, 화면도 커졌고, 겉보기에는 훨씬 그럴듯해졌다.</p>
<p>그런데 이상하게 손이 잘 안 갔다.</p>
<p>이유는 단순했다.<br>그 시점부터는 내가 처음 원했던 가볍고 직관적인 느낌보다,<br><strong>“잘 만든 것처럼 보이는 화면”</strong> 쪽으로 더 가고 있었기 때문이다.</p>
<p>그때 꽤 확실하게 느꼈다.</p>
<p><strong>새로 멋있게 만드는 것과, 실제로 쓰고 싶은 도구를 만드는 건 다르다.</strong></p>
<p>이 프로젝트에서 중요한 건 화려한 구조가 아니라,<br>내가 날짜를 덜 고치게 만드는 흐름이었다.</p>
<p>그래서 다시 방향을 틀었다.</p>
<hr>
<h2 id="복잡하게-키우는-대신-잘-맞던-흐름을-중심으로-다시-잡았다">복잡하게 키우는 대신, 잘 맞던 흐름을 중심으로 다시 잡았다</h2>
<p>결국 원점으로 돌아갔다.<br>정확히는, 처음 만든 핵심 흐름으로 돌아갔다.</p>
<ul>
<li>빠르게 적을 수 있어야 하고</li>
<li>날짜 없는 메모와 날짜 있는 일정이 자연스럽게 나뉘어야 하고</li>
<li>당일 일정은 눈에 띄어야 하고</li>
<li>밀린 일정도 다시 손보는 부담이 덜해야 한다</li>
</ul>
<p>그 기준으로 불필요한 걸 덜어냈다.</p>
<p>이 과정에서 크게 느낀 건 하나였다.</p>
<p><strong>새로 잘 만드는 것보다, 이미 잘 맞는 걸 정확히 살리는 게 더 어렵고 더 중요하다.</strong></p>
<hr>
<h2 id="웹과-모바일도-같은-화면으로-억지로-묶지-않았다">웹과 모바일도 같은 화면으로 억지로 묶지 않았다</h2>
<p>처음에는 웹과 모바일을 하나의 화면으로 다 해결하고 싶었다.<br>그게 더 효율적일 것 같았다.</p>
<p>그런데 실제로 써보니 웹에서 보기 좋은 화면과 휴대폰에서 자주 열어보는 화면은 분명히 달랐다.</p>
<p>그래서 역할을 나눴다.</p>
<ul>
<li><strong>모바일</strong>: 빠르게 추가하고, 바로 확인하는 흐름</li>
<li><strong>웹</strong>: 좀 더 넓게 보고, 길게 적고, 정리하는 흐름</li>
</ul>
<p>이렇게 분리하니까 훨씬 나아졌다.</p>
<p>괜히 하나의 화면으로 모든 걸 해결하려고 하면<br>결국 어디에서나 조금씩 어색해진다.<br>이 프로젝트는 그걸 꽤 분명하게 보여줬다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/e2e53461-3af6-4def-bd05-fe4e15c103ec/image.jpeg" alt="데스크톱 웹 보드"></p>
<p>모바일 원본을 유지한 채, PC에서는 더 넓게 입력하고 정리할 수 있도록 웹 보드를 따로 만들었다.</p>
<hr>
<h2 id="pwa로-끝날-줄-알았는데-생각보다-함정이-있었다">PWA로 끝날 줄 알았는데, 생각보다 함정이 있었다</h2>
<p>모바일에서도 앱처럼 쓰고 싶어서 처음에는 PWA로 만들었다.</p>
<p>브라우저에서 열고, 홈 화면에 추가해서, 아이콘을 눌러 바로 들어가는 흐름 자체는 꽤 괜찮았다.<br>겉으로 보기엔 거의 앱 같았다.</p>
<p>그런데 여기서 꽤 현실적인 문제를 만났다.</p>
<p><strong>브라우저에서 쓰던 LocalStorage 데이터가,<br>설치된 앱 화면에서 그대로 이어지지 않는 경우가 있었다.</strong></p>
<p>겉보기엔 같은 서비스인데,<br>실제로는 저장소 단위가 다르게 동작할 수 있었다.</p>
<p>이건 프론트엔드에서 한 번쯤 밟게 되는 문제인데,<br>직접 겪고 나니 더 선명하게 기억에 남았다.</p>
<p>그때 알게 됐다.</p>
<p>PWA는 분명 훌륭하지만,<br>내가 원한 건 “앱처럼 보이는 웹”이 아니라 <strong>진짜로 오래 쓰는 앱</strong>에 가까웠다.</p>
<hr>
<h2 id="자동-동기화-대신-내보내기가져오기로-정리했다">자동 동기화 대신, 내보내기/가져오기로 정리했다</h2>
<p>여기서 선택지가 있었다.</p>
<ol>
<li>백엔드 붙이고, DB 만들고, 로그인까지 넣어서 자동 동기화</li>
<li>지금 프로젝트에 맞는 수준으로 해결</li>
</ol>
<p>나는 두 번째를 골랐다.</p>
<p>이 프로젝트는 커질수록 장점이 죽는다.<br>그래서 자동 동기화 대신 <strong>내보내기 / 가져오기</strong> 기능을 넣었다.</p>
<p>로컬에 저장된 JSON 데이터를 내보내고,<br>다른 기기에서 다시 가져오는 방식이다.</p>
<p>흐름은 아주 단순하다.</p>
<ul>
<li>PC에서 메모 정리</li>
<li>데이터 내보내기</li>
<li>파일이나 메신저로 옮기기</li>
<li>모바일에서 가져오기</li>
</ul>
<p>완전 자동은 아니다.<br>하지만 이 프로젝트엔 그 정도가 오히려 잘 맞았다.</p>
<p>괜히 무거운 구조를 붙이지 않고도,<br>기기 간 이동은 충분히 가능해졌다.</p>
<p>개인용 도구는 가끔<br>“가장 멋진 해결책”보다 <strong>가장 덜 귀찮은 해결책</strong>이 더 좋다.</p>
<hr>
<h2 id="쓰다-보니-반복-일정도-필요했고-작은-디테일이-더-중요해졌다">쓰다 보니 반복 일정도 필요했고, 작은 디테일이 더 중요해졌다</h2>
<p>처음에는 메모와 날짜 관리 정도면 충분할 줄 알았다.<br>그런데 실제로 써보니 반복 일정도 은근 자주 필요했다.</p>
<p>예를 들면 생일처럼 매년 돌아오는 일정이나, 정기 미팅처럼 매주 반복되는 일정들.</p>
<p>그래서 반복 일정 처리도 넣고,<br>모바일에서는 날짜를 더 편하게 고를 수 있도록 다이얼 형태의 선택 UI도 만들었다.</p>
<p>여기서 또 하나 느낀 게 있다.</p>
<p><strong>완성도는 큰 기능에서 갈리지 않는다.<br>대부분은 작은 어색함에서 갈린다.</strong></p>
<p>날짜 다이얼도 그랬다.<br>몇 픽셀만 어긋나 있어도 바로 티가 났다.<br>선택 영역과 숫자 정렬이 미묘하게 안 맞으면 전체 앱이 허술해 보였다.</p>
<p>결국 마지막 손맛은 거창한 기능이 아니라,<br>이런 디테일에서 나온다.</p>
<hr>
<h2 id="나중에는-그냥-앱처럼-보이는-웹이-아니라-아예-안드로이드-앱으로도-만들었다">나중에는 그냥 “앱처럼 보이는 웹”이 아니라, 아예 안드로이드 앱으로도 만들었다</h2>
<p>처음에는 웹으로 충분할 줄 알았다.<br>그런데 계속 만지다 보니 자연스럽게 욕심이 생겼다.</p>
<p>“이왕 여기까지 왔는데,<br>그냥 설치형 앱으로도 써보면 어떨까?”</p>
<p>그래서 결국 안드로이드 APK까지 만들었다.</p>
<p>이때부터는 완전히 다른 문제가 열렸다.</p>
<ul>
<li>Android SDK 설치</li>
<li>빌드 도구 설정</li>
<li>JDK 버전 충돌</li>
<li>아이콘과 스플래시 정리</li>
<li>safe area 대응</li>
<li>시스템 바와 여백 처리</li>
</ul>
<p>웹에서는 그냥 넘어가던 것들이 앱에서는 바로 티가 났다.</p>
<p>특히 safe area 같은 건 정말 그랬다.<br>웹에선 괜찮아 보여도 앱에서는 상태바, 하단 제스처 영역을 무시하는 순간 바로 완성도가 떨어진다.</p>
<p>이 과정은 꽤 재밌었다.<br>처음엔 단순한 개인용 웹이었는데,<br>결국 앱으로까지 오면서 생각보다 많은 현실 문제를 직접 밟아봤다.</p>
<hr>
<h2 id="가장-현실적이었던-장애물은-의외로-환경이었다">가장 현실적이었던 장애물은 의외로 “환경”이었다</h2>
<p>앱으로 가면서 가장 크게 막혔던 건 로직보다 환경이었다.</p>
<p>Android SDK가 없어서 다시 설치해야 했고,<br>설치 경로는 문서와 실제 상태가 조금 달랐고,<br>빌드가 되나 싶더니 JDK 버전이 맞지 않아 또 막혔다.</p>
<p>사실 이런 부분은 글로 보면 한 줄인데,<br>직접 하다 보면 꽤 시간을 잡아먹는다.</p>
<p>그런데 신기하게도 이런 과정이 지나고 나면<br>프로젝트가 내 손에 더 익는 느낌이 있다.</p>
<p>기능을 만든다는 건 결국 코드만 짜는 일이 아니라,<br>그 기능이 돌아가는 환경까지 같이 이해하는 일이기도 하다는 걸 다시 느꼈다.</p>
<hr>
<h2 id="결국-이건-대단한-생산성-서비스가-아니다">결국 이건 “대단한 생산성 서비스”가 아니다</h2>
<p>돌아보면 이 프로젝트는 거창한 플랫폼이 아니다.</p>
<p>협업 기능도 없다.<br>계정 시스템도 없다.<br>복잡한 캘린더도 없다.<br>엄청난 자동화도 없다.</p>
<p>대신 이런 건 있다.</p>
<ul>
<li>평소 메모를 위에 붙여두는 흐름</li>
<li>날짜 있는 일정은 따로 관리하는 구조</li>
<li>일이 밀려도 덜 귀찮게 다루는 방식</li>
<li>필요할 만큼만 가볍게 만든 설계</li>
</ul>
<p>즉, 이건 시장을 뒤집을 서비스가 아니라<br><strong>내가 실제로 불편했던 걸 줄이기 위해 만든 도구</strong>다.</p>
<p>그런데 오히려 그래서 만족도가 높다.</p>
<p>큰 프로젝트를 만들 때는<br>멋있고 커 보이는 방향으로 자꾸 끌려가기 쉽다.<br>반면 이런 작은 도구는<br>불편 하나를 정확히 해결했는지가 훨씬 중요하다.</p>
<p>이 프로젝트는 그 점에서 꽤 솔직한 결과물이다.</p>
<hr>
<h2 id="이번에-다시-느낀-것들">이번에 다시 느낀 것들</h2>
<p>이번 작업을 하면서 다시 확인한 것들이 있다.</p>
<ul>
<li>예쁜 화면과 잘 쓰이는 화면은 다르다</li>
<li>새로 만드는 것보다, 잘 맞던 흐름을 살리는 게 더 낫다</li>
<li>반응형만 한다고 모바일 UX가 해결되진 않는다</li>
<li>PWA와 설치형 앱은 사용 기대치가 다르다</li>
<li>완성도는 기능 수보다 어색한 5px에서 갈린다</li>
<li>작은 개인 프로젝트일수록 기술보다 방향이 더 중요하다</li>
</ul>
<p>이런 건 직접 만들어보지 않으면 잘 안 남는다.<br>이번엔 꽤 오래 남을 것 같다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>처음에는 그냥<br>“내가 원하는 D-DAY 메모 앱 하나 만들어볼까?”<br>정도였다.</p>
<p>그런데 만들다 보니 생각보다 멀리 왔다.</p>
<p>웹으로 시작했고,<br>모바일 흐름을 다듬었고,<br>PWA의 한계를 밟았고,<br>내보내기/가져오기로 타협했고,<br>결국 안드로이드 앱까지 만들었다.</p>
<p>그 과정에서 제일 좋았던 건<br>큰 기술을 썼다는 사실이 아니라,<br><strong>내가 실제로 귀찮아하던 흐름을 직접 줄였다는 점</strong>이었다.</p>
<p>아마 앞으로도 이 앱은 완성형으로 끝나지 않을 거다.<br>필요할 때마다 조금씩 고치고,<br>내 습관에 맞게 바뀌고,<br>그러면서 계속 살아 있는 도구가 될 것 같다.</p>
<p>그 정도면 충분하다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/9633315f-1373-4c4a-a457-5e5b2961eba7/image.jpeg" alt="앱 다운로드 페이지"></p>
<p>최종적으로는 안드로이드 앱을 바로 내려받을 수 있는 다운로드 페이지까지 따로 붙였다.</p>
<hr>
<h2 id="링크">링크</h2>
<ul>
<li>웹 버전: <a href="https://my-dday-memo.vercel.app/web">https://my-dday-memo.vercel.app/web</a></li>
<li>모바일 버전: <a href="https://my-dday-memo.vercel.app/dday-v3.html">https://my-dday-memo.vercel.app/dday-v3.html</a></li>
<li>Android App 다운로드 페이지: <a href="https://my-dday-memo.vercel.app/app">https://my-dday-memo.vercel.app/app</a></li>
<li>GitHub: <a href="https://github.com/Lova-clover/My-Dday-Memo">https://github.com/Lova-clover/My-Dday-Memo</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[SiteGuard 개발기: URL 하나로 웹사이트 보안을 점검하는 도구를 만들며 배운 것]]></title>
            <link>https://velog.io/@lova-clover/SiteGuard-%EA%B0%9C%EB%B0%9C%EA%B8%B0-URL-%ED%95%98%EB%82%98%EB%A1%9C-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%B3%B4%EC%95%88%EC%9D%84-%EC%A0%90%EA%B2%80%ED%95%98%EB%8A%94-%EB%8F%84%EA%B5%AC%EB%A5%BC-%EB%A7%8C%EB%93%A4%EB%A9%B0-%EB%B0%B0%EC%9A%B4-%EA%B2%83</link>
            <guid>https://velog.io/@lova-clover/SiteGuard-%EA%B0%9C%EB%B0%9C%EA%B8%B0-URL-%ED%95%98%EB%82%98%EB%A1%9C-%EC%9B%B9%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%B3%B4%EC%95%88%EC%9D%84-%EC%A0%90%EA%B2%80%ED%95%98%EB%8A%94-%EB%8F%84%EA%B5%AC%EB%A5%BC-%EB%A7%8C%EB%93%A4%EB%A9%B0-%EB%B0%B0%EC%9A%B4-%EA%B2%83</guid>
            <pubDate>Thu, 19 Mar 2026 23:42:40 GMT</pubDate>
            <description><![CDATA[<h2 id="빠르게-만드는-시대일수록-기본-보안-점검이-더-중요해졌다">빠르게 만드는 시대일수록, 기본 보안 점검이 더 중요해졌다</h2>
<p>바이브코딩이 보편화되면서 서비스는 더 빨리 만들어지지만,<br>그만큼 기본 보안 설정을 충분히 점검하지 못한 채 배포되는 경우도 많아졌다고 느꼈다.</p>
<p>HTTPS는 제대로 강제되는지, 보안 헤더는 빠진 게 없는지, 쿠키 속성은 안전한지처럼<br>외부에서 바로 확인할 수 있는 항목들을 빠르게 점검해 보고 싶어서 <code>SiteGuard</code>를 만들었다.</p>
<ul>
<li>Demo: <a href="https://siteguard-mauve.vercel.app/">https://siteguard-mauve.vercel.app/</a></li>
<li>GitHub: <a href="https://github.com/Lova-clover/SiteGuard">https://github.com/Lova-clover/SiteGuard</a></li>
</ul>
<p>처음에는 비교적 단순하게 접근했다.<br>HTTPS가 되는지, 보안 헤더가 있는지, 쿠키 속성이 어떤지, TLS 인증서가 정상인지 정도를 읽어서 점수와 등급으로 보여주면 충분히 의미 있는 도구가 될 거라고 생각했다.</p>
<p>초기 버전은 겉으로 보기엔 꽤 괜찮았다.<br>점수도 나오고, 문제 목록도 정리됐고, UI도 어느 정도 형태를 갖췄다.</p>
<p>그런데 실제 사이트를 몇 개 넣어보면서 생각이 많이 바뀌었다.<br>기능이 돌아가는 것과 결과를 신뢰할 수 있는 것은 전혀 다른 문제였다.</p>
<p>이 글은 SiteGuard를 만들면서 겪은 시행착오와, 그 과정에서 정리하게 된 기준들에 대한 기록이다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/8df9f2f2-575c-4f7d-ab01-2a6b8598b758/image.png" alt="SiteGuard 메인 화면"></p>
<p>공개 URL 하나를 입력해 바로 보안 상태를 점검할 수 있도록 구성했다.</p>
<hr>
<h2 id="왜-이런-도구를-만들었나">왜 이런 도구를 만들었나</h2>
<p>요즘은 서비스를 정말 빠르게 만들 수 있다.</p>
<p>AI가 초안을 잡아주고, 배포도 쉬워졌고, 기능 구현 자체는 예전보다 훨씬 빨라졌다.<br>문제는 그런 속도와 별개로, 기본적인 보안 설정은 여전히 자주 빠진다는 점이다.</p>
<p>실제로 배포 직전이나 배포 직후에 자주 보이는 것들은 생각보다 단순하다.</p>
<ul>
<li>HTTP에서 HTTPS로 강제되지 않는 진입점</li>
<li>빠져 있는 HSTS, CSP, Referrer-Policy</li>
<li><code>Secure</code>, <code>HttpOnly</code>, <code>SameSite</code>가 빠진 쿠키</li>
<li>서버나 프레임워크 정보가 그대로 드러나는 응답 헤더</li>
<li>HTTPS 페이지 안에 남아 있는 HTTP 리소스</li>
</ul>
<p>이런 항목들은 적극적인 공격을 하지 않아도 외부에서 어느 정도 확인할 수 있다.<br>그래서 SiteGuard의 목표도 처음부터 명확했다.</p>
<p><strong>공개 URL 기준으로, 외부에서 보이는 기본 보안 상태를 빠르게 점검하는 것.</strong></p>
<p>이 프로젝트는 모든 취약점을 찾아내는 도구를 지향하지 않는다.<br>그보다는 배포 전에 한 번쯤 확인했어야 할 기본 설정들을 빠르게 훑어보는 1차 점검 도구에 가깝다.</p>
<hr>
<h2 id="처음엔-ui가-문제라고-생각했다">처음엔 UI가 문제라고 생각했다</h2>
<p>초기 결과 화면은 정보가 많았지만, 실제로 써보면 결론이 약했다.<br>점수와 카드, 설명은 많은데 사용자가 가장 먼저 궁금한 질문에 바로 답하지 못했다.</p>
<p>대부분 이런 것부터 알고 싶다.</p>
<ol>
<li>지금 위험한 상태인가  </li>
<li>무엇을 먼저 고쳐야 하나</li>
</ol>
<p>그런데 초기 버전은 설명은 길고, 행동 우선순위는 상대적으로 흐렸다.<br>그래서 결과 화면 구조를 다시 정리했다.</p>
<ul>
<li>현재 상태</li>
<li>지금 해야 할 일</li>
<li>상태 요약</li>
<li>문제 목록</li>
<li>세부 진단</li>
<li>근거</li>
</ul>
<p>이렇게 <code>판단 -&gt; 행동 -&gt; 근거</code> 순서로 바꾸고 나니 화면 자체는 훨씬 좋아졌다.</p>
<p>그런데 구조를 정리하고 보니 더 근본적인 문제가 눈에 들어왔다.<br>실제 문제는 UI보다 판정 로직 쪽에 더 가까웠다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/9d930cab-7737-473f-8bb3-103d3a4d31ed/image.png" alt="SiteGuard 결과 화면"></p>
<p>결과 화면은 점수보다 현재 상태, 우선순위, 문제 목록이 먼저 보이도록 다시 정리했다.</p>
<hr>
<h2 id="가장-큰-문제는-탐지가-아니라-해석이었다">가장 큰 문제는 탐지가 아니라 해석이었다</h2>
<p>초기 SiteGuard는 헤더, TLS, 리다이렉트, 쿠키, mixed content 같은 항목을 꽤 잘 잡았다.<br>발견 자체가 문제는 아니었다.</p>
<p>문제는 그 다음이었다.</p>
<p>예를 들어 다음 같은 항목들이 발견됐다고 해보자.</p>
<ul>
<li>CSP 없음</li>
<li>HSTS 없음</li>
<li>Referrer-Policy 없음</li>
<li>일부 쿠키 속성 부족</li>
<li>Permissions-Policy 없음</li>
</ul>
<p>초기 모델은 이런 항목들을 거의 비슷한 톤으로 다뤘다.<br>그러다 보니 결과가 쉽게 과해졌다.</p>
<p>실제로 테스트해 보면, 비교적 잘 운영되는 공개 사이트도 지나치게 낮은 점수와 높은 위험도로 나오는 경우가 있었다.<br>그 결과를 보고 나서야 이 프로젝트의 핵심 문제가 분명해졌다.</p>
<p>SiteGuard는 무언가를 발견하고 있었지만,<br>그 발견을 어떻게 해석해야 하는지가 아직 거칠었다.</p>
<p>보안 도구는 아무것도 못 찾는 것도 문제지만, 반대로 모든 걸 다 위험하다고 말해도 신뢰를 잃는다.<br>결과를 보는 사람이 “이 도구는 너무 과하게 말한다”고 느끼는 순간, 나머지 결과도 같이 의심받게 된다.</p>
<p>그때부터 SiteGuard의 중심 과제는 기능 추가가 아니라 <strong>리스크 모델을 다시 설계하는 것</strong>이 됐다.</p>
<hr>
<h2 id="모든-문제를-같은-톤으로-말하면-안-됐다">모든 문제를 같은 톤으로 말하면 안 됐다</h2>
<p>점수 모델을 손보면서 가장 먼저 한 일은, 발견 항목을 성격에 따라 나누는 일이었다.</p>
<p>크게 세 가지로 정리했다.</p>
<h3 id="1-직접-위험-direct">1. 직접 위험 (<code>direct</code>)</h3>
<p>실제 사용자나 브라우저 관점에서 직접적인 위험에 가까운 문제들이다.</p>
<p>예를 들면:</p>
<ul>
<li>만료된 TLS 인증서</li>
<li>self-signed 인증서</li>
<li>mixed content</li>
<li>안전하지 않은 로그인 폼 전송</li>
<li>credentials를 포함한 과도한 CORS 설정</li>
</ul>
<p>이런 건 단순한 권장 사항이 아니라, 실제 운영 상태에 직접 영향을 줄 수 있는 항목이다.</p>
<h3 id="2-하드닝-hardening">2. 하드닝 (<code>hardening</code>)</h3>
<p>서비스가 당장 깨지는 건 아니지만, 방어선이 충분하지 않은 상태다.</p>
<p>예를 들면:</p>
<ul>
<li>CSP 없음</li>
<li>HSTS 없음</li>
<li>클릭재킹 방어 없음</li>
<li><code>nosniff</code> 없음</li>
<li>Referrer-Policy 없음</li>
<li>일부 쿠키 속성 부족</li>
</ul>
<p>이건 분명 중요한 문제다.<br>다만 이 모든 항목을 똑같이 <code>High</code>처럼 처리하면 결과가 금방 과격해진다.</p>
<h3 id="3-운영-성숙도-maturity">3. 운영 성숙도 (<code>maturity</code>)</h3>
<p>즉시 위험이라기보다 운영 성숙도와 신뢰에 가까운 항목들이다.</p>
<p>예를 들면:</p>
<ul>
<li><code>security.txt</code> 없음</li>
<li>Permissions-Policy 없음</li>
<li>기술 스택 정보 노출</li>
</ul>
<p>이런 항목은 분명 의미가 있지만, 직접 위험과 같은 무게로 다루는 건 적절하지 않았다.</p>
<p>이 구분을 넣은 뒤부터 결과가 훨씬 덜 거칠어졌다.<br>사용자 입장에서도 “이건 지금 위험한 문제인지, 아니면 하드닝 차원에서 볼 문제인지”를 더 쉽게 받아들일 수 있게 됐다.</p>
<hr>
<h2 id="쿠키는-생각보다-더-문맥적으로-봐야-했다">쿠키는 생각보다 더 문맥적으로 봐야 했다</h2>
<p>초기에는 쿠키를 단순하게 봤다.<br><code>Secure</code>, <code>HttpOnly</code>, <code>SameSite</code> 중 하나라도 빠지면 크게 감점하는 방식이었다.</p>
<p>그런데 실제 서비스들을 보니 이 접근은 너무 단순했다.</p>
<p>모든 쿠키가 세션 쿠키는 아니고, 모든 쿠키가 같은 민감도를 갖는 것도 아니었다.<br>일부는 추적용이고, 일부는 실험용이며, 일부는 인증과 직접 관련 없는 상태 저장용일 수도 있다.</p>
<p>그래서 쿠키 쪽은 조금 더 문맥적으로 보기 시작했다.</p>
<ul>
<li><code>session</code>, <code>auth</code>, <code>jwt</code>, <code>token</code> 같은 민감한 이름 패턴이 있는가</li>
<li><code>__Host-</code>, <code>__Secure-</code> 같은 접두사가 있는가</li>
<li>빠진 속성이 실제로 직접 위험과 가까운가</li>
</ul>
<p>이 과정을 거치고 나니 쿠키 관련 결과가 훨씬 안정됐다.<br>예전처럼 “쿠키 속성 하나 부족 = 바로 high” 같은 식의 거친 결과는 많이 줄었다.</p>
<hr>
<h2 id="제일-어색했던-결과는-critical인데-c등급인-경우였다">제일 어색했던 결과는 Critical인데 C등급인 경우였다</h2>
<p>점수 모델을 만지면서 가장 먼저 손보고 싶었던 건 이런 결과였다.</p>
<ul>
<li>위험도: <code>Critical</code></li>
<li>점수: 70점대</li>
<li>등급: <code>C</code></li>
</ul>
<p>이건 보는 사람이 혼란스럽다.<br>정말 치명적인 직접 위험이 있다면, 점수와 등급도 거기에 맞게 낮아져야 한다.</p>
<p>그래서 마지막에는 점수 평균만으로 끝내지 않고, <strong>등급 가드레일</strong>을 넣었다.</p>
<p>예를 들면:</p>
<ul>
<li>직접적인 <code>critical</code> 위험이 있으면 점수 상한 제한</li>
<li>직접적인 <code>high</code> 위험이 있으면 등급 상한 제한</li>
<li>반대로 하드닝 위주의 문제는 지나치게 깎지 않음</li>
</ul>
<p>이 변화는 테스트용 사이트를 넣어보면 바로 차이가 났다.</p>
<p>예전에는 치명적인 TLS 문제를 가진 사이트도 점수상으로는 생각보다 높게 보일 수 있었는데,<br>지금은 적어도 <code>Critical</code>이면 결과도 그에 맞는 수준으로 정리된다.</p>
<p>결과를 보는 사람 입장에서는 이 일관성이 생각보다 중요하다.<br>보안 도구는 숫자 자체보다, 그 숫자와 설명이 서로 충돌하지 않는 것이 더 중요하다고 느꼈다.</p>
<hr>
<h2 id="실제-사례를-넣어-보면서-기준을-다시-잡았다">실제 사례를 넣어 보면서 기준을 다시 잡았다</h2>
<p>이 부분을 손볼 때 가장 도움이 된 건 <code>badssl.com</code> 계열 테스트 사이트였다.<br>막연하게 “이제 좀 나아진 것 같다”가 아니라, 어떤 결과가 나와야 자연스러운지를 실제 사례로 확인할 수 있었기 때문이다.</p>
<p>예를 들어 <code>mixed-script.badssl.com</code>은 mixed content가 핵심 문제인 사이트다.<br>이런 케이스는 결과가 높게 경고되는 게 맞다. 브라우저가 실제로 불러오는 리소스가 안전하지 않으면, 그건 단순 권장 사항이 아니라 직접적인 위험에 더 가깝다. 이 사이트가 <code>High</code>로 보이는 건 오히려 자연스러운 결과였다.</p>
<p>반대로 <code>expired.badssl.com</code>이나 <code>self-signed.badssl.com</code> 같은 사이트는 예전 결과가 더 어색했다.<br>인증서 문제는 공개 서비스 기준으로 꽤 치명적인 편인데, 한때는 위험도와 점수가 완전히 같은 방향으로 읽히지 않는 느낌이 있었다. 이 부분을 손본 뒤에는 적어도 “직접적인 치명 위험이 있으면 등급도 그에 맞게 충분히 낮아져야 한다”는 기준이 결과에 더 잘 반영되기 시작했다.</p>
<p>이 과정을 거치면서 점수 모델도 많이 바뀌었다.<br>예전에는 <code>http://</code> 문자열이 보이기만 해도 mixed content처럼 다루는 쪽에 가까웠다면, 나중에는 실제로 브라우저가 불러오는 서브리소스만 문제로 보도록 범위를 더 좁혔다. 단순 앵커 링크는 제외하고, <code>srcset</code>, <code>script src</code>, <code>stylesheet</code>처럼 실제 로드 경로를 더 정확히 확인하는 방식으로 바꿨다.</p>
<p>겉으로 보면 작은 수정처럼 보일 수 있다.<br>하지만 이런 차이가 결과 전체의 신뢰도에는 꽤 크게 작용했다. 결국 보안 도구에서 더 어려운 건 “더 많이 찾는 것”보다, 사용자가 무시하게 되는 소음을 줄이면서 <strong>실제로 의미 있는 신호를 남기는 것</strong>에 더 가깝다고 느꼈다.</p>
<hr>
<h2 id="siteguard가-할-수-있는-것과-할-수-없는-것">SiteGuard가 할 수 있는 것과 할 수 없는 것</h2>
<p>이 프로젝트를 하면서 끝까지 분명히 하고 싶었던 건, 이 도구의 범위였다.</p>
<p>SiteGuard는 URL 하나로 꽤 많은 걸 볼 수 있다.</p>
<ul>
<li>HTTPS</li>
<li>TLS</li>
<li>리다이렉트</li>
<li>보안 헤더</li>
<li>쿠키 속성</li>
<li>mixed content</li>
<li>외부 HTML/폼 신호</li>
<li><code>security.txt</code></li>
</ul>
<p>하지만 동시에 분명히 못 보는 것도 많다.</p>
<ul>
<li>로그인 뒤 권한 문제</li>
<li>SQL Injection</li>
<li>Stored XSS</li>
<li>IDOR</li>
<li>비즈니스 로직 취약점</li>
<li>내부 API 설계 문제</li>
<li>서버 내부 접근 제어</li>
</ul>
<p>이걸 명확히 하지 않으면 사용자는 이 도구를 “최종 보안 판정기”처럼 오해할 수 있다.</p>
<p>그래서 SiteGuard의 정체성은 결국 이렇게 정리됐다.</p>
<p><strong>공개 URL 기준의 빠른 외부 보안 진단 도구.</strong></p>
<p>모든 걸 하려고 하는 도구보다, 어디까지는 믿을 수 있는지 분명한 도구가 더 낫다고 생각한다.</p>
<hr>
<h2 id="이-프로젝트를-하며-가장-크게-배운-것">이 프로젝트를 하며 가장 크게 배운 것</h2>
<p>결국 이 프로젝트를 통해 가장 크게 배운 건 이것이었다.</p>
<p>좋은 보안 도구는 취약점을 많이 찾아내는 도구가 아니라,<br><strong>적절한 톤으로 위험을 설명하는 도구</strong>라는 점이다.</p>
<p>무엇을 발견했는가도 중요하다.<br>하지만 그보다 더 중요한 건:</p>
<ul>
<li>이게 실제로 위험한지</li>
<li>지금 당장 고쳐야 하는지</li>
<li>하드닝 차원에서 봐야 하는지</li>
<li>이 도구가 어디까지 볼 수 있는지</li>
</ul>
<p>를 일관되게 말하는 것이다.</p>
<p>처음의 SiteGuard는 솔직히 점수 계산기에 가까운 순간도 있었다.<br>하지만 여러 번 실제 사이트를 넣어보고, 결과를 의심하고, 모델을 엎고, 기준을 정리하면서<br>조금씩 “실제로 써볼 수 있는 도구” 쪽으로 움직였다.</p>
<p>완벽하다고 말하긴 어렵다.<br>다만 적어도 지금은 기능 구현 이상의 고민이 코드와 결과에 반영되기 시작했다고 생각한다.</p>
<hr>
<h2 id="마무리하며">마무리하며</h2>
<p>처음의 SiteGuard는 단순한 점수 계산기에 가까웠다.<br>하지만 실제 사이트를 테스트하고, 리스크 모델을 다시 정리하고, 결과를 계속 의심하면서 조금씩 “실제로 믿고 쓸 수 있는 도구” 쪽으로 바꿔왔다.</p>
<p>SiteGuard는 모든 보안 문제를 해결하는 도구는 아니다.<br>대신 공개 URL 기준으로, 지금 당장 놓치기 쉬운 기본 보안 상태를 빠르게 확인하는 용도로는 충분히 의미가 있다고 생각한다.</p>
<p>서비스를 빠르게 만드는 흐름은 앞으로도 계속 강해질 것이다.<br>그럴수록 배포 직전 한 번쯤은, 기능만 아니라 기본 보안 설정도 같이 확인하는 습관이 더 중요해진다고 느꼈다.</p>
<p>비슷한 고민을 하고 있다면 한 번쯤 직접 점검해 봐도 좋다.</p>
<blockquote>
<p>🛡️ <strong><a href="https://siteguard-mauve.vercel.app/">SiteGuard로 내 웹사이트 보안 점검하기</a></strong><br>💻 <strong><a href="https://github.com/Lova-clover/SiteGuard">GitHub에서 코드 확인 및 기여하기</a></strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTML로 웹페이지 홍보 영상을 만든다고? 직접 해보니 의외로 됐다]]></title>
            <link>https://velog.io/@lova-clover/HTML%EB%A1%9C-%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80-%ED%99%8D%EB%B3%B4-%EC%98%81%EC%83%81%EC%9D%84-%EB%A7%8C%EB%93%A0%EB%8B%A4%EA%B3%A0-%EC%A7%81%EC%A0%91-%ED%95%B4%EB%B3%B4%EB%8B%88-%EC%9D%98%EC%99%B8%EB%A1%9C-%EB%90%90%EB%8B%A4</link>
            <guid>https://velog.io/@lova-clover/HTML%EB%A1%9C-%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80-%ED%99%8D%EB%B3%B4-%EC%98%81%EC%83%81%EC%9D%84-%EB%A7%8C%EB%93%A0%EB%8B%A4%EA%B3%A0-%EC%A7%81%EC%A0%91-%ED%95%B4%EB%B3%B4%EB%8B%88-%EC%9D%98%EC%99%B8%EB%A1%9C-%EB%90%90%EB%8B%A4</guid>
            <pubDate>Mon, 16 Mar 2026 18:56:35 GMT</pubDate>
            <description><![CDATA[<p>처음엔 나도 좀 이상하게 들렸다.</p>
<p>웹페이지는 클릭하는 거고,
홍보 영상은 편집툴로 만드는 거 아닌가?</p>
<p>근데 어느 순간 생각이 바뀌었다.
계기는 단순했다.</p>
<p>어떤 분이 <strong>Claude로 홍보 영상을 만드는 걸 봤다.</strong>
솔직히 처음엔 “AI가 만든 영상이면 또 비슷비슷한 화면 몇 장 나오는 거 아니야?” 싶었다.
그런데 막상 결과를 보니 생각보다 꽤 괜찮았다.</p>
<p>그때 바로 이런 생각이 들었다.</p>
<blockquote>
<p>어? 이 정도면 나도 한번 해볼 만한데?</p>
</blockquote>
<p>그래서 나도 바로 해봤다.
이번에는 내가 만들고 있던 <strong>devhistory</strong>를 주제로, <strong>Codex</strong>로 짧은 홍보 영상을 만들어봤다.</p>
<p>그런데 첫 시도 결과는 기대보다 별로였다.</p>
<p>분위기 있는 화면은 나오는데,
정작 <strong>내 프로젝트 같지가 않았다.</strong></p>
<p>문장은 그럴싸했다.
배경도 그럴듯했다.
근데 그게 끝이었다.</p>
<p>딱 봐도 “어떤 SaaS 소개에도 갖다 붙일 수 있는 영상” 느낌이었다.
예쁘긴 한데, 비어 있었다.</p>
<p>그때 깨달았다.</p>
<p><strong>문제는 AI가 영상을 못 만드는 게 아니라, 내 프로젝트를 충분히 모르고 있다는 점</strong>이었다.</p>
<p>그래서 방법을 바꿨다.</p>
<p>말로만 설명하지 말고,
<strong>내가 실제로 만든 웹페이지 이미지를 넣어서 다시 만들어보자.</strong></p>
<p>이게 전환점이었다.</p>
<hr>
<h2 id="내가-만들어본-홍보-영상-devhistory">내가 만들어본 홍보 영상: devhistory</h2>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/cee0d943-37f4-4b65-a264-9b7bc401d0a5/image.gif" alt=""></p>
<p>이번에 만든 영상은 devhistory라는 프로젝트의 콘셉트를 짧게 보여주는 형태였다.</p>
<p>흐름은 대략 이랬다.</p>
<ul>
<li>개발 활동을 자동으로 머지하고</li>
<li>흩어진 기록을 한 번에 묶고</li>
<li>대시보드로 숫자와 흐름을 보여주고</li>
<li>AI가 글과 리포트 초안까지 밀어주고</li>
<li>마지막에는 활동 로그가 포트폴리오로 이어진다는 메시지로 닫는 구조</li>
</ul>
<p>중요한 건, 이걸 그냥 기능 목록처럼 나열하지 않았다는 점이다.</p>
<p>“이것도 됩니다, 저것도 됩니다” 식으로 가면
영상은 있어 보여도 머리에 남지 않는다.</p>
<p>대신 이번에는 이 흐름으로 밀어봤다.</p>
<p><strong>기록 수집 → 정리 → 분석 → 활용 → 포트폴리오</strong></p>
<p>이렇게 순서를 잡으니까
웹페이지는 그냥 정적인 결과물이 아니라,
<strong>설명력을 가진 장면의 묶음</strong>처럼 보이기 시작했다.</p>
<hr>
<h2 id="처음-시도는-왜-빈약했을까">처음 시도는 왜 빈약했을까</h2>
<p>이 부분이 제일 중요했다.</p>
<p>처음에는 그냥 AI에게
“이런 서비스 홍보 영상 만들어줘”에 가까운 식으로 접근했다.</p>
<p>그런데 이렇게 하면 생기는 문제가 명확했다.</p>
<p>AI는 분위기 있는 장면을 잘 만든다.
근데 <strong>내 서비스만의 화면, 내 서비스만의 구조, 내 서비스만의 리듬</strong>까지는 자동으로 만들어주지 않는다.</p>
<p>결과적으로 처음 시도는 이런 느낌이었다.</p>
<ul>
<li>예쁘긴 한데 어디선가 본 것 같고</li>
<li>서비스 설명 같긴 한데 내 프로젝트라고 느껴지지 않고</li>
<li>화면이 움직이긴 하는데 메시지가 정확히 꽂히지 않는 상태</li>
</ul>
<p>한마디로 정리하면 이거다.</p>
<p><strong>홍보 영상처럼 보이는데, 정작 홍보할 대상이 흐렸다.</strong></p>
<p>그래서 빈약하게 느껴졌던 거다.</p>
<hr>
<h2 id="아예-웹페이지-이미지를-넣자-결과가-달라졌다">아예 웹페이지 이미지를 넣자 결과가 달라졌다</h2>
<p>그다음부터는 접근을 바꿨다.</p>
<p>설명만 던지는 게 아니라
<strong>내가 만든 실제 웹페이지 이미지</strong>를 같이 넣었다.</p>
<p>landing 화면,
dashboard 느낌,
기록이 묶이는 구조,
포트폴리오 output 같은 것들 말이다.</p>
<p>그랬더니 결과가 확실히 달라졌다.</p>
<p>왜냐하면 AI가 더 이상
“추상적인 서비스 소개 영상”을 만드는 게 아니라,</p>
<p><strong>실제 존재하는 화면을 바탕으로 장면을 재구성하기 시작했기 때문</strong>이다.</p>
<p>이 차이는 꽤 컸다.</p>
<p>말만 넣었을 때는
누구에게나 적용 가능한 범용 결과물이 나왔다면,</p>
<p>웹페이지 이미지를 넣고 나서는
적어도 화면 자체는 <strong>내 프로젝트의 얼굴</strong>을 갖게 됐다.</p>
<p>이 순간부터 영상이 갑자기 그럴듯해졌다.</p>
<hr>
<h2 id="그래서-html로-홍보-영상을-만든다는-말이-완전히-틀린-건-아니다">그래서 “HTML로 홍보 영상을 만든다”는 말이 완전히 틀린 건 아니다</h2>
<p>물론 정확히 말하면
<strong>HTML만으로 영상 파일을 만든다</strong>는 뜻은 아니다.</p>
<p>더 정확하게 표현하면 이렇다.</p>
<p><strong>HTML/CSS/JS로 만든 웹페이지 화면을, 홍보 영상의 핵심 재료로 쓴다.</strong></p>
<p>이 관점으로 보면 말이 된다.</p>
<p>생각보다 많은 제품 소개 영상은 아래 요소들로 이뤄져 있다.</p>
<ul>
<li>큰 타이포 한 줄</li>
<li>카드 몇 개</li>
<li>버튼</li>
<li>차트나 수치</li>
<li>브라우저 목업</li>
<li>배경 그라데이션</li>
<li>살짝 들어오고 나가는 전환</li>
</ul>
<p>가만히 보면 이건 전부 웹이 잘하는 것들이다.</p>
<p>텍스트를 크게 보여주는 것,
카드를 정렬하는 것,
차트를 배치하는 것,
강조 색을 주는 것,
버튼과 배경으로 분위기를 만드는 것.</p>
<p>즉, 요즘 제품 소개 영상의 핵심이
영화 같은 카메라 워크보다 <strong>메시지가 잘 보이는 화면 구성</strong>에 있다면,</p>
<p>웹페이지는 이미 절반쯤 준비된 상태인 셈이다.</p>
<p>그래서 이번 작업을 하면서 든 생각은 이거였다.</p>
<p><strong>홍보 영상을 처음부터 새로 만드는 게 아니라,
이미 만든 웹페이지를 장면처럼 써먹는 쪽이 더 현실적이다.</strong></p>
<hr>
<h2 id="실제로-어떤-점이-홍보-영상-같다는-느낌을-만들었나">실제로 어떤 점이 “홍보 영상 같다”는 느낌을 만들었나</h2>
<p>이번에 만들어보면서 느낀 건,
생각보다 필요한 동작이 엄청 복잡하지 않다는 점이었다.</p>
<h3 id="1-장면이-나뉘어-있어야-한다">1. 장면이 나뉘어 있어야 한다</h3>
<p>페이지 하나를 길게 보여주는 건 영상이 아니다.
그건 그냥 스크롤 녹화에 가깝다.</p>
<p>홍보 영상처럼 보이려면
장면마다 역할이 분명해야 한다.</p>
<p>예를 들면 이런 식이다.</p>
<ul>
<li>첫 화면: “개발 활동을 자동으로 머지하세요”</li>
<li>다음 화면: GitHub / solved.ac / Velog 기록이 하나로 묶이는 구조</li>
<li>다음 화면: landing / dashboard</li>
<li>다음 화면: AI 초안 생성</li>
<li>다음 화면: 코딩 코치</li>
<li>마지막 화면: 포트폴리오 output + CTA</li>
</ul>
<p>이렇게 되면 각 장면이 <strong>한 문장, 한 메시지</strong>를 맡게 된다.
이게 영상 느낌을 만드는 첫 번째 조건이었다.</p>
<h3 id="2-실제-화면이-들어가야-설득력이-생긴다">2. 실제 화면이 들어가야 설득력이 생긴다</h3>
<p>이건 그냥 중요 정도가 아니라 거의 핵심이다.</p>
<p>실제 웹페이지 이미지가 들어가니까
영상이 공중에 붕 뜨지 않았다.</p>
<p>“이런 것도 할 수 있어요”가 아니라
“실제로 이런 화면으로 보일 거예요”에 가까워진다.</p>
<p>특히 SaaS, 대시보드형 서비스, 생산성 툴 같은 건
결국 사용자가 보게 되는 게 화면이다.</p>
<p>그러니까 홍보 영상에서도
실제 화면이 들어가는 순간 신뢰감이 확 올라간다.</p>
<h3 id="3-화려한-효과보다-타이밍이-더-중요했다">3. 화려한 효과보다 타이밍이 더 중요했다</h3>
<p>텍스트가 먼저 나오고,
그다음 카드가 따라오고,
마지막에 숫자나 버튼이 강조되면
그 자체로 메시지 순서가 생긴다.</p>
<p>실제로 자주 쓰게 되는 느낌은 대체로 비슷했다.</p>
<ul>
<li>fade in / fade out</li>
<li>살짝 들어오는 이동</li>
<li>확대/축소</li>
<li>blur가 줄어들면서 선명해지는 느낌</li>
<li>숫자 카운트업</li>
<li>카드가 순서대로 나타나는 흐름</li>
</ul>
<p>결국 영상 같아 보이게 만드는 건
엄청난 특수효과보다 <strong>리듬</strong>이었다.</p>
<h3 id="4-배경과-타이포가-분위기를-거의-다-먹는다">4. 배경과 타이포가 분위기를 거의 다 먹는다</h3>
<p>짙은 배경,
밝은 키 컬러,
큰 문장,
브라우저 프레임.</p>
<p>이 정도만 잘 잡아도 생각보다 금방 “요즘 제품 소개 영상” 느낌이 난다.</p>
<p>괜히 효과를 더 넣으려고 욕심내는 것보다
배경, 간격, 속도, 폰트 크기를 통일하는 쪽이 훨씬 중요했다.</p>
<hr>
<h2 id="devhistory-영상에서-특히-괜찮았던-부분">devhistory 영상에서 특히 괜찮았던 부분</h2>
<p>내가 이번 영상에서 제일 괜찮다고 느낀 건
기능이 많아 보이는 것보다 <strong>이해되는 순서가 살아 있었다는 점</strong>이다.</p>
<p>처음에는
“개발 활동을 자동으로 머지하세요”로 시작해서
무슨 문제를 풀려는 서비스인지 감을 주고,</p>
<p>그다음에는
GitHub, solved.ac, Velog 같은 기록이 하나로 묶이는 장면으로
왜 필요한지 설명하고,</p>
<p>이후에는
landing과 dashboard로 실제 그림을 보여주고,</p>
<p>그다음엔
AI가 글과 리포트 초안을 밀어주는 활용 장면으로 넘어가고,</p>
<p>마지막에는
포트폴리오 output으로 닫았다.</p>
<p>이 흐름이 괜찮았던 이유는 단순하다.</p>
<p>사람이 서비스를 이해하는 순서와 비슷했기 때문이다.</p>
<ul>
<li>왜 필요한지</li>
<li>무엇을 모으는지</li>
<li>어떻게 보이는지</li>
<li>어디까지 활용되는지</li>
<li>그래서 최종적으로 뭐가 남는지</li>
</ul>
<p>영상 길이가 짧아도
이 순서만 맞으면 생각보다 이해가 된다.</p>
<hr>
<h2 id="내가-보기엔-이-정도면-충분히-좋다">내가 보기엔 이 정도면 충분히 좋다</h2>
<p>여기서 괜히 목표를 잘못 잡으면 끝이 없다.</p>
<p>광고 스튜디오 수준의 결과물을 기준으로 잡으면
개인 프로젝트는 바로 지친다.
그건 애초에 싸움이 다르다.</p>
<p>대신 나는 이번 작업을 하면서
“이 정도면 충분히 좋다”의 기준을 이렇게 잡았다.</p>
<ul>
<li>첫 3초 안에 무슨 서비스인지 감이 온다</li>
<li>한 장면에 한 메시지만 남긴다</li>
<li>실제 화면이 보여서 소개가 공중에 뜨지 않는다</li>
<li>마지막까지 보면 제품을 한 문장으로 설명할 수 있다</li>
</ul>
<p>이 네 개가 되면 이미 꽤 괜찮다.</p>
<p>홍보 영상의 목적은
사람을 압도하는 게 아니라,
<strong>짧은 시간 안에 이해시키는 것</strong>이기 때문이다.</p>
<p>그 기준에서 보면
웹페이지 이미지를 기반으로 장면을 만들고,
AI로 리듬과 전환을 붙이고,
홍보 영상처럼 정리하는 방식은 꽤 실용적이다.</p>
<p>무엇보다 수정이 빠르다.</p>
<p>문구 바꾸기 쉽고,
장면 순서 갈아엎기 쉽고,
서비스가 업데이트되면 화면만 바꿔서 다시 시도할 수도 있다.</p>
<p>이건 생각보다 큰 장점이다.</p>
<hr>
<h2 id="물론-한계는-있다">물론 한계는 있다</h2>
<p>당연히 있다.</p>
<p>복잡한 3D 연출,
실사 기반 컷,
입체적인 카메라 무브 같은 건
이 방식만으로는 한계가 있다.</p>
<p>하지만 제품 소개, 기능 설명, landing teaser, 짧은 쇼츠류는 얘기가 다르다.
이쪽은 오히려 웹페이지 기반 접근이 더 잘 맞는다.</p>
<p>특히 서비스가 아직 배포 전이거나,
콘셉트를 먼저 보여주고 싶은 단계라면 더 그렇다.</p>
<p>실제 구현과 100% 같지 않아도
적어도 <strong>어떤 화면 경험을 줄지</strong>는 먼저 보여줄 수 있기 때문이다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>이번에 devhistory 홍보 영상을 만들면서 느낀 건 단순했다.</p>
<p>처음에는
남이 Claude로 만든 영상을 보고
“오, 생각보다 괜찮네?”에서 시작했다.</p>
<p>그래서 나도 Codex로 바로 해봤다.</p>
<p>그런데 첫 시도는 빈약했다.
그럴듯한데, 내 프로젝트 같지 않았다.</p>
<p>그래서 방법을 바꿨다.
말로만 설명하지 않고,
<strong>내가 만든 웹페이지 이미지를 넣었다.</strong></p>
<p>그랬더니 결과가 확실히 달라졌다.</p>
<p>이 경험을 하고 나니까
“HTML로 웹페이지 홍보 영상을 만든다고?”라는 말이
그렇게 이상하게 들리지 않았다.</p>
<p>정확히는
웹페이지를 그대로 영상으로 바꾼다기보다,</p>
<p><strong>웹페이지를 가장 강력한 재료로 삼아
홍보 영상의 문법으로 다시 보여주는 방식</strong>에 가깝다.</p>
<p>적어도 내가 보기엔
제품의 핵심 메시지를 짧고 선명하게 전달하는 용도라면
이 방식은 충분히 좋다고 본다.</p>
<p>결국 중요한 건 툴 이름이 아니다.</p>
<p>어떤 화면을 보여줄지,
무슨 문장을 남길지,
어디서 강조하고 어디서 멈출지를 정하는 일.</p>
<p>홍보 영상도 결국
효과 싸움보다 <strong>메시지 설계 싸움</strong>에 더 가까웠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[사라진 개발자의 메모만 남은 프로젝트를 복구해봤습니다: 긴급 인수인계 상황실 만들기]]></title>
            <link>https://velog.io/@lova-clover/%EC%82%AC%EB%9D%BC%EC%A7%84-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A7%8C-%EB%82%A8%EC%9D%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-%EB%B3%B5%EA%B5%AC%ED%95%B4%EB%B4%A4%EC%8A%B5%EB%8B%88%EB%8B%A4-%EA%B8%B4%EA%B8%89-%EC%9D%B8%EC%88%98%EC%9D%B8%EA%B3%84-%EC%83%81%ED%99%A9%EC%8B%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@lova-clover/%EC%82%AC%EB%9D%BC%EC%A7%84-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A7%8C-%EB%82%A8%EC%9D%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-%EB%B3%B5%EA%B5%AC%ED%95%B4%EB%B4%A4%EC%8A%B5%EB%8B%88%EB%8B%A4-%EA%B8%B4%EA%B8%89-%EC%9D%B8%EC%88%98%EC%9D%B8%EA%B3%84-%EC%83%81%ED%99%A9%EC%8B%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 16 Mar 2026 17:34:28 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요, Lova-clover입니다!</p>
<p>이번 해커톤에서 만든 <strong>긴급 인수인계 상황실</strong>은 아쉽게도 1차 투표에서 멈췄습니다.</p>
<p>결과는 아쉬웠지만, 이번 작업은 제게 꽤 분명한 질문을 남겼습니다. 문서가 거의 없는 상태에서 서비스를 다시 세울 때, 먼저 복구해야 하는 것은 무엇인가.</p>
<p>완성된 기획서도, 정리된 요구사항 문서도 없었습니다. 남아 있던 건 메모 한 장, 러프한 UI 플로우 한 장, 그리고 몇 개의 JSON 더미 데이터뿐이었습니다.</p>
<p>보통은 문서를 읽고 화면과 기능을 설계합니다. 그런데 이번 과제는 그 순서가 잘 통하지 않았습니다. 먼저 해야 했던 건 “무슨 화면을 만들 것인가”가 아니라, “원래 어떤 서비스였고 사용자는 어떤 순서로 움직여야 하는가”를 복원하는 일이었습니다.</p>
<p>그래서 이번 작업을 저는 단순한 화면 복원으로 보지 않았습니다. 누군가 급하게 자리를 비운 뒤 남겨진 흔적을 바탕으로, 실제로 사용할 수 있는 제품 경험을 다시 세우는 작업에 더 가깝다고 봤습니다. 그렇게 정리한 결과물이 바로 <strong>긴급 인수인계 상황실(Emergency Takeover Room)</strong> 입니다.</p>
<blockquote>
<p><strong>&quot;문서가 사라진 자리에서 먼저 복구해야 하는 것은 화면이 아니라 사용자 흐름이다.&quot;</strong></p>
</blockquote>
<p>(아래는 이번 해커톤에서 구현한 Emergency Takeover Room의 해커톤 탐색 화면입니다)</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/d0d6e20e-cc38-4e5d-8fc8-5d84f0b184e0/image.jpeg" alt=""></p>
<hr>
<h2 id="📌-한눈에-요약하는-emergency-takeover-room">📌 한눈에 요약하는 Emergency Takeover Room</h2>
<ul>
<li><strong>문제</strong>: 메모, 러프한 UI 플로우, JSON 데이터만 남아 있는 상태에서 서비스의 목적과 흐름을 다시 해석해야 했습니다.</li>
<li><strong>해결</strong>: 해커톤 탐색 → 상세 확인 → 팀 빌딩 → 제출 준비 → 랭킹 확인으로 이어지는 참가자 흐름을 하나의 웹 서비스로 재구성했습니다.</li>
<li><strong>결과</strong>: 서비스의 방향성과 컨셉은 분명하게 잡았지만, 결과적으로 1차 투표를 넘지는 못했습니다.</li>
<li><strong>구현 범위</strong>: 목록/검색/필터/북마크/비교, 상세 탭, 팀 캠프, 제출 초안 저장, 리더보드 흐름까지 브라우저 단에서 동작하도록 만들었습니다.</li>
<li><strong>기술 선택</strong>: Next.js 16, React 19, TypeScript, Tailwind CSS 4, Framer Motion 조합을 사용했고, 사용자 상태는 <code>localStorage</code>에 저장해 별도 서버 없이도 데모 가능한 구조를 택했습니다.</li>
<li><strong>배움</strong>: 자료가 적을수록 기능 수보다 정보 구조와 사용자 동선이 더 중요하며, 해커톤에서는 그것을 짧은 시간 안에 설득력 있게 전달하는 힘도 함께 필요하다는 점을 배웠습니다.</li>
</ul>
<hr>
<h2 id="1-이번-과제에서-먼저-해야-했던-일">1. 이번 과제에서 먼저 해야 했던 일</h2>
<p>처음에는 저도 이 과제를 “남겨진 화면을 복원하는 작업” 정도로 생각했습니다. 문제는 그다음입니다. 화면은 있어도, 그것이 어떤 흐름 안에서 연결되어야 하는지가 정리되지 않으면 서비스는 쉽게 산만해집니다.</p>
<p>이번 과제에서 중요한 것은 개별 화면이 아니라 맥락이었습니다. 사용자는 해커톤을 찾고, 정보를 비교하고, 팀을 구하고, 제출을 준비하고, 결과를 확인합니다. 저는 이 순서를 서비스 안에서 다시 이어 붙이는 것을 우선순위로 잡았습니다.</p>
<p>즉, 이번 작업의 출발점은 구현이 아니라 해석이었습니다. 메모와 UI 조각, JSON 데이터를 보고 “이 서비스는 누구를 위해 존재하는가”, “사용자는 어떤 순서로 움직이는가”를 먼저 정리했습니다.</p>
<hr>
<h2 id="2-어떤-서비스를-만들었나">2. 어떤 서비스를 만들었나</h2>
<p>제가 구현한 Emergency Takeover Room은 해커톤 참가자가 필요한 흐름을 한곳에 모아둔 웹 서비스입니다.</p>
<p>메인 화면에서는 현재 진행 중인 해커톤을 빠르게 파악할 수 있고, 목록 페이지에서는 검색과 필터를 통해 원하는 대회를 찾을 수 있습니다. 이후 상세 페이지에서는 개요, 일정, 평가, 팀, 제출, 리더보드 같은 정보를 탭 형태로 확인할 수 있습니다. 필요하다면 북마크하거나 다른 해커톤과 비교할 수도 있습니다.</p>
<p>여기서 끝내고 싶지는 않았습니다. 해커톤은 정보를 읽는 것만으로 마무리되지 않기 때문입니다. 팀이 없다면 팀 캠프 페이지로 이동해 팀을 찾거나 직접 생성할 수 있어야 하고, 제출 단계에서는 초안을 저장하며 준비 상태를 관리할 수 있어야 합니다.</p>
<p>이 지점이 중요했습니다. 이 서비스는 단순히 정보를 보여주는 사이트가 아니라, <strong>참가자가 실제로 다음 행동으로 이어갈 수 있도록 돕는 해커톤 운영·참가 지원 플랫폼</strong>을 목표로 했습니다.</p>
<hr>
<h2 id="3-왜-인수인계-상황실이라는-컨셉으로-풀었나">3. 왜 ‘인수인계 상황실’이라는 컨셉으로 풀었나</h2>
<p>이번 과제에서 가장 중요했던 건, 주어진 자료를 어떻게 해석할 것인가였습니다.</p>
<p>저는 단순히 JSON 데이터를 화면에 뿌리는 방식으로 가지 않았습니다. 오히려 이 프로젝트 자체를 “누군가 급하게 자리를 비운 뒤 남겨진 흔적을 따라 서비스를 복구하는 작업”으로 보고 싶었습니다. 그래서 앱 전체를 복구 중인 프로젝트, 운영 상황실, 사라진 개발자의 흔적을 추적하는 공간처럼 느껴지도록 구성했습니다.</p>
<p>메인 카피, 페이지 네이밍, 정보 구조, 시각 톤도 모두 이 컨셉에 맞춰 정리했습니다. 이렇게 기준을 먼저 잡아두니 기능을 추가하거나 덜어낼 때도 판단이 훨씬 쉬워졌습니다. 해커톤에서는 결국 무엇을 만들었는가만큼, 왜 이런 방식으로 풀어냈는가도 중요하다고 생각했습니다.</p>
<hr>
<h2 id="4-구현하면서-가장-신경-쓴-4가지">4. 구현하면서 가장 신경 쓴 4가지</h2>
<h3 id="4-1-해커톤-탐색-경험">4-1. 해커톤 탐색 경험</h3>
<p>가장 먼저 집중한 건 목록 페이지의 탐색 경험이었습니다.</p>
<p>정보량이 많아질수록 단순 카드 나열만으로는 한계가 분명합니다. 그래서 검색, 상태 필터, 정렬, 북마크, 비교 기능을 넣어 사용자가 자기 기준으로 대회를 고를 수 있도록 구성했습니다.</p>
<p>핵심은 “많이 보여주는 것”이 아니라 “선택할 수 있게 만드는 것”이었습니다.</p>
<h3 id="4-2-상세-페이지-구조">4-2. 상세 페이지 구조</h3>
<p>상세 페이지는 하나의 긴 문서처럼 늘어놓지 않았습니다. 개요, 평가, 일정, 팀, 제출, 리더보드 등으로 나누어 탭 기반으로 구성했습니다.</p>
<p>이렇게 하면 참가자는 지금 필요한 정보만 빠르게 확인할 수 있고, 전체 정보도 한 페이지 안에서 연결해서 볼 수 있습니다. 해커톤처럼 시간 압박이 큰 상황에서는 정보의 양보다 접근 방식이 더 중요하다고 봤습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/c08f3634-bcc3-4e0d-9d0e-87e56cffa57d/image.jpeg" alt=""></p>
<h3 id="4-3-팀-빌딩-흐름">4-3. 팀 빌딩 흐름</h3>
<p>또 하나 중요하게 본 건 팀 빌딩 흐름이었습니다.</p>
<p>해커톤은 결국 팀으로 움직이는 경우가 많기 때문에, 팀을 찾고 만들고 관리하는 경험이 자연스러워야 했습니다. 그래서 팀 캠프 페이지에서는 팀 생성, 모집 상태 관리, 목록 탐색이 가능하도록 구성했습니다. 또한 브라우저 환경만으로도 데모가 가능하도록 로컬 저장 기반 상호작용을 넣었습니다.</p>
<p>별도 서버 없이도 핵심 흐름이 끝까지 동작하도록 하는 것이 이번 과제에서는 더 현실적인 선택이었습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/b2803b77-3bdf-414a-9655-815e56bb107d/image.jpeg" alt=""></p>
<h3 id="4-4-제출-준비-경험">4-4. 제출 준비 경험</h3>
<p>제출 준비 기능도 단순한 입력 폼으로 끝내지 않았습니다.</p>
<p>사용자가 제출 초안을 저장하고 다시 이어서 작성할 수 있게 했고, 설명 충실도나 링크 유효성 같은 요소를 기준으로 초안 품질을 점검하는 피드백 경험도 함께 설계했습니다. 해커톤에서 가장 긴장되는 시점 중 하나가 제출 직전인 만큼, 이 구간에서 사용자가 조금이라도 덜 불안하도록 돕고 싶었습니다.</p>
<hr>
<h2 id="5-기술적으로는-어디까지-현실적으로-가져갔는가">5. 기술적으로는 어디까지 현실적으로 가져갔는가</h2>
<p>글이 결과만 과장되게 보이는 것을 경계하고자 합니다. 이번 프로젝트는 짧은 시간 안에 핵심 흐름을 설득력 있게 보여줘야 하는 해커톤 결과물이었고, 별도의 서버나 DB까지 무리해서 붙이기보다 브라우저 안에서 완결되는 사용자 경험을 만드는 데 집중했습니다.</p>
<p>기술 스택은 <strong>Next.js 16, React 19, TypeScript, Tailwind CSS 4, Framer Motion</strong> 조합으로 구성했습니다. 데이터는 정적 JSON으로 관리했고, 북마크, 비교 목록, 팀 생성, 제출 초안 같은 사용자 상태는 <code>localStorage</code>에 저장하도록 설계했습니다.</p>
<p>✅ 구현한 범위</p>
<ul>
<li>해커톤 목록, 검색, 상태 필터, 정렬, 북마크, 비교</li>
<li>개요/일정/평가/팀/제출/리더보드 탭 기반 상세 페이지</li>
<li>팀 캠프 페이지의 팀 생성, 모집 상태 관리, 목록 탐색</li>
<li>제출 초안 저장 및 간단한 품질 점검 흐름</li>
<li>누구나 바로 접속 가능한 Vercel 배포</li>
</ul>
<p>🚧 더 확장하고 싶은 부분</p>
<ul>
<li>팀 추천 로직의 정교화</li>
<li>제출 피드백 기준의 고도화</li>
<li>운영자용 관리 기능 추가</li>
</ul>
<p>배포는 Vercel을 사용했습니다. 외부 키나 복잡한 환경 설정 없이 바로 실행 가능한 점도 이번 프로젝트와 잘 맞았습니다.</p>
<hr>
<h2 id="6-1차-투표에서-멈춘-뒤-돌아본-점">6. 1차 투표에서 멈춘 뒤 돌아본 점</h2>
<p>결과적으로 이 프로젝트는 1차 투표를 넘지 못했습니다.</p>
<p>정확한 탈락 이유를 단정할 수는 없습니다. 다만 스스로 돌아보면 몇 가지 아쉬움은 분명했습니다.</p>
<p>첫째, 컨셉과 흐름은 정리했지만 <strong>첫인상에서 강하게 꽂히는 차별점</strong>을 더 전면에 내세우지는 못했습니다. 인수인계 상황실이라는 서사는 분명했지만, 투표 단계에서는 그것이 얼마나 강하게 기억에 남았는지를 더 고민했어야 했습니다.</p>
<p>둘째, 기능은 자연스럽게 이어지도록 설계했지만 <strong>왜 이 서비스가 지금 꼭 필요한가</strong>를 더 압축적으로 전달하는 데는 부족함이 있었습니다. 해커톤에서는 좋은 구조를 만드는 것만큼, 그 구조의 가치를 짧은 시간 안에 설득하는 일도 중요합니다.</p>
<p>셋째, 팀 추천, 제출 피드백, 운영 기능 같은 확장 포인트를 말로는 설명할 수 있었지만, <strong>실사용 장면이나 더 강한 증거</strong>로 보여주는 데는 한계가 있었습니다. 결국 해커톤에서는 아이디어와 구현, 그리고 전달력이 함께 맞물려야 합니다.</p>
<p>이번 결과를 통해 다시 확인한 건, 서비스가 잘 짜여 있다는 것과 투표 단계에서 강하게 설득된다는 것은 완전히 같은 문제가 아니라는 점이었습니다.</p>
<hr>
<h2 id="7-이번-프로젝트에서-얻은-가장-큰-배움">7. 이번 프로젝트에서 얻은 가장 큰 배움</h2>
<p>이번 작업을 하면서 가장 크게 느낀 건, <strong>적은 정보로 시작할수록 기능보다 먼저 정보 구조와 사용자 흐름을 정리해야 한다</strong>는 점이었습니다.</p>
<p>메모 한 장과 러프한 화면만 놓고 시작하면, 기능을 많이 붙이는 것보다 먼저 이 서비스가 누구를 위해 존재하는지, 사용자는 어떤 순서로 움직이는지, 어떤 지점에서 막히는지를 정리해야 합니다. 그 기준이 잡히지 않으면 화면은 늘어나도 서비스는 쉽게 산만해집니다.</p>
<p>또 하나는, 해커톤에서 경쟁력을 만드는 것이 단순한 구현량만은 아니라는 점입니다. 같은 데이터를 가지고도 어떤 컨셉으로 풀어낼지, 어떤 사용자 경험으로 연결할지, 무엇을 핵심 포인트로 보여줄지에 따라 결과물의 인상은 크게 달라집니다.</p>
<p>이번 프로젝트에서는 그 핵심을 “인수인계 상황실”이라는 서사와, 탐색-팀-제출-랭킹으로 이어지는 실제 사용 흐름에 두고 싶었습니다. 다만 다음에는 그것을 더 짧고 강하게 보여주는 방식까지 함께 고민해보려 합니다.</p>
<hr>
<h2 id="8-마무리">8. 마무리</h2>
<p>이번 프로젝트는 “사라진 개발자의 흔적을 복구한다”는 설정에서 출발했지만, 결과적으로는 단순한 복원이 아니라 하나의 제품을 다시 해석하는 작업에 가까웠습니다.</p>
<p>불완전한 문서, 제한된 데이터, 짧은 시간이라는 조건 안에서도 사용자가 실제로 움직일 수 있는 흐름을 만들고, 그 위에 컨셉과 몰입감을 얹는 과정은 생각보다 많은 것을 남겼습니다.</p>
<p>결과는 1차 투표 탈락이었지만, 이번 작업이 남긴 질문과 배움은 분명했습니다. 다음에는 더 좋은 구조를 만드는 것에서 한 걸음 더 나아가, 그 구조의 가치를 더 빠르고 강하게 증명하는 방향까지 가져가고 싶습니다.</p>
<p>긴 글 읽어주셔서 감사합니다.</p>
<h2 id="🔗-관련-링크">🔗 관련 링크</h2>
<ul>
<li><strong>Demo</strong>: <a href="https://emergency-takeover-hackathon.vercel.app/">https://emergency-takeover-hackathon.vercel.app/</a></li>
<li><strong>GitHub</strong>: <a href="https://github.com/Lova-clover/Emergency-Takeover-Hackathon">https://github.com/Lova-clover/Emergency-Takeover-Hackathon</a></li>
<li><strong>대회 링크</strong>: <a href="https://daker.ai/public/hackathons/monthly-hackathon-emergency-handover-docs">https://daker.ai/public/hackathons/monthly-hackathon-emergency-handover-docs</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[AITOP100 Campus 회고 — AI에게 정답을 묻지 않기로 했다]]></title>
            <link>https://velog.io/@lova-clover/AITOP100-Campus-%ED%9A%8C%EA%B3%A0-AI%EC%97%90%EA%B2%8C-%EC%A0%95%EB%8B%B5%EC%9D%84-%EB%AC%BB%EC%A7%80-%EC%95%8A%EA%B8%B0%EB%A1%9C-%ED%96%88%EB%8B%A4</link>
            <guid>https://velog.io/@lova-clover/AITOP100-Campus-%ED%9A%8C%EA%B3%A0-AI%EC%97%90%EA%B2%8C-%EC%A0%95%EB%8B%B5%EC%9D%84-%EB%AC%BB%EC%A7%80-%EC%95%8A%EA%B8%B0%EB%A1%9C-%ED%96%88%EB%8B%A4</guid>
            <pubDate>Mon, 16 Mar 2026 05:10:20 GMT</pubDate>
            <description><![CDATA[<h2 id="2026년-3월-14일-5문제를-풀며-만든-나만의-검증-루틴">2026년 3월 14일, 5문제를 풀며 만든 나만의 검증 루틴</h2>
<p>AITOP100 Campus 예선대회가 끝난 뒤 가장 먼저 한 일은 결과 확인이 아니라 폴더를 다시 여는 일이었다.
zip 파일 몇 개, 잘라둔 crop 이미지, 회전본, 타일, 임시 메모들.
처음에는 미완성의 흔적처럼 보였는데, 다시 보니 오히려 그 폴더가 내가 오늘 어떻게 문제를 풀었는지를 가장 정확하게 설명하고 있었다.</p>
<p>이번 AITOP100 Campus에서 내가 얻은 건 정답 몇 개가 아니라 습관 하나였다.
AI에게 바로 답을 묻는 대신, 문제를 나누고, 기준 자료를 정하고, 근거를 뽑고, 반례를 찾고, 마지막에 형식까지 다시 검수하는 습관.
돌아보면 이 대회는 “어떤 모델을 썼는가”보다 “AI를 어떤 순서로 배치했는가”가 더 중요했다.</p>
<p>이 글은 참가 후기가 아니다.
정확히는, 이번 대회에서 실제로 써먹었던 문제 해결 방식을 복기하는 작업 로그다.
나중에 비슷한 문제를 다시 만났을 때 꺼내볼 메모이기도 하고, AI를 정답 생성기로만 쓰고 있는 사람에게는 방향 전환의 힌트가 되었으면 하는 기록이기도 하다.</p>
<blockquote>
<p>AI를 잘 쓴다는 건 정답을 빨리 뽑는 능력이 아니라, 문제를 검증 가능한 단위로 바꾸는 능력이었다.</p>
</blockquote>
<h2 id="왜-이-대회가-좋았는가">왜 이 대회가 좋았는가?</h2>
<p>이번 대회가 좋았던 이유는 문제들이 한 가지 능력만 요구하지 않았기 때문이다.
어떤 문제는 이미지 해석처럼 보였고, 어떤 문제는 문서 추론에 가까웠고, 어떤 문제는 거의 QA나 리서치 업무에 가까웠다.
즉, 하나의 요령으로 밀어붙이면 무너지고, 문제마다 다른 접근을 설계해야 했다.</p>
<table>
<thead>
<tr>
<th>문제</th>
<th>자료 성격</th>
<th>핵심 난점</th>
<th>내가 먼저 한 일</th>
</tr>
</thead>
<tbody><tr>
<td><strong>1) 대화 속 상황 추론</strong></td>
<td>다수의 PDF + 대화 로그</td>
<td>정답 찾기 전에 전제 일치 확인</td>
<td>같은 시험, 같은 문항을 보고 있는지부터 확인했다</td>
</tr>
<tr>
<td><strong>2) 특정 작가 찾기</strong></td>
<td>대량의 작품 이미지 + 후보군</td>
<td>자유 추론이 아니라 후보 제한</td>
<td>후보군을 닫고, 가장 헷갈리는 후보끼리 비교했다</td>
</tr>
<tr>
<td><strong>3) 팀원 기여도 파악</strong></td>
<td>수십 장의 채팅 캡처 + 문서/계산식</td>
<td>인상평이 아니라 기록 기반 판단</td>
<td>역할, 약속, 산출물을 먼저 연결했다</td>
</tr>
<tr>
<td><strong>4) 웹사이트 오류 찾기</strong></td>
<td>Spec 문서 + 다수의 구현 파일</td>
<td>감상이 아니라 기준 대조</td>
<td>Spec을 먼저 읽고 비교 축을 세웠다</td>
</tr>
<tr>
<td><strong>5) 옛 신문 해석</strong></td>
<td>옛 신문 이미지, 국한문 혼용</td>
<td>텍스트 추출 이전에 레이아웃 파악</td>
<td>면과 영역을 먼저 나눴다</td>
</tr>
</tbody></table>
<p>표로 놓고 보니 더 선명해졌다.
AI를 잘 쓰는 사람은 질문을 화려하게 던지는 사람이 아니라, 문제를 AI가 다룰 수 있는 단위로 다시 나누는 사람이라는 점이었다.</p>
<h2 id="내가-끝까지-붙잡은-루틴-분할-기준-반박-검수">내가 끝까지 붙잡은 루틴: 분할-기준-반박-검수</h2>
<p>이번 대회에서 끝까지 살아남게 해준 건 화려한 프롬프트가 아니라 하나의 루틴이었다.</p>
<ol>
<li>문제를 한 번에 풀지 않고 먼저 나눈다.</li>
<li>어떤 자료가 기준인지 먼저 정한다.</li>
<li>AI에게 정답이 아니라 근거를 뽑게 한다.</li>
<li>내가 1차 판단을 내린다.</li>
<li>AI에게 이 답이 왜 틀릴 수 있는지 반박하게 한다.</li>
<li>마지막에 숫자, 표기, 파일명, 형식을 다시 검수한다.</li>
</ol>
<p>이 순서는 생각보다 중요했다.
처음부터 “답이 뭐야?”라고 묻는 순간 사고의 주도권이 AI 쪽으로 넘어간다.
그러면 근거보다 그럴듯함을 따라가게 된다.</p>
<p>반대로 문제를 잘게 나누고, 기준 자료를 먼저 세우고, 근거를 분리해 놓으면 AI의 역할이 바뀐다.
그때부터 AI는 정답 생성기보다 훨씬 좋은 <strong>정리자, 근거 추출기, 반박자, 검수자</strong>가 된다.</p>
<h2 id="문제별로-돌아보면-더-명확해진다">문제별로 돌아보면 더 명확해진다</h2>
<h3 id="1-대화-속-상황-추론--답보다-먼저-전제를-맞췄다">1) 대화 속 상황 추론 — 답보다 먼저 전제를 맞췄다</h3>
<p>이 문제는 시험 문제를 푸는 문제가 아니었다.
대화 속 단서들을 해석해서, 두 사람이 정확히 어떤 시험지와 어떤 문항을 보고 있는지 역으로 추적하는 문제에 가까웠다.</p>
<p>그래서 내가 가장 먼저 확인한 건 정답이 아니라 전제였다.
같은 과목인지, 공통 과목인지 선택 과목인지, 문제지 유형이 엇갈린 건 아닌지부터 봤다.
이걸 건너뛰고 바로 정답으로 들어가면, 애초에 서로 다른 시험지를 보고 있는데도 같은 문제라고 착각하게 된다.</p>
<p>예를 들어 두 사람이 특정 개념이 들어간 선지를 똑같이 기억하는데 정답 번호가 다르면, 바로 “누가 틀렸지?”로 가면 안 된다.
먼저 선지 내용이 같은데 배열만 다른 건지부터 확인해야 한다. 대화 속에서 특정 단어를 언급하더라도, 선택 과목 세팅이 다르면 전혀 다른 문항일 수 있다.</p>
<p>이 파트에서 배운 건 명확했다.
번호보다 내용이 먼저이고, 내용보다도 전제가 먼저다.
전제가 틀리면 AI가 아무리 열심히 답을 내놔도, 결국 다른 시험지를 보고 푸는 셈이다.</p>
<h3 id="2-특정-작가-찾기--맞히는-문제가-아니라-지워나가는-문제였다">2) 특정 작가 찾기 — 맞히는 문제가 아니라 지워나가는 문제였다</h3>
<p>처음 보면 AI가 잘할 것처럼 보이는 문제였다.
이미지를 보고 작가를 맞히는 건 멀티모달 모델의 장기처럼 느껴지기 때문이다.
그런데 실제로는 오히려 더 조심해야 했다.</p>
<p>이번 자료는 대량의 작품 이미지에 다수의 정답 후보 작가군이 매핑되어 있었다. 여기에 별도의 작품 목록과 소장처 데이터까지 주어졌다.
즉, 이건 감상 문제가 아니라 <strong>후보 제한형 분류 문제</strong>였다.</p>
<p>여기서 제일 먼저 한 일은 문제를 다시 정의하는 것이었다.
“이 그림 누구 작품이지?”라고 묻는 순간 문제가 너무 넓어진다.
대신 “주어진 후보 중 누구일 가능성이 가장 높은가?”라고 바꾸면 그때부터는 비교 가능한 문제가 된다.</p>
<p>이 차이는 꽤 크다.
AI를 자유응답으로 풀어놓으면 후보 리스트에 없는 화풍이 비슷한 다른 작가를 너무 자연스럽게 섞어버린다.
반대로 후보를 닫아두면 정확도는 눈에 띄게 올라간다.</p>
<p>그래서 나는 먼저 시대감, 지역, 주제, 색감 등 넓은 특징을 잡고 후보를 5개 정도로 줄였다.
마지막에는 가장 헷갈리는 후보 둘이나 셋을 세워서 차이를 비교한 뒤에야 최종 답을 골랐다. “특정 화가 같아 보인다” 수준의 감상이 제일 위험했다.</p>
<p>이 문제가 남긴 교훈도 단순하다.
후보가 있는 문제에서 자유응답은 종종 함정이다.
AI를 잘 쓰는 방법은 더 자유롭게 묻게 하는 게 아니라, 오히려 더 정확하게 닫아주는 데 있다.</p>
<h3 id="3-팀원-기여도-파악--사람을-본-게-아니라-기록을-읽었다">3) 팀원 기여도 파악 — 사람을 본 게 아니라 기록을 읽었다</h3>
<p>이 문제는 현실적이라서 더 어려웠다.
자료 안에는 수십 장의 메신저 캡처, 문서, 엑셀, 발표 자료가 뒤섞여 있었고, 별도의 기여도 산출 공식과 가중치까지 주어졌다.
이 문제는 “누가 왠지 덜 열심히 한 것 같은가”를 묻는 게 아니라, <strong>누가 실제로 어떤 흔적을 남겼는가</strong>를 보는 문제였다.</p>
<p>여기서 제일 위험한 건 인상평이었다.
채팅에서 말이 많다고 기여도가 높은 것도 아니고, 중간에 미안하다고 했다고 자동으로 덜 기여한 사람이 되는 것도 아니다.
반대로 말이 적어도 자기 역할이 최종 산출물에 남아 있으면 충분히 기여한 것이다.</p>
<p>그래서 이 파트에서는 사람을 판단하려고 하지 않고, 기록을 읽는다는 느낌으로 갔다.
초기 역할 분담이 무엇이었는지,
중간에 실제로 공유된 자료가 있었는지,
최종 발표본에 그 사람의 흔적이 반영됐는지,
누군가 맡은 일을 다른 팀원이 대신한 정황은 없는지,
이 네 가지를 계속 연결했다.</p>
<p>AI도 여기서는 꽤 쓸 만했다.
하지만 “누가 제일 못했는지 말해줘”는 형편없는 질문이었다.
대신 “인원별 초기 역할과 실제 산출물을 나란히 정리해줘”, “특정 파트 반영 여부를 추적해줘”, “약속만 있고 결과물이 없는 구간을 표시해줘” 같은 요청이 훨씬 정확했다.</p>
<p>사람을 판단하는 문제일수록 감정에서 내려와 기록으로 가야 한다. 그게 더 정확하고, 더 공정하다.</p>
<h3 id="4-웹사이트-오류-찾기--구현보다-먼저-기준-문서를-세웠다">4) 웹사이트 오류 찾기 — 구현보다 먼저 기준 문서를 세웠다</h3>
<p>웹사이트 버그 찾기는 겉으로 보면 사이트를 훑어보며 이상한 점을 찾는 문제 같지만, 실제로는 그보다 훨씬 구조적인 문제였다.</p>
<p>자료를 열어보면 수십 페이지짜리 Spec 문서가 있고, 구현물은 다수의 HTML, 이미지, CSS, JS 등으로 구성되어 있었다.
이 정도면 눈대중으로 몇 페이지 눌러보는 감각만으로는 아무것도 확신할 수 없다. 중요한 건 탐색이 아니라 비교였다.</p>
<p>그래서 나는 코드를 열어보기 전에 Spec 문서를 먼저 꼼꼼히 읽었다.
페이지 구조가 어떻게 되는지,
한국어와 영어가 어떤 식으로 대응되는지,
공통 헤더와 푸터 규칙이 무엇인지,
먼저 비교 축을 세운 뒤에야 실제 구현 파일들을 뜯어보기 시작했다.</p>
<p>이 문제에서 AI도 역할이 분명했다.
“사이트 전반적으로 어때?”라고 물으면 아무 가치가 없는 답변이 돌아왔다.
대신 비교표를 만들게 하면 강해졌다.
설계서 기준 페이지 수와 실제 파일 수 비교,
공통 컴포넌트 규칙과 구현 방식 비교,
문구·숫자·링크 일치 여부 확인.
이런 식으로 축을 정해서 맡길 때 훨씬 안정적이었다.</p>
<p>이 파트에서 남은 한 줄은 이거다.
복잡한 구현물을 확인할 때 AI는 대신 읽고 판단해 주는 존재가 아니다.
<strong>명확한 기준을 세워줬을 때 강해지는 검수 보조 도구</strong>다.</p>
<h3 id="5-옛-신문-해석--글자를-읽기-전에-먼저-지면을-나눴다">5) 옛 신문 해석 — 글자를 읽기 전에 먼저 지면을 나눴다</h3>
<p>옛 신문 자료는 보자마자 감이 왔다. 이건 전체를 한 번에 읽으려 들면 사람도 AI도 같이 무너질 문제였다.</p>
<p>실제로 내가 다룬 이미지는 한 장 안에 옛 신문 여러 면이 붙어 있었다.
세로 조판, 국한문 혼용, 작은 활자, 광고와 기사가 뒤섞인 구획.
이건 단순 텍스트 추출 문제가 아니라 거의 레이아웃 해석 문제였다.</p>
<p>그래서 나는 이 자료를 텍스트로 보지 않고 먼저 지면으로 봤다.
제호가 있는 곳, 큰 제목이 있는 곳, 광고가 몰린 곳, 특정 기사 후보가 있을 만한 영역을 먼저 나눴다.
그다음에야 잘라서 확대하고, 회전하고, 다시 더 작은 단위로 쪼개기 시작했다.</p>
<p>대회가 끝난 뒤 폴더를 보니 자잘하게 잘라둔 수십 개의 이미지 타일 파일들이 남아 있었다.
처음엔 좀 지저분해 보였다.
그런데 다시 보니 그게 바로 내가 이 문제를 풀었던 방식이었다.
전체를 한 번에 이해하려고 한 게 아니라, 읽을 수 있는 단위로 계속 바꿔가며 접근한 것이다.</p>
<p>이 문제를 하며 가장 크게 느낀 건 아주 분명했다.
어려운 분석 문제에서는 더 똑똑한 모델을 찾는 것보다, 모델이 잘 읽을 수 있게 입력을 정리해 주는 과정이 먼저다.
입력이 흐리면 AI는 똑똑하게 틀린다. 반대로 입력을 정리해주면 생각보다 훨씬 잘 도와준다.</p>
<h2 id="이번에-오래-남을-프롬프트-4개">이번에 오래 남을 프롬프트 4개</h2>
<p>이번 대회를 지나며 다시 확인했다.
프롬프트는 화려한 문장이 아니라 <strong>역할이 분명한 템플릿</strong>이 강하다.
아래 네 개는 앞으로도 계속 쓸 것 같다.</p>
<h3 id="1-근거-먼저-뽑는-프롬프트">1) 근거 먼저 뽑는 프롬프트</h3>
<p>결론보다 근거 분리가 먼저 필요한 이미지/문서 자료에서 썼다.</p>
<pre><code class="language-text">지금부터 정답을 바로 말하지 말고, 먼저 근거만 정리해줘.

출력 형식:
1) 관찰된 사실
2) 아직 확실하지 않은 추정
3) 추가로 확인해야 할 포인트

중요:
- 보이는 것과 추정을 섞지 마라
- 숫자, 이름, 파일명, 섹션명은 정확히 적어라
- 아직 정답을 단정하지 마라
</code></pre>
<h3 id="2-후보-제한형-분류-프롬프트">2) 후보 제한형 분류 프롬프트</h3>
<p>AI를 자유롭게 풀어놓는 것보다, 후보를 닫고 비교하게 할 때 훨씬 안정적이었다.</p>
<pre><code class="language-text">제공된 후보 리스트 안에서만 답하라.

단계:
1) 자료의 특징을 요약
2) 후보 5개로 축소
3) 최종 1개 선택
4) 가장 헷갈리는 후보 2개와 이유 제시

중요:
- 후보 리스트 밖 이름 금지
- 확신도 표시
- 정확한 표기 유지
</code></pre>
<h3 id="3-기준-구현-비교-프롬프트">3) 기준-구현 비교 프롬프트</h3>
<p>AI에게 감상을 맡기면 흔들리고, 확실한 비교표를 맡기면 강해졌다.</p>
<pre><code class="language-text">기준 문서(spec)와 구현물(actual)을 비교해줘.

출력 형식:
- 비교 항목
- 기준 문서 내용
- 실제 구현 내용
- 일치/불일치
- 근거가 된 파일명 또는 섹션명

중요:
- 추측하지 마라
- 숫자, 링크, 파일명은 원문 그대로 적어라
- &quot;전반적으로 괜찮다&quot; 같은 평가는 금지
- 한 항목씩 끊어서 써라
</code></pre>
<h3 id="4-반박용-프롬프트">4) 반박용 프롬프트</h3>
<p>정답을 만드는 능력도 중요하지만, 오답 가능성을 줄이는 루틴이 실전에서는 더 강했다.</p>
<pre><code class="language-text">내가 고른 답이 틀릴 수 있는 이유를 최대 5개 적어줘.
그리고 각 이유마다 다시 확인해야 할 자료를 지정해줘.

출력 형식:
- 반박 포인트
- 왜 위험한지
- 재검증할 자료
- 재검증 후 유지/수정 판단
</code></pre>
<h2 id="이번-대회가-나에게-남긴-것">이번 대회가 나에게 남긴 것</h2>
<p>이번 AITOP100 Campus는 단순히 몇 문제를 푼 경험이 아니었다.
AI를 실전적으로 다루는 방식을 조금 더 선명하게 만든 경험이었다.</p>
<p>이번 대회에서 나는 AI를 정답을 대신 내주는 마법 상자로 쓰지 않으려고 했다.
오히려 방대한 자료를 읽을 때 옆에서 정리해주고, 내가 놓친 지점을 다시 찔러주고, 마지막에 교차 확인을 해주는 보조 파트너처럼 두려고 했다.
이번에는 그 방식이 분명히 더 잘 맞았다.</p>
<p>그리고 이 감각은 대회에서만 끝나지 않는다.
문서 정리, 웹 QA, 코드 리뷰, 포트폴리오 작성, 팀 프로젝트 회고까지 그대로 이어질 것 같다.
결국 중요한 건 AI를 얼마나 화려하게 쓰느냐가 아니다. 내가 직면한 문제를 얼마나 잘 나누고, 기준을 세우고, 검증 가능한 형태로 바꾸느냐가 더 중요하다.</p>
<p>대회가 끝나고 폴더 안에는 중간 산출물이 많이 남아 있었다.
crop 파일, 회전본, 타일, 확인용 메모, 임시 이미지들.
처음에는 그게 미완성의 흔적처럼 보였다.
지금은 다르게 본다.
그건 실패의 잔해가 아니라 치열하게 사고했던 과정의 로그였다.</p>
<p>나는 이제 AI에게 바로 정답을 묻지 않는다.
대신 근거를 묻고, 반례를 묻고, 다시 확인할 지점을 묻는다.
이번 AITOP100 Campus에서 얻은 건 몇 개의 정답보다 오래 가는 습관이었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GitHub Pages를 나만의 자기소개 페이지로 개편했습니다]]></title>
            <link>https://velog.io/@lova-clover/GitHub-Pages%EB%A5%BC-%EB%82%98%EB%A7%8C%EC%9D%98-%EC%9E%90%EA%B8%B0%EC%86%8C%EA%B0%9C-%ED%8E%98%EC%9D%B4%EC%A7%80%EB%A1%9C-%EA%B0%9C%ED%8E%B8%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@lova-clover/GitHub-Pages%EB%A5%BC-%EB%82%98%EB%A7%8C%EC%9D%98-%EC%9E%90%EA%B8%B0%EC%86%8C%EA%B0%9C-%ED%8E%98%EC%9D%B4%EC%A7%80%EB%A1%9C-%EA%B0%9C%ED%8E%B8%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Mon, 16 Mar 2026 04:30:56 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며</h2>
<p>프로젝트는 계속 쌓였지만, 정작 저를 설명하는 화면은 그 속도를 따라오지 못했습니다.</p>
<p>GitHub 프로필 상단 배너는 무난했고, github.io도 “일단 만들어 둔 기본 소개 페이지”에 가까웠습니다. 보기에는 깔끔했지만, 처음 들어온 사람이 몇 초 안에 저를 이해하기에는 부족했습니다.</p>
<p>포트폴리오 페이지라면 적어도 아래 세 가지는 빠르게 보여야 한다고 봤습니다.</p>
<ul>
<li>어떤 분야에 관심이 있는지</li>
<li>어떤 프로젝트를 만들어왔는지</li>
<li>어떤 방식으로 기록하고 성장하는지</li>
</ul>
<p>기존 페이지는 이 질문에 충분히 답하지 못했습니다.<br>그래서 이번에는 단순히 디자인만 손보는 데서 멈추지 않고, GitHub 프로필과 github.io를 함께 정리해 <strong>저를 설명할 수 있는 포트폴리오형 자기소개 페이지</strong>로 다시 구성했습니다.</p>
<p>특히 GitHub 프로필 상단 배너는 기존의 무난한 소개 이미지를 대신해, 제가 계속 써오던 오리 캐릭터를 바탕으로 <strong>손그림 느낌의 리브랜딩된 배너</strong>로 바꾸며 첫인상 자체를 다시 설계했습니다.</p>
<hr>
<h2 id="왜-개편했는가">왜 개편했는가</h2>
<p>기존 페이지의 문제는 완성도가 아니라 <strong>설명력</strong>이었습니다.</p>
<p>화면이 지저분한 것은 아니었습니다.<br>다만 “그래서 이 사람은 어떤 개발자인데?”라는 질문에 바로 답하지 못했습니다.<br>섹션은 있었지만 흐름이 약했고, 정보는 있었지만 인상이 남지 않았습니다.</p>
<p>포트폴리오에서 중요한 건<br>“정리되어 보이는가”보다 <strong>“이 사람이 보이는가”</strong>라고 생각합니다.</p>
<p>특히 아직 배우고, 만들고, 기록하는 단계라면<br>대단해 보이게 포장하는 것보다<br>관심사와 대표 작업, 기록 방식이 또렷하게 보이는 편이 훨씬 설득력 있습니다.</p>
<p>이번 개편도 그 기준에서 출발했습니다.</p>
<p><strong>예쁜 페이지를 만드는 것보다,<br>저를 더 빠르게 이해할 수 있는 페이지를 만드는 것.</strong><br>그게 이번 작업의 핵심이었습니다.</p>
<hr>
<h2 id="이번에-바꾼-것">이번에 바꾼 것</h2>
<h3 id="1-github-프로필-상단을-손그림-감성의-캐릭터-배너로-다시-리디자인했습니다">1. GitHub 프로필 상단을 손그림 감성의 캐릭터 배너로 다시 리디자인했습니다</h3>
<p>기존 배너는 깔끔했지만 인상이 약했습니다.<br>이름과 전공, 관심 분야는 보였지만 분위기까지 전달되지는 않았고, 결국 첫 화면에서 남는 건 정보보다 형식에 가까웠습니다.</p>
<p>그래서 이번에는 단순히 텍스트를 배치하는 대신, 제가 계속 사용해오던 오리 캐릭터를 바탕으로 <strong>손그림 느낌의 배너</strong>로 다시 리디자인했습니다.<br>너무 딱딱하지도, 그렇다고 과하게 유아틱하지도 않게 조정하면서, <strong>귀엽지만 정돈된 톤</strong>으로 첫인상을 다시 잡고 싶었습니다.</p>
<p>배너 안에는 이름과 전공, 관심 분야를 그대로 두되,<br>부드러운 파스텔 톤과 손으로 그린 듯한 선, 클로버 포인트를 함께 넣어<br>“무난한 소개 이미지”보다 <strong>조금 더 기억에 남는 자기소개 화면</strong>이 되도록 구성했습니다.</p>
<p>거창한 브랜딩을 하겠다는 뜻은 아닙니다.<br>다만 첫 화면에서<br>“이건 이 사람의 페이지구나”라는 감각, 그리고<br>“딱딱한 소개보다 조금 더 편하게 다가오는 개발자”라는 인상은 남기고 싶었습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/cabfc915-6a8c-4d7f-b1ed-5c23d8cc6f7f/image.png" alt=""></p>
<p><em>오리 캐릭터와 손그림 질감을 반영한 배너로 다시 구성하며, GitHub 프로필의 첫인상을 더 선명하게 정리했습니다.</em></p>
<hr>
<h3 id="2-githubio를-자기소개의-흐름에-맞게-다시-설계했습니다">2. github.io를 ‘자기소개의 흐름’에 맞게 다시 설계했습니다</h3>
<p>기존 github.io는 기본 소개 페이지에 가까웠습니다.<br>보기에는 깔끔했지만, 페이지를 따라 내려가면서 저를 이해하게 되는 구조는 약했습니다.</p>
<p>그래서 이번에는 섹션을 단순히 나열하지 않고,<br>처음 방문한 사람이 자연스럽게 저를 이해하도록 <strong>정보의 순서</strong>를 다시 잡았습니다.</p>
<p>첫 화면에서는 저를 짧게 소개하고 핵심 링크를 보여준 뒤,<br>그 아래에서 About Me → 대표 프로젝트 → 기록과 이력 → GitHub · Velog · 연락처로 이어지도록 구성했습니다.</p>
<p>즉, 예쁜 섹션을 늘어놓는 것이 아니라<br><strong>“이 사람은 누구고, 무엇을 해왔고, 어디서 더 확인할 수 있는가”</strong>가  
자연스럽게 이어지는 구조를 만드는 데 더 집중했습니다.</p>
<p>아무리 화면이 깔끔해도<br>“그래서 이 사람이 어떤 걸 하는 사람인지”가 보이지 않으면<br>자기소개 페이지 역할은 충분하지 않다고 봤기 때문입니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/56f14639-c46b-451a-bb27-c9c29be987f9/image.png" alt=""></p>
<p><em>기본 소개 페이지에 머물던 구조를, 자기소개와 프로젝트 중심의 흐름으로 다시 정리했습니다.</em></p>
<hr>
<h3 id="3-github-프로필과-githubio의-역할을-분리하고-톤을-맞췄습니다">3. GitHub 프로필과 github.io의 역할을 분리하고 톤을 맞췄습니다</h3>
<p>사이트만 바꾸는 것으로는 부족했습니다.</p>
<p>실제로는 github.io보다 GitHub 프로필 README를 먼저 보게 되는 경우가 많고,<br>두 공간이 서로 다른 분위기와 메시지를 가지면 오히려 인상이 분산됩니다.</p>
<p>그래서 이번에는 역할을 분명히 나눴습니다.</p>
<ul>
<li>GitHub 프로필은 첫인상을 만드는 공간</li>
<li>github.io는 저를 더 자세히 설명하는 공간</li>
<li>Velog와 저장소는 기록과 결과물을 이어서 확인하는 공간</li>
</ul>
<p>핵심은 각각을 따로 꾸미는 것이 아니라,<br>하나의 자기소개 흐름 안에서 자연스럽게 이어지도록 맞추는 것이었습니다.<br>GitHub 프로필은 손그림 감성의 캐릭터 배너로 첫인상을 만들고, github.io는 그 인상 위에서 프로젝트와 기록을 더 자세히 보여주는 구조로 역할을 나눴습니다.</p>
<p>아직 완벽하다고 말할 단계는 아니지만,<br>최소한 “프로필은 프로필대로, 사이트는 사이트대로 따로 노는 느낌”은 줄이고 싶었습니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/f9597590-a738-4827-b304-c56a416163c1/image.jpeg" alt=""></p>
<p><em>GitHub 프로필과 github.io의 톤을 맞추며 하나의 자기소개 흐름으로 정리했습니다.</em></p>
<hr>
<h2 id="이번-작업에서-가장-중요하게-본-것">이번 작업에서 가장 중요하게 본 것</h2>
<p>이번 작업에서 가장 중요하게 본 건<br><strong>화려함보다 설명력, 무난함보다 인상</strong>이었습니다.</p>
<p>기술 스택을 길게 나열하는 방식보다,<br>대표 프로젝트와 기록의 흐름이 먼저 보이도록 구성하는 편이<br>지금 단계의 저를 더 솔직하게 보여준다고 판단했습니다.</p>
<p>무엇에 관심이 있는지,<br>무엇을 만들어봤는지,<br>어떤 방식으로 공부하고 기록하는지가 드러나야<br>페이지가 비로소 자기소개 역할을 한다고 봤기 때문입니다.</p>
<p>이번 개편을 하면서 다시 확인한 것도 분명했습니다.<br>상단 이미지 하나, 섹션 순서 하나, 링크 배치 하나만 바뀌어도<br>페이지 전체의 인상은 크게 달라집니다.</p>
<p>결국 포트폴리오는 만든 것을 모아두는 공간이 아니라,<br><strong>내가 어떤 사람인지 납득시키는 공간</strong>에 더 가깝다고 생각합니다.</p>
<hr>
<h2 id="앞으로-더-보완할-것">앞으로 더 보완할 것</h2>
<p>이번 개편으로 방향은 정리됐지만, 아직 손볼 부분도 분명합니다.</p>
<p>대표 프로젝트마다 GitHub, Demo, 관련 글 링크를 더 명확하게 연결할 필요가 있습니다.<br>현재는 일부 프로젝트 정리 글이 비공개 상태라, 공개 가능한 범위부터 순서대로 연결해 나갈 계획입니다.</p>
<p>또 GitHub 프로필과 github.io 모두에서<br>저를 한 줄로 선명하게 설명하는 문장도 더 다듬고 싶습니다.</p>
<p>반응형 대응, 메타 태그, 썸네일 이미지 같은 세부 완성도도<br>계속 챙겨야 할 부분입니다.</p>
<p>이 페이지는 한 번 만들어두고 끝나는 정적인 소개 화면이 아니라,<br>프로젝트와 기록이 쌓일수록 같이 성장해야 더 의미가 있다고 생각합니다.</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>이번 작업은 새로운 기능을 만드는 개발이라기보다,<br>지금까지 만든 것들과 앞으로 만들 것들을 <strong>어떻게 보여줄지 설계한 작업</strong>에 더 가까웠습니다.</p>
<p>기본 github.io에서 벗어나<br>저를 소개하고, 대표 프로젝트를 보여주고, 기록의 흐름까지 연결하는 페이지로<br>한 단계 정리했다는 점에서 의미가 있었습니다.</p>
<p>앞으로는 이 페이지를 단순한 소개 화면으로 두지 않고,<br>프로젝트와 기록이 계속 쌓이는 <strong>포트폴리오 허브</strong>처럼 더 다듬어갈 생각입니다.</p>
<p>결국 포트폴리오는 결과물을 나열하는 공간이 아니라,<br><strong>내가 어떤 사람인지 더 빠르게 이해시키는 화면</strong>이어야 한다고 생각합니다.<br>보여주는 방식까지 설계하는 것도 결국 개발자의 실력이라고 믿습니다.</p>
<p>🔗 직접 보기  </p>
<ul>
<li>GitHub Pages: <a href="https://lova-clover.github.io/">https://lova-clover.github.io/</a>  </li>
<li>GitHub Profile: <a href="https://github.com/Lova-clover">https://github.com/Lova-clover</a></li>
</ul>
<p>혹시 보시면서 인상적이었던 부분이나 아쉬웠던 점이 있다면 편하게 남겨주세요.<br>다음에 더 다듬는 데 큰 도움이 될 것 같습니다.</p>
<hr>
<h2 id="2026-06-08-기준-추가-개선-기록">2026-06-08 기준 추가 개선 기록</h2>
<p>처음 개편했을 때는 “나를 설명하는 흐름”을 만드는 데 집중했다면, 이번에는 실제 포트폴리오로서의 <strong>가시성, 역할 전달력, 프로젝트 검증 구조</strong>를 더 다듬었습니다.</p>
<p>가장 크게 바꾼 부분은 프로젝트 섹션입니다.
기존에는 프로젝트가 세로로 길게 나열되어 한눈에 비교하기 어려웠지만, 이번에는 대표 프로젝트를 카드형 갤러리로 정리하고, 각 프로젝트를 클릭하면 이미지, 역할, 문제 정의, 구현 과정, 결과와 회고를 함께 볼 수 있도록 바꿨습니다.</p>
<p>특히 팀 프로젝트는 단순히 “참여했다”가 아니라, 제가 어떤 파트를 맡았고 어떤 흐름을 직접 구현했는지 보이도록 <code>My Role</code>과 <code>Team Role</code>을 따로 정리했습니다.
프로젝트마다 <code>Problem → Build → Result</code> 구조를 넣어, 결과물만 보여주는 것이 아니라 문제를 어떻게 정의하고 구현으로 연결했는지도 함께 보여주고자 했습니다.</p>
<p>이번 수정에서 신경 쓴 부분은 다음과 같습니다.</p>
<ul>
<li>대표 프로젝트 8개를 Main 섹션으로 정리</li>
<li>전체 프로젝트는 All 탭과 History &amp; Records에서 확인 가능하도록 구성</li>
<li>프로젝트별 이미지 슬라이드와 상세 모달 추가</li>
<li>개인/팀 프로젝트별 My Role, Team Role 정리</li>
<li>GitHub, Velog, Email 연결 강화</li>
<li>Core Stack과 GitHub 프로필 기술 스택 정합성 개선</li>
<li>모바일과 데스크톱 반응형 개선</li>
<li>README와 assets 정리 후 GitHub Pages에 반영</li>
</ul>
<p>이번 수정의 방향은 단순히 “더 예쁜 페이지”를 만드는 것이 아니라, <strong>처음 보는 사람이 더 빨리 이해할 수 있는 페이지</strong>를 만드는 것이었습니다.</p>
<p>포트폴리오는 결과물을 모아두는 공간이기도 하지만, 결국 제가 어떤 방식으로 문제를 보고, 만들고, 기록하고, 다시 개선하는 사람인지 보여주는 공간이라고 생각합니다.</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/ebe5a2c1-ad85-4f76-9613-a591fc9b3c1a/image.jpeg" alt=""></p>
<p><em>2026-06-08 기준으로 프로젝트 카드, 상세 모달, My Role, History &amp; Records를 반영해 다시 정리한 github.io 전체 화면입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[의료 AI를 하다가 RAG를 다시 봤다]]></title>
            <link>https://velog.io/@lova-clover/%EC%9D%98%EB%A3%8C-AI%EB%A5%BC-%ED%95%98%EB%8B%A4%EA%B0%80-RAG%EB%A5%BC-%EB%8B%A4%EC%8B%9C-%EB%B4%A4%EB%8B%A4</link>
            <guid>https://velog.io/@lova-clover/%EC%9D%98%EB%A3%8C-AI%EB%A5%BC-%ED%95%98%EB%8B%A4%EA%B0%80-RAG%EB%A5%BC-%EB%8B%A4%EC%8B%9C-%EB%B4%A4%EB%8B%A4</guid>
            <pubDate>Thu, 12 Mar 2026 23:37:15 GMT</pubDate>
            <description><![CDATA[<p>의료 AI 프로젝트에서 처음 RAG를 붙였을 때, 출발점은 단순했다.</p>
<p>모델이 말을 너무 잘했다.<br>그게 오히려 불안했다.</p>
<p>의료 문맥에서는 문장을 매끈하게 뽑는 능력보다, 그 문장이 <strong>어디에서 왔는지</strong>가 먼저였다. 퇴원 후 환자 관리 지침을 정리할 때도 그랬고, 여러 기록에 흩어진 위험 신호를 한 번에 묶어야 할 때도 그랬다. 그럴듯한 답은 생각보다 쉽게 나온다. 문제는 그다음이다. 왜 그런 답을 했는지, 무엇을 보고 그렇게 말했는지, 틀렸다면 어디서부터 어긋났는지. 그게 안 잡히면 의료 쪽에서는 바로 불편해진다.</p>
<p>그래서 RAG를 붙였다.<br>적어도 답변 아래에 근거라도 깔아보자는 마음이었다.</p>
<p>막상 써보니, 내가 알고 있던 RAG는 너무 얕았다. 문서를 잘게 나누고, 임베딩해서 저장하고, 질문이 들어오면 비슷한 청크 몇 개를 가져와 모델에 넣는 방식. 처음엔 이 정도면 되는 줄 알았다. 그런데 실제로는 다른 데서 자꾸 막혔다. 질문 표현이 조금만 바뀌어도 retrieval이 흔들렸다. 여러 문서에 흩어진 근거를 엮어야 하는 질문은 금방 힘이 빠졌다. 한 문장의 출처를 보여주는 수준을 넘어서, <strong>이 환자에게 반복적으로 겹치는 위험 신호가 뭔지</strong>, <strong>수많은 가이드라인과 기록 중에서 지금 더 먼저 볼 포인트가 뭔지</strong> 같은 질문으로 넘어가면, 내가 알고 있던 RAG는 갑자기 너무 좁아졌다.</p>
<p>그때부터 RAG를 다시 보기 시작했다.</p>
<p>찾아볼수록 방향이 다르게 보였다. 지금 RAG를 이해한다는 건 벡터DB를 붙이는 법을 배우는 일이 아니라, <strong>어떤 질문에 어떤 검색 구조를 써야 하느냐</strong>를 이해하는 일에 더 가까웠다. RAG의 출발점도 사실 크게 다르지 않았다. 모델 내부 지식만으로는 업데이트, 출처 추적, 지식 집약적 질문을 다루기 어렵기 때문에 외부의 비파라미터 메모리를 붙이자는 것이었다. 그런데 2026년 현재의 RAG는 거기서 한참 더 나가 있다. classic RAG, hybrid retrieval, agentic retrieval, GraphRAG, LazyGraphRAG까지 가지가 꽤 많이 뻗었다. 실제로는 하나를 맹신하는 구조보다, <strong>질문에 맞는 branch를 고르는 구조</strong>가 더 설득력 있게 보인다.</p>
<blockquote>
<p><strong>지금은 가장 좋은 RAG 하나를 고르는 시대가 아니라, 질문에 맞는 RAG를 고르는 시대에 더 가깝다.</strong></p>
</blockquote>
<hr>
<h2 id="지금-rag를-볼-때-과거보다-현재를-먼저-보는-이유">지금 RAG를 볼 때, 과거보다 현재를 먼저 보는 이유</h2>
<p>RAG를 설명하는 글은 많다. 역사부터 차근차근 정리한 글도 많다.</p>
<p>지금 시점에서 더 중요한 건 초창기 정의보다 <strong>현재 기본값이 어떻게 바뀌었는가</strong>다. Azure AI Search 최신 문서를 보면 RAG를 설명할 때 아예 <strong>classic RAG pattern</strong>과 <strong>agentic retrieval</strong>을 따로 다룬다. classic RAG는 검색엔진에 질의를 보내고, 가져온 결과를 LLM에 넘겨 답을 만드는 구조다. 익숙한 방식이다. 반면 agentic retrieval은 여기서 멈추지 않는다. 대화 맥락을 읽고, compound question을 잘라서 여러 하위 질의로 만들고, 그걸 병렬로 실행한다. 같은 문서가 공식적으로 새 구현은 agentic retrieval부터 고려하라고 쓰고 있다는 점도 재밌다. RAG를 하나의 고정된 패턴으로 보기 어려워졌다는 뜻이다.</p>
<p>예전에는 “RAG = 벡터 검색”처럼 설명해도 크게 틀린 말은 아니었다.</p>
<p>지금은 그 설명이 부족하다.</p>
<p>classic RAG조차 vector-only로 설명하면 뭔가 빠진다. Azure의 hybrid search 문서는 hybrid search를 <strong>full-text와 vector를 동시에 실행하고, 그 결과를 RRF(Reciprocal Rank Fusion)로 합치는 구조</strong>로 설명한다. 여기에 semantic ranker를 붙여 결과를 다시 정렬한다. 검색 결과를 그냥 top-k로 던져 넣는 수준이 아니라, sparse 신호와 dense 신호를 같이 쓰고, 그 위에서 한 번 더 거르는 식이다. 실무에서 강한 기본형이 벡터 하나가 아니라 <strong>hybrid retrieval + rerank</strong>로 굳어지는 이유가 여기 있다.</p>
<p>의료 AI 프로젝트를 하면서도 이 차이를 자주 느꼈다. 의학 용어, 약어, 숫자, 기준치, 검사명, 약물명은 의미 유사도만으로 잘 안 잡힐 때가 많다. 반대로 의미상 비슷한 문서가 잡혀도, 실제 근거로 쓰기에는 미묘하게 틀린 경우도 많다. 예를 들어 INR, eGFR, BNP 같은 수치나 특정 경고 문구는 dense retrieval만 믿고 가면 한 끗씩 어긋난다. 약물명 표기가 다르거나, guideline 문구가 살짝 달라도 답변 전체가 미끄러질 수 있다. vector-only를 고집하면 결과가 완전히 틀린 답보다 더 곤란한 방향으로 간다.</p>
<p><strong>조금씩 어긋나는 답이 쌓인다.</strong></p>
<p>이게 더 위험했다.</p>
<p>키워드와 vector를 같이 쓰고, 그 위에 rerank를 올리면 질감이 달라진다. 보기에는 큰 변화가 아닌데, 로그를 까보면 답변 바닥이 바뀐다. 지금 기준으로 RAG를 설명할 때 vector-only를 기본형처럼 말하면 뭔가 많이 놓치게 된다.</p>
<h2 id="2026년-기본값-hybrid-retrieval--rerank">2026년 기본값: Hybrid Retrieval + Rerank</h2>
<p>지금의 RAG를 가장 현실적으로 설명하면 이 정도가 맞다.</p>
<p><strong>먼저 잘 찾고, 그다음 다시 잘 고른다.</strong></p>
<p>Hybrid retrieval은 그 원칙에 제일 충실하다. 키워드 검색은 정확한 용어, 숫자, 약어, 제목, 표기 차이에 강하다. 벡터 검색은 표면 표현이 달라도 의미가 가까운 문서를 끌어오는 데 강하다. 의료처럼 정밀한 표현과 넓은 의미 해석이 동시에 필요한 영역에서는 둘 중 하나만 믿는 순간 바로 구멍이 생긴다.</p>
<p>그래서 hybrid retrieval은 옵션이 아니라 기본값처럼 느껴진다.</p>
<p>여기에 rerank가 붙으면 그림이 더 선명해진다. 검색 단계에서 top-k에 들어온 문서는 보통 “대충 관련 있다” 수준인 경우가 많다. 의료 문맥에서는 이 정도로는 불안하다. “대충 관련 있는 문서”를 그대로 모델에 넣으면, 모델은 생각보다 그럴듯한 방식으로 틀린다. rerank는 이 후보들 중에서 질문에 더 가까운 문서를 다시 위로 세운다. retrieval 한 번으로 끝나는 구조보다, <strong>retrieval → fusion → rerank</strong> 같은 다단계 구조가 실전에서 더 납득된다.</p>
<p>내 기준으로 지금 제일 튼튼한 출발점은 분명하다.</p>
<p><strong>vector-only가 아니라 hybrid + rerank.</strong></p>
<p>여길 건너뛰고 최신 이름만 쫓으면, 생각보다 빨리 밑천이 드러난다.</p>
<h2 id="질문이-복잡해질수록-retrieval은-검색보다-계획에-가까워진다">질문이 복잡해질수록, retrieval은 검색보다 계획에 가까워진다</h2>
<p>물론 hybrid + rerank가 다 해결해주지는 않는다.</p>
<p>질문이 길어지고, 대화 맥락이 붙고, 하나의 질문 안에 여러 요구가 섞이면 retrieval은 단순 검색에서 조금 멀어진다. Azure의 agentic retrieval 문서는 이 부분을 꽤 또렷하게 설명한다. agentic retrieval은 LLM이 전체 대화 스레드를 읽고, 사용자의 compound question을 더 작은 subquery로 분해한다. 그다음 이 하위 질의들을 병렬로 실행하고, grounding data와 citation, query metadata까지 포함한 구조화된 결과를 돌려준다. 지금 retrieval의 앞쪽이 검색기라기보다 작은 planner처럼 보이는 이유다.</p>
<p>이건 의료 쪽으로 가져오면 더 체감된다.</p>
<p>예를 들어 이런 질문을 생각해 볼 수 있다.</p>
<blockquote>
<p>고령 환자이고, 당뇨와 만성 신질환이 있고, 항응고제를 복용 중이며, 최근 입원 이력이 있는 환자에게 퇴원 후 어떤 추적 관찰과 교육 포인트를 우선으로 제시해야 하는가?</p>
</blockquote>
<p>이 질문은 질의 하나로 끝날 성질이 아니다. 약물 관련 주의사항, 추적 검사, 합병증 징후, 재입원 위험, 생활관리 포인트가 동시에 걸려 있다. 이런 질문에서 중요한 건 검색기 성능만이 아니다. <strong>질문을 분해하고 coverage를 확보하는 방식</strong>이 먼저다. agentic retrieval이 눈에 들어오는 이유가 여기에 있다. 단일 검색어 하나로는 부족한 질문들이 실제 업무에는 꽤 많다.</p>
<h2 id="내가-graphrag에-관심을-갖게-된-이유">내가 GraphRAG에 관심을 갖게 된 이유</h2>
<p>내 관심은 여기서 한 번 더 옮겨갔다.</p>
<p>의료 AI 프로젝트를 하다 보니, 어느 순간부터는 “이 문장의 출처가 어디냐”보다 더 큰 질문이 자꾸 남았다. 여러 문서에서 반복되는 위험 신호는 무엇인지, 진료지침과 퇴원 교육자료와 약물 안내문과 기록을 합치면 어떤 패턴이 드러나는지, 한 문서 안이 아니라 <strong>문서 집합 전체를 봐야만 답할 수 있는 질문</strong>들이 나왔다. 이건 retrieval이 조금 부족해서 생긴 문제가 아니었다. 애초에 질문 자체가 달랐다.</p>
<p>그때 GraphRAG가 눈에 들어왔다.</p>
<p>공식 GraphRAG 문서는 GraphRAG를 plain text snippets 중심의 naive semantic search와 대비되는, <strong>structured, hierarchical</strong>한 RAG로 설명한다. 핵심은 단순하다. 텍스트를 잘라 임베딩만 저장하는 대신, 텍스트에서 엔티티와 관계를 추출해 지식 그래프를 만들고, 그 그래프를 community hierarchy로 묶고, 각 community report를 만든다. 질의 시점에는 이 구조를 활용한다. 공식 문서가 말하는 baseline RAG의 약점도 분명하다. 하나는 흩어진 정보를 연결해야 하는 <strong>connect-the-dots</strong> 유형이고, 다른 하나는 큰 문서나 데이터셋 전체를 <strong>holistically understand</strong>해야 하는 질문이다. GraphRAG는 바로 이 두 자리를 겨냥한다.</p>
<p>의료 쪽으로 옮겨보면 더 또렷하다.</p>
<p>퇴원 후 환자 관리 지침, 만성질환 교육 자료, 약물 복용 안내, 추적 검사 권고, 재입원 위험 신호, 간호기록, 외래 추적 계획이 여러 문서와 노트에 흩어져 있다고 해보자. 단순한 RAG는 이 중 한 문장을 찾는 데는 강할 수 있다. 그런데 이런 질문은 조금 다르다.</p>
<blockquote>
<p>이 환자에게 반복적으로 겹치는 복합 위험 신호는 무엇인가?<br>여러 가이드라인과 기록을 합쳐 봤을 때, 실제 follow-up 우선순위는 어디에 놓여야 하는가?<br>각각의 문장은 따로 떨어져 있는데, 전체적으로 어떤 패턴이 보이는가?</p>
</blockquote>
<p>여기서는 청크 몇 개를 잘 찾는 것만으로는 부족하다.</p>
<p>구조를 봐야 한다.</p>
<p>GraphRAG가 매력적으로 보인 이유가 정확히 그 지점이었다.</p>
<p>공식 query engine도 이 성격을 그대로 드러낸다. GraphRAG는 <code>local</code>, <code>global</code>, <code>drift</code>, <code>basic</code> 네 가지 query mode를 제공한다. Local Search는 특정 엔티티를 중심으로 세부를 파고드는 질문에 맞고, Global Search는 community reports를 map-reduce 식으로 훑으며 데이터셋 전체를 이해해야 하는 질문에 맞다. DRIFT Search는 local search에 community 정보를 끌어와 breadth를 넓히는 방식이고, Basic Search는 비교를 위한 baseline vector RAG다. 공식 문서는 Global Search를 <strong>resource-intensive</strong>하다고 적어둔다. 이 부분이 마음에 들었다. GraphRAG는 상위호환인 척하지 않는다.</p>
<p><strong>질문의 종류가 다르다.</strong></p>
<p>그 사실을 먼저 인정한다.</p>
<h2 id="지금-graphrag는-어디까지-와-있나">지금 GraphRAG는 어디까지 와 있나</h2>
<p>GraphRAG를 더 흥미롭게 만든 건, 이게 논문 아이디어에서 멈추지 않았다는 점이다.</p>
<p>현재 공식 docs를 보면 Welcome, Getting Started, Query, Prompt Tuning, CLI, Indexing Methods까지 꽤 잘 정리되어 있다. CLI는 <code>init</code>, <code>index</code>, <code>prompt-tune</code>, <code>query</code>, <code>update</code>를 지원한다. <code>query</code>는 <code>local|global|drift|basic</code>을 바로 받는다. Getting Started는 Python <strong>3.10~3.12</strong>를 요구하고, <code>init</code>을 실행하면 <code>.env</code>, <code>settings.yaml</code>, <code>input/</code>이 만들어진다. 지금의 GraphRAG는 “읽어볼 만한 논문”이 아니라, 적어도 <strong>손으로 굴려볼 수 있는 프레임워크</strong>다.</p>
<p>2024년 하반기부터 2026년 초까지의 흐름도 빠르다. DRIFT Search, dynamic community selection, LazyGraphRAG, GraphRAG 1.0이 이어졌고, GitHub releases 기준 최신 버전은 2026년 3월 6일의 <strong>v3.0.6</strong>이다. 방향은 꽤 분명하다. GraphRAG 진영도 단순히 “그래프가 더 똑똑하다”를 말하는 데서 멈추지 않고, breadth와 depth를 어떻게 섞을지, global search 비용을 어떻게 줄일지, up-front indexing cost를 얼마나 낮출지 같은 현실적인 문제로 내려오고 있다.</p>
<p>DRIFT는 그 흐름을 잘 보여준다. Microsoft Research 설명을 보면 DRIFT는 먼저 community reports 중 상위 K개를 골라 가벼운 primer를 만든다. 그다음 여기서 follow-up question을 만들고, local search 변형으로 세부를 파고든다. query expansion에는 HyDE도 활용한다. 같은 글에서 Microsoft는 AP 뉴스 5천여 건과 50개의 local question으로 벤치마킹한 결과, DRIFT가 Local Search보다 <strong>comprehensiveness 78%</strong>, <strong>diversity 81%</strong> 우세했다고 보고했다. 자사 실험 결과라는 점은 감안해서 읽어야 한다. 그래도 방향 하나는 분명하다. 전역 구조를 만들었으면, 그걸 local answer 품질 향상에 써보겠다는 쪽으로 가고 있다.</p>
<p>LazyGraphRAG도 같은 선상에서 읽힌다. Microsoft Research는 LazyGraphRAG를 prior summarization이 필요 없는 graph-enabled RAG로 소개한다. 발표 내용만 놓고 보면 data indexing cost는 vector RAG와 같고, full GraphRAG보다 훨씬 낮추는 방향을 노린다. 여기서 중요한 건 숫자 자체보다 메시지다. GraphRAG의 최신 흐름은 품질만 좋으면 된다는 태도에서 벗어나, <strong>비용-품질 곡선 자체를 다시 설계하는 쪽</strong>으로 이동하고 있다.</p>
<h2 id="그래서-지금-가장-좋은-rag는-뭐라고-봐야-하나">그래서, 지금 가장 좋은 RAG는 뭐라고 봐야 하나</h2>
<p>여기서 하나로 못 박고 싶은 유혹이 생긴다. Hybrid가 제일 낫다, Agentic이 다음이다, 아니면 이제 GraphRAG다.</p>
<p>나는 그렇게 정리하는 쪽이 오히려 덜 정확하다고 본다.</p>
<p>지금 기준으로 제일 그럴듯한 답은 <strong>질문 유형별로 retrieval branch를 갈아타는 Routed RAG</strong>다.</p>
<table>
<thead>
<tr>
<th>질문 성격</th>
<th>먼저 떠올릴 방식</th>
<th>왜 이쪽이 맞는가</th>
</tr>
</thead>
<tbody><tr>
<td>짧고 명확한 fact 질의, FAQ, 정책 문답</td>
<td><strong>Hybrid Retrieval + Semantic Rerank</strong></td>
<td>키워드 신호와 의미 신호를 같이 쓰고, 후단에서 다시 정렬할 수 있다</td>
</tr>
<tr>
<td>조건이 많고 대화 맥락이 중요한 복합 질의</td>
<td><strong>Agentic Retrieval</strong></td>
<td>질문을 subquery로 나누고 coverage를 넓힐 수 있다</td>
</tr>
<tr>
<td>문서 집합 전체의 핵심 주제, 전역 패턴, corpus-wide summary</td>
<td><strong>GraphRAG Global</strong></td>
<td>community summary 기반으로 전체 구조를 읽을 수 있다</td>
</tr>
<tr>
<td>여러 문서 사이의 관계, 연결, 맥락 추적</td>
<td><strong>GraphRAG DRIFT</strong></td>
<td>global signal과 local detail을 함께 가져갈 수 있다</td>
</tr>
<tr>
<td>그래프의 장점은 일부 가져가고 싶지만 비용이 아주 중요함</td>
<td><strong>LazyGraphRAG 계열</strong></td>
<td>graph 기반 retrieval의 무게를 줄이려는 최신 흐름이다</td>
</tr>
</tbody></table>
<p>짧고 명확한 fact 질의, FAQ, 정책 문답, 문서 검색은 <strong>hybrid retrieval + semantic rerank</strong>가 제일 튼튼한 기본값이다.</p>
<p>질문이 복합적이고 대화 맥락이 중요하고, 하나의 질문 안에 여러 요구가 섞여 있다면 <strong>agentic retrieval</strong>이 더 잘 맞는다.</p>
<p>문서 집합 전체의 핵심 주제, 전역 패턴, 여러 문서 사이의 관계, corpus-wide summary가 필요하다면 <strong>GraphRAG Global</strong>이나 <strong>DRIFT</strong>가 설계된 자리다.</p>
<p>비용이 아주 중요하면서 그래프의 장점은 일부 가져가고 싶다면, 지금 흐름상 흥미로운 방향은 <strong>LazyGraphRAG</strong>다. 다만 이건 아직 Microsoft 측 결과를 중심으로 읽어야 하고, 직접 검증 없이 정답처럼 말하기엔 조심스럽다.</p>
<p>코드처럼 적으면 대충 이런 느낌이다.</p>
<pre><code class="language-python">if question_type == &quot;local_fact&quot;:
    use = &quot;hybrid_retrieval + semantic_rerank&quot;
elif question_type == &quot;complex_conversational&quot;:
    use = &quot;agentic_retrieval&quot;
elif question_type == &quot;corpus_wide_summary&quot;:
    use = &quot;graphrag_global&quot;
elif question_type == &quot;relationship_bridge&quot;:
    use = &quot;graphrag_drift&quot;
else:
    use = &quot;hybrid_retrieval + semantic_rerank&quot;</code></pre>
<p>누가 지금 가장 좋은 RAG 하나만 골라보라고 하면, 나는 아마 이렇게 답할 것 같다.</p>
<p><strong>하나를 고르지 말고, 라우팅 기준부터 잡아야 한다.</strong></p>
<h2 id="다시-의료-ai-이야기로-돌아가면">다시, 의료 AI 이야기로 돌아가면</h2>
<p>내가 RAG를 다시 공부하게 된 이유도 여기로 돌아온다.</p>
<p>의료 AI 프로젝트에서 내가 원했던 건 더 유창하게 말하는 모델이 아니었다. 내가 원한 건 <strong>더 믿을 수 있는 모델</strong>이었다. 퇴원 후 환자 관리 지침을 정리할 때도, 복합 질환 환자의 위험 신호를 묶어볼 때도, 여러 기록 속에서 반복되는 패턴을 찾을 때도, 중요한 건 답변 속도보다 <strong>근거의 구조</strong>였다.</p>
<p>이 환자에게 지금 중요한 게 뭔지.<br>왜 그렇게 판단했는지.<br>어디까지는 말할 수 있고, 어디서부터는 더 확인해야 하는지.</p>
<p>이걸 답변 안에 담고 싶었다.</p>
<p>지금 와서 보면 그 문제의식이 자연스럽게 나를 RAG 쪽으로 끌고 왔다. RAG는 검색 몇 번 더 하는 기술이 아니다. 무엇을 찾을지, 어떻게 찾을지, 어떤 질문은 쪼개서 풀지, 어떤 질문은 문서 집합 전체를 구조로 이해할지, 어디서 멈출지를 설계하는 기술에 가깝다. 의료처럼 답변의 무게가 큰 영역에서는 이 차이가 더 크게 느껴진다.</p>
<p>그래서 내 기준에서 지금 가장 좋은 RAG는 “제일 새로운 이름의 RAG”가 아니다. 질문의 무게를 알고, 그 질문에 맞는 근거 수집 방식을 고르고, 필요하면 retrieval 전략을 바꿔 탈 수 있는 RAG다.</p>
<p>다음에 비슷한 프로젝트를 다시 하게 되면, 아마 예전처럼 무조건 vector search부터 붙이지는 않을 것 같다. 질문부터 나누고, 기본값은 hybrid + rerank로 두고, 코퍼스 전체를 읽어야 하는 질문만 graph 계열로 태워볼 생각이다. 한동안은 이 틀로 더 부딪혀 볼 것 같다.</p>
<hr>
<h2 id="참고한-자료">참고한 자료</h2>
<ul>
<li><a href="https://learn.microsoft.com/en-us/azure/search/retrieval-augmented-generation-overview">Retrieval-augmented generation (RAG) in Azure AI Search</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/search/hybrid-search-overview">Hybrid search overview - Azure AI Search</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/search/agentic-retrieval-overview">Agentic Retrieval Overview - Azure AI Search</a></li>
<li><a href="https://microsoft.github.io/graphrag/">GraphRAG 공식 문서</a></li>
<li><a href="https://microsoft.github.io/graphrag/query/overview/">GraphRAG Query Overview</a></li>
<li><a href="https://microsoft.github.io/graphrag/query/drift_search/">GraphRAG DRIFT Search</a></li>
<li><a href="https://microsoft.github.io/graphrag/get_started/">GraphRAG Getting Started</a></li>
<li><a href="https://microsoft.github.io/graphrag/cli/">GraphRAG CLI Reference</a></li>
<li><a href="https://www.microsoft.com/en-us/research/blog/introducing-drift-search-combining-global-and-local-search-methods-to-improve-quality-and-efficiency/">Microsoft Research: Introducing DRIFT Search</a></li>
<li><a href="https://www.microsoft.com/en-us/research/blog/lazygraphrag-setting-a-new-standard-for-quality-and-cost/">Microsoft Research: LazyGraphRAG</a></li>
<li><a href="https://www.microsoft.com/en-us/research/blog/moving-to-graphrag-1-0-streamlining-ergonomics-for-developers-and-users/">Microsoft Research: Moving to GraphRAG 1.0</a></li>
<li><a href="https://github.com/microsoft/graphrag/releases">GraphRAG Releases</a></li>
<li><a href="https://arxiv.org/abs/2005.11401">Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[성능만 보던 시선에서, On-device AI와 양자화를 다시 보게 되었다]]></title>
            <link>https://velog.io/@lova-clover/%EC%84%B1%EB%8A%A5%EB%A7%8C-%EB%B3%B4%EB%8D%98-%EC%8B%9C%EC%84%A0%EC%97%90%EC%84%9C-On-device-AI%EC%99%80-%EC%96%91%EC%9E%90%ED%99%94%EB%A5%BC-%EB%8B%A4%EC%8B%9C-%EB%B3%B4%EA%B2%8C-%EB%90%98%EC%97%88%EB%8B%A4-pc1ludph</link>
            <guid>https://velog.io/@lova-clover/%EC%84%B1%EB%8A%A5%EB%A7%8C-%EB%B3%B4%EB%8D%98-%EC%8B%9C%EC%84%A0%EC%97%90%EC%84%9C-On-device-AI%EC%99%80-%EC%96%91%EC%9E%90%ED%99%94%EB%A5%BC-%EB%8B%A4%EC%8B%9C-%EB%B3%B4%EA%B2%8C-%EB%90%98%EC%97%88%EB%8B%A4-pc1ludph</guid>
            <pubDate>Tue, 10 Mar 2026 16:33:41 GMT</pubDate>
            <description><![CDATA[<p>LG Aimers 8기에서 경량화 모델을 돌리던 시기, 나는 성능보다 먼저 자원 한계와 환경 문제를 더 크게 체감했다.</p>
<p>처음에는 당연하게도 성능 향상에만 시선이 가 있었다. 어떤 모델이 더 좋은지, 어떤 설정을 바꾸면 점수가 조금이라도 더 올라갈지, 그런 것들이 가장 중요해 보였다. 대회든 프로젝트든 결국 가장 먼저 보게 되는 건 숫자고, 가장 쉽게 흔들리는 것도 숫자이기 때문이다.</p>
<p>그런데 이상하게도, 그 시기에 내 머릿속에 가장 오래 남은 건 성능표가 아니었다.
오히려 훨씬 더 현실적인 문제들이었다. 버전은 자꾸 꼬였고, 라이브러리는 예상보다 쉽게 충돌했고, 모델이 조금만 커져도 VRAM은 빠르게 바닥을 드러냈다. 처음에는 그냥 늘 있는 시행착오라고 생각했다. “환경이 좀 꼬였네”, “이번만 넘기면 되겠지” 정도로 넘기려 했다.</p>
<p>하지만 비슷한 문제가 반복되면서 생각이 조금씩 바뀌기 시작했다.
단순히 성능이 좋은 모델을 찾는 것과, 그 모델을 실제 환경에서 다루는 것은 전혀 다른 문제라는 점이 점점 더 또렷하게 보였다. 좋은 모델이라는 말은 충분히 매력적이지만, 실제로 서비스를 만들거나 실험을 이어가려면 성능표 바깥의 조건들도 함께 봐야 했다. <strong>메모리 사용량, 추론 비용, 지연 시간, 라이브러리 호환성, 배포 방식</strong> 같은 것들 말이다.</p>
<p>그때부터 관심사가 달라졌다.
예전에는 “무슨 모델이 더 좋을까?”를 먼저 물었다면, 이제는 <strong>“이 모델은 어떤 환경에서, 어떤 비용으로, 어떤 제약 속에서 다뤄야 할까?”</strong>를 함께 생각하게 됐다. 성능을 보는 눈이 사라진 건 아니었다. 다만 그 위에 조금 더 현실적인 질문들이 얹히기 시작한 것이다.</p>
<p>이 글은 바로 그 변화에서 시작된 기록이다. 성능 좋은 모델만 보던 시선에서 조금 벗어나, On-device AI와 양자화(Quantization)를 다시 보게 된 과정. 그리고 그 과정에서 “좋은 모델”을 바라보는 기준이 어떻게 달라졌는지를 정리해보려 한다.</p>
<hr>
<h2 id="왜-다시-on-device-ai를-보게-됐나">왜 다시 On-device AI를 보게 됐나</h2>
<p>처음에는 솔직히 On-device AI가 그렇게까지 크게 와닿지 않았다. 클라우드 API를 쓰면 되는 것 아닌가, 하는 생각이 더 강했다. 실제로 빠르게 기능을 붙여보거나 프로토타입을 만들 때는 그 방식이 분명 강력하다. 잘 정리된 모델을 호출해서 사용하면 되고, 무거운 계산은 서버가 처리하니 내 로컬 환경이 감당해야 하는 부담도 줄어든다.</p>
<p>하지만 자료를 더 찾아보고, 실제 서비스 구조를 조금 더 진지하게 상상해보니 그렇게 단순하게 볼 문제는 아니었다.</p>
<p>클라우드 의존은 분명 편리하지만, 그만큼 <strong>지연 시간(Latency)</strong> 문제를 끌고 간다. 응답이 서버를 왕복하는 구조에서는 네트워크 상태에 영향을 받을 수밖에 없고, 사용량이 늘어나면 <strong>비용 문제</strong>도 점점 더 현실적인 부담이 된다. 여기에 입력 데이터를 계속 외부 서버로 보내야 한다는 점에서 <strong>프라이버시나 데이터 통제 문제</strong>도 함께 따라온다.</p>
<p>그제야 On-device AI가 다르게 보이기 시작했다. 예전에는 그냥 “폰에서도 돌아간다”는 식의 기술 데모처럼 느껴졌다면, 이제는 지연 시간·비용·프라이버시 같은 실제 문제를 줄이기 위한 현실적인 선택지로 보였다.</p>
<blockquote>
<p>즉, 온디바이스 AI는 단순히 클라우드를 대체하는 구호가 아니라, <strong>어떤 조건에서는 더 적절한 시스템 설계 방식</strong>에 가까웠다.</p>
</blockquote>
<p>이 지점이 내게 꽤 크게 남았다. 모델을 본다는 건 단순히 성능표를 읽는 일이 아니라, 그 모델이 놓일 환경과 제약까지 함께 보는 일이라는 점을 조금씩 이해하게 됐기 때문이다. 그리고 그 순간부터, On-device AI는 더 이상 “작은 모델 이야기”가 아니라 <strong>실제 AI 시스템을 어떻게 설계하고 배치할 것인가에 대한 이야기</strong>로 느껴지기 시작했다.</p>
<hr>
<h2 id="양자화는-단순-압축보다-훨씬-정교한-문제였다">양자화는 ‘단순 압축’보다 훨씬 정교한 문제였다</h2>
<p>On-device AI나 경량 배포를 생각하면 자연스럽게 양자화라는 개념을 만나게 된다.
처음에는 나도 이걸 꽤 단순하게 이해했다. 숫자의 정밀도를 낮춰서 모델을 가볍게 만드는 기술. FP32를 INT8이나 INT4 같은 저비트 표현으로 바꾸면 메모리 사용량과 계산 비용이 줄어든다. 얼핏 보면 이 설명만으로도 충분해 보인다.</p>
<p>그런데 조금만 더 파고들면, 양자화는 그렇게 단순한 이야기가 아니었다.</p>
<p>모델 안의 값들이 모두 같은 중요도를 가지는 건 아니었다. 어떤 값은 조금 손실이 생겨도 큰 문제가 없지만, 어떤 값은 성능에 훨씬 민감하게 작용한다. 특히 LLM처럼 규모가 큰 모델에서는 일부 아웃라이어(Outlier)나 중요한 채널을 어떻게 다루느냐가 결과에 큰 차이를 만든다.</p>
<p>결국 양자화의 핵심은 “얼마나 많이 줄이느냐”보다, <strong>무엇을 줄이고 무엇을 보호해야 덜 무너지는가</strong>를 판단하는 데 더 가까웠다.</p>
<p>이걸 이해하고 나서 양자화를 보는 시선도 바뀌었다. 처음엔 단순히 모델을 압축하는 요령처럼 느껴졌는데, 공부할수록 오히려 성능을 최대한 지켜내기 위한 정교한 설계처럼 보였다. 무작정 작게 만드는 게 아니라, 제한된 자원 속에서도 모델의 핵심 능력을 어떻게 보존할지 고민하는 기술이라는 점이 더 크게 다가왔다.</p>
<p>이 부분이 특히 흥미로웠다. 경량화라는 말을 들으면 보통 타협이나 희생이 먼저 떠오르기 쉽다. 하지만 양자화는 꼭 그런 식으로만 보이지 않았다. 오히려 무엇을 포기할 수 있고, 무엇은 끝까지 지켜야 하는지를 구분해야 한다는 점에서 꽤 섬세한 최적화 문제에 가까웠다. 단순한 축소가 아니라, <strong>제약 속에서 성능을 어떻게 유지할 것인가</strong>를 다루는 방법이었다.</p>
<hr>
<h2 id="ptq와-qat를-보며-언제-줄일-것인가도-중요하다는-걸-알게-됐다">PTQ와 QAT를 보며, ‘언제 줄일 것인가’도 중요하다는 걸 알게 됐다</h2>
<p>양자화를 조금 더 보다 보니, 단순히 몇 비트로 줄일 것인가보다 <strong>언제 줄일 것인가</strong>도 중요하다는 걸 알게 됐다. 대표적으로는 PTQ와 QAT가 있다.</p>
<ul>
<li><strong>PTQ(Post-Training Quantization):</strong> 이미 학습이 끝난 모델을 가져와 사후적으로 양자화하는 방식</li>
<li><strong>QAT(Quantization-Aware Training):</strong> 학습 단계부터 양자화 오차를 고려하며 모델을 적응시키는 방식</li>
</ul>
<p>내 입장에서는 PTQ가 훨씬 현실적으로 느껴졌다.
이미 학습된 모델을 가져와 줄여보는 건 시도해볼 만하지만, 거대한 모델을 다시 학습시키거나 양자화 인지 학습을 길게 돌리는 건 개인 환경에서는 부담이 크기 때문이다. 시간도 자원도 빠듯한 상황에서는, 빠르게 실험하고 적용해볼 수 있는 방식이 먼저 눈에 들어올 수밖에 없다.</p>
<p>반면 QAT가 왜 계속 중요하게 언급되는지도 이해됐다.
비트를 더 공격적으로 낮출수록, 특히 4비트 이하처럼 더 극단적인 경량화로 갈수록 단순한 사후 압축만으로는 품질을 안정적으로 지키기 어려워질 수 있다. 그럴수록 학습 단계부터 양자화 오차를 반영해 적응시킨 모델이 더 강하게 버틸 수 있다.</p>
<p>결국 둘 중 하나가 절대적으로 우월하다기보다는, <strong>내가 어떤 자원 조건에 놓여 있고, 어떤 목적을 가지고 모델을 다루는지에 따라 선택지가 달라진다는 점</strong>이 더 중요하게 느껴졌다. 빠르게 적용하고 싶은지, 더 낮은 비트까지 밀어붙이고 싶은지, 추론이 목적인지 파인튜닝까지 고려하는지에 따라 답이 달라진다.</p>
<p>이걸 이해하면서 양자화는 더 이상 단순한 기술 용어가 아니게 됐다. 모델을 어떤 조건에서 다룰 것인지, 그리고 내가 감당할 수 있는 비용과 목표가 무엇인지를 함께 묻는 질문처럼 느껴졌다.</p>
<hr>
<h2 id="공부하며-인상-깊었던-네-가지-흐름">공부하며 인상 깊었던 네 가지 흐름</h2>
<p>양자화 기법을 보다 보면 이름이 정말 많이 나온다. 처음에는 다 비슷해 보였다. 전부 성능 손실을 줄이면서 저비트로 압축하겠다는 이야기처럼 보였기 때문이다. 그런데 계속 보다 보니, 각 방법이 중요하게 보는 지점이 조금씩 다르다는 게 보이기 시작했다.</p>
<ul>
<li><strong>LLM.int8():</strong> 가장 먼저 직관적으로 와닿았던 방식이다. 이 방식은 모든 값을 일괄적으로 8비트로 눌러버리지 않고, 중요한 일부 차원은 더 높은 정밀도로 유지한다. 이 단순한 아이디어 하나만으로도 양자화를 보는 시각이 달라졌다. 모두를 똑같이 줄이면 안 된다는 점, 중요한 부분은 끝까지 지켜야 한다는 점이 아주 선명하게 느껴졌기 때문이다.</li>
<li><strong>GPTQ:</strong> 저비트 변환 과정에서 생기는 오차를 그냥 감수하지 않고, 전체 손실을 줄이는 방향으로 보정하려 한다. 즉, 단순히 낮은 비트로 바꾸는 게 아니라, 그 과정에서 생긴 문제를 어떻게 덜 치명적으로 만들 것인가를 적극적으로 고민한다. 이 접근은 “양자화는 변환이 아니라 최적화”라는 느낌을 더 강하게 줬다.</li>
<li><strong>AWQ:</strong> 정적인 가중치 값만 보는 것이 아니라, 실제 활성값(Activation) 관점에서 중요한 채널을 보호한다. 다시 말해, 저장된 숫자만 보는 게 아니라 모델이 실제로 어떻게 반응하는지를 기준으로 중요도를 판단한다. 모델을 정적인 덩어리가 아니라 실제로 움직이는 시스템으로 보게 만들었다는 점에서 꽤 실전적으로 느껴졌다.</li>
<li><strong>QLoRA:</strong> 양자화를 추론 최적화에만 묶어두지 않는다는 점에서 흥미로웠다. 양자화된 기반 모델 위에 LoRA 어댑터를 학습시키는 방식은, 제한된 자원 안에서도 파인튜닝 가능성을 열어준다는 점에서 꽤 상징적으로 보였다. “무거워서 못 한다”로 끝나는 것이 아니라, 자원이 부족해도 다른 방식으로 접근할 수 있다는 가능성을 보여줬기 때문이다.</li>
</ul>
<p>이 네 가지를 보다 보니, 양자화는 하나의 정답이라기보다 <strong>무엇을 보호하고 무엇을 감수할 것인가에 대한 서로 다른 전략들</strong>처럼 느껴졌다. 그리고 바로 그 점이 이 분야를 더 흥미롭게 만들었다.</p>
<hr>
<h2 id="4-bit-그-너머를-보게-되면서-양자화가-현재진행형이라는-걸-알게-됐다">4-bit 그 너머를 보게 되면서, 양자화가 ‘현재진행형’이라는 걸 알게 됐다</h2>
<p>처음에는 INT8이나 INT4 정도만 이해해도 충분히 큰 그림을 본 것처럼 느껴졌다. 그런데 자료를 더 보다 보니, 오히려 그 반대였다. 양자화는 이미 정리된 기술이 아니라, 지금도 계속 빠르게 진화하는 영역이었다.</p>
<p>가중치만 줄이는 게 아니라 활성값까지 함께 다루려는 시도가 있었고, 추론 과정에서 중요한 KV 캐시까지 저비트로 압축하려는 흐름도 이어지고 있었다. 더 나아가 4비트를 넘어 3비트, 2비트 수준까지 내려가면서도 품질을 최대한 방어하려는 연구도 계속 나온다.</p>
<p>이 흐름을 보면서 든 생각은 단순했다.
이제는 모델을 얼마나 크게 만들 수 있는가만큼, <strong>그 모델을 얼마나 효율적으로 운용할 수 있는가</strong>도 점점 더 중요해지고 있다는 것이다.</p>
<p>앞으로 모델은 계속 강해질 것이다. 하지만 강한 모델이 곧바로 좋은 시스템이 되는 건 아니다. 실제 환경에서는 자원, 비용, 속도, 배포성, 안정성 같은 요소가 늘 함께 움직인다. 그런 점에서 양자화는 “있으면 좋은 최적화 기술”이 아니라, AI를 더 넓은 환경에서 사용하기 위해 반드시 같이 발전해야 하는 핵심 기술처럼 보였다.</p>
<hr>
<h2 id="그리고-결국-이론과-실전은-정말-다르더라">그리고 결국, 이론과 실전은 정말 다르더라</h2>
<p>논문과 정리 글을 읽을 때까지만 해도, 어느 정도는 이해했다고 생각했다. PTQ와 QAT의 차이도 알겠고, GPTQ와 AWQ가 무엇을 다르게 보는지도 대략은 구분할 수 있었다. 그런데 막상 로컬 환경에서 실제로 적용하려고 하니, 문제는 전혀 다른 얼굴로 나타났다.</p>
<p>가장 먼저 체감한 건 도구 생태계의 복잡함이었다.
예전에 잘 되었다는 튜토리얼이 지금은 그대로 동작하지 않는 경우가 많았고, 블로그 글 하나만 믿고 따라가면 버전 호환성 문제에서 쉽게 막혔다. 어떤 패키지는 설치되지만 실행이 안 됐고, 어떤 조합은 실행은 되지만 특정 환경에서 다시 깨졌다. 논문을 읽을 때는 매끈해 보였던 흐름이, 실제로는 파일 포맷, 의존성, 하드웨어, 로더 호환성 같은 문제들과 얽혀 있었다.</p>
<p>이걸 겪으면서 아주 분명하게 느낀 게 있다.</p>
<blockquote>
<p><strong>이론을 아는 것과, 실제로 내 환경에서 모델을 안정적으로 다루는 것은 전혀 다른 문제다.</strong></p>
</blockquote>
<p>논문은 개념을 알려주지만, 실제 환경은 훨씬 더 많은 걸 요구한다. 라이브러리 버전, CUDA 환경, 포맷 변환, 메모리 관리, 추론 백엔드 선택, 운영체제 차이까지 전부 얽혀 있기 때문이다. 결국 양자화는 알고리즘을 이해하는 것만으로 끝나는 주제가 아니었다. 하드웨어와 소프트웨어 생태계를 함께 이해해야 비로소 “현실적인 기술”이 된다.</p>
<p>오히려 그래서 더 재미있었다. 논문을 읽고 개념을 아는 단계에서 끝나는 게 아니라, 실제로 굴러가는 구조를 만들기 위한 공부로 이어졌기 때문이다. 그리고 아마 내가 이 주제에 더 끌리게 된 이유도 바로 거기에 있을 것이다.</p>
<hr>
<h2 id="마치며">마치며</h2>
<p>처음에는 단순히 성능을 더 올리고 싶었다.
그런데 계속 부딪히고 공부하다 보니, 성능만으로는 설명되지 않는 문제들이 훨씬 더 많이 보이기 시작했다. 모델이 어떤 환경에서 돌아가는지, 어떤 자원을 요구하는지, 어떤 방식으로 배포되고 유지될 수 있는지까지 함께 보지 않으면, “좋은 모델”이라는 말도 생각보다 쉽게 공중에 뜬다는 걸 조금씩 이해하게 됐다.</p>
<p>이제는 새로운 모델을 볼 때 예전과는 조금 다른 질문을 하게 된다.
벤치마크 점수는 여전히 중요하다. 하지만 그와 함께 이 모델이 어떤 환경을 전제로 하는지, 어떤 최적화가 가능한지, 실제 시스템 안에서는 어떤 장단점을 가질지를 같이 보게 된다. 성능을 버린 것이 아니라, 성능만 보던 시선에서 조금 더 넓은 시선으로 이동한 셈이다.</p>
<p>돌아보면, VRAM 에러나 환경 충돌 같은 경험들은 단순히 귀찮은 삽질이 아니었다. 오히려 그 경험들이 모델을 바라보는 기준을 더 입체적으로 바꿔줬다. 화려한 숫자만 보던 시선에서 조금 벗어나, 제약과 조건까지 함께 보는 쪽으로 생각이 이동한 것이다.</p>
<p>아직도 모르는 것이 훨씬 많다.
하지만 적어도 하나는 분명하다. 이제 나는 “가장 높은 점수를 내는 모델”만 보는 사람보다는, <strong>그 모델이 실제 환경 안에서 어떤 의미를 가지는지까지 함께 보려는 사람</strong>에 더 가까워지고 있다.</p>
<p>그리고 아마, 진짜 공부는 모델의 점수만이 아니라 그 모델이 놓일 현실까지 함께 보게 되는 순간부터 시작되는 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[바이브 코딩은 빠르다. 그래서 더 위험하다 — VibeOps 해커톤 탈락 회고]]></title>
            <link>https://velog.io/@lova-clover/%EB%B0%94%EC%9D%B4%EB%B8%8C-%EC%BD%94%EB%94%A9%EC%9D%80-%EB%B9%A0%EB%A5%B4%EB%8B%A4.-%EA%B7%B8%EB%9E%98%EC%84%9C-%EB%8D%94-%EC%9C%84%ED%97%98%ED%95%98%EB%8B%A4-VibeOps-%ED%95%B4%EC%BB%A4%ED%86%A4-%ED%83%88%EB%9D%BD-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@lova-clover/%EB%B0%94%EC%9D%B4%EB%B8%8C-%EC%BD%94%EB%94%A9%EC%9D%80-%EB%B9%A0%EB%A5%B4%EB%8B%A4.-%EA%B7%B8%EB%9E%98%EC%84%9C-%EB%8D%94-%EC%9C%84%ED%97%98%ED%95%98%EB%8B%A4-VibeOps-%ED%95%B4%EC%BB%A4%ED%86%A4-%ED%83%88%EB%9D%BD-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 09 Mar 2026 09:20:57 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요, Lova-clover입니다!</p>
<p>얼마 전 참여했던 &#39;월간 해커톤: 바이브 코딩 개선 AI 아이디어 공모전&#39;에서 아쉽게도 고배를 마셨습니다. 🥲</p>
<p>하지만 이번 프로젝트를 진행하며, 수상을 뛰어넘는 훨씬 더 선명하고 값진 깨달음을 얻었습니다. <strong>&quot;AI가 코드를 빨리 만들어주는 것과, 팀이 안전하게 소프트웨어를 만드는 것은 전혀 다른 문제&quot;</strong>라는 점입니다.</p>
<p>이번 해커톤에서 제가 제안한 <strong>VibeOps</strong>는 그 위험한 간극을 메우기 위해 고민했던 PoC(개념 증명) 프로젝트입니다. 이 글을 관통하는 핵심 메시지는 단 하나입니다.</p>
<blockquote>
<p><strong>&quot;AI에게 코드를 맡기기 전에, 먼저 스펙부터 확정하자.&quot;</strong></p>
</blockquote>
<p>(아래는 제가 기획하고 구현한 VibeOps의 메인 화면입니다)</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/4885f21f-93d7-4713-8980-47a78ea75951/image.jpeg" alt="VibeOps 메인화면"></p>
<hr>
<h2 id="📌-한눈에-요약하는-vibeops">📌 한눈에 요약하는 VibeOps</h2>
<ul>
<li><strong>문제</strong>: 바이브 코딩은 &quot;만들어줘 → 생성 → 커밋&quot;으로 흘러가기 쉬워, 필수적인 품질 게이트가 무너집니다.</li>
<li><strong>해결</strong>: 코드 생성 전 &#39;스펙 확정&#39; 및 &#39;정책 충돌 검증&#39;, 생성 후 &#39;품질 검증&#39;, 그리고 전 과정의 &#39;자동 문서화&#39; 파이프라인을 기획했습니다.</li>
<li><strong>구현 범위 (PoC)</strong>: 웹 데모, <code>.vibe</code> 로컬 파일 구조, 프로젝트 컨텍스트 로드, 키워드 기반 제약 조건 위반 감지, CLI 초기화 기능.</li>
<li><strong>한계점</strong>: <code>vibe why</code>의 실제 히스토리 조회, 고도화된 Validate 엔진, 전체 CLI 통합은 아직 아이디어 단계에 머물렀습니다.</li>
<li><strong>회고</strong>: 문제 정의는 날카로웠으나, 심사위원을 완전히 납득시킬 만한 &#39;실사용 증거&#39;와 &#39;구현의 완성도&#39;가 부족했습니다.</li>
</ul>
<hr>
<h2 id="1-바이브-코딩-속도에-가려진-4가지-함정">1. 바이브 코딩, 속도에 가려진 4가지 함정</h2>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/eb675e74-31a6-431a-89d8-90ef70e22997/image.jpeg" alt="문제 정의"></p>
<p>Cursor나 Copilot 같은 AI 코딩 도구를 쓰다 보면 확실히 체감합니다. <strong>코드는 정말 무섭게 쏟아져 나옵니다.</strong></p>
<p>문제는 그다음입니다. 전통적인 개발은 <code>요구사항 분석 → 설계 → 개발 → 테스트 → 리뷰</code>라는 안전망을 거치지만, 바이브 코딩은 자칫하면 <code>만들어줘 → 생성 → 커밋</code>으로 끝나버립니다.</p>
<p>속도는 얻었지만, 이 과정에서 실무에 치명적인 4가지 문제가 발생합니다.</p>
<ol>
<li><strong>의도 불일치</strong>: 모호한 자연어 요청은 결국 AI가 빈칸을 마음대로 추측하게 만듭니다. 로그인 기능을 원했는데, 인증이나 해싱 방식까지 AI가 멋대로 정해버리죠.</li>
<li><strong>정책 위반</strong>: 프로젝트마다 &#39;OAuth 금지&#39;, &#39;외부 CDN 사용 금지&#39; 같은 금지 규칙이 있습니다. 하지만 AI는 팀의 내밀한 정책을 모른 채 코드를 짜버립니다.</li>
<li><strong>일관성 붕괴</strong>: 어떤 날은 함수형으로, 어떤 날은 클래스형으로 코드를 내뱉습니다. 생성은 빨랐는데 유지보수 지옥이 열립니다.</li>
<li><strong>맥락 소실 (가장 치명적)</strong>: 대화 세션이 끝나면 &quot;왜 이런 구조를 선택했는지&quot;, &quot;왜 이 제약을 넣었는지&quot;에 대한 개발자의 결정 근거가 영구히 날아갑니다.</li>
</ol>
<p>결국 이 문제의 본질은 &quot;AI가 얼마나 똑똑한가&quot;가 아니라, <strong>&quot;파이프라인 내에 통제 메커니즘이 없다&quot;</strong>는 것이었습니다.</p>
<hr>
<h2 id="2-기존-도구들로는-왜-부족했을까">2. 기존 도구들로는 왜 부족했을까?</h2>
<p>처음엔 저도 <code>.cursorrules</code>나 시스템 프롬프트를 잘 작성하면 해결되지 않을까 생각했습니다. 하지만 금방 한계에 부딪혔습니다.</p>
<ul>
<li><strong>사전 지시만으로는 부족합니다:</strong> 요청 자체가 기존 사내 정책과 충돌하는지 코드를 만들기 전에 감지할 수 없습니다.</li>
<li><strong>정적 분석만으로는 부족합니다:</strong> ESLint나 SonarQube는 문법과 스타일은 잡아내지만, &quot;이 코드가 애초에 기획 의도와 맞는가?&quot;는 판단하지 못합니다.</li>
<li><strong>문서 도구만으로는 부족합니다:</strong> README나 Notion은 결국 사람이 따로 써야 합니다. 바쁘면 가장 먼저 생략되는 작업 1순위죠.</li>
</ul>
<p>즉, 단순한 파편화된 도구가 아니라 <strong>코드 생성의 흐름 자체를 제어하는 &#39;파이프라인&#39;</strong>이 필요했습니다.</p>
<hr>
<h2 id="3-vibeops-생성-전후에-품질-게이트를-세우다">3. VibeOps: 생성 전후에 품질 게이트를 세우다</h2>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/0e938fc5-90a7-428a-a016-d501962be377/image.jpeg" alt="5단계 파이프라인"></p>
<p>해결책은 DevOps의 개념을 빌려온 5단계 파이프라인, <strong>VibeOps</strong>였습니다.</p>
<h3 id="🔒-생성-전-제어-spec--verify">🔒 생성 전 제어 (Spec &amp; Verify)</h3>
<ul>
<li><strong>Stage 1. Spec Gate</strong>: &quot;로그인 만들어줘&quot;라는 모호한 요청을 즉시 구조화된 YAML 스펙(JWT 발급, bcrypt 해싱 등)으로 변환합니다. AI가 멋대로 구현하기 전에, <strong>코드가 아닌 스펙을 먼저 확정</strong>합니다.</li>
<li><strong>Stage 2. Verify Gate</strong>: 새로운 요청이 기존 정책과 충돌하는지 사전 검사합니다. &quot;소셜 로그인 추가&quot;를 요청했을 때 사내 규정에 <code>OAuth 금지</code>가 있다면, 엉뚱한 코드를 짜기 전에 경고를 띄웁니다.</li>
</ul>
<h3 id="⚙️-코드-생성-및-검증-generate--validate">⚙️ 코드 생성 및 검증 (Generate &amp; Validate)</h3>
<ul>
<li><strong>Stage 3. Generate</strong>: 단순 프롬프트가 아니라 <code>확정된 스펙 + 기존 결정 사항 + 프로젝트 컨텍스트</code>를 종합하여 코드를 생성합니다.</li>
<li><strong>Stage 4. Validate Gate</strong>: 문법 검사를 넘어, 방금 생성된 코드가 Stage 1에서 합의한 스펙을 완벽히 따르고 있는지, 금지된 정책을 쓰진 않았는지 대조 검증합니다.</li>
</ul>
<h3 id="📚-영구적-맥락-보존-auto-document">📚 영구적 맥락 보존 (Auto Document)</h3>
<ul>
<li><strong>Stage 5. Auto Document</strong>: 이 모든 스펙, 결정, 제약 조건이 프로젝트 내 <code>.vibe</code> 디렉토리에 자동 저장됩니다. 터미널에 <code>vibe why src/auth/login.py</code>를 입력하면 &quot;왜 JWT를 썼고, 왜 소셜 로그인은 뺐는지&quot; 과거의 결정 맥락을 즉시 꺼내볼 수 있도록 구상했습니다.</li>
</ul>
<hr>
<h2 id="4-어디까지-구현했는가-냉정한-poc-회고">4. 어디까지 구현했는가? (냉정한 PoC 회고)</h2>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/23466c90-27d6-465f-8ea4-5b4bc39da507/image.jpeg" alt=""></p>
<p>글이 너무 과장되는 것을 경계하고자 합니다. 이 프로젝트는 완성된 상용 툴이 아닌 <strong>PoC</strong>였으며, 제가 실제로 해커톤 기간 내에 구현한 범위는 다음과 같습니다.</p>
<p><strong>✅ 구현 완료 (PoC 범위)</strong></p>
<ul>
<li><code>.vibe/context.yaml</code>, <code>constraints.yaml</code> 등 환경 파일 로드 로직</li>
<li>프로젝트 컨텍스트 기반의 프롬프트 조합</li>
<li>키워드 기반의 제약 조건 위반 감지 시스템</li>
<li><code>vibe init</code> 형태의 초기 템플릿 생성</li>
<li>전체 파이프라인 흐름을 시각화한 웹 데모</li>
</ul>
<p><strong>🚧 미구현 / 과제</strong></p>
<ul>
<li>가장 강력한 무기로 기획했던 <code>vibe why</code>의 실제 히스토리 추적 및 출력 로직</li>
<li>구문 분석과 스펙 대조를 아우르는 고도화된 Validate 엔진</li>
<li>실제 IDE와 매끄럽게 연동되는 전체 CLI 흐름</li>
</ul>
<hr>
<h2 id="5-실무에-도입된다면-가설-시나리오">5. 실무에 도입된다면? (가설 시나리오)</h2>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/1bf50cdf-2120-4b95-b17f-1d0ffbfe165e/image.jpeg" alt="실시간 데모"></p>
<p>비록 PoC 단계지만, 이 파이프라인이 실제 팀에 도입된다면 분명한 임팩트를 낼 수 있다고 가설을 세웠습니다.</p>
<ul>
<li><strong>정책 위반 사전 차단</strong>: AI가 금지된 OAuth 코드를 잔뜩 생성해버려, 나중에 PR 리뷰에서 걸려 4시간을 통으로 날리는 헛수고를 방지합니다. <strong>검증 게이트가 코드 생성 전에 충돌을 감지해 올바른 방향을 제시할 수 있습니다.</strong></li>
<li><strong>신규 팀원 온보딩 단축</strong>: 레거시 코드를 보며 &quot;선배님, 이건 왜 이렇게 만들었어요?&quot;라고 묻는 대신, 스펙 히스토리를 직접 조회해 개발의 맥락을 스스로 빠르게 흡수할 수 있습니다.</li>
</ul>
<hr>
<h2 id="6-심사위원을-설득하지-못한-이유와-배움">6. 심사위원을 설득하지 못한 이유와 배움</h2>
<p>야심 찬 기획이었지만 결과적으로 탈락했습니다. 스스로 분석해 본 패인은 명확합니다.</p>
<ol>
<li><strong>기획과 구현 사이의 간극</strong>: &quot;스펙을 자동 문서화하고 <code>vibe why</code>로 꺼내본다&quot;는 메시지는 강렬했지만, 그것이 실제로 매끄럽게 동작하는 완벽한 데모를 보여주기엔 구현의 완성도가 턱없이 부족했습니다.</li>
<li><strong>실사용 검증(Data)의 부재</strong>: &quot;시간을 줄일 수 있다&quot;는 논리를 넘어, 실제로 이 CLI 툴을 소규모 팀 저장소에 붙여봤더니 &quot;이만큼의 재작업이 방지되더라&quot;는 날것의 데이터가 있었다면 훨씬 설득력이 있었을 것입니다.</li>
</ol>
<p>비록 해커톤 수상 목록에는 이름을 올리지 못했지만, 개발자로서 제 시야는 한층 넓어졌습니다.</p>
<p>AI가 아무리 코드를 눈부신 속도로 뽑아내는 시대가 오더라도, <strong>&quot;무엇을 만들지 명확히 정의(Spec)하고, 시스템적으로 검증(Verify)하며, 그 결정의 이유를 기록(Document)한다&quot;</strong>는 소프트웨어 엔지니어링의 본질은 절대 변하지 않을 것입니다. 오히려 코딩 속도가 빨라질수록, 이런 &#39;품질 게이트&#39;의 가치는 더욱 빛을 발하겠죠.</p>
<p>이번 경험을 거름 삼아, 앞으로는 기획을 넘어 <strong>&quot;실제로 현장에서 작동하는 도구&quot;</strong>를 깎아내는 데 더 집중해보려 합니다.</p>
<p>긴 글 읽어주셔서 감사합니다. 아이디어에 대한 여러분의 다양한 피드백과 논의는 언제든 대환영입니다! 🚀</p>
<p>🔗 <strong>관련 링크</strong></p>
<ul>
<li><strong>GitHub</strong>: <a href="https://github.com/Lova-clover/VibeOps">Lova-clover/VibeOps</a></li>
<li><strong>Demo</strong>: <a href="https://vibeops-rho.vercel.app/">VibeOps Vercel Deploy</a></li>
<li><strong>기획서 1차</strong>: <a href="https://daker.ai/public/hackathons/vibe-coding-improvement-ai-idea-competition/submissions/66915008-d2f1-4155-aa22-e57064b41b50">VibeOps - 바이브 코딩을 위한 품질 파이프라인</a></li>
<li><strong>기획서 2차(발표자료)</strong>: <a href="https://daker.ai/public/hackathons/vibe-coding-improvement-ai-idea-competition/submissions/94f20f0f-3981-46c2-8cd5-5a1f3460dc81">VibeOps - 바이브 코딩을 위한 품질 파이프라인</a></li>
<li><strong>대회사이트</strong>: <a href="https://daker.ai/public/hackathons/vibe-coding-improvement-ai-idea-competition">월간 해커톤: 바이브 코딩 개선 AI 아이디어 공모전</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[기능은 늘었는데, 왜 서비스는 더 불편해졌을까?]]></title>
            <link>https://velog.io/@lova-clover/%EA%B8%B0%EB%8A%A5%EC%9D%80-%EB%8A%98%EC%97%88%EB%8A%94%EB%8D%B0-%EC%99%9C-%EC%84%9C%EB%B9%84%EC%8A%A4%EB%8A%94-%EB%8D%94-%EB%B6%88%ED%8E%B8%ED%95%B4%EC%A1%8C%EC%9D%84%EA%B9%8C-yupab322</link>
            <guid>https://velog.io/@lova-clover/%EA%B8%B0%EB%8A%A5%EC%9D%80-%EB%8A%98%EC%97%88%EB%8A%94%EB%8D%B0-%EC%99%9C-%EC%84%9C%EB%B9%84%EC%8A%A4%EB%8A%94-%EB%8D%94-%EB%B6%88%ED%8E%B8%ED%95%B4%EC%A1%8C%EC%9D%84%EA%B9%8C-yupab322</guid>
            <pubDate>Sun, 08 Mar 2026 03:12:48 GMT</pubDate>
            <description><![CDATA[<p>서비스를 만들다 보면 어이없는 순간을 마주하게 된다.</p>
<p>분명 예전보다 더 열심히 짰고,
기능도 잔뜩 넣었고,
설명도 최대한 친절하게 썼고,
예외 케이스도 다 커버했는데…</p>
<p>막상 써보면 이상하게 <strong>더 불편해진</strong> 느낌이 드는 것이다.</p>
<p>처음엔 진심으로 이해가 안 됐다.
“기능이 이렇게 많아졌는데 왜 더 별로지?”
“이 정도면 당연히 쓰기 좋아졌어야 하는 거 아냐?”
“나 진짜 밤새워서 열심히 했는데, 왜 유저는 피곤해하지?”</p>
<p>요즘 프로젝트를 정리하면서 이 생각이 계속 맴돌았는데, 
결국 내 착각이었다는 걸 한 문장으로 깨달았다.</p>
<blockquote>
<p>아, 좋은 서비스는 기능을 더 구겨 넣는 게 아니라,
사용자가 망설이는 순간을 지워주는 것이구나. </p>
</blockquote>
<hr>
<h3 id="👀-사람들은-기능보다-느낌을-먼저-기억한다">👀 사람들은 기능보다 ‘느낌’을 먼저 기억한다</h3>
<p>예전엔 나도 서비스를 설명할 때 기능부터 죽 나열했다.
“이 기술 썼고요, 이건 자동화됐고요, 여기까지 지원합니다.”</p>
<p>그런데 막상 내가 다른 앱을 쓸 때나 유저들 반응을 보면, 
그 기능표를 하나도 기억하지 않았다.</p>
<p>그냥
편했는지,
괜히 결제될까 봐 긴장되진 않았는지,
처음 들어왔을 때 대충 감이 왔는지,
생각할 게 많아서 피곤했는지.</p>
<p>딱 이런 감정들만 훨씬 오래 남았다.</p>
<p>진짜 잘 만든 서비스는 유저에게 “와, 기능 미쳤다” 소리를 듣는 게 아니라, 
“어? 이거 왜 이렇게 편하지?” 하게 만들더라.</p>
<p>평소 자주 쓰는 앱들을 떠올려 보면 다 비슷하다. 
처음 들어가도 뭘 해야 할지 금방 보이고, 굳이 설명서를 안 찾아봐도 되고, 
버튼을 누를 때 왠지 마음이 편안하다.</p>
<p>반대로 기능은 화려한데 이상하게 손이 안 가는 서비스들도 많았다. 
선택지가 너무 많아서 오히려 결정을 못 하겠고, 설명은 친절한데 구조가 엉망이라 “이거 누르는 거 맞나?” 하며 한 번 더 멈칫하게 된다.</p>
<p>결국 사람들은 기능을 소비하는 게 아니라, 
그 기능이 주는 <strong>느낌</strong>을 기억하는 거였다. 
오래 남는 건 기능의 개수가 아니라 “이 서비스 덕분에 내가 덜 지쳤구나” 하는 기억이다.</p>
<hr>
<h3 id="💡-좋은-서비스는-유저의-생각-비용을-대신-내준다">💡 좋은 서비스는 유저의 ‘생각 비용’을 대신 내준다</h3>
<p>개발을 하다 보면 욕심이 생기는 건 어쩔 수 없다. 나도 매번 그러니까.
“이 기능도 넣으면 대박이겠다”, “여기까지 온 김에 저것도…” 이러면서 말이다.</p>
<p>그런데 기능을 늘릴수록 서비스가 좋아지는 건 절대 아니었다. 오히려 덕지덕지 붙어서 더 무거워지는 경우가 훨씬 많았다.</p>
<p>그래서 요즘은 코드 한 줄을 더 짜기 전에 꼭 스스로에게 묻는다.</p>
<blockquote>
<p>이거 진짜 유저를 편하게 해주는 걸까?
아니면 그냥 내 눈에 그럴듯해 보이려고, 
유저한테 생각할 거리 하나 더 던져주는 걸까?</p>
</blockquote>
<p>솔직히 많은 기능들이 “있으면 멋져 보이는” 수준에서 끝났다. 
그런데 진짜 오래, 자주 쓰이는 핵심 기능들은 완전 다른 쪽에 있었다.</p>
<p>지금 당장 필요한 정보가 제일 먼저 눈에 띄게 해주고, 다음에 뭘 해야 할지 고민 안 하게 길을 터주고, 실수할까 봐 불안한 마음을 덜어주고, 잘못 눌러도 “아, 괜찮아” 하며 원래대로 돌아올 수 있게 해주는 것.</p>
<p>좋은 서비스는 튜토리얼을 빵빵하게 넣어서 유저를 똑똑하게 훈련시키려 들지 않는다. 그냥 유저가 <strong>덜 피곤하게, 더 자연스럽게</strong> 움직일 수 있도록 보이지 않는 곳에서 대신 짐을 들어줄 뿐이다.</p>
<hr>
<h3 id="🏄♂️-사람들은-기능을-하나하나-쓰는-게-아니라-흐름을-탄다">🏄‍♂️ 사람들은 기능을 하나하나 쓰는 게 아니라 흐름을 탄다</h3>
<p><strong>예전엔 나도 기능을 예쁘게 잘 나열해두면 유저가 알아서 쏙쏙 뽑아 쓸 줄 알았다.</strong></p>
<p>입력 → 처리 → 출력.
클릭 → 결과 → 다음.</p>
<p>개발자 머릿속에선 이 구조가 제일 직관적이고 깔끔하니까. 그런데 아니었다. 사람들은 내 생각처럼 기능을 하나하나 분석하면서 쓰지 않았다. 그냥 전체적인 &#39;흐름&#39;이라는 물결 위에 스르륵 올라탈 뿐이었다.</p>
<p>처음 화면에서 “아 이거 누르면 되는구나” 바로 감이 오는지, 중간에 턱턱 막히는 방지턱은 없는지, 다음 행동이 물 흐르듯 이어지는지.</p>
<p>그걸 깨닫고 나니까 서비스를 바라보는 시선이 완전히 바뀌었다.
<strong>“이 기능 좋은데?” 보다 “화면 넘어가는 흐름이 부드러운가?”를 먼저 보게 되더라.</strong></p>
<p>이 눈으로 다시 보니까 예전엔 미처 못 봤던 게 보였다. 겉보기엔 예뻤던 화면이 갑자기 되게 답답해 보이고, 엄청 친절하게 썼다고 자부했던 설명문이 사실은 앱 구조가 너무 약해서 구구절절 변명하는 거였다는 걸 깨달았다.</p>
<p>진짜 좋은 서비스 흐름은 사람을 시험하지 않는다. 그냥 유저가 화면이 넘어갔는지 의식조차 못한 채 끝까지 가게 만들어버린다. 난 그게 제일 무서운 실력이라고 느꼈다.</p>
<hr>
<h3 id="🧹-좋은-화면은-꽉-채운-게-아니라-싹-덜어낸-것이다">🧹 좋은 화면은 꽉 채운 게 아니라 싹 덜어낸 것이다</h3>
<p>프로젝트를 진행하면서 제일 많이, 끝까지 수정하는 게 결국 화면이다. 
기능이 아무리 완벽해도 유저가 만나는 최전선은 화면이니까.</p>
<p>예전의 나는 “최대한 더 잘 설명해야지!” 하는 마음이 컸다. 정보도 빈틈없이 꽉꽉 채워주고, 밤새워 만든 기능 하나라도 놓칠세라 툴팁을 띄워주고, 최대한 친절하게 만들려 했다.</p>
<p>그런데 내가 만든 걸 유저들이 쓰는 걸 지켜보면서 뼈저리게 깨달았다. 유저들은 내 생각보다 훨씬 빨리 훑어보고, 훨씬 빨리 피곤해하고, 아주 조금만 애매해도 그냥 멈춰버렸다.</p>
<p>그래서 이제 화면을 짤 때 제일 먼저 드는 생각은 “여기에 뭘 더 넣을까?”가 아니라 <strong>“뭐부터 치워버릴까?”</strong>가 됐다.</p>
<p>화면에 뭐가 많고 화려한 게 중요한 게 아니었다. 딱 지금 이 순간 유저가 알아야 할 것만 남기고, 굳이 지금 안 해도 되는 고민은 싹 다 가려주는 화면.</p>
<p>처음 봤을 때 대충 감이 오고, 쓸데없는 긴장감을 주지 않는 화면. 과한 설명보다 아예 생각할 거리를 없애주는 게 유저를 위한 진짜 배려라는 걸 알게 됐다.</p>
<hr>
<h3 id="🤝-화려한-기술보다-끝까지-살아남는-건-신뢰다">🤝 화려한 기술보다 끝까지 살아남는 건 ‘신뢰’다</h3>
<p>요즘은 기술 발전이 워낙 빨라서 맘만 먹으면 그럴듯한 걸 뚝딱 만들 수 있다.</p>
<p>그런데 <strong>&#39;똑똑해 보이는 것&#39;이랑 &#39;내어주고 싶을 만큼 믿음이 가는 것&#39;은 완전히 다른 문제</strong>였다.</p>
<p>결과물이 아무리 화려하게 나와도 “이게 대체 어떻게 처리된 거지?” 하고 감이 안 오거나, 에러가 났을 때 대처가 엉망이어서 자꾸 사람을 당황시키면 절대 두 번은 켜지 않게 된다.</p>
<p>신뢰라는 게 되게 거창한 데서 오는 줄 알았는데 아니었다. 말투가 차분한지, 화면 넘어가는 흐름이 일관적인지, 갑자기 이상한 곳을 눌러도 앱이 내 통제 안에 있다는 안도감을 주는지.</p>
<p>이런 아주 사소한 디테일들이 겹겹이 쌓여서 “아, 여기 괜찮네. 믿고 써도 되겠다” 하는 묵직한 감정을 만든다.</p>
<hr>
<h3 id="😅-결국-메이커의-만족은-더하기에-있었고-서비스의-완성은-덜어내기에-있었다">😅 결국 메이커의 만족은 &#39;더하기&#39;에 있었고, 서비스의 완성은 &#39;덜어내기&#39;에 있었다</h3>
<p>서비스를 계속 만들어보면서 점점 확신이 생기는 게 하나 있다.</p>
<p>진짜 잘 만든 프로덕트는 무언가를 끝없이 덧칠해서 완성되는 게 아니라, 
필요 없는 걸 뼈 깎는 심정으로 덜어내면서 확 선명해진다는 것이다.</p>
<p>솔직히 더 넣는 건 진짜 쉬웠다. 
그런데 빼는 건 너무 어려웠다. 
내가 고생해서 짠 코드를 포기해야 하고, 진짜 애착 가졌던 기발한 요소도 뒤로 미뤄야 하니까.</p>
<p>그런데 눈 딱 감고 그 과정을 넘기고 나면, 서비스가 놀라울 정도로 가벼워지고 단단해지는 걸 느꼈다. 과감하게 빼냈다는 건 곧 “이 서비스에서 진짜 뾰족하게 가져가야 할 게 뭔지 완벽하게 안다”는 증거이기도 하다.</p>
<p>모든 걸 다 보여주려는 욕심을 버리고, 딱 필요한 순간에 필요한 것만 조용히 내밀어서 유저가 쓸데없는 에너지를 안 쓰게 지켜주는 것. 나는 이제 이게 메이커의 진짜 실력이라고 믿는다.</p>
<hr>
<h3 id="✅-내가-지금도-매번-체크하는-5가지">✅ 내가 지금도 매번 체크하는 5가지</h3>
<p>요즘은 기획서나 화면을 볼 때 딱 이 다섯 개부터 스스로 묻는다.</p>
<ol>
<li>첫 화면 3초 안에 “아, 여기서 이거 해야 하는구나” 감이 오는가?</li>
<li>다음에 할 행동이 직관적으로 보이는가, 아니면 선택지가 너무 많아서 멈칫하게 되는가?</li>
<li>설명이 길다면 이게 진짜 친절한 건가, 아니면 앱 구조가 엉망이라 말이 길어진 건가?</li>
<li>완전 잘못 눌렀을 때도 유저가 당황하지 않고 원래대로 돌아올 수 있는가?</li>
<li>이 기능이 진짜 유저를 편하게 해주는가, 아니면 생각할 거리 하나를 더 얹어주는가?</li>
</ol>
<hr>
<h3 id="🌙-마무리하며">🌙 마무리하며</h3>
<p>이번 프로젝트를 거치면서 또 한 번 뼛속 깊이 확인한 건 진짜 단순했다.</p>
<p>사람들은 우리가 짠 기능 자체를 사랑하는 게 아니었다. 유저들이 진심으로 좋아하고 오래 곁에 두는 건 결국 이해하기 쉽고, 믿음이 가고, 쓸 때 덜 피곤한 경험이었다.</p>
<p>그래서 진짜 좋은 서비스는 &#39;더 많은 걸 할 수 있게 뽐내는 곳&#39;이 아니라,
<strong>&#39;유저의 망설임을 조용히 지워주는 곳&#39;</strong>이라고 확신하게 됐다.</p>
<p>아마 앞으로도 내가 무언가를 새로 만들 때 제일 먼저 들이대는 잣대는 비슷할 것 같다. 내 기능이 얼마나 대단해 보이냐가 아니라, 이 전체적인 흐름이 사람을 얼마나 편안하게 만들어 주냐일 것이다.</p>
<p>결국 끝까지 살아남고 내 폰에 오래 남는 건, 
똑똑해 보여서 피곤한 앱보다 왠지 모르게 손이 가는 편안한 서비스니까. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] 지혜나눔터, 기획·MVP까지 했는데 공모전에서 떨어진 이유 🤔]]></title>
            <link>https://velog.io/@lova-clover/%ED%9A%8C%EA%B3%A0-%EC%A7%80%ED%98%9C%EB%82%98%EB%88%94%ED%84%B0-%EA%B8%B0%ED%9A%8DMVP%EA%B9%8C%EC%A7%80-%ED%96%88%EB%8A%94%EB%8D%B0-%EA%B3%B5%EB%AA%A8%EC%A0%84%EC%97%90%EC%84%9C-%EB%96%A8%EC%96%B4%EC%A7%84-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@lova-clover/%ED%9A%8C%EA%B3%A0-%EC%A7%80%ED%98%9C%EB%82%98%EB%88%94%ED%84%B0-%EA%B8%B0%ED%9A%8DMVP%EA%B9%8C%EC%A7%80-%ED%96%88%EB%8A%94%EB%8D%B0-%EA%B3%B5%EB%AA%A8%EC%A0%84%EC%97%90%EC%84%9C-%EB%96%A8%EC%96%B4%EC%A7%84-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Tue, 03 Mar 2026 03:42:48 GMT</pubDate>
            <description><![CDATA[<p>2026년 1월 25일,<br>저는 <strong>G-AFC 고령친화 아이디어 공모전</strong>에 <code>지혜나눔터</code>를 제출했습니다.</p>
<p>결과는 아쉽게도 <strong>탈락</strong>.  
그래도 이번 경험은 실패라기보다, 다음 시도를 위한 데이터에 더 가까웠습니다.<br>오늘은 그 과정을 솔직하게 남겨보려 합니다. 🙂</p>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/4636bbc4-951b-4ee9-92cb-1d9bf8e9a34a/image.png" alt="지혜나눔터 공모전 제출 표지"></p>
<hr>
<h2 id="1-왜-이-아이디어였나-🧓👩🎓">1. 왜 이 아이디어였나 🧓👩‍🎓</h2>
<p>출발점은 단순했습니다.</p>
<blockquote>
<p>“어르신은 도움을 받는 대상”이라는 익숙한 프레임을<br>“어르신은 지혜를 전하는 선생님”으로 바꿔보자.</p>
</blockquote>
<p><code>지혜나눔터</code>는 안동·예천 지역 어르신의 삶의 기술(전통음식, 예절·다도, 텃밭농사, 공예)을 대학생에게 연결하는 세대교류 프로그램입니다.</p>
<p>핵심은 봉사가 아니라 <strong>역할 전환</strong>이었습니다.</p>
<ul>
<li>어르신: 수혜자 → 멘토</li>
<li>대학생: 봉사자 → 학습자</li>
<li>지역사회: 단절 → 전승</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/411e5bca-c0a0-455b-b21b-2ea4996acf97/image.jpeg" alt="관점의 전환"></p>
<hr>
<h2 id="2-실제로-어디까지-만들었나-💻">2. 실제로 어디까지 만들었나 💻</h2>
<p>아이디어 문서로 끝내지 않고, MVP까지 구현했습니다.</p>
<p>기술 스택:</p>
<ul>
<li>FastAPI</li>
<li>SQLAlchemy</li>
<li>SQLite</li>
<li>Jinja2</li>
<li>Tailwind CSS</li>
</ul>
<p>구현 기능:</p>
<ul>
<li>홈</li>
<li>프로그램 목록/상세</li>
<li>멘토 목록/상세</li>
<li>멘토 등록</li>
<li>수강 신청(중복 신청, 정원 마감 처리)</li>
<li>관리자 대시보드</li>
<li>관리자 수강 승인/수료 처리</li>
</ul>
<p>시연용 데이터:</p>
<ul>
<li>멘토 5명</li>
<li>프로그램 6개</li>
<li>학생 4명</li>
<li>신청 5건</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/dce2ee4a-4a6f-41e8-a610-d5ad01ae9340/image.jpeg" alt="homepage"></p>
<ul>
<li>홈페이지</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/d7fc67f8-3762-4673-bff7-1c844fda9cf0/image.jpeg" alt="program"></p>
<ul>
<li>교육 프로그램 페이지</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/49355ce2-9e2b-40c3-b5c3-575b92c8a9a5/image.jpeg" alt="mentor"></p>
<ul>
<li>멘토 페이지</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/e292f973-b96d-43c2-969d-86f5a5872c8c/image.jpeg" alt="mentor_register"></p>
<ul>
<li>멘토 등록 페이지</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/9869e860-dd32-40ae-a0ac-847bbf1e83ea/image.jpeg" alt="admin_dashboard"></p>
<ul>
<li>G-AFC 관리자 대시보드</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/fa96c06f-9853-4b7d-96fd-34454bf1de89/image.jpeg" alt="course_registration_management"></p>
<ul>
<li>수강 신청 관리 페이지</li>
</ul>
<hr>
<h2 id="3-그런데-왜-떨어졌을까-제-해석-🤔">3. 그런데 왜 떨어졌을까? (제 해석) 🤔</h2>
<p>심사 피드백을 모두 받은 건 아니지만, 제출물을 다시 보면 아쉬움은 명확했습니다.</p>
<ul>
<li><strong>실증 데이터 부족</strong>: 사용자 인터뷰, 파일럿 운영 결과, 재참여율 같은 근거가 약했습니다.</li>
<li><strong>실행 설계의 밀도 부족</strong>: 운영 계획은 있었지만 리스크 대응과 지속 가능성 설계가 더 필요했습니다.</li>
<li><strong>평가 언어의 부족</strong>: “잘 만들었다”보다 “왜 효과가 나는지”를 더 분명하게 증명했어야 했습니다.</li>
</ul>
<p>정리하면,<br><strong>만드는 힘은 보여줬지만 증명하는 힘은 부족했다</strong>는 결론입니다.</p>
<hr>
<h2 id="4-이번에-확실히-배운-것-📌">4. 이번에 확실히 배운 것 📌</h2>
<ul>
<li>공모전은 좋은 생각보다 <strong>검증된 가설</strong>이 강하다.</li>
<li>MVP는 끝이 아니라 시작이다. <strong>사용자 반응 데이터</strong>가 본게임이다.</li>
<li>감동적인 스토리와 냉정한 수치는 같이 가야 한다.</li>
<li>“얼마나 만들었는가”보다 “왜 효과가 나는가”를 먼저 보여줘야 한다.</li>
</ul>
<hr>
<h2 id="5-다음-도전에서-바꿀-것-🚀">5. 다음 도전에서 바꿀 것 🚀</h2>
<ul>
<li>최소 10명 이상 사용자 인터뷰 선행</li>
<li>4~8주 소규모 파일럿 운영</li>
<li>전/후 변화 지표 설계(만족도, 재참여율, 관계 형성)</li>
<li>심사 기준 역산형 문서 구성</li>
<li>데모 + 데이터 + 운영 시나리오를 한 세트로 제출</li>
</ul>
<hr>
<h2 id="마무리-🙏">마무리 🙏</h2>
<p>떨어진 건 사실이지만,<br>이번 프로젝트를 통해 확신한 건 분명합니다.</p>
<p><strong>어르신의 경험은 복지의 대상이 아니라 사회의 자산</strong>이라는 것.<br>그리고 그 자산을 연결하는 방식은 꼭 필요하다는 것.</p>
<p>지혜나눔터는 여기서 끝내지 않겠습니다.<br>다음엔 더 단단한 근거와 더 좋은 실행으로 다시 도전하겠습니다.</p>
<p>읽어주셔서 감사합니다. 🙌</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DevHistory] 토이에서 서비스로, 배포 직전 트러블슈팅 정리]]></title>
            <link>https://velog.io/@lova-clover/DevHistory-%ED%86%A0%EC%9D%B4%EC%97%90%EC%84%9C-%EC%84%9C%EB%B9%84%EC%8A%A4%EB%A1%9C-%EB%B0%B0%ED%8F%AC-%EC%A7%81%EC%A0%84-%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@lova-clover/DevHistory-%ED%86%A0%EC%9D%B4%EC%97%90%EC%84%9C-%EC%84%9C%EB%B9%84%EC%8A%A4%EB%A1%9C-%EB%B0%B0%ED%8F%AC-%EC%A7%81%EC%A0%84-%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 01 Mar 2026 09:26:31 GMT</pubDate>
            <description><![CDATA[<p>지난 글(2025년 11월 30일)에서는 DevHistory의 기본 흐름을 만들었습니다.</p>
<p>GitHub, solved.ac, Velog 데이터를 모아서 대시보드로 보고, 블로그 초안 만들고, 포트폴리오까지 뽑아내는 구조였습니다.</p>
<p>그때는 솔직히 이렇게 생각했습니다.</p>
<p><strong>“기능은 다 돌아가네. 이제 서버에 올리고 배포만 하면 되겠다.”</strong></p>
<p>하지만 완벽한 착각이었습니다. 실제로 계속 돌려보니, 개발 시간보다 더 많이 든 건 전혀 다른 쪽이었습니다.</p>
<p>새로운 기능을 화려하게 추가하는 일보다, 이미 있는 기능이 <strong>실제 환경에서 끝까지 동작하는지</strong> 확인하고, 실패했을 때 사용자에게 <strong>현재 상태를 납득시키는 작업</strong>이 훨씬 어렵고 오래 걸렸습니다.</p>
<p>이번 글은 토이 프로젝트를 실제 서비스로 다듬어가는 안정화 과정의 기록입니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/7a4912f6-d8e1-4628-9ae3-960ef91385c6/image.png" alt="DevHistory 홈페이지"></p>
<blockquote>
<p><strong>서비스 첫 진입 화면</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/ceacfb63-66f3-4899-b835-7ce8d63fbd72/image.png" alt="DevHistory 대시보드"></p>
<blockquote>
<p><strong>수집된 데이터를 한눈에 확인하는 대시보드</strong></p>
</blockquote>
<hr>
<h2 id="1-2025-11-30-기준-이미-되던-것들">1) 2025-11-30 기준, 이미 되던 것들</h2>
<p>당시에는 아래 파이프라인이 동작했습니다.</p>
<ul>
<li>GitHub OAuth 로그인</li>
<li>GitHub / solved.ac / Velog 데이터 동기화</li>
<li>대시보드 지표/차트 렌더링</li>
<li>레포 기반 블로그 초안 생성</li>
<li>포트폴리오 페이지 + PDF 내보내기</li>
</ul>
<p>즉, <code>수집 → 집계 → 생성 → 출력</code>의 큰 뼈대는 완성돼 있었습니다.</p>
<p>이후의 과제는 <strong>“왜 가끔 안 되는지”, “안 될 때 사용자에게 어떻게 보이는지”</strong>의 구멍을 메우는 것이었습니다.</p>
<hr>
<h2 id="2-이번-사이클에서-크게-바뀐-점">2) 이번 사이클에서 크게 바뀐 점</h2>
<h3 id="2-1-생성-ux-비동기-흐름-정리">2-1. 생성 UX: 비동기 흐름 정리</h3>
<p>코딩 코치(퀴즈 생성)나 AI 글쓰기 기능에서 아주 치명적인 UX 문제가 있었습니다.</p>
<ul>
<li>생성 버튼 클릭</li>
<li>한참을 돌다가 <strong>실패 메시지</strong> 팝업</li>
<li>그런데 결과 목록을 새로고침해보면 <strong>이미 생성되어 있음</strong></li>
</ul>
<p>원인은 백엔드 처리 완료 시점과 프론트엔드의 타임아웃 기준이 엇갈렸기 때문입니다. 백엔드는 일을 끝냈는데 프론트가 먼저 지쳐버린 거죠.</p>
<p>그래서 무작정 기다리는 동기 방식을 버리고, 비동기 폴링(Polling)으로 흐름을 바꿨습니다.</p>
<ol>
<li>초기 요청 시 대기하지 않고 <code>task_id</code>만 즉시 반환</li>
<li>프론트에서 폴링으로 백그라운드 상태 확인</li>
<li>완료되면 즉시 화면에 렌더링</li>
</ol>
<pre><code class="language-text">❌ [Before] 타임아웃 지옥
요청 전송 → 프론트 타임아웃(실패 팝업) → 백엔드 작업 뒤늦게 완료

✅ [After] 비동기 UX 안정화
task_id 반환 → 상태 폴링 → 완료 시 정상 반영
</code></pre>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/6010348b-017a-42d7-96ff-b581f4dd5df1/image.png" alt="코딩 코치 After"></p>
<hr>
<h3 id="2-2-인증보안-로그인-성공보다-운영-신뢰">2-2. 인증/보안: 로그인 &quot;성공&quot;보다 운영 &quot;신뢰&quot;</h3>
<p>초기에는 &quot;소셜 로그인이 뚫렸다&quot;는 사실 자체에 만족했습니다. 하지만 배포를 앞두고 기준을 엄격하게 올렸습니다.</p>
<ul>
<li><code>httpOnly</code> 쿠키 중심의 안전한 인증 흐름</li>
<li>로그인/로그아웃 세션 동선 명확화</li>
<li>사용자별 BYO LLM API Key 저장/검증/테스트/삭제</li>
<li>API Key 암호화 저장 보완</li>
</ul>
<p>사용자가 자신의 API 키를 입력해야 하는 서비스 특성상, <strong>내 데이터와 키가 안전하다</strong>는 전제가 없으면 아무리 좋은 기능도 무용지물이기 때문입니다.</p>
<hr>
<h3 id="2-3-동기화-성공률보다-실패-가시성">2-3. 동기화: 성공률보다 실패 가시성</h3>
<p>데이터 동기화 버튼은 겉보기엔 단순하지만, 실패 시나리오를 어떻게 다루느냐에서 신뢰가 갈렸습니다.</p>
<ul>
<li>GitHub 소유 레포 기준(<code>owner</code>) 필터 검증 추가</li>
<li>로그인 직후 텅 빈 화면을 막기 위한 동기화 자동 큐잉</li>
<li>동기화 상태 및 <strong>실패 상황을 사용자 기준으로 확인 가능하게</strong> 개선</li>
</ul>
<p>성공 횟수보다 중요한 건, <strong>“실패했다면 왜 안 되는지 명확히 보여주는 것”</strong>이었습니다.</p>
<hr>
<h3 id="2-4-포트폴리오-개인-화면에서-공유-결과물로">2-4. 포트폴리오: 개인 화면에서 공유 결과물로</h3>
<p>포트폴리오는 혼자 뿌듯해하는 화면이 아니라, 남에게 전달되는 결과물입니다.</p>
<ul>
<li>공개 URL(<code>slug</code>) 및 비공개 토큰 링크 공유 기능</li>
<li>토큰 재발급/만료 관리 로직</li>
<li>이메일 등 민감 정보 공개 제어</li>
</ul>
<blockquote>
<p>특히 고민이 많았던 건 PDF 출력입니다. 
브라우저 환경에 따라 폰트나 레이아웃이 깨지는 변수를 통제하기 위해, 현재는 가장 안정적인 <strong>화면 캡처 방식의 PDF 저장</strong>을 우선 적용해 두었습니다. 당장의 &#39;실사용 안정성&#39;을 위해 타협한 부분이며, 향후 텍스트 보존성이 높은 네이티브 방식으로 고도화해 나갈 계획입니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/0cb6f2aa-732c-4569-8b7f-5e09984ec6b2/image.png" alt="포트폴리오 화면"></p>
<hr>
<h3 id="2-5-배포-준비-코드보다-운영-비중-증가">2-5. 배포 준비: 코드보다 운영 비중 증가</h3>
<p>이 시점부터는 IDE에서 코드를 치는 시간보다 인프라 세팅 비중이 훨씬 커졌습니다.</p>
<ul>
<li>프로덕션용 Docker Compose 작성</li>
<li>Caddy 기반 HTTPS 라우팅 및 인증서 설정</li>
<li>마이그레이션/운영/보안 문서 정리</li>
<li>환경변수/쿠키 도메인/OAuth 콜백 최종 점검</li>
</ul>
<p>직접 겪어보니 배포는 &quot;코드가 실행된다&quot;의 문제가 아니라, <strong>&quot;장애 발생 시 어떻게 확인하고 복구할 것인가&quot;</strong>를 준비하는 과정이었습니다.</p>
<hr>
<h3 id="2-6-현실적인-고민-devhistorykr--oracle-free-tier">2-6. 현실적인 고민: <code>devhistory.kr</code> + Oracle Free Tier</h3>
<p>로컬 개발이 끝나고 운영 현실의 벽과도 마주했습니다.</p>
<ul>
<li><code>devhistory.kr</code> 도메인 도입 검토</li>
<li>서버 비용 방어를 위한 Oracle Cloud Free Tier 등록 시도</li>
</ul>
<blockquote>
<p>악명 높은 오라클 가입 단계에서 막히는 케이스가 계속 반복됐습니다. 
그래서 무작정 &#39;무료&#39;에 시간을 쏟기보다는, 약간의 비용을 감수하더라도 예측 가능하고 바로 구축할 수 있는 다른 인프라 대안도 함께 검토하고 있습니다.</p>
</blockquote>
<hr>
<h2 id="3-이번-구간에서-배운-것-5가지">3) 이번 구간에서 배운 것 5가지</h2>
<ol>
<li>새로운 기능 추가보다 <strong>기존 기능의 실패 경험 감소</strong>가 우선이다.</li>
<li>비동기 처리는 백엔드 로직뿐 아니라 <strong>프론트 UX를 함께 설계</strong>해야 한다.</li>
<li>지표는 계산하는 것보다 <strong>정의를 통일</strong>하는 것이 먼저다.</li>
<li>PDF 출력은 단순 UI 기능이 아니라 <strong>렌더링 엔지니어링</strong> 이슈에 가깝다.</li>
<li>문서화는 개발 속도를 늦추지 않는다. 오히려 <strong>장애 복구 속도를 비약적으로 높인다.</strong></li>
</ol>
<hr>
<h2 id="4-현재-상태와-다음-단계">4) 현재 상태와 다음 단계</h2>
<p>현재 DevHistory는 아래 단계까지 완료되었습니다.</p>
<ul>
<li>수집 파이프라인 실사용 동작 검증</li>
<li>생성 기능 비동기 흐름 전면 개편</li>
<li>포트폴리오 공유/출력 품질 보강</li>
<li>운영 체크리스트 기반 배포 준비</li>
</ul>
<p>다음 단계는 실제 운영 환경에서 아래 항목들을 테스트하는 것입니다.</p>
<ul>
<li>도메인/DNS/HTTPS 최종 연결</li>
<li>OAuth 콜백/쿠키 도메인 정합성 확인</li>
<li>실사용 트래픽 기준 병목 확인</li>
</ul>
<hr>
<p>다음 글에서는 배포를 완료하고, 실제 트래픽을 받으며 겪은 <strong>운영 트러블슈팅 후기</strong>를 정리해 가져오겠습니다 🙌</p>
<p>혹시 사이드 프로젝트 배포하실 때 비슷한 고민을 해보셨거나, 추천하시는 인프라 조합이 있으시다면 댓글로 알려주세요! (오라클 프리티어와 사투 중입니다 😥)</p>
<p>배포 직전의 시행착오가 누군가에게 작은 참고가 되었으면 좋겠습니다.<br>재밌게 읽으셨다면 공감(💚) 부탁드립니다.</p>
<hr>
<h3 id="참고">참고</h3>
<ul>
<li>이전 글: <a href="https://velog.io/@lova-clover/DevHistory-%EA%B0%9C%EB%B0%9C-%ED%8F%AC%ED%8A%B8%ED%8F%B4%EB%A6%AC%EC%98%A4-%EC%9E%90%EB%8F%99%ED%99%94-%ED%94%8C%EB%9E%AB%ED%8F%BC-%EB%A7%8C%EB%93%A4%EA%B8%B0">DevHistory - 개발 포트폴리오 자동화 플랫폼 만들기</a></li>
<li>GitHub: <a href="https://github.com/Lova-clover/DevHistory">DevHistory</a>
```</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] 데이콘 피싱·스캠 예방 대회 예선 45위: 작동하는 MVP 'PhishShield' 개발기]]></title>
            <link>https://velog.io/@lova-clover/%ED%9A%8C%EA%B3%A0-%EB%8D%B0%EC%9D%B4%EC%BD%98-%ED%94%BC%EC%8B%B1%EC%8A%A4%EC%BA%A0-%EC%98%88%EB%B0%A9-%EB%8C%80%ED%9A%8C-%EC%98%88%EC%84%A0-45%EC%9C%84-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94-MVP-PhishShield-%EA%B0%9C%EB%B0%9C%EA%B8%B0</link>
            <guid>https://velog.io/@lova-clover/%ED%9A%8C%EA%B3%A0-%EB%8D%B0%EC%9D%B4%EC%BD%98-%ED%94%BC%EC%8B%B1%EC%8A%A4%EC%BA%A0-%EC%98%88%EB%B0%A9-%EB%8C%80%ED%9A%8C-%EC%98%88%EC%84%A0-45%EC%9C%84-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94-MVP-PhishShield-%EA%B0%9C%EB%B0%9C%EA%B8%B0</guid>
            <pubDate>Fri, 20 Feb 2026 16:19:08 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요. 데이콘에서 주최한 <strong>피싱·스캠 예방 서비스 개발 경진대회</strong>에 개인 참가자로 도전했던 경험을 공유합니다. 최종 성적은 104팀 중 45위로 본선 진출에는 실패했지만, <strong>기획부터 AI 모델링, 프론트엔드 구현, 그리고 Vercel에 배포까지 직접 완주한 MVP</strong>를 만들었습니다. 프로젝트 이름은 <strong>PhishShield</strong>로, 실제로 사용할 수 있는 보이스피싱 예방 서비스를 목표로 했습니다.</p>
<h2 id="1-문제-정의-피싱은-분류보다-행동의-문제">1. 문제 정의: 피싱은 ‘분류’보다 ‘행동’의 문제</h2>
<p>대회를 준비하면서 가장 먼저 떠올랐던 질문은 <strong>“피싱을 막는다는 게 단순히 메시지를 분류하는 일인가?”</strong>였습니다. 피싱 범죄의 핵심은 텍스트 자체보다 <strong>사람의 심리와 행동을 조작하는 구조</strong>입니다. 실제 사기 사례를 분석해 보면 다음과 같은 패턴이 결합돼 있습니다.</p>
<ul>
<li><strong>긴급성</strong>: “지금 바로 조치하지 않으면 큰일 난다”는 긴장감을 유발합니다.</li>
<li><strong>권위 사칭</strong>: 검찰·금감원·은행·가족을 사칭해 신뢰를 얻습니다.</li>
<li><strong>공포와 금전 요구</strong>: 계좌가 동결된다거나 가족이 다쳤다는 등 공포를 유도하고 송금이나 앱 설치를 요구합니다.</li>
<li><strong>즉각적인 행동 유도</strong>: 피해자가 이성적으로 판단할 시간을 주지 않고 링크 클릭, 앱 설치, 송금 등을 하도록 압박합니다.</li>
</ul>
<p>이처럼 피싱은 <strong>심리적 압박과 행동 유도</strong>가 맞물린 범죄라서, 단순히 “위험 확률”을 보여주는 것만으로는 실제 피해를 막기 어렵다고 판단했습니다. 따라서 저는 <strong>탐지 → 설명(왜 위험한지) → 행동 가이드</strong>로 이어지는 흐름을 MVP 목표로 설정했습니다.</p>
<h2 id="2-phishshield의-구성과-핵심-기능">2. PhishShield의 구성과 핵심 기능</h2>
<p>프로젝트의 목표는 위험 메시지를 감지하고, <strong>사용자가 바로 상황을 파악한 뒤 안전하게 대처할 수 있도록 돕는 서비스</strong>를 만드는 것이었습니다. 이를 위해 다음 네 가지 기능을 중심으로 설계했습니다.</p>
<h3 id="21-피싱-dna-12요소-분석">2.1 피싱 DNA 12요소 분석</h3>
<p>피싱 메시지에서 반복적으로 나타나는 패턴을 <strong>12가지 DNA 요소</strong>로 분류했습니다. 긴급성 압박, 권위 사칭, 금전 요구, 의심스러운 링크 포함 등 각 요소에 키워드와 설명을 부여했습니다. AI 모델은 텍스트를 전처리한 후 <strong>TF‑IDF</strong>로 벡터화하고, 각 메시지에서 이 패턴을 얼마나 충족하는지를 계산합니다. 이렇게 하면 “위험도 85%”와 같은 숫자만 보여 주는 대신, <strong>어떤 요소 때문에 의심되는지 구체적인 근거</strong>를 사용자에게 제시할 수 있습니다.</p>
<h3 id="22-패밀리-세이프워드family-safeword">2.2 패밀리 세이프워드(Family Safe‑Word)</h3>
<p>딥페이크 기술로 가족의 얼굴과 목소리까지 위조되는 시대에 ‘앱 안에서 비밀번호를 묻고 답하는 방식’은 오히려 위험합니다. 그래서 <strong>세이프워드는 데이터베이스에 저장하지 않고</strong>, 가족끼리만 아는 질문·답변을 오프라인에서 확인하도록 설계했습니다. 앱은 세이프워드 등록·리마인드만 도와주고, 의심 상황에서는 <strong>“지금 바로 가족에게 전화를 걸어 확인하세요”</strong>라는 안내를 제공합니다. 이는 README에서도 강조한 차별점 중 하나입니다.</p>
<h3 id="23-게임화된-대화-훈련">2.3 게임화된 대화 훈련</h3>
<p>피싱 위험을 알고 있어도 실제 상황에서는 쉽게 당황합니다. 그래서 <strong>실제 사기 사례를 바탕으로 20개의 시나리오</strong>를 만들고, 사용자가 메신저 대화 형식으로 직접 체험해 보는 훈련 모드를 도입했습니다. 각 시나리오는 보이스피싱, 메신저 피싱, 스미싱 등 다양한 유형을 다루며, <strong>올바른 대응을 선택하면 추가 정보를 제공하고 잘못된 행동을 하면 즉시 경고</strong>합니다. 이를 통해 <strong>어떤 패턴에 취약한지 스스로 알아갈 수 있도록</strong> 설계했습니다.</p>
<h3 id="24-시니어-모드">2.4 시니어 모드</h3>
<p>피싱 범죄의 주요 피해자는 고령층이 많습니다. AI 알고리즘이 아무리 좋아도 대상이 <strong>직접 사용할 수 없는 인터페이스</strong>라면 의미가 없다고 생각했습니다. 그래서 <strong>큰 글씨, 단순한 UI, 버튼 최소화</strong> 등 접근성을 최우선으로 한 <strong>시니어 모드</strong>를 제공했습니다. 이는 단순하지만 실제 사용자에게는 매우 중요한 요소입니다.</p>
<h2 id="3-기술적-접근-설명-가능한-ai-베이스라인">3. 기술적 접근: 설명 가능한 AI 베이스라인</h2>
<p>대회에서는 큰 딥러닝 모델을 사용하면 성능 점수가 올라갈 수 있었지만, 제가 혼자서 개발한 MVP에서는 다음 세 가지를 우선순위에 두었습니다.</p>
<ol>
<li><strong>실시간 처리 속도</strong>: 모바일에서 바로 판단해야 하므로 복잡한 모델은 지연을 초래할 수 있습니다.</li>
<li><strong>설명 가능성</strong>: 사용자가 왜 위험한지 이해해야 경고를 믿고 행동을 멈춥니다.</li>
<li><strong>데모 안정성</strong>: 발표와 심사에서 오류 없이 돌아가는 것이 가장 중요했습니다.</li>
</ol>
<h3 id="31-텍스트-전처리와-tfidf">3.1 텍스트 전처리와 TF‑IDF</h3>
<ul>
<li><strong>토큰화</strong>: 한국어 메시지에서 한글/영문/숫자만 남기고 나머지 기호를 제거했습니다. </li>
<li><strong>불용어 제거와 N‑그램</strong>: “입니다”, “에게” 같은 의미 없는 토큰을 제거하고, 2gram·3gram 형태로 구문을 만들어 패턴을 더 잘 포착했습니다.</li>
<li><strong>TF‑IDF 벡터화</strong>: 각 단어의 등장 빈도와 전체 말뭉치에서의 희소성을 고려해 벡터를 만들었습니다. 이는 문서 간 유사성을 계산하기 위해 기본이 되는 표현입니다.</li>
</ul>
<h3 id="32-유사도-계산과-패턴-스캔">3.2 유사도 계산과 패턴 스캔</h3>
<ul>
<li><strong>코사인 유사도</strong>: 피싱 메시지 코퍼스와 안전 메시지 코퍼스에 대해 각각 TF‑IDF 벡터를 만들어 메시지와의 유사도를 계산했습니다. 피싱 코퍼스와 가까울수록 위험 점수가 올라갑니다.</li>
<li><strong>DNA 패턴 매칭</strong>: 앞서 정의한 12개 DNA 요소에 대해 <strong>키워드 가중치와 조건</strong>을 부여하고, 메시지에 몇 개가 포함되는지 스캔했습니다. 패턴이 겹칠수록 위험을 더 높게 평가합니다.</li>
<li><strong>URL 분석과 구조 분석</strong>: 메시지에 포함된 URL을 추출해 <strong>위험한 도메인이나 짧은 링크, 유사 도메인</strong> 여부를 검사했습니다. 또한 문장이 특정 구조(긴급 문구 + 은행 계좌 등)로 나타나는지 확인해 추가 신호로 사용했습니다.</li>
<li><strong>개인화</strong>: 시니어 모드처럼 사용자 프로필을 고려해, 고령자에게 더 강한 경고를 보여주거나 은행 업무 경험이 적은 사용자에게 상세한 설명을 추가했습니다.</li>
</ul>
<h3 id="33-점수-합산과-위험-분류">3.3 점수 합산과 위험 분류</h3>
<p>최종 위험 점수는 <strong>여러 신호를 합산</strong>해 계산했습니다. 예를 들어 DNA 패턴 점수, NLP 유사도 점수, URL 점수, N‑그램/구조 점수를 <strong>가중치로 조합</strong>했습니다. 또, 특정 패턴이 동시에 나타날 때 가중치를 높이는 <strong>휴리스틱을 설계</strong>하고, false positive를 줄이기 위한 보정 규칙을 추가했습니다. 마지막으로 전체 점수를 기준으로 <strong>안전(safe)–낮음(low)–중간(medium)–높음(high)</strong> 네 단계로 분류했습니다. 이런 다층 구조 덕분에 모델은 딥러닝만큼 복잡하지 않지만, 사용자에게 <strong>이해하기 쉬운 근거와 함께 신뢰할 만한 판단</strong>을 제공할 수 있었습니다.</p>
<h2 id="4-개발-과정에서의-고민과-트레이드오프">4. 개발 과정에서의 고민과 트레이드오프</h2>
<p>프로젝트를 혼자 진행하다 보니 모든 결정을 스스로 내려야 했습니다. 그 과정에서 다음과 같은 고민이 컸습니다.</p>
<ul>
<li><strong>경고 빈도와 사용자 피로감</strong>: 경고가 너무 잦으면 사용자가 무시합니다. 반대로 문턱을 높이면 위험 메시지를 놓칠 수 있습니다. 그래서 경고를 단순 팝업이 아니라 <strong>근거 2~3줄과 행동 가이드</strong>가 포함된 리포트 형태로 제공했습니다.</li>
<li><strong>세이프워드의 보안 딜레마</strong>: 처음에는 OTP처럼 서버에서 검증하려고 했지만, 중간에서 탈취될 위험이 있었습니다. 그래서 결국 <strong>세이프워드를 오프라인 규칙</strong>으로 두는 설계로 회귀했습니다.</li>
<li><strong>10초 룰</strong>: 사용자가 앱을 켜고 <strong>10초 안에 이해하지 못하면</strong> 바로 이탈한다는 사실을 반영해 인터페이스를 최대한 단순화했습니다. 기능을 더 추가하려는 욕심을 버리고 <strong>동선과 설명 텍스트를 끊임없이 수정</strong>했습니다.</li>
</ul>
<h2 id="5-마무리하며-남은-과제와-배운-점">5. 마무리하며: 남은 과제와 배운 점</h2>
<p>본선 진출은 못 했지만, 다음과 같은 실질적인 교훈을 얻었습니다.</p>
<ol>
<li><strong>기획부터 MVP까지</strong>: 간단한 기획으로 시작하여, 작동하는 MVP까지 만들어보면서 데모가 기획서만 있는 것 보다 훨씬 설득력 있다는 것을 깨달았습니다.</li>
<li><strong>XAI와 UX의 중요성</strong>: 보안·헬스케어 같은 도메인에서 AI를 적용할 때는 높은 정확도보다 <strong>설명 가능성과 행동 유도</strong>가 더 중요합니다.</li>
<li><strong>개발과 일정 관리</strong>: 혼자서 모든 걸 진행하려면 <strong>역할 분담과 일정 관리</strong>가 더 어려워집니다. 기능 욕심을 버리고 마감 전에 사양을 동결하는 용기도 필요했습니다.</li>
</ol>
<p>향후에는 <strong>DNA 규칙을 더 정교하게 다듬고</strong>, 시스템 안정성을 해치지 않는 범위에서 <strong>경량화된 언어 모델</strong>을 결합해 “왜 위험한지 한 줄로 요약해 주는 기능”을 추가해보고 싶습니다. </p>
<p>끝까지 읽어주셔서 감사합니다. 프로젝트에 대한 의견이나 조언이 있다면 언제든 환영합니다.</p>
<h2 id="🔗-관련-링크">🔗 관련 링크</h2>
<ul>
<li><strong>DACON 코드 공유</strong>: <a href="https://dacon.io/competitions/official/236666/codeshare/13833">https://dacon.io/competitions/official/236666/codeshare/13833</a></li>
<li><strong>PhishShield 라이브 데모 (Vercel)</strong>: <a href="https://phish-shield-phi.vercel.app">https://phish-shield-phi.vercel.app</a></li>
<li><strong>Github 코드:</strong> : <a href="https://github.com/Lova-clover/PhishShield">https://github.com/Lova-clover/PhishShield</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[🏆 DACON K리그 AI 경진대회 15등(장려상) – 모멘텀 그래프·스토리 카드 자동화 K-MOMENTO AI 후기]]></title>
            <link>https://velog.io/@lova-clover/DACON-K%EB%A6%AC%EA%B7%B8-AI-%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C-15%EB%93%B1%EC%9E%A5%EB%A0%A4%EC%83%81-%EB%AA%A8%EB%A9%98%ED%85%80-%EA%B7%B8%EB%9E%98%ED%94%84%EC%8A%A4%ED%86%A0%EB%A6%AC-%EC%B9%B4%EB%93%9C-%EC%9E%90%EB%8F%99%ED%99%94-K-MOMENTO-AI-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@lova-clover/DACON-K%EB%A6%AC%EA%B7%B8-AI-%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C-15%EB%93%B1%EC%9E%A5%EB%A0%A4%EC%83%81-%EB%AA%A8%EB%A9%98%ED%85%80-%EA%B7%B8%EB%9E%98%ED%94%84%EC%8A%A4%ED%86%A0%EB%A6%AC-%EC%B9%B4%EB%93%9C-%EC%9E%90%EB%8F%99%ED%99%94-K-MOMENTO-AI-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Tue, 10 Feb 2026 17:49:46 GMT</pubDate>
            <description><![CDATA[<h2 id="한-줄-소개">한 줄 소개</h2>
<p><strong>90분의 열광을 18초 만에 하이라이트로 바꾸는 AI</strong><br>K리그 경기 데이터를 xG/xT 기반으로 분석해 모멘텀 그래프와 스토리 카드를 자동 생성하는 시스템을 만들었습니다.</p>
<hr>
<h2 id="🎯-대회-개요">🎯 대회 개요</h2>
<p><strong>DACON Track2: K리그-서울시립대 공개 AI 경진대회 (아이디어 개발 부문)</strong></p>
<ul>
<li><strong>기간</strong>: 2025.12.01 ~ 2026.01.12</li>
<li><strong>참가팀</strong>: 38팀</li>
<li><strong>결과</strong>: <strong>15등 장려상 수상</strong></li>
<li><strong>팀명</strong>: MomentoLab</li>
<li><strong>대회 링크</strong>: <a href="https://dacon.io/competitions/official/236648">DACON 대회 페이지</a></li>
<li><strong>제출 코드</strong>: <a href="https://dacon.io/competitions/official/236648/codeshare/13760">수상작 코드</a></li>
</ul>
<hr>
<h2 id="💡-아이디어-배경">💡 아이디어 배경</h2>
<h3 id="문제-인식">문제 인식</h3>
<p>K리그 경기를 보고 나면 항상 아쉬웠던 점:</p>
<ol>
<li><strong>&quot;저 장면이 진짜 중요했을까?&quot;</strong> – 경기 흐름 파악이 어려움</li>
<li><strong>하이라이트 편집에 5시간+</strong> – 영상 크리에이터의 수작업 고통</li>
<li><strong>전문가 해설 의존</strong> – 일반 팬들은 전술 이해 어려움</li>
<li><strong>K리그 낮은 시청률</strong> – 맞춤형 콘텐츠 부족</li>
</ol>
<h3 id="솔루션-k-momento-ai">솔루션: K-MOMENTO AI</h3>
<blockquote>
<p>&quot;경기가 끝나면 AI가 자동으로 핵심 전환점을 찾아내고, 전술 해설이 담긴 스토리 카드를 만들어줍니다.&quot;</p>
</blockquote>
<hr>
<h2 id="🏗️-시스템-구조">🏗️ 시스템 구조</h2>
<h3 id="기술-스택">기술 스택</h3>
<table>
<thead>
<tr>
<th>분야</th>
<th>기술</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Backend</strong></td>
<td>FastAPI (Python 3.11), Pandas, NumPy</td>
</tr>
<tr>
<td><strong>AI/ML</strong></td>
<td>Scikit-learn (xG), Markov Chain (xT), SciPy Signal</td>
</tr>
<tr>
<td><strong>Visualization</strong></td>
<td>Matplotlib, Pillow</td>
</tr>
<tr>
<td><strong>Frontend</strong></td>
<td>Next.js 14, TypeScript, Tailwind CSS</td>
</tr>
<tr>
<td><strong>AI 해설</strong></td>
<td>Rule-based + GPT-4</td>
</tr>
</tbody></table>
<h3 id="데이터">데이터</h3>
<ul>
<li><strong>raw_data.csv</strong>: 579,306개 이벤트 (패스, 슛, 캐리 등)</li>
<li><strong>match_info.csv</strong>: 198경기 메타데이터</li>
</ul>
<hr>
<h2 id="⚙️-핵심-알고리즘">⚙️ 핵심 알고리즘</h2>
<h3 id="1-xg-expected-goals--슈팅-골-확률-예측">1. xG (Expected Goals) – 슈팅 골 확률 예측</h3>
<pre><code class="language-python"># Logistic Regression 기반
features = [
    &#39;distance_to_goal&#39;,    # 골대까지 거리
    &#39;angle&#39;,               # 슈팅 각도
    &#39;body_part&#39;,          # 발/머리
    &#39;assist_type&#39;         # 크로스/패스
]

xg = 1 / (1 + exp(-logit))  # 0~1 확률값</code></pre>
<p><strong>배운 점:</strong></p>
<ul>
<li>합성 데이터 생성으로 데이터 부족 해결</li>
<li>중앙 위치 여부(<code>y_central</code>) 피처가 정확도를 15% 향상</li>
</ul>
<h3 id="2-xt-expected-threat--공격-위협도-계산">2. xT (Expected Threat) – 공격 위협도 계산</h3>
<pre><code class="language-python"># Markov Chain 전이 확률
grid = create_grid(12x8)  # 필드를 96칸으로 분할
xt[i,j] = P(goal | position(i,j))

# 재귀적 계산
xt[i,j] = Σ P(move) * (reward + xt[next])</code></pre>
<p><strong>어려웠던 점:</strong></p>
<ul>
<li>16x12 그리드로 시작했다가 계산 복잡도 과다 → 12x8로 축소</li>
<li>반복 계산 수렴 조건 설정 (20회 vs 50회 비교 실험)</li>
</ul>
<h3 id="3-momentum-calculation--경기-흐름-수치화">3. Momentum Calculation – 경기 흐름 수치화</h3>
<pre><code class="language-python"># 점수 계산
Score(t) = ΔxT + xG + GoalBonus

# 스무딩
momentum_smoothed = rolling_window(momentum, window=5)

# 전환점 탐지 (SciPy)
from scipy.signal import find_peaks

peaks, _ = find_peaks(
    momentum,
    prominence=0.3,      # 최소 변화량
    distance=300,        # 최소 간격 (초)
)</code></pre>
<p><strong>시행착오:</strong></p>
<ul>
<li>처음엔 prominence=0.5로 설정 → 전환점이 1개만 잡힘</li>
<li><code>distance=180</code>으로 했다가 3분 내 중복 이벤트 발생 → 300초로 조정</li>
</ul>
<hr>
<h2 id="🎨-시각화-결과">🎨 시각화 결과</h2>
<h3 id="1-모멘텀-그래프">1. 모멘텀 그래프</h3>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/bcd8c6c9-5a4f-49b2-8a6d-f55018374a58/image.png" alt="모멘텀 그래프 예시"></p>
<p><strong>실제 분석 예시: 전북 현대 모터스 vs 대전 하나 시티즌 (2024.03.01)</strong></p>
<ul>
<li>10분: 대전 선제골 </li>
<li>40분: 전북 득점골 </li>
<li>3개 전환점 자동 탐지 완료 ✅</li>
</ul>
<p><strong>특징:</strong></p>
<ul>
<li>양 팀 색상 구분 (빨강/파랑)</li>
<li>골 이벤트 점선 표시</li>
<li>전환점 Top 3 강조</li>
<li><strong>라벨 겹침 방지 알고리즘</strong> (4개 존으로 분할 배치)</li>
</ul>
<p><strong>개선 이력:</strong></p>
<ul>
<li>V1: 라벨 전부 겹침 😭</li>
<li>V2: 상하 번갈아 배치 → 여전히 겹침</li>
<li>V3: 좌우 지그재그 → 겹침</li>
<li><strong>V4 (최종)</strong>: 4개 존(Zone) 기반 충돌 회피 ✅</li>
</ul>
<h3 id="2-스토리-카드">2. 스토리 카드</h3>
<p><img src="https://velog.velcdn.com/images/lova-clover/post/b0085960-42d3-4bed-bdae-fa0f4bfba6df/image.png" alt="스토리 카드 예시"></p>
<p><strong>울산 vs 포항 경기 #2 전환점 (35분 57초)</strong></p>
<ul>
<li>아라비제 슛, 아타루 패스, 루빅손 패스, 황인재 패스 연계 플레이</li>
<li>AI가 자동으로 주요 이벤트 3개 선정</li>
</ul>
<p><strong>포함 내용:</strong></p>
<ul>
<li>전환점 순위 (#1, #2, #3)</li>
<li>시간대 및 모멘텀 변화량</li>
<li>주요 이벤트 3개 (시간, 선수, xG/xT)</li>
<li>GPT-4 전술 해설</li>
</ul>
<p><strong>디자인 시행착오:</strong></p>
<ul>
<li>처음엔 그라데이션·그림자 남발 → 너무 복잡한 느낌</li>
<li><strong>최종</strong>: 기본 폰트 + 심플 색상 (Red/Blue/Orange) → 가독성 상승</li>
</ul>
<hr>
<h2 id="🤖-gpt-4-ai-해설-생성">🤖 GPT-4 AI 해설 생성</h2>
<h3 id="프롬프트-설계">프롬프트 설계</h3>
<pre><code class="language-python">prompt = f&quot;&quot;&quot;
당신은 K리그 전문 해설가입니다.
다음 경기 데이터를 보고 전환점을 설명하세요:

- 경기: {home_team} vs {away_team}
- 전환점 시간: {time_seconds}초
- 모멘텀 변화: {momentum_delta}
- 주요 이벤트:
  {event1}: {player_name} ({xg_value})
  {event2}: {player_name} ({xt_value})

팬들이 이해하기 쉽게 2문장으로 설명해주세요.
&quot;&quot;&quot;</code></pre>
<p><strong>예시 출력:</strong></p>
<blockquote>
<p>&quot;85분, 울산의 역습이 xT 0.42로 측정되며 포항 진영을 압박했습니다. 이 플레이가 결국 결승골로 이어지며 경기의 흐름이 완전히 뒤집혔습니다.&quot;</p>
</blockquote>
<hr>
<h2 id="📈-성과">📈 성과</h2>
<table>
<thead>
<tr>
<th>지표</th>
<th>수치</th>
</tr>
</thead>
<tbody><tr>
<td>xG 예측 정확도</td>
<td>87.3%</td>
</tr>
<tr>
<td>xT 계산 속도</td>
<td>0.15초/경기</td>
</tr>
<tr>
<td>전환점 탐지 재현율</td>
<td>92.1%</td>
</tr>
<tr>
<td><strong>전체 분석 시간</strong></td>
<td><strong>18초/경기</strong></td>
</tr>
<tr>
<td>API 응답 시간</td>
<td>&lt;500ms</td>
</tr>
</tbody></table>
<hr>
<h2 id="🚧-어려웠던-점들">🚧 어려웠던 점들</h2>
<h3 id="1-한글-폰트-문제-□□□-깨짐">1. 한글 폰트 문제 (<code>□□□</code> 깨짐)</h3>
<pre><code class="language-python"># Windows vs Linux 폰트 경로 차이
FONT_PATHS = [
    &quot;C:\\Windows\\Fonts\\malgun.ttf&quot;,      # Windows
    &quot;/usr/share/fonts/truetype/nanum/&quot;,    # Linux
]</code></pre>
<p><strong>해결</strong>: OS별 폰트 경로 리스트로 자동 탐색</p>
<h3 id="2-샘플-데이터-vs-전체-데이터">2. 샘플 데이터 vs 전체 데이터</h3>
<ul>
<li><strong>전체 데이터</strong>: 579K 행 → 분석 시간 2분+</li>
<li><strong>샘플 데이터</strong>: 58K 행 (20경기) → 분석 시간 18초</li>
</ul>
<p><strong>배포 전략</strong>: 샘플 데이터로 빠른 응답 → 추후 Redis 캐싱으로 전체 데이터 지원</p>
<h3 id="3-모델-재학습-vs-캐싱">3. 모델 재학습 vs 캐싱</h3>
<pre><code class="language-python"># xG/xT 모델 캐싱
if os.path.exists(&#39;backend/outputs/cache/xg_model.pkl&#39;):
    xg_model = pickle.load(open(&#39;cache/xg_model.pkl&#39;, &#39;rb&#39;))
else:
    xg_model = train_xg_model()
    pickle.dump(xg_model, open(&#39;cache/xg_model.pkl&#39;, &#39;wb&#39;))</code></pre>
<p><strong>결과</strong>: 모델 로딩 시간 15초 → 0.2초</p>
<hr>
<h2 id="💭-회고">💭 회고</h2>
<h3 id="잘한-점-✅">잘한 점 ✅</h3>
<ol>
<li><strong>실용성 우선</strong>: &quot;멋진 기술&quot;보다 &quot;실제로 쓸 수 있는 기능&quot;에 집중</li>
<li><strong>빠른 프로토타입</strong>: MVP를 3일 만에 완성 → 피드백 반영 시간 확보</li>
<li><strong>문서화</strong>: README.md, ARCHITECTURE.md로 코드 설명 충실</li>
</ol>
<h3 id="아쉬운-점-😅">아쉬운 점 😅</h3>
<ol>
<li><strong>배포 포기</strong>: Render.com 배포 시도했으나 무료 티어 메모리 부족 → 로컬 실행 영상 제출</li>
<li><strong>실시간 분석 미구현</strong>: 경기 중 실시간 모멘텀 업데이트 기능 못 만듦</li>
<li><strong>테스트 코드 부족</strong>: 급하게 개발하다 보니 Unit Test 생략</li>
<li><strong>시간 분배 실패</strong>: PPT 완벽하게 만들지 못함 ㅠ</li>
</ol>
<h3 id="배운-것-📚">배운 것 📚</h3>
<p><strong>기술적:</strong></p>
<ul>
<li>Markov Chain을 실전에 적용하는 법</li>
<li>SciPy Signal Processing (Peak Detection)</li>
<li>GPT-4 API 프롬프트 엔지니어링</li>
</ul>
<p><strong>비기술적:</strong></p>
<ul>
<li>&quot;완벽한 코드&quot;보다 &quot;작동하는 MVP&quot;가 우선</li>
<li>사용자 피드백 = 개발 방향의 나침반</li>
</ul>
<hr>
<h2 id="🙏-마치며">🙏 마치며</h2>
<p><strong>15등이라는 결과보다 더 값진 것:</strong></p>
<ol>
<li>xG/xT를 “읽기”에서 끝내지 않고 실제로 제품 형태로 옮긴 경험</li>
<li>혼자 끝까지 구현하면서, 병목(속도/폰트/렌더/캐싱)을 해결한 경험</li>
<li>“AI가 경기를 이해하게 만들 수 있구나”를 데모로 증명한 것</li>
</ol>
<p><strong>K리그 팬 여러분에게:</strong></p>
<blockquote>
<p>&quot;데이터는 숫자가 아니라 이야기입니다. AI는 그 이야기를 읽어주는 해설가가 될 수 있습니다.&quot;</p>
</blockquote>
<hr>
<h2 id="🔗-링크">🔗 링크</h2>
<ul>
<li><strong>GitHub</strong>: <a href="https://github.com/Lova-clover/K-MOMENTO-AI">K-MOMENTO-AI</a></li>
<li><strong>DACON 코드</strong>: <a href="https://dacon.io/competitions/official/236648/codeshare/13760">수상작 코드</a></li>
<li><strong>발표자료</strong>: <a href="https://github.com/Lova-clover/K-MOMENTO-AI/blob/main/docs/K-MOMENT%20%EC%B5%9C%EC%A2%85.pdf">PDF</a> | <a href="https://github.com/Lova-clover/K-MOMENTO-AI/blob/main/docs/K-MOMENT%20%EC%B5%9C%EC%A2%85.pptx">PPT</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>