<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>CrowRish Blog</title>
    <description>개발 경험과 학습 내용을 기록하고 공유하는 공간입니다. 주로 프론트엔드 개발, 그리고 새로운 기술 스택에 대한 이야기를 다룹니다.</description>
    <link>https://crowrish.com</link>
    <language>ko</language>
    <lastBuildDate>Mon, 28 Sep 2026 04:17:08 GMT</lastBuildDate>
    <atom:link href="https://crowrish.com/rss" rel="self" type="application/rss+xml" />
    <image>
      <url>https://crowrish.com/og-image.png</url>
      <title>CrowRish Blog</title>
      <link>https://crowrish.com</link>
    </image>
    <item>
      <title>LLM AI로 간식 추천 서비스 만들기</title>
      <link>https://crowrish.com/blog/snacklink-gpt-chat</link>
      <guid isPermaLink="true">https://crowrish.com/blog/snacklink-gpt-chat</guid>
      <description>LLM API를 백엔드에 붙여 AI 간식 추천 챗을 만들고, 없는 간식을 추천하던 문제를 프롬프트와 DB 검증으로 잡은 기록</description>
      <dc:creator>CrowRish</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:00:00 GMT</pubDate>
      <media:content url="https://crowrish.com/blog/snacklink-gpt-chat/opengraph-image" medium="image" />
      <category>AI</category>
      <category>LLM</category>
      <category>React</category>
      <category>Next.js</category>
      <category>GPT</category>
      <content:encoded><![CDATA[<p>스낵링크는 사무실 간식 큐레이션 서비스였습니다. 회사 총무 담당자가 탕비실 간식을 고르는 데 생각보다 시간이 많이 드는데, 그걸 1분 안에 끝내 보자는 게 목표였어요.</p><p>AI 챗은 대표님의 오더로 시작했습니다. &quot;사무실 간식 5만원어치 알려줘&quot;처럼 말만 하면 간식 구성을 짜 주는 기능이요. 개발은 백엔드 개발자 한 분과 저, 둘이서 했습니다. GPT를 부르고 결과를 가공하는 건 백엔드, 그 응답을 받아 화면에 풀어내는 건 제 몫이었어요. 둘이서 서비스 전체를 만든 이야기는 따로 써 보려고 합니다.</p><p>이번 글은 그중 AI 챗 이야기입니다. 백엔드와 프론트가 LLM을 어떻게 나눠 맡았는지, 그리고 AI가 없는 간식을 추천하던 문제를 어떻게 잡았는지를 정리했습니다.</p><figure><img src="https://crowrish.com/blog-images/dd9e1210910b9275813c9e09effcc699.webp" alt="스낵링크 AI 추천 챗. 말로 요청하면 간식 구성이 돌아온다" /><figcaption>스낵링크 AI 추천 챗. 말로 요청하면 간식 구성이 돌아온다</figcaption></figure><blockquote><p>글에 실린 화면은 서비스 종료 후 만든 데모에서 다시 찍었습니다. UI는 원래 코드 그대로지만, 화면 속 답변 문장은 GPT가 아닌 데모용 모델이 만든 것입니다.</p></blockquote><h2>화면이 먼저 나왔습니다</h2><p>챗 화면은 GPT가 붙기 전에 먼저 만들었습니다. 2024년 10월 말, 백엔드에 아직 아무것도 없을 때 더미 데이터로 시작했어요.</p><p><a href="https://crowrish.com/blog/snacklink-gpt-chat">계속 읽기 →</a></p>]]></content:encoded>
    </item>
    <item>
      <title>LLM AI로 상품 큐레이션 도구 만들기</title>
      <link>https://crowrish.com/blog/curation-tool-gemini</link>
      <guid isPermaLink="true">https://crowrish.com/blog/curation-tool-gemini</guid>
      <description>서버 없는 상품 큐레이션 도구에 LLM API(Gemini)를 붙여 요구사항 문장으로 상품과 장바구니를 채우고, 응답 잘림·모델 교체·API 키 노출 문제를 다룬 기록</description>
      <dc:creator>CrowRish</dc:creator>
      <pubDate>Tue, 15 Sep 2026 00:00:00 GMT</pubDate>
      <media:content url="https://crowrish.com/blog/curation-tool-gemini/opengraph-image" medium="image" />
      <category>AI</category>
      <category>LLM</category>
      <category>React</category>
      <category>Vite</category>
      <category>Gemini</category>
      <content:encoded><![CDATA[<p>친하게 지내는 MD 동료의 부탁으로 만든 상품 큐레이션 도구가 있습니다. 화면 헤더에 &quot;for Awesome MDs&quot;라고 적어 둔 것도 그래서예요.</p><p>고객사별로 간식 구성을 짜는 웹앱인데요, 가격표와 운영 가능 상품, 고객사별 특별단가가 들어 있는 엑셀을 올리면 브라우저 안에 상품 DB가 만들어지고, 거기서 검색해 고객사 탭마다 장바구니를 채운 다음 정해진 양식의 엑셀로 내보냅니다.</p><p>서버는 없습니다. Vite + React로 만든 SPA이고, 데이터는 전부 브라우저의 IndexedDB(Dexie)에 들어갑니다. 여기에 LLM(Gemini)을 붙인 과정을 정리해 봤습니다.</p><blockquote><p>글의 화면은 촬영용으로 만든 샘플 엑셀(상품 164개, 고객사 5곳)로 다시 찍었습니다. 상품명·고객사·단가는 모두 가짜이고, AI 결과는 실제 Gemini 응답입니다.</p></blockquote><figure><img src="https://crowrish.com/blog-images/a7d62696aeaa8ba57300abbc234f757c.webp" alt="상품 큐레이션 도구. 위는 상품 검색, 아래는 고객사별 장바구니. 특별단가가 있는 고객사는 배지와 행 색으로 구분된다" /><figcaption>상품 큐레이션 도구. 위는 상품 검색, 아래는 고객사별 장바구니. 특별단가가 있는 고객사는 배지와 행 색으로 구분된다</figcaption></figure><figure><img src="https://crowrish.com/blog-images/b7ea7531df518d46804278eb3be01af7.webp" alt="엑셀을 올리면 시트별로 브라우저 안의 상품 DB가 된다" /><figcaption>엑셀을 올리면 시트별로 브라우저 안의 상품 DB가 된다</figcaption></figure><h2>규칙으로 할 수 있는 데까지</h2><p>AI부터 붙인 건 아닙니다. 추천 기능은 이렇게 늘어났어요.</p><p><a href="https://crowrish.com/blog/curation-tool-gemini">계속 읽기 →</a></p>]]></content:encoded>
    </item>
    <item>
      <title>useMemo, 컴파일러에 맡겨도 될까</title>
      <link>https://crowrish.com/blog/usememo-react-compiler</link>
      <guid isPermaLink="true">https://crowrish.com/blog/usememo-react-compiler</guid>
      <description>React Compiler 1.0이 실제로 만드는 코드를 열어 보고, 조용히 건너뛰는 컴포넌트와 잡지 못하는 버그를 확인한 기록</description>
      <dc:creator>CrowRish</dc:creator>
      <pubDate>Mon, 13 Oct 2025 00:00:00 GMT</pubDate>
      <media:content url="https://crowrish.com/blog/usememo-react-compiler/opengraph-image" medium="image" />
      <category>React</category>
      <category>Next.js</category>
      <content:encoded><![CDATA[<blockquote><p>2025년 10월에 쓴 글을 2026년 9월에 다시 썼습니다.</p></blockquote><p>2025년 10월, Next.js 16 베타가 나온 직후에 이 주제로 글을 썼습니다. 다시 읽어 보니 발표 자료를 옮겨 적은 수준이었습니다. 컴파일러가 &quot;알아서 최적화해 준다&quot;고 써 놓고, 정작 컴파일러가 뭘 만드는지는 한 번도 열어 보지 않았습니다.</p><p>그래서 이번엔 직접 돌려 봤습니다. <code>babel-plugin-react-compiler</code> 1.0으로 예제 컴포넌트와 이 블로그 코드를 컴파일하고, 결과를 보면서 원래 질문에 다시 답해 봤습니다.</p><h2>처음 질문</h2><pre><code>function ProductList({ products, onSelect }) {
  const filtered = products.filter((p) =&gt; p.inStock);

  return (
    &lt;ul&gt;
      {filtered.map((p) =&gt; (
        &lt;ProductCard key={p.id} product={p} onSelect={() =&gt; onSelect(p.id)} /&gt;
      ))}
    &lt;/ul&gt;
  );
}</code></pre><p>예전 같으면 여기서 고민이 시작됩니다. <code>filtered</code>는 <code>useMemo</code>로 감쌀지, <code>onSelect</code>에 넘기는 화살표 함수는 <code>useCallback</code>으로 뺄지. 팀마다 답이 다르고, 결국 &quot;일단 다 감싸자&quot;가 이기는 경우가 많았습니다.</p><p>React 팀도 이걸 문제로 봤습니다. Meta 안에서 수동 메모이제이션이 들어간 PR은 전체의 8% 정도였는데, 그런 PR은 작성 시간이 31~46% 더 걸렸다고 합니다. 감싸는 것보다 의존성 배열을 맞추는 데 품이 들기 때문입니다.</p><p><a href="https://crowrish.com/blog/usememo-react-compiler">계속 읽기 →</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Fumadocs 한글 검색 기능 구현하기</title>
      <link>https://crowrish.com/blog/fumadocs-korean-search</link>
      <guid isPermaLink="true">https://crowrish.com/blog/fumadocs-korean-search</guid>
      <description>Fumadocs의 기본 검색 엔진인 Orama가 한글을 제대로 지원하지 않는 문제를 해결하기 위해 커스텀 한글 검색 엔진을 구현한 과정을 공유합니다.</description>
      <dc:creator>CrowRish</dc:creator>
      <pubDate>Mon, 18 Aug 2025 00:00:00 GMT</pubDate>
      <media:content url="https://crowrish.com/blog-images/d9acf0457ab75a4520a16b40c477e6c1.webp" medium="image" />
      <category>Fumadocs</category>
      <category>Next.js</category>
      <category>es-hangul</category>
      <content:encoded><![CDATA[<p><img src="https://crowrish.com/blog-images/617ef75114df52a023fb2cd79118278b.webp" alt="" /></p><p>문서 사이트를 운영하다 보면 검색 기능은 필수입니다. 특히 한국어 컨텐츠가 많은 사이트에서는 한글에 특화된 검색 기능이 중요합니다. 이번 글에서는 Fumadocs의 기본 검색 엔진인 Orama가 한글을 제대로 지원하지 않는 문제를 해결하기 위해 커스텀 한글 검색 엔진을 구현한 과정을 공유합니다.</p><h2>문제 발생</h2><blockquote><p>😮 : 한글 검색에 문제가 있나?</p></blockquote><p>Fumadocs를 사용해 문서 사이트를 구축했는데, 한 가지 큰 문제가 있었습니다. <strong>한글 검색이 제대로 작동하지 않는 것</strong>이었습니다.</p><h3>원인 분석</h3><p>Fumadocs는 기본적으로 <strong>Orama</strong>라는 검색 엔진을 사용하는데, 검색 결과 알게된 사실은…</p><p><a href="https://github.com/orgs/oramasearch/discussions/748"><strong>GitHub Discussion #748</strong></a>에서 Orama 팀의 답변:</p><p><a href="https://crowrish.com/blog/fumadocs-korean-search">계속 읽기 →</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>