<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ougi FE</title>
    <link>https://baeougi.tistory.com/</link>
    <description>FrontEnd 개발자로서 성장을 위해 열심히 정리합니다</description>
    <language>ko</language>
    <pubDate>Mon, 15 Jun 2026 18:53:09 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ougi</managingEditor>
    <image>
      <title>ougi FE</title>
      <url>https://tistory1.daumcdn.net/tistory/7038270/attach/2e5d11a651a246c7ac37a496a6e65c0b</url>
      <link>https://baeougi.tistory.com</link>
    </image>
    <item>
      <title>n8n 이용해서 AI로 기획부터 개발, 수정까지 자동화하기!</title>
      <link>https://baeougi.tistory.com/77</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 제가 최근에 전화 면접과 과제를 하면서 AI 활용도에 대해서 묻는 질문을 많이 받아서 AI를 좀 더 잘 활용해보자&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;라는 생각이 들어 n8n이라는 것을 사용하게 되었습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYbenJ/dJMcaiis5nP/iLEAZU66K1YFatlfLzPnr0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYbenJ/dJMcaiis5nP/iLEAZU66K1YFatlfLzPnr0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYbenJ/dJMcaiis5nP/iLEAZU66K1YFatlfLzPnr0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYbenJ%2FdJMcaiis5nP%2FiLEAZU66K1YFatlfLzPnr0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;330&quot; height=&quot;264&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;n8n? 그게 뭐임&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djZaBI/dJMcaibJw9O/JE89acyje9AZDvPu8y4qE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djZaBI/dJMcaibJw9O/JE89acyje9AZDvPu8y4qE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djZaBI/dJMcaibJw9O/JE89acyje9AZDvPu8y4qE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjZaBI%2FdJMcaibJw9O%2FJE89acyje9AZDvPu8y4qE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;228&quot; height=&quot;228&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AI 기능도 붙일 수 있고, 반복 업무도 자동으로 처리해주는 워크플로 도구&lt;/b&gt;&lt;span&gt;입니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;쉽게 말하면 &lt;/span&gt;&lt;b&gt;여러 앱과 서비스를 연결해서 사람이 하던 일을 자동으로 대신하게 만드는 프로그램&lt;/b&gt;입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 도구는 정말 어마어마한 확장성을 가지고 있다고 개인적으로 말할 수 있을거 같습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잘 사용하면 작업 속도가 매우 빨라집니다&lt;/li&gt;
&lt;li&gt;다른 서비스와 잘 조합되어 사용 가능합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잘 사용하지 못하면 오히려 더 오랜 시간이 걸리고 작업이 늘어납니다&lt;/li&gt;
&lt;li&gt;초기 세팅이 귀찮고 힘들 수 있습니다&lt;/li&gt;
&lt;li&gt;100% 신뢰할 수 없습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;어떻게 활용했을까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 총 3가지 파이프라인을 구성했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서대로 하나씩 말씀 드리겠습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기획 파이프라인&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1906&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bexDZK/dJMcag52JOZ/VNfkmmxDLUWPZW4YfZ9kvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bexDZK/dJMcag52JOZ/VNfkmmxDLUWPZW4YfZ9kvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bexDZK/dJMcag52JOZ/VNfkmmxDLUWPZW4YfZ9kvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbexDZK%2FdJMcag52JOZ%2FVNfkmmxDLUWPZW4YfZ9kvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1906&quot; height=&quot;308&quot; data-origin-width=&quot;1906&quot; data-origin-height=&quot;308&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;매주 월요일 9시에 열려있는 이슈와 최근 커밋을 조회합니다&lt;/li&gt;
&lt;li&gt;앞에 조회한 결과로 Gemini에게 보낼 payload를 생성합니다&lt;/li&gt;
&lt;li&gt;Gemini에게 기획 아이디어를 요청합니다&lt;/li&gt;
&lt;li&gt;아이디 데이터를 정리합니다&lt;/li&gt;
&lt;li&gt;Github Issue에 등록 해줍니다&lt;/li&gt;
&lt;li&gt;이슈들을 정리해서 디스코드 웹훅을 이용해서 전달합니다&lt;/li&gt;
&lt;li&gt;괜찮은 이슈를 골라 ai-implement 라벨을 달아줍니다&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2229&quot; data-origin-height=&quot;1097&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1q5EC/dJMcaaEL6Qp/seKWftEtjVb943A7dmrim1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1q5EC/dJMcaaEL6Qp/seKWftEtjVb943A7dmrim1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1q5EC/dJMcaaEL6Qp/seKWftEtjVb943A7dmrim1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1q5EC%2FdJMcaaEL6Qp%2FseKWftEtjVb943A7dmrim1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;1097&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2229&quot; data-origin-height=&quot;1097&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-03-30 at 8.21.37 PM.png&quot; data-origin-width=&quot;383&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PyxmW/dJMcah4Xkgh/YdVo16Z82SHO2sVvtpBOJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PyxmW/dJMcah4Xkgh/YdVo16Z82SHO2sVvtpBOJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PyxmW/dJMcah4Xkgh/YdVo16Z82SHO2sVvtpBOJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPyxmW%2FdJMcah4Xkgh%2FYdVo16Z82SHO2sVvtpBOJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;383&quot; height=&quot;210&quot; data-filename=&quot;Screenshot 2026-03-30 at 8.21.37 PM.png&quot; data-origin-width=&quot;383&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;개발 파이프라인&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-01 at 11.39.27 PM.png&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ9dLr/dJMcajhnqsE/Wm0xx9Ahd6lK4txxHqsYQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ9dLr/dJMcajhnqsE/Wm0xx9Ahd6lK4txxHqsYQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ9dLr/dJMcajhnqsE/Wm0xx9Ahd6lK4txxHqsYQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ9dLr%2FdJMcajhnqsE%2FWm0xx9Ahd6lK4txxHqsYQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1168&quot; height=&quot;164&quot; data-filename=&quot;Screenshot 2026-04-01 at 11.39.27 PM.png&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 파이프라인도 만들어두었는데 이건 자동화 하는 것이 비효율적인 것 같다고 느껴져서 추후에 제거하게 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 어떤 흐름으로 진행 되었는지 말씀 드리자면&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;깃허브에서 ai-implement 라벨이 달린 이슈를 찾아서 가져옵니다&lt;/li&gt;
&lt;li&gt;이슈들 중에 ai-pr-created 라벨이 없는 이슈를 찾아 한가지를 선택합니다&lt;/li&gt;
&lt;li&gt;선택한 이슈에 ai-implementing 라벨을 추가합니다&lt;/li&gt;
&lt;li&gt;깃허브에서 구현에 필요한 기존 코드 읽어줍니다&lt;/li&gt;
&lt;li&gt;파일 내용 디코딩을 하여 Gemini 프롬프트를 생성합니다&lt;/li&gt;
&lt;li&gt;Gemini에게 구현을 요청하고 응답을 받아 파싱합니다&lt;/li&gt;
&lt;li&gt;새 ai/~~ 브랜치를 생성하여 commit, push, pr 생성을 합니다&lt;/li&gt;
&lt;li&gt;draft로 변경 후 ai-pr-created&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라벨 추가하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;ai-implementing&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ai-implement 라벨은&lt;/span&gt;&lt;span&gt;&amp;nbsp;제거합니다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Discord로 구현 완료 알림을 전송합니다&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-08 at 11.48.52 AM.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4fteo/dJMcafsCBWl/QEvhqhhjVdhmCUhLHPewhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4fteo/dJMcafsCBWl/QEvhqhhjVdhmCUhLHPewhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4fteo/dJMcafsCBWl/QEvhqhhjVdhmCUhLHPewhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4fteo%2FdJMcafsCBWl%2FQEvhqhhjVdhmCUhLHPewhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;636&quot; data-filename=&quot;Screenshot 2026-04-08 at 11.48.52 AM.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-08 at 11.50.54 AM.png&quot; data-origin-width=&quot;2822&quot; data-origin-height=&quot;1868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cv3877/dJMcaju0wyv/L4d7rasm4GKiaQQrnKug01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cv3877/dJMcaju0wyv/L4d7rasm4GKiaQQrnKug01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cv3877/dJMcaju0wyv/L4d7rasm4GKiaQQrnKug01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcv3877%2FdJMcaju0wyv%2FL4d7rasm4GKiaQQrnKug01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;1868&quot; data-filename=&quot;Screenshot 2026-04-08 at 11.50.54 AM.png&quot; data-origin-width=&quot;2822&quot; data-origin-height=&quot;1868&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;자동 수정 파이프라인&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-08 at 11.58.53 AM.png&quot; data-origin-width=&quot;2546&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pN5Dh/dJMcahcUjJd/grxVxPavKHU8xcoA19zfPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pN5Dh/dJMcahcUjJd/grxVxPavKHU8xcoA19zfPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pN5Dh/dJMcahcUjJd/grxVxPavKHU8xcoA19zfPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpN5Dh%2FdJMcahcUjJd%2FgrxVxPavKHU8xcoA19zfPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2546&quot; height=&quot;434&quot; data-filename=&quot;Screenshot 2026-04-08 at 11.58.53 AM.png&quot; data-origin-width=&quot;2546&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;PR 리뷰를 웹훅 수신으로 계속 확인합니다&lt;/li&gt;
&lt;li&gt;Gemini 봇 리뷰인지 확인합니다&lt;/li&gt;
&lt;li&gt;PR 정보 추출하여 코멘트와 변경사항을 조회합니다&lt;/li&gt;
&lt;li&gt;리뷰/파일/코멘트 컨텍스트 정리하고 수정할 내용이 있다면 진행합니다&lt;/li&gt;
&lt;li&gt;현재 변경 파일을 한 번 더 확인하고 Gemini에 리뷰 반영과 CI 수정 요청을 진행합니다&lt;/li&gt;
&lt;li&gt;수정 결과를 파싱하고 한 번에 커밋 후 PR 코멘트를 작성합니다&lt;/li&gt;
&lt;li&gt;Discord 알림 전송합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.03.53 PM.png&quot; data-origin-width=&quot;1836&quot; data-origin-height=&quot;952&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PU263/dJMcajobMpi/X05JksQ0F8lGHsvZhtONV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PU263/dJMcajobMpi/X05JksQ0F8lGHsvZhtONV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PU263/dJMcajobMpi/X05JksQ0F8lGHsvZhtONV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPU263%2FdJMcajobMpi%2FX05JksQ0F8lGHsvZhtONV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1836&quot; height=&quot;952&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.03.53 PM.png&quot; data-origin-width=&quot;1836&quot; data-origin-height=&quot;952&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.04.58 PM.png&quot; data-origin-width=&quot;1026&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m6m3F/dJMcaf0rz9T/kOx2OED6kQzjt5GA68qIU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m6m3F/dJMcaf0rz9T/kOx2OED6kQzjt5GA68qIU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m6m3F/dJMcaf0rz9T/kOx2OED6kQzjt5GA68qIU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm6m3F%2FdJMcaf0rz9T%2FkOx2OED6kQzjt5GA68qIU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;585&quot; height=&quot;466&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.04.58 PM.png&quot; data-origin-width=&quot;1026&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;코멘트 기반 수정 파이프라인&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.09.23 PM.png&quot; data-origin-width=&quot;1736&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9nSgH/dJMcaco84y3/zT8jjj9dUMkjSCREwj3MR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9nSgH/dJMcaco84y3/zT8jjj9dUMkjSCREwj3MR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9nSgH/dJMcaco84y3/zT8jjj9dUMkjSCREwj3MR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9nSgH%2FdJMcaco84y3%2FzT8jjj9dUMkjSCREwj3MR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1736&quot; height=&quot;690&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.09.23 PM.png&quot; data-origin-width=&quot;1736&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공통 시작&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;PR 코멘트 이벤트를 수신합니다&lt;/li&gt;
&lt;li&gt;새 코멘트인지 확인합니다&lt;/li&gt;
&lt;li&gt;/fix-build&lt;span&gt;, &lt;/span&gt;/fix-lint&lt;span&gt;, &lt;/span&gt;/fix&lt;span&gt; 중 하나 감지합니다&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/fix-build&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.14.30 PM.png&quot; data-origin-width=&quot;1776&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj5Flc/dJMcagd1k7M/Ph8YBBcT2TrTEbCCmqiie1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj5Flc/dJMcagd1k7M/Ph8YBBcT2TrTEbCCmqiie1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj5Flc/dJMcagd1k7M/Ph8YBBcT2TrTEbCCmqiie1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj5Flc%2FdJMcagd1k7M%2FPh8YBBcT2TrTEbCCmqiie1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1776&quot; height=&quot;460&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.14.30 PM.png&quot; data-origin-width=&quot;1776&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;PR 파일 + CI 실패를 조회합니다&lt;/li&gt;
&lt;li&gt;Gemini로 빌드/타입 수정합니다&lt;/li&gt;
&lt;li&gt;수정 파일 있으면 한 번에 커밋합니다&lt;/li&gt;
&lt;li&gt;auto-format workflow 실행합니다&lt;/li&gt;
&lt;li&gt;PR 코멘트를 작성합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/fix-lint&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;PR JS/TS 파일을 조회합니다&lt;/li&gt;
&lt;li&gt;Gemini로 Prettier 포맷 수정 합니다&lt;/li&gt;
&lt;li&gt;수정 파일 있으면 한 번에 커밋합니다&lt;/li&gt;
&lt;li&gt;PR 코멘트를 작성합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/fix&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.15.38 PM.png&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;2096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQfdfs/dJMcagLRB8G/mgmkbsOolGjFuniniKuVU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQfdfs/dJMcagLRB8G/mgmkbsOolGjFuniniKuVU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQfdfs/dJMcagLRB8G/mgmkbsOolGjFuniniKuVU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQfdfs%2FdJMcagLRB8G%2FmgmkbsOolGjFuniniKuVU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;503&quot; height=&quot;683&quot; data-filename=&quot;Screenshot 2026-04-08 at 12.15.38 PM.png&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;2096&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;원본 리뷰 코멘트를 조회 합니다&lt;/li&gt;
&lt;li&gt;해당 파일 + 관련 파일을 읽어 파악합니다&lt;/li&gt;
&lt;li&gt;Gemini로 리뷰 코멘트를 반영합니다&lt;/li&gt;
&lt;li&gt;수정 파일 있으면 한 번에 커밋합니다&lt;/li&gt;
&lt;li&gt;auto-format workflow 실행합니다&lt;/li&gt;
&lt;li&gt;리뷰 코멘트에 답글 작성합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;글을 마치며&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;157&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pbg3w/dJMcacbuLdI/lkbzTLeUSlgJgkbiIUP0Xk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pbg3w/dJMcacbuLdI/lkbzTLeUSlgJgkbiIUP0Xk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pbg3w/dJMcacbuLdI/lkbzTLeUSlgJgkbiIUP0Xk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpbg3w%2FdJMcacbuLdI%2FlkbzTLeUSlgJgkbiIUP0Xk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;290&quot; height=&quot;157&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;157&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일매일 하던 생각이 AI 시대에 맞게 제가 AI를 잘 활용하고 있는지 고민했었는데 이런 좋은 기능을 사용해서 AI를 적극적으로 활용해 제 프로젝트를 유지보수할 수 있어서 너무 좋았던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하면서 계속 ci가 터지거나 여러 이슈를 한 번에 가져와버린다던지 여러 오류들이 있어서 조금 힘든 점도 있었지만 다른 것도 자동화 하고 싶은 마음이 가득해지는 경험이었습니다&lt;/p&gt;</description>
      <category>AI</category>
      <category>Fe</category>
      <category>n8n</category>
      <category>Study</category>
      <category>개발</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/77</guid>
      <comments>https://baeougi.tistory.com/77#entry77comment</comments>
      <pubDate>Wed, 8 Apr 2026 12:17:31 +0900</pubDate>
    </item>
    <item>
      <title>Sentry 사용해보자</title>
      <link>https://baeougi.tistory.com/76</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 오늘은 제가 앱 개발을 하면서 crash 수집을 위해서 사용했던 sentry에 대해서 알아보겠습니다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;기능이 굉장히 여러가지인 것 같아서 글을 작성하게 되었습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;941&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DrU1L/dJMcaaxJHVT/s1YQSS0zk7ipyDYsJl8BHk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DrU1L/dJMcaaxJHVT/s1YQSS0zk7ipyDYsJl8BHk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DrU1L/dJMcaaxJHVT/s1YQSS0zk7ipyDYsJl8BHk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDrU1L%2FdJMcaaxJHVT%2Fs1YQSS0zk7ipyDYsJl8BHk%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;227&quot; height=&quot;262&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;941&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Sentry란?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ndq7q/dJMcaaqXQ3i/kRVoziIEKyo40HO9Atg6N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ndq7q/dJMcaaqXQ3i/kRVoziIEKyo40HO9Atg6N0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ndq7q/dJMcaaqXQ3i/kRVoziIEKyo40HO9Atg6N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNdq7q%2FdJMcaaqXQ3i%2FkRVoziIEKyo40HO9Atg6N0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;900&quot; height=&quot;500&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sentry(센트리)는 영어로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;보초, 파수꾼, 감시병&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;을 뜻하고 이름 뜻과 잘어울리게 에러 추적, 성능 모니터링 도구 등 여러 역할을 하면서 서비스의 오류를 빠르게 진단, 해결 하는데 많은 도움이 됩니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;특히 API 통신 때 발생하는 오류를 실시가능로 수집하고 분석하는 기능이 Sentry가 가진 가장 큰 장점입니다!&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;왜 사용하냐?&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에러가 나면 바로 알 수 있습니다&lt;/li&gt;
&lt;li&gt;스택 트레이스, URL, 브라우저, OS, 앱 버전, 사용자 행동 흐름 같은 걸 같이 남겨줘서 에러 재현이 쉬워집니다&lt;/li&gt;
&lt;li&gt;배포 후 문제를 바로 잡을 수 있습니다&lt;/li&gt;
&lt;li&gt;로그만으로는 에러 추적이 어렵습니다&lt;/li&gt;
&lt;li&gt;발생 빈도, 영향 받은 사용자 수, 최근 발생 여부같은 걸 보여줘서 우선 순위를 판단하기 쉽습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;대표기능 정리&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;에러 모니터링&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기본적인 기능입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱에서 발생한 예외, 크래시, unhandled error를 수집해서 이슈 단위로 보여줍니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택 트레이스, 발생 횟수, 처음/마지막 발생 시점, 영향받은 사용자 수 같은 정보도 같이 볼 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이슈 그룹핑&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 원인의 에러를 자동으로 묶어서 보여줍니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 같은 에러가 수백 번 터져도 하나의 이슈로 관리할 수 있고 중복 확인 시간이 줄어듭니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;성능 추적&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 메시지만 주는 게 아니라 어떤 파일/라인에서 터졌는지와 함께 URL, 브라우저, OS, 디바이스, 릴리즈 버전, 환경 정보들을 남겨줍니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;세션 리플레이&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 세션을 다시 보듯이 재생해서, 실제 사용 흐름 중 어디서 문제가 났는지 확인할 수 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트엔드에게 특히 좋은 기능이니 잘 활용하시면 좋을거 같습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;릴리즈 추적&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포 버전 기준으로 이슈를 묶고, 어느 릴리즈 이후 에러가 증가했는지 추적할 수 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포 직후 장애 원인 파악할 때 핵심적으로 사용됩니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;알림 연동&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 에러가 급증하거나, 성능 임계치를 넘거나, 새 릴리즈에서 문제가 생기면 Slack, 이메일 등으로 알림을 보낼 수 있습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Sentry 회원가입 및 로그인&lt;/li&gt;
&lt;li&gt;프로젝트 생성&lt;/li&gt;
&lt;li&gt;나의 어플리케이션에 세팅&lt;/li&gt;
&lt;li&gt;알림 봇 추가&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이렇게 사용 했습니다&lt;/p&gt;
&lt;pre id=&quot;code_1773195525120&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @sentry/react-native&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1773195444122&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// layout.tsx

import { Stack } from 'expo-router';
import { View } from 'react-native';
import '../../global.css';
import { useCustomFonts } from '@/shared/assets/fonts/fontLoader';
import Toast from 'react-native-toast-message';
import QueryProvider from '../shared/lib/QueryProvider';
import '@/shared/lib/sentry';
import * as SentryRN from '@sentry/react-native';

export default function RootLayout() {
  const fontsLoaded = useCustomFonts();
  if (!fontsLoaded) return null;
  return (
    &amp;lt;View className=&quot;mb-6 flex-1 bg-white&quot;&amp;gt;
      &amp;lt;QueryProvider&amp;gt;
        &amp;lt;SentryRN.ErrorBoundary fallback={&amp;lt;&amp;gt;&amp;lt;/&amp;gt;}&amp;gt;
          &amp;lt;Stack
            screenOptions={{
              headerShown: false,
              animation: 'fade',
              gestureEnabled: true,
              gestureDirection: 'horizontal',
            }}
          /&amp;gt;
        &amp;lt;/SentryRN.ErrorBoundary&amp;gt;
        &amp;lt;Toast /&amp;gt;
      &amp;lt;/QueryProvider&amp;gt;
    &amp;lt;/View&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1773195382036&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// sentry.ts

import * as Sentry from '@sentry/react-native';

Sentry.init({
  dsn: 'SENTRY_DSN',
});&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;글을 마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 에러에 대한 대응을 좀 더 잘 하기 위해서 sentry를 이용해서 크러시를 수집하였습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해놓으니까 좀 더 수고스러움이 줄은거 같아서 좋았던거 같습니다&lt;/p&gt;</description>
      <category>Fe</category>
      <category>frontend</category>
      <category>sentry</category>
      <category>Study</category>
      <category>개발</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/76</guid>
      <comments>https://baeougi.tistory.com/76#entry76comment</comments>
      <pubDate>Wed, 11 Mar 2026 11:19:02 +0900</pubDate>
    </item>
    <item>
      <title>refresh Token 트러블 슈팅</title>
      <link>https://baeougi.tistory.com/75</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 오늘은 프로젝트를 진행하면서 생긴 refresh Token으로 Token을 재발급할 때&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;제대로 발급 안되는 문제들에 대해 어떻게 해결 했는지 트러블 슈팅을 작성 해봤어요~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;363&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y6OKa/dJMcahwwROi/ghwboW4GNr11jLc7sXQnq0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y6OKa/dJMcahwwROi/ghwboW4GNr11jLc7sXQnq0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y6OKa/dJMcahwwROi/ghwboW4GNr11jLc7sXQnq0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY6OKa%2FdJMcahwwROi%2FghwboW4GNr11jLc7sXQnq0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;363&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;363&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;생긴 문제들 정리 및 원인 파악&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;refresh Token 요청이 무한으로 가는 문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCyJGm/dJMcacIK2SZ/a8GkOVjQIqu6JWVrjr6P6K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCyJGm/dJMcacIK2SZ/a8GkOVjQIqu6JWVrjr6P6K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCyJGm/dJMcacIK2SZ/a8GkOVjQIqu6JWVrjr6P6K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCyJGm%2FdJMcacIK2SZ%2Fa8GkOVjQIqu6JWVrjr6P6K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;420&quot; height=&quot;298&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인을 모르고 refresh Token 요청이 계속 실패하면서 무한으로 요청이 계속 가는 문제가 발생했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 이 요청이 무한으로 가고 있는 줄도 모르고 계속 요청을 보내게 되어서 서버가 잠시 다운될 정도였습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때까지는 refresh Token 요청이 안되는 이유를 찾지는 못하였습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;refresh Token이 동시에 여러 요청이 가서 발급이 안되는 문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPkvXb/dJMcaflajUZ/UxYf3yhAx0kOQriav6cup1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPkvXb/dJMcaflajUZ/UxYf3yhAx0kOQriav6cup1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPkvXb/dJMcaflajUZ/UxYf3yhAx0kOQriav6cup1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dPkvXb/dJMcaflajUZ/UxYf3yhAx0kOQriav6cup1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;refresh Token 요청이 거의 동시에 여러 개가 보내지면서 모든 요청이 실패가 되는 상황이 벌어졌습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 제대로 된 이유도 파악하지 못하고 미뤄두고 있었는데 하루 날을 잡고 안되는 이유들을 찾으려고 몇가지를 나열하니&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금방 해결되었던거 같습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제별 해결 방법&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bItwnV/dJMcahwygLT/lBBjsNSzdzbxXoKbUrOnyK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bItwnV/dJMcahwygLT/lBBjsNSzdzbxXoKbUrOnyK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bItwnV/dJMcahwygLT/lBBjsNSzdzbxXoKbUrOnyK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbItwnV%2FdJMcahwygLT%2FlBBjsNSzdzbxXoKbUrOnyK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;471&quot; height=&quot;314&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;refresh Token 요청이 무한으로 가는 문제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 정말 간단하게 해결 했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios retry 횟수를 정해 같은 요청이 계속 실패해도 다시 가지 않도록 3회 정도로 제한을 두었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 겪고 혹시 모를 상황을 대비하여서 항상 retry 횟수를 정해두는 습관을 가졌습니다&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;refresh Token이 동시에 여러 요청이 가서 발급이 안되는 문제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결한 방법은 40&lt;span style=&quot;color: #333333;&quot;&gt;1(Unauthorized)이 발생한 에러들을 모두 큐에 적재하여 하나씩 꺼내 refresh Token 요청을 보내도록 했습니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이렇게 하면 바로 요청을 보내는게 아니라 큐에 적재하여 하나씩 꺼내서 처리 하기 때문에 동시에 여러 요청이 가는 문제를 막을 수 있었습니다&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;해결 코드&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1770362066026&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import axios, {
  AxiosError,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios';
import { authConfig } from '../config/auth';
import {
  AUTH_TOKEN_KEY,
  AUTH_REFRESH_TOKEN_KEY,
  getCookie,
  setCookie,
  clearTokens,
} from '@/entities/user';

export const baseURL = process.env.NEXT_PUBLIC_API_URL;

export const instance = axios.create({
  baseURL,
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json',
  },
});

const refreshClient = axios.create({
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json',
  },
});

let isRefreshing = false;

let failedQueue: Array&amp;lt;{
  resolve: (token: string) =&amp;gt; void;
  reject: (error: any) =&amp;gt; void;
}&amp;gt; = [];

const processQueue = (error: any, token: string | null = null) =&amp;gt; {
  failedQueue.forEach(({ resolve, reject }) =&amp;gt; {
    if (error) reject(error);
    else resolve(token!);
  });
  failedQueue = [];
};

instance.interceptors.request.use(
  (config: InternalAxiosRequestConfig) =&amp;gt; {
    if (typeof window !== 'undefined') {
      const accessToken = getCookie(AUTH_TOKEN_KEY);
      if (accessToken) {
        config.headers.Authorization = `Bearer ${accessToken}`;
      }
    }
    return config;
  },
  (error: AxiosError) =&amp;gt; Promise.reject(error),
);

instance.interceptors.response.use(
  (response: AxiosResponse) =&amp;gt; response,
  async (error: AxiosError) =&amp;gt; {
    if (typeof window === 'undefined') return Promise.reject(error);

    const originalRequest = error.config as InternalAxiosRequestConfig &amp;amp; {
      _retry?: boolean;
    };

    if (error.response?.status !== 401) return Promise.reject(error);

    const url = originalRequest.url ?? '';

    const SKIP_PATHS = [
      '/api/admin/signin',
      '/api/signin',
      '/api/auth/reissue',
      '/auth/reissue',
    ];

    if (SKIP_PATHS.some((p) =&amp;gt; url.includes(p))) {
      return Promise.reject(error);
    }

    if (originalRequest._retry) return Promise.reject(error);
    originalRequest._retry = true;

    if (isRefreshing) {
      return new Promise((resolve, reject) =&amp;gt; {
        failedQueue.push({
          resolve: (token: string) =&amp;gt; {
            originalRequest.headers.Authorization = `Bearer ${token}`;
            resolve(instance(originalRequest));
          },
          reject,
        });
      });
    }

    isRefreshing = true;

    try {
      const refreshToken = getCookie(AUTH_REFRESH_TOKEN_KEY);
      if (!refreshToken) throw new Error('No refresh token available');

      const res = await refreshClient.patch&amp;lt;{ accessToken: string }&amp;gt;(
        '/api/auth/reissue',
        null,
        {
          headers: {
            refreshtoken: refreshToken,
          },
        },
      );

      const { accessToken } = res.data;

      setCookie(AUTH_TOKEN_KEY, accessToken, 86400);

      processQueue(null, accessToken);
      originalRequest.headers.Authorization = `Bearer ${accessToken}`;
      return instance(originalRequest);
    } catch (refreshError) {
      processQueue(refreshError, null);
      clearTokens();

      const currentPath = window.location.pathname;
      const isProtectedPage = authConfig.protectedPages.some((path: string) =&amp;gt;
        currentPath.startsWith(path),
      );

      if (isProtectedPage) {
        window.location.replace(authConfig.signInPage);
      }

      return Promise.reject(refreshError);
    } finally {
      isRefreshing = false;
    }
  },
);&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;글을 마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 Token 재발급 문제를 트러블슈팅으로 간단히 정리해봤습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 해결하는 과정에서 여러 가설을 세우고 하나씩 검증해 나가니 배운 점도 많았고 해결 속도도 빨라졌다고 느꼈습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽어주셔서 감사합니당&lt;/p&gt;</description>
      <category>Fe</category>
      <category>frontend</category>
      <category>refresh</category>
      <category>refresh token</category>
      <category>Study</category>
      <category>개발</category>
      <category>트러블 슈팅</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/75</guid>
      <comments>https://baeougi.tistory.com/75#entry75comment</comments>
      <pubDate>Fri, 6 Feb 2026 16:15:19 +0900</pubDate>
    </item>
    <item>
      <title>Goodbye By-ye-ye 2025</title>
      <link>https://baeougi.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 저에게 너무 배운 게 많은 2025년도를 보내고 2026년도를 반길 준비를 하려고 이렇게 글을 써보게 되었습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLLpBE/dJMb99ZkONO/nq6aKodifYENsNHm8ifA9K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLLpBE/dJMb99ZkONO/nq6aKodifYENsNHm8ifA9K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLLpBE/dJMb99ZkONO/nq6aKodifYENsNHm8ifA9K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLLpBE%2FdJMb99ZkONO%2Fnq6aKodifYENsNHm8ifA9K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;364&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;작년 나의 목표&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;첫번째 다짐은 깔끔한 코드를 작성하는 것 입니다&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 계획은 어느정도 이루어진거 같습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1학년 땐 아무것도 모르고 프로젝트를 전체적으로 보는 능력이 부족했던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 코드가 모두 응집되어 있고 하나의 역할을 하지 않아서 더욱 더 코드를 보기 힘들었던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 요즘은 저만의 스타일을 가지고 함수를 나누고 나름 깔끔한 코드를 작성할 수 있다고 할 수 있을거 같습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;두번째는&amp;nbsp;AI&amp;nbsp;의존도를&amp;nbsp;현저히&amp;nbsp;낮추는&amp;nbsp;것&amp;nbsp;입니다&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 목표는 어느 부분에서는 맞고 어느 부분에서는 틀린 것 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 AI에 모든 걸 물어보지 않습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 해야하는 부분과 AI에게 부탁할 수 있는 부분을 나누어 AI 의존도가 어느 부분에서는 늘고 어느 부분에서는 적어진거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 요즘 제 생각으로는 AI 의존도를 높이는게 더욱 더 똑똑한 개발자 같다고 생각하여서 어떻게 더 많이 효율적으로 사용할지 고민하는거 같습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;올해 내가 한 일&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 제가 올해 한 가장 큰 일들은 전교 회장이 된 것과 학교기업의 리더가 된 것 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 가지를 하면서 맡은 일도 굉장히 많았고 한 번에 일이 몰려올 때가 많아 버거웠던 거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 어떤 고비들이 있었는지 정리해보자면&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;전교 회장&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 당선을 위해 선거운동을 하는 과정부터 힘든 것이 굉장히 많았던 거 같습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공약 중에 자격증 페이백이라는 공약이 있었는데 처음에는 괜찮다고 하셨는데 갑자기 안된다고 하셔서 2일 만에 공약을 삭제하기도 하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나머지 공약을 이루는데도 엄청나게 많은 시간과 들이고 논의를 많이 하여 결국 가능하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이뿐만 아니라 올해 선생님들이 모두 바뀌면서 규칙이 바뀌고 기존과 너무 많이 크게 달라져 마찰이 있었던 게 많이 힘들었던 거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두의 의견을 들으면서 좋은 방향으로 가고 싶은데 양 쪽 입장 모두 이해가 가고 잘 조정해서 하고 싶었지만 회장이 된 지 많이 되지 않았고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힘이 더 강한 의견만 듣고 따라간 것 같아 더 깊게 고민해보지 못한 것이 후회가 됐던 거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음은 축제 준비였습니다 생각보다 학생회가 해야 하는 일이 너무 많고 무슨 일을 해야 하는지도 잘 몰라 헤맸던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저희 학교 학생들이 축제 참여도가 낮아서 프로그램을 진행하는 데 어려움이 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공연을 해주는 친구들도 별로 없어 찬조팀을 많이 불렀는데 노래가 너무 많이 겹치는 일이 발생해서 많이 곤란하기도 했던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당일에도 긴장의 틈을 놓치지 못하고 너무 많이 혼났던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전교 회장을 하면서 사람들이랑 부딪치고 선생님들에게 혼나는 일이 많아서 몸이 고단한 것보단 정신적으로 힘든 것이 많았던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 그러면서 마음이 더 단단해지고 다른 사람의 마음을 이해하고&amp;nbsp; 수용하는 법을 배운거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 완전히 악한 사람은 없다고 생각이 바뀌게 된 계기가 된 것 같습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;학교기업 리더&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학교기업 리더를 하면서 외주 프로젝트 3가지 정도를 하면서 일년을 보냈던 것 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전부 학교기업에 프로젝트인 건 아니지만 멤버가 거의 같아 같이 적겠습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 두 개의 프로젝트의 기간이 완전히 겹쳐서 더욱 힘들었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;광탈페&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로젝트를 하면서 8기 리더로서 2차 릴리즈부터 집중적으로 직접 장학사님과 소통하고 많은 이야기를 한 것 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요구사항이 계속 생기고 결과물도 몇 번이나 피드백을 받고 다시 제작했던거 같습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 축제 전날에는 불안한 마음에 맘을 새며 계속 테스트를 했던 기억이 납니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;축제 당일에 가서 실제로 발로 뛰며 행사를 운영하였고 성공적으로 마무리하고 정말 눈물이 날거 같았습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 하면서 장학사님에게 심한 말도 많이 들었고 점심시간에 급하게 일을 주셔서 밥을 못챙길 때도 정말 많았습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 그걸 견뎌내서 좋은 결과가 있었다고 생각합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시민화폐, 광산&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로젝트로는 아직도 애를 쓰고 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 프로젝트 인원이 4명이나 이탈하면서 이 자리를 두 명에서 다 보완하게 되었습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갑자기 앱까지 개발하게 되었고 다 개발이 되었어도 출시라는 너무 큰 벽이 존재했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iOS는 법인 계정을 만드는 것부터 막혔습니다 현재 반려당해 큰 어려움을 겪고 있습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Android도 비공개 테스트에서 한 번 반려당한 상태입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 꾸준히 확인하며 메일도 보내고 있으니 빨리 출시가 되길 바라고 있습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Expo&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로젝트는 그래도 앞에 두 프로젝트가 거의 마무리 됐을 때 하게 된 프로젝트입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 처음부터 다시 제작한 것이 아니라 선배님들이 만들어놓으신 프로젝트를 리팩토링하는 식으로 진행 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 프로젝트를 처음할 때도 어려움이 있었습니다 프로젝트의 이해도도 떨어지고 선배님들이 모두 취업에 나가셔서 인수인계를 받지 못하고 구현하게 되었습니다 이런 것 치고는 앞에 두 프로젝트를 한 경험 덕분인지 요구사항을 명확하게 구현하여서 큰 어려움 없이 순탄하게 마무리 했던 프로젝트 였던거 같습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;위 프로젝트에서 발생했던 트러블 슈팅&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 두 가지 정도가 기억에 남는 트러블 슈팅이었던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;SSE 동작하지 않는 문제&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1542&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cce3tG/dJMcadHqxRq/k8X5V4cVNv7MOsOgRx0ck1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cce3tG/dJMcadHqxRq/k8X5V4cVNv7MOsOgRx0ck1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cce3tG/dJMcadHqxRq/k8X5V4cVNv7MOsOgRx0ck1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcce3tG%2FdJMcadHqxRq%2Fk8X5V4cVNv7MOsOgRx0ck1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1542&quot; height=&quot;868&quot; data-origin-width=&quot;1542&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 일단 경험해보기 어려운 기술이었던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학교 프로젝트를 하면서 굳이 실시간으로 이루어져야 할 상황도 없었고 처음 구현할 때 개념조차 모르던 기술이었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 문제는 저는 백엔드 쪽은 잘 몰라 이해하지 못했지만 투표시작하기와 다음팀 넘어가기 api 두가지가 존재 했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 다음 팀 넘어가기 호출 후에 투표 시작하기를 호출 해야 하는데 반대 순서로 진행하여 어려움이 있었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 접속에 성공한 다음 받은 event 명에 addEventListener를 하여 계속 이벤트를 listen 해야 사용할 수 있는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 부분이 누락되어 접속만 성공하고 그 다음 값이 변경될 때 이벤트를 받지 못하는 문제가 있었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;환경에 따라 다르게 깨지는 UI&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2026-01-06 at 4.56.03 AM.png&quot; data-origin-width=&quot;1028&quot; data-origin-height=&quot;952&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9la3C/dJMcaaKJQMZ/7xjfvKBaKK3yKncE9OcL41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9la3C/dJMcaaKJQMZ/7xjfvKBaKK3yKncE9OcL41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9la3C/dJMcaaKJQMZ/7xjfvKBaKK3yKncE9OcL41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9la3C%2FdJMcaaKJQMZ%2F7xjfvKBaKK3yKncE9OcL41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;387&quot; data-filename=&quot;Screenshot 2026-01-06 at 4.56.03 AM.png&quot; data-origin-width=&quot;1028&quot; data-origin-height=&quot;952&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 실제로 문제를 발견하지 못할 뻔 했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평소 어플을 개발을 할 때 실제 핸드폰이 아닌 그냥 에뮬레이터를 써서 개발을 계속 진행 했었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핸드폰으로 중간점검을 하다가 발견했습니다 에뮬레이터에서는 정상적으로 동작하였지만 핸드폰에서는 심각하게 ui가 깨졌습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인 분석을 해보니 요소가 많아 ScrollView가 부모였습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ScrollView 안에 View 태그를 하나 더 해 자식 요소에 flex-1 스타일을 주었는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flex-1은 남은 공간을 모두 차지하는 속성인데, 크기가 무한히 확장되는 ScrollView의 자식 요소에 적용되어 문제가 발생했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결방법은 flex-1을 제거하고 여백을 주었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 트러블 슈팅을 통해 다양한 환경에서 테스트 해보는 것을 중요하게 여기게 되었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 태그나 스타일 속성에 대해 본질을 깊게 생각할 기회가 되어 좋았던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;성장&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bha3Az/dJMcadm4vmW/Pdlm5kwidLpcLEWYSeZg1K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bha3Az/dJMcadm4vmW/Pdlm5kwidLpcLEWYSeZg1K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bha3Az/dJMcadm4vmW/Pdlm5kwidLpcLEWYSeZg1K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbha3Az%2FdJMcadm4vmW%2FPdlm5kwidLpcLEWYSeZg1K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;242&quot; height=&quot;208&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;포기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 올해 느꼈었던 성장은 포기하지 않았던 점입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 너무 힘들면 회피하려고 하는 경향이 있었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 작년에 이걸 고치고 싶다고 했던 것 같은데 올해는 거의 한 번도 포기하고 도망치려 하지 않았던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 목표를 이루니 좀 더 좋은 사람이 되고 싶은 욕심이 생기고 저의 대한 목표도 많아졌습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이해&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상대방을 이해하는 능력이 커진 것 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 전 제가 한 번 아니라고 생각하는 사람은 미워하고 단정 지어 버리고 다시 보려고 하지 않았던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이제 그 사람이 왜 그렇게 행동하고 생각 했는지 듣고 그 사람의 입장에서도 세상을 바라볼 수 있는 마음을 좀 더 갖게 된 것 같습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기술적으로 많이 성장한 경험&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술적으로 많이 성장한 경험은 처음 학교기업으로 들어왔을 때 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학교기업에 들어와서 제대로 된 팀원과 선배님들에게 코드리뷰를 받으면서 제 코드 스타일이 생기고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협업 능력도 급격하게 성장했던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 느낀 점은 확실히 코드 리뷰가 중요하다는 것을 깨달았고 학교기업실에서 선배님들이랑 토론을 하면서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 트렌드, 기술 등에 대해 많이 이야기할 수 있어서 성장을 많이 했던거 같습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;부족했던 점&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7O51y/dJMcabbL8VB/0r3zB8YLRVAa7uEFLgQG50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7O51y/dJMcabbL8VB/0r3zB8YLRVAa7uEFLgQG50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7O51y/dJMcabbL8VB/0r3zB8YLRVAa7uEFLgQG50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7O51y%2FdJMcabbL8VB%2F0r3zB8YLRVAa7uEFLgQG50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;341&quot; height=&quot;342&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;건강&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 일을 한 번에 많이하고 여기저기서 스트레스를 받다보니 건강이 많이 악화 됐던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 번 쓰러지기도 하고 최근에는 입원을 하면서 위/대장 내시경을 하면서 더 힘들었던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 뿐만 아니라 계속 안좋은 자세로 개발을 하다보니 허리, 손목 여러 곳이 아파서 고생했습니다..&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;세심함&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일을 급하게 여러가지를 처리하다보니 놓치는 것들이 많았습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세심하게 하나하나 계산에서 확실하게 챙기는 것이 부족했다고 많이 느낍니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 이것 때문에도 많이 혼났습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;개인 시간&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 어쩔 수 없는 이야기지만 개인 시간이 많이 부족했던거 같습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회장 일을 하면서 개인 공부를 할 시간이나 여가할 시간이 부족할 때가 많았습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 회장이 된 걸 한 번도 후회하지 않았다고 말하면 거짓말일 수밖에 없습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2026년도 목표&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;시간 분배를 잘하자&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이렇게 여러 일을 한 번에 해본 적이 없어서 어리버리하며 시간을 많이 날렸습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버린 시간들이 너무 아까워서 최대한 시간 분배를 조금 더 잘해서 더 많은 성장을 하고 싶습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내년에는 꼭 시간을 잘 분배하여 사용해서 발전 해보겠습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;todo mate 성실하게 작성하기&lt;/li&gt;
&lt;li&gt;큰 목표 작은 목표 분류하여 마감기간 정하기&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;건강을 챙기자&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;건강하지 않으면 또 시간을 뺏기는거 같습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 제가 아무리 노력을 많이하고 멋진 사람이 되어도 나중에 건강하지 않으면 소용이 없기 때문에&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;규칙적인 수면&lt;/li&gt;
&lt;li&gt;바른 자세&lt;/li&gt;
&lt;li&gt;취미생활(운동, 먹방)을 통한 스트레스 관리&lt;/li&gt;
&lt;li&gt;스트레칭&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;조금 더&lt;/b&gt; &lt;b&gt;신중하자&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일을 마치더라도 그냥 끝내는 것이 아닌 그 일에 대해서 몇 번이고 반복해서 확인하여 실수를 좀 더 줄이고 싶습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 일에 신중하게 하면 결국 제가 신뢰할 수 있는 사람이 되는 길이라고 생각합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내년에는 취업을 해야하니 저를 좀 더 신뢰할 수 있는 사람으로 만들고 싶습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무슨 일이든 여러 번 다시 확인하고 마무리하기&lt;/li&gt;
&lt;li&gt;셀프 체크리스트 만들기&lt;/li&gt;
&lt;li&gt;일이 끝난 후 한 일 되돌아보기&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;AI 활용하여 생산성 높이기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 AI가 정말 대단한 것 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국엔 남는 건 AI를 잘 활용하는 개발자가 남을거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 여러 AI를 공부하여 상황에 맞게 잘 활용하여 생산성을 수직 상승시키는게 저의 목표입니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;좋은 프롬프트 작성 연습하기&lt;/li&gt;
&lt;li&gt;용도별 AI 분리하여 사용하기&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;b&gt;취업&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;취업 준비 어떻게 할 것인가?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 지금 그래도 제 기준으로는 어느 정도 포트폴리오 틀은 잡았다고 생각하여서 그 틀에 맞춰 내용을 다 작성 후 많은 사람들에게 공유하여 다른 시선에서 최대한 많은 피드백을 받아보는 것이 목표입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 얼마전에 서류가 하나 붙어서 과제를 했었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 과제를 진행하면서 떨어졌었는데 실패 원인 분석도 해보며 이것저것 보완하면서 더 준비해보려고 할거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실패 -&amp;gt; 보완 -&amp;gt; 도전&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;취업하고 싶은 회사&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 저는 제 &lt;b&gt;시야를 많이 넓혀줄 수 있는 회사&lt;/b&gt;에 가고 싶습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업무 강도가 높더라도 알아가고 배울 수 있는게 많은 회사면 아마 그 회사에 갈거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 회사가 새로운 프로젝트를 준비하고 있었으면 좋겠습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 프로젝트에 초기부터 합류하여 그 프로젝트에 애정을 가지고 깊게 프로젝트와 회사에 스며들고 싶습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저는 현재 광주에 거주 중인데 저는 광주에서 취업하지 않고 위쪽으로 올라가고 싶습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서울이나 경기도 쪽이 채용 공고가 많은 것도 있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익숙한 환경이 아닌 완전히 새로운 환경에서 독립하여 자립심을 키우고 싶습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;글을 마치며..&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 학교에 와서 처음으로 1학년 때 1년을 제대로 돌아보았고 벌써 두 번째로 보내는 글을 작성하고 있다는 사실에 놀라고 시간이 빨리 가는게 조금 무섭게 느껴졌습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 내년에 더 후회 없는 삶을 살기 위해서 더욱 더 열심히 달리겠습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열심히 해서 취업 성공하고 싶습니당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글 읽어주셔서 정말 감사합니다&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;035&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/035.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/035.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>회고록</category>
      <category>2025</category>
      <category>2026</category>
      <category>Fe</category>
      <category>Study</category>
      <category>개발자</category>
      <category>회고</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/74</guid>
      <comments>https://baeougi.tistory.com/74#entry74comment</comments>
      <pubDate>Wed, 31 Dec 2025 17:57:59 +0900</pubDate>
    </item>
    <item>
      <title>무한 스크롤과 가상 스크롤에 대해서 알아보자</title>
      <link>https://baeougi.tistory.com/73</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 저희 팀 친구가 정말 가볍고 좋은 무한 스크롤 그리고 가상 스크롤 라이브러리를 내서&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;저희 프로젝트에 적용 하는 겸 이렇게 무한 스크롤과 가상 스크롤에 대해서 글을 쓰게 되었습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8xqtg/dJMcac9gTmC/xgrP6wxEq6NSbkjPqOf80K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8xqtg/dJMcac9gTmC/xgrP6wxEq6NSbkjPqOf80K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8xqtg/dJMcac9gTmC/xgrP6wxEq6NSbkjPqOf80K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8xqtg%2FdJMcac9gTmC%2FxgrP6wxEq6NSbkjPqOf80K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;411&quot; data-origin-width=&quot;735&quot; data-origin-height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;무한 스크롤이란?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;739&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7BfcC/dJMcagYceqw/gEMBTnj8CjHTJaVfWWZ7jK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7BfcC/dJMcagYceqw/gEMBTnj8CjHTJaVfWWZ7jK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7BfcC/dJMcagYceqw/gEMBTnj8CjHTJaVfWWZ7jK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7BfcC%2FdJMcagYceqw%2FgEMBTnj8CjHTJaVfWWZ7jK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;346&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;739&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무한스크롤이란 말 그대로 연속적인 스크롤을 제공하는 UI/UX 요소입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면에 표시된 아이템 목록의 끝까지 내려갔을 때 자동으로 다음 데이터를 요청하여 추가 아이템을 불러오는 기술입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지네이션과의 차이는 페이지네이션은 다음 페이지로 넘어갈 때 api가 호출되어 데이터를 불러오지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무한 스크롤은 스크롤할 때마다 api가 데이터를 불러옵니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번에 모든 데이터를 불러오는 것이 아니라서 큰 장점이 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용 사례는 유튜브, 인스타그램 등 많은 소셜 미디어에 적용되어 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 페이지에 과도한 요소가 추가되면 브라우저 성능이 저하되어 페이지 로딩에 실패하거나 브라우저가 다운될 수 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 1500개 이하 권장&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무한스크롤은 사용자가 콘텐츠를 끊김 없이 탐색할 수 있습니다 자연스러운 사용자 경험 제공&lt;/li&gt;
&lt;li&gt;스크롤만으로 추가 콘텐츠가 로드되기 때문에 사용자가 더 많은 콘텐츠를 소비하게 유도합니다&lt;/li&gt;
&lt;li&gt;스크롤만으로 콘텐츠 탐색이 가능해 사용자에게 편리함을 제공합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지나치게 많은 스크롤을 요구할 수 있습니다&lt;/li&gt;
&lt;li&gt;사용자의 기기 성능과 네트워크 속도에 따라 느려질 수 있습니다&lt;/li&gt;
&lt;li&gt;특정 콘텐츠에 바로 접근하기 어려워지고 원하는 정보를 찾는 것에 어려움이 생깁니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무한 스크롤 적용하는 방법&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Scroll Event&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 스크롤을 할 때 특정 위치에 도달하면 새로운 데이터를 자동으로 불러오는 방식입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크롤 이벤트를 통해 현재 스크롤 위치를 감지하고 페이지의 끝에 가까워지면 데이터를 추가로 로드합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 간단하게 구현 가능하지만 성능상 좋지 않을 수 있습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Intersection Observer API&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 요소가 뷰포트에 나타나는 시점을 감지하고 해당 시점에 새로운 데이터를 로드하는 방식입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소와 뷰포트 간의 교차를 비동기적으로 관찰할 수 있고 스크롤 성능에 미치는 영향을 줄일 수 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법은 최신 브라우저에서 지원됩니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;가상 스크롤이란?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAcwzE/dJMcagw8mAG/0yC1iaeseXK7fIcEL7UOsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAcwzE/dJMcagw8mAG/0yC1iaeseXK7fIcEL7UOsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAcwzE/dJMcagw8mAG/0yC1iaeseXK7fIcEL7UOsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAcwzE%2FdJMcagw8mAG%2F0yC1iaeseXK7fIcEL7UOsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;481&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저 입장에서 직접 보이는 요소들만 렌더링하고 보이지 않는 요소들은 렌더링하지 않는 기술입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이템이 너무 많을 때 모든 요소를 렌더링하고 있으면 성능이 분명히 안좋아질 것입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때 필요한 것이 바로 가상 스크롤입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대용량 데이터를 한번에 보여주거나 무한 스크롤에서 계속 요소들이 쌓일 때, 로그 화면처럼 엄청난 스크롤이 생길 때 유용합니다&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원리&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;높이 계산&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스크롤 위치 계산 및 보여야 할 요소계산&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;높이 계산&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 아이템의 높이와 폭을 알고 있어야 하고 존재하는 모든 아이템의 높이와 폭을 알아야 합니다&lt;/p&gt;
&lt;pre id=&quot;code_1764004189001&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const totalHeight = itemHeight * itemCount;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스크롤 위치를 감지해&lt;span&gt;&amp;nbsp;&lt;/span&gt;현재 필요한 인덱스만 계산&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 스크롤을 할 때 보여야 할 아이템을 구해야합니다&lt;/p&gt;
&lt;pre id=&quot;code_1764004423306&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const startIndex = floor(스크롤이 내려간 거리 / itemHeight);
const endIndex = startIndex + 화면에 필요한 아이템 수;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;빈 공간 주기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이템이 전부 렌더링 되지 않기 때문에 중간에 위치해야 할 실제 자리로 배치하려면 위 아래에 빈 공간을 주어서 실제로는 다른 요소들이&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;있는 것처럼 속인다&lt;/p&gt;
&lt;pre id=&quot;code_1764004724449&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const offsetTop = 100 * 50 = 5000;
const offsetBottom = 100 * 50 = 5000;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무한 스크롤 vs 가상 스크롤&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘은 이름은 비슷하지만 완전히 다른 기능입니다 하지만 두 기능 같이 유용하게 쓰입니다 두 기능의 차이를 정리 해보았습니다&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 139px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;무한 스크롤&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;가상 스크롤&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;데이터 계속 불러오기&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;렌더링 최적화하기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;핵심 동작&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;리스트 끝 도달 시 api 요청 전송&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;스크롤 위치 변화에 따라 렌더 구간 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;데이터 크기&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;계속 증가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;동일, 증가하지 않음 (단지 렌더링만 최적화)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;렌더링 수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;무제한 증가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;항상 일정한 개수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;메모리 영향&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;시간이 지날수록 증가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;일정하게 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;내가 적용한 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 scrolloop라는 라이브러리를 사용하여서 가상 스크롤을 적용하였습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/scrolloop&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.npmjs.com/package/scrolloop&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 링크를 타고 가시면 라이브러리에 대해서 더 자세히 알 수 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이 라이브러리를 이용하여 간단한 구현에 성공 하였습니다 제가 구현한 코드를 보여드리겠습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 뚝뚝 끊기거나 마지막에 부자연스럽게 아이템이 사라지는 경우가 있었는데 overscan을 올리니 아무 문제 없이 잘 작동하였습니다&lt;/p&gt;
&lt;pre id=&quot;code_1764005026544&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { RefreshControl } from 'react-native';
import Post from '~/shared/ui/Post';
import { useLocalSearchParams } from 'expo-router';
import { ProductType } from '~/shared/types/type';
import { ModeType } from '~/shared/types/mode';
import { useCallback, useState } from 'react';
import { useGetPosts } from '~/shared/model/useGetPosts';
import { returnValue } from '~/view/post/model/handleCategory';
import { Category } from '~/view/post/model/category';
import { VirtualList } from 'scrolloop/native';

export default function PostList({ category }: { category: Category }) {
  const { type } = useLocalSearchParams&amp;lt;{ type: ProductType; mode?: ModeType }&amp;gt;();

  const [refreshing, setRefreshing] = useState(false);
  const currentMode = category ? returnValue(category) : undefined;

  const { data = [], refetch } = useGetPosts(
    currentMode as ModeType | undefined,
    type as ProductType | undefined
  );

  const onRefresh = useCallback(async () =&amp;gt; {
    setRefreshing(true);
    try {
      await refetch();
    } finally {
      setRefreshing(false);
    }
  }, [refetch]);

  return (
    &amp;lt;VirtualList
      decelerationRate={0}
      refreshControl={&amp;lt;RefreshControl refreshing={refreshing} onRefresh={onRefresh} /&amp;gt;}
      itemSize={120} // 아이템 사이즈
      overscan={12} // 보이는 아이템 갯수 말고 얼마나 더 렌더링 할 것인지
      count={data.length} // 아이템 갯수
      renderItem={(index) =&amp;gt; {
        const item = data[index];
        if (!item) return null;

        return &amp;lt;Post {...item} /&amp;gt;;
      }}
    /&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;글을 마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 제가 제 프로젝트 refactor 성능 개선을 하면서 어떤 걸 도입해야 좋을지 고민하며 공부하고 제가 적용한 것을 보여드렸습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 하면서 한 번에 두마리 토끼를 잡은 것 같아서 좋았던거 같습니다 여러분들도 더 좋은 방법을 잘 골라서 사용하시면 좋을거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 꼭 제가 직접 한 번 구현해보는 것도 괜찮을거 같습니다 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;글을 읽어주셔서 감사합니다&lt;/span&gt;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/challenge/large/005.png&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-name=&quot;005&quot; data-emoticon-type=&quot;challenge&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;emoticon&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/challenge/large/005.png&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>라이브러리</category>
      <category>EVENT</category>
      <category>Fe</category>
      <category>frontend</category>
      <category>js</category>
      <category>SCROLL</category>
      <category>Study</category>
      <category>가상 스크롤</category>
      <category>개발</category>
      <category>무한 스크롤</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/73</guid>
      <comments>https://baeougi.tistory.com/73#entry73comment</comments>
      <pubDate>Tue, 25 Nov 2025 02:26:19 +0900</pubDate>
    </item>
    <item>
      <title>동시성 모드(Concurrent mode)에 대해서 알아보자</title>
      <link>https://baeougi.tistory.com/72</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 제가 매일매일 확인하는 메일매일 질문에서 동시성 모드라는 것이 왔는데 제대로 아는 것이 없어서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;오늘 알아보고자 이렇게 글을 써보게 되었습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U4Gog/dJMcacBtXAe/Z53vRhio2WanbRpWG3XbY0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U4Gog/dJMcacBtXAe/Z53vRhio2WanbRpWG3XbY0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U4Gog/dJMcacBtXAe/Z53vRhio2WanbRpWG3XbY0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU4Gog%2FdJMcacBtXAe%2FZ53vRhio2WanbRpWG3XbY0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;236&quot; height=&quot;248&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;동시성 모드(Concurrent&amp;nbsp;mode)란?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0zSZV/dJMcabP6Jop/nHqS3t875NunWd2POHPro1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0zSZV/dJMcabP6Jop/nHqS3t875NunWd2POHPro1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0zSZV/dJMcabP6Jop/nHqS3t875NunWd2POHPro1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0zSZV%2FdJMcabP6Jop%2FnHqS3t875NunWd2POHPro1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;572&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 작업을 비동기적으로 동시에 처리하면서도 중간에 더 중요한 작업이 들어오면 &lt;b&gt;우선순위를 바꿔서 그 작업을 먼저 처리하는 기능&lt;/b&gt;입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전 리액트는 스택 구조로 이루어져 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 Fiber 구조로 이루어져 있어서 동시성 모드로 중간에 멈추거나 작업을 잠시 뒤로 미뤄둘 수 있게 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성 모드를 사용하면 더 부드럽고 즉각적인 반응의 애플리케이션 경험을 줄 수 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반응성과 성능이 향상됩니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 비동기 렌더링&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번에 끝내지 않고 필요에 따라 나누어 처리합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 작업이 생기면 중단, 해당 중요 작업을 먼저 처리 후 렌더링 작업 이어하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시) 사용자가 스크롤 하는 동안 데이터가 로드될 때 스크롤 동작을 우선 처리해 화면이 끊기지 않게 합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 우선순위 기반 작업 처리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업의 긴급도를 평가하여서 높은 우선순위의 작업을 먼저 처리합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시) 높은 우선순위: 사용자의 입력, 애니메이션/낮은 우선순위: 비동기 업데이트, 백그라운드 데이터 로드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 중단 및 재개&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링 작업을 중단하고 나중에 이어서 처리가 가능합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저가 다른 중요한 작업을 먼저 수행하도록 합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Suspense와 통합&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Suspense는 데이터를 기다리는 동안 로딩 UI를 보여줍니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 요청 데이터를 가져오는 동안 로딩 UI를 보여주는데 높은 우선순위는 로딩 UI 낮은 우선순위는 데이터 요청입니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 버전 18부터는 기본적으로 concurrent mode가 적용되게 되어있지만 createRoot를 하지 않으면 lagacy mode가 됩니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;동시성 모드를 사용하면 리액트 18 버전에서 동시성 렌더링을 제공하는 새로운 기능을 사용할 수 있습니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt; 대표적으로는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;useTransition&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;useDeferredValue&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;훅이 있습니다&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;usetransition&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;useTransition&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 훅을 사용하면 isPending과 startTransition을 반환합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #212529; text-align: start;&quot;&gt;Transition마다 우선순위가 존재하며 불필요한 렌더링은 건너뛰고 마지막 상태만 반영합니다&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;isPending&lt;/b&gt;: 현재 상태가 업데이트가 진행중인지 끝나서 보여줄 준비가 됐는지 판단 (boolean)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;startTransition&lt;/b&gt;: 콜백함수를 인자로 받고 콜백함수 안에서 우선순위를 낮춰 렌더링할 setState 함수 실행 (function)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;useDeferredValue&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;startTransition는 콜백함수 내부에 setState를 사용해야 하지만 useEfferredValue는 state값을 인자로 받아서 지연된 값을&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;return 합니다 업데이트 중에 먼저 이전 값을 보여주고 백그라운드에서 업데이트가 왼료되면 새 값으로 다시 렌더링을 시도합니다&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;어떨 때 사용할까?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;필요한 경우는 주로 사용자와의 상호작용이 빈번하고 응답성이 중요한 경우입니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;검색 필터링, 자동완성 같은 기능이 예로 있고 무거운 데이터나 리스트를 로딩하는 경우 유용합니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;그리고 또한 애니메이션이 포함된 화면 전환이나 중요도가 높은 사용자 입력작업도 좋습니다&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;글을 마치며&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이렇게 동시성 모드에 대해서 알아보았는데 이런 mode에 존재도 모르고 사용해왔던 저에게 한 번 더 놀랐습니다&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;궁금증은 가진 적이 있었는데 더 파보려고 하지 않았습니다&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;다음부터는 항상 호기심을 가지고 탐구하려는 자세를 가져야겠다고 생각했습니다&lt;/span&gt;&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;019&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/019.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/019.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>React</category>
      <category>concurrent mode</category>
      <category>Fe</category>
      <category>frontend</category>
      <category>react</category>
      <category>Study</category>
      <category>개발</category>
      <category>동시성 모드</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/72</guid>
      <comments>https://baeougi.tistory.com/72#entry72comment</comments>
      <pubDate>Mon, 17 Nov 2025 00:24:00 +0900</pubDate>
    </item>
    <item>
      <title>꼭 나에게 필요한 일과 해야하는 일, 그렇지 않은 일</title>
      <link>https://baeougi.tistory.com/71</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 최근 제가 일정이 겹치면서 꼭 필요하고 나한테 꼭 필요한 일인지 판단하기 어렵고 판단할 생각조차 하고 있지 못했던 거 같습니다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 최근 깨달은 바가 있는거 같아 이렇게 글을 작성하게 되었습니다&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;제 주관적인 내용이 많이 들어있으니 글을 읽으시면서 주의하셨으면 좋겠습니다&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;여러분들이 이 글을 읽는다면 읽고 자신의 생각을 남겨주셔도 좋을 거 같습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kMhZt/dJMb9Lqq3IF/JjFNGudn6kpyKhQCB40GoK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kMhZt/dJMb9Lqq3IF/JjFNGudn6kpyKhQCB40GoK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kMhZt/dJMb9Lqq3IF/JjFNGudn6kpyKhQCB40GoK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkMhZt%2FdJMb9Lqq3IF%2FJjFNGudn6kpyKhQCB40GoK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;236&quot; height=&quot;236&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이런 생각을 하게 된 계기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;419&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dypVN2/dJMb9O8xgly/csADZJRK8N3uyEqWkS5RV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dypVN2/dJMb9O8xgly/csADZJRK8N3uyEqWkS5RV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dypVN2/dJMb9O8xgly/csADZJRK8N3uyEqWkS5RV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdypVN2%2FdJMb9O8xgly%2FcsADZJRK8N3uyEqWkS5RV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;419&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;419&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이 학교에서 현재 회장 자리에도 있고 학교기업이라는 팀에 소속되어 있습니다 그리고 현재 고등학교 2학년입니다... 저는 도전할 기회가 있다면 무조건 다 잡는 것이 좋다고 생각을 해서 뭐든 할 수 있고 기회가 되는 일을 다 해보려고 했던 거 같습니다 물론 도전하는 것도 좋지만 그렇게 일을 하고 나서 내가 쏟은 노력에 비해서 얻어가는 것이 없다고 생각되는 경험이 몇몇 있었던 거 같습니다 그래서 차라리 이 시간에 다른 일을 할 걸 이라고 후회하는 상황이 많아 자기가 해야 할 일만 골라서 하는 친구들을 보고 저도 그 기준을 세워놓는 게 좋다고 생각이 되어 이렇게 글을 적게 된 거 같습니다&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;꼭 해야 하는 일&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KDh0O/dJMb9NIyxqO/L3MPjgiOA3h5su1TfTnGZK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KDh0O/dJMb9NIyxqO/L3MPjgiOA3h5su1TfTnGZK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KDh0O/dJMb9NIyxqO/L3MPjgiOA3h5su1TfTnGZK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKDh0O%2FdJMb9NIyxqO%2FL3MPjgiOA3h5su1TfTnGZK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;216&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 생각하는 꼭 해야하는 일을 크게 몇 가지로 나누어 말씀드리겠습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;기록에 남는 일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 말하는 기록에 남는 일에 대해서 설명 드리자면 자격증, 입상 등이 있을 거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 활동을 하면 제가 딱히 잘 기록을 자세히 해놓지 않아도 이런 활동을 했다느넥 확실하게 기록에 남습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 어쨋든 이런 기록에 남는 일들은 사회에서도 증명된 활동일 가능성이 높습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;처음 도전 하는 일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 도전을 할 수 있는 좋은 기회가 있습니다 제가 후회한 도전이 있다고 했었는데 후회를 해보는 것도 좋은 경험인거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 처음 도전하는 일이 정말 저에게 도움이 되고 맞는 일일 수도 있습니다 좋은 기회를 놓치는 것보단 처음 도전하여 안좋은 일이면 후회도 하고 하며 경험을 얻는 것이 맞는거라고 생각합니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;계획된 일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신이 목표에 두고 꾸준히 계획했던 일을 포기하는 것은 정말 안좋다고 생각이 들었습니다 목표를 세우고 이루는거까지 꼭 해야한다고 생각합니다 포기하는 습관을 한 번 가지면 끝 없이 포기하게 됩니다 그래서 자신이 확실히 하기로 했고 계획을 세웠던 일은 마무리까지 하는 것이 best라고 생각합니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;책임이 있는 일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 자기 자신이 이미 이걸 하기로 했고 맡을 책임이 있는 일은 중간에 포기하면 안되고 무조건 해야한다고 생각합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학교에서 여러 활동, 프로젝트를 하면서 무책임한 사람이 얼마나 안좋은 사람인지 많이 깨달았습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 모습을 많이 봐왔으니 남에게 해를 끼치지 않고 저라도 책임이 있는 일은 꼭 해야한다고 생각했습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;하지 않아도 되는 일&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clcoKE/dJMb80A4JZo/0JNEkkJZnWk2hp5VOX9Q40/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clcoKE/dJMb80A4JZo/0JNEkkJZnWk2hp5VOX9Q40/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clcoKE/dJMb80A4JZo/0JNEkkJZnWk2hp5VOX9Q40/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclcoKE%2FdJMb80A4JZo%2F0JNEkkJZnWk2hp5VOX9Q40%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;243&quot; height=&quot;243&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;등 떠밀려 하는 일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러분들이 하고자 하는 의지가 없고 정말 쓸모 없다고 생각되는 일들이 하나씩 있을 것입니다 근데 그걸 자꾸 강요 당하고 등 떠민다고 해도 남들의 말을 무조건 들을 것이 아니라 잘 경청하고도 그 일이 나에게 도움이 안된다고 생각하면 등 떠밀려 하는 것이 아닌 그 일 대신 다른 일을 선택하는 것이 더 좋다고 생각합니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;건강을 버리면서까지 하는 일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 모든 일을 하려고 애쓰면서 건강에 지장이 갈 만큼 무리하여 하는 친구들을 많이 봤습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 일이 많다고 해도 결국 다들 목표는 행복하게 자신이 하고 싶은 일을 하는 것일거라고 생각 됩니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이렇게 건강까지 포기하며 일을 하면 결국 다 소용이 없어질 것입니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나를 잘 챙기면서 일을 하는 것이 중요하다고 생각합니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;여러 번 후회한 일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러분들이 해본 여러 경험 중에 많은 비슷한 경험들이 있을 것입니다 그 비슷한 경험들 중 후회가 많고 실패라고 생각된 경험들을 굳이 되풀이 하지 않았으면 좋겠습니다&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;하면서 계속 스트레스 받는 일&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하면서 계속 스트레스 받으며 이게 맞는지 생각이 드는 일은 되도록 피하셨으면 좋겠습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 많은 스트레스를 받는다면 그 일을 잠깐 쉬며 휴식을 하고 돌아와서 다시하는 방법도 좋은 방법이라고 생각됩니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;글을 마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 생각을 이렇게 적어보았는데 여러분들도 할 일을 잘 구분하여 시간을 효율적으로 사용하셨으면 좋겠습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 많은 일들을 하여 좋은 미래가 있길 바래요&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;face&quot; data-emoticon-name=&quot;023&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/023.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/face/large/023.png&quot; width=&quot;80&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Fe</category>
      <category>Study</category>
      <category>개발자</category>
      <category>고등학생</category>
      <category>일</category>
      <category>일관리</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/71</guid>
      <comments>https://baeougi.tistory.com/71#entry71comment</comments>
      <pubDate>Sat, 18 Oct 2025 14:15:46 +0900</pubDate>
    </item>
    <item>
      <title>광탈페 회고</title>
      <link>https://baeougi.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 드디어 제가 열심히 준비하던 광주탈렌트페스티벌이 끝났습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9/27에 실제 공연장에서 실시간으로 했었는데 이 공연장에서 겪었던게 많은거 같아요&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트 시작&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn9wEU/btsQ3v86ZFm/C0srS3QCBz47E3pzRdbFo1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn9wEU/btsQ3v86ZFm/C0srS3QCBz47E3pzRdbFo1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn9wEU/btsQ3v86ZFm/C0srS3QCBz47E3pzRdbFo1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn9wEU%2FbtsQ3v86ZFm%2FC0srS3QCBz47E3pzRdbFo1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;236&quot; height=&quot;198&quot; data-origin-width=&quot;236&quot; data-origin-height=&quot;198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이 프로젝트를 어떻게 시작하게 되었는지부터 이야기 해보려고 합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 학교에서는 매주 목요일에 전공 동아리 활동을 진행하는데 저는 새로 신설 된 인큐브 동아리에서 새로 시작하는 마음으로 참여하게 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동아리 활동 두번째 시간쯤 되었을 때 갑자기 동아리 부장 선배님이 광탈페라는 프로젝트를 할 사람을 모으신다고 하셨습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이 프로젝트가 외주라는 이야기를 듣고 좋은 경험이 될 것 같아서 바로 저도 합류하고 싶다고 말씀드렸습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;첫 회의&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;247&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpG2ha/btsQ3q1cfRm/wB8UM1hiw6aeYxFSbpmcQk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpG2ha/btsQ3q1cfRm/wB8UM1hiw6aeYxFSbpmcQk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpG2ha/btsQ3q1cfRm/wB8UM1hiw6aeYxFSbpmcQk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpG2ha%2FbtsQ3q1cfRm%2FwB8UM1hiw6aeYxFSbpmcQk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;247&quot; height=&quot;204&quot; data-origin-width=&quot;247&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 회의 때는 프로젝트 인원을 확정 짓고 일정을 정리했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저희는 디자인이 중요한 프로젝트 였어서 디자인 레퍼런스를 찾아보았습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 팀원은 디자인 2명, 프론트 3명, 백엔드 3명으로 구성되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 일정은 이렇게 됐습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;6월&lt;/b&gt;: 슬로건 공모&lt;/li&gt;
&lt;li&gt;&lt;b&gt;7월&lt;/b&gt;: 참여 신청 및 영상 심사&lt;/li&gt;
&lt;li&gt;&lt;b&gt;8월&lt;/b&gt;: 예선&lt;/li&gt;
&lt;li&gt;&lt;b&gt;9월&lt;/b&gt;: 본선&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2차 회의&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차 회의는 교육청 장학사님과 함께 진행 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 저희가 정확한 갈피를 잡지 못하였는데 이번에 장학사님과 이야기하면서 구체화 되었습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 연령층이 사용하므로 UX가 굉장히 중요&lt;/li&gt;
&lt;li&gt;반응형 중요&lt;/li&gt;
&lt;li&gt;메인 페이지 디자인&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3차 회의&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차 회의는 각자 전공 별로 나눠져 개발 파트를 나누고 기술 스택을 정했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 1차 릴리즈에서 슬로건 응모 페이지를 맡았습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;next 15&lt;/li&gt;
&lt;li&gt;tailwind&lt;/li&gt;
&lt;li&gt;tanstack-query&lt;/li&gt;
&lt;li&gt;sooner (toast)&lt;/li&gt;
&lt;li&gt;package manager: npm&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;슬로건 응모 페이지&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;854&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A4WFi/btsQ2qU48pu/eUdJoF0mAK50cRBQKabdD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A4WFi/btsQ2qU48pu/eUdJoF0mAK50cRBQKabdD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A4WFi/btsQ2qU48pu/eUdJoF0mAK50cRBQKabdD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA4WFi%2FbtsQ2qU48pu%2FeUdJoF0mAK50cRBQKabdD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;642&quot; height=&quot;487&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;854&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-04 오후 10.43.32.png&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GBcOI/btsQ1qBi69t/SlfUTU1f7wA5QMRxa4Tnak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GBcOI/btsQ1qBi69t/SlfUTU1f7wA5QMRxa4Tnak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GBcOI/btsQ1qBi69t/SlfUTU1f7wA5QMRxa4Tnak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGBcOI%2FbtsQ1qBi69t%2FSlfUTU1f7wA5QMRxa4Tnak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1328&quot; height=&quot;438&quot; data-filename=&quot;스크린샷 2025-10-04 오후 10.43.32.png&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 페이지는 광탈페 슬로건을 정하는데 응모형식으로 슬로건을 등록하는 페이지를 만드는 것이 제 역할이었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 기술들을 사용하여서 페이지를 구현하였습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 페이지를 운영 준비를 하다가 제가 큰 실수를 한 번 했었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경험을 하고 많은 반성을 하면서 많이 느낀거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 슬로건 응모 페이지 공개 날이 제가 여수에 워크샵을 가는 날이었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확히 오후 6시에 공개하기로 했지만 제가 알림을 맞춰놓고 핸드폰 주변에 있지 않아서 6시를 놓치는 일이 발생했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 6시에 맞춰 오픈 되는 것으로 했었는데 타임존 문제로 자꾸 오픈되지 않는 문제가 있어서 나중에 수정하려고 했지만 시간을 놓쳐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 수동으로 열게 되었는데 배포 시간조차 놓쳐버려 장학사님께 20통 넘는 전화가 왔던 걸로 기억이 납니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 조금의 귀찮음, 무심함으로 이런 결과를 만들어낸 것으로 많은 반성을 하고 다시는 제가 맡은 프로젝트에 책임감 없이 행동하지 말자고 몇 번이고 다짐하였습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;본선 관련 페이지 개발&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본선 때 사용하는 페이지 어드민 쪽을 대부분 제가 구현하게 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;투표 제어 페이지 -&amp;gt; 투표자 랜덤 선정 -&amp;gt; 투표, 심사&amp;nbsp; -&amp;gt; 인기 투표 결과 공개&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 순서로 진행되고 마지막에 통계를 내 랭크 페이지를 공개하는 흐름으로 진행했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flow가 길고 페이지가 많기도 하고 실시간으로 이루어지는 것들이었기 때문에 많은 신경을 썼던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본선 마지막 날 수도 없이 많은 테스트를 하고 밤새 페이지를 보완하며 다음날 행사를 철저하게 준비했던거 같습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;본선 당일&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당일 오전부터 리허설이 진행 되었는데 제가 당일 새벽에 다리를 다쳐서 오전 리허설에는 아쉽게 참여하지 못하였습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 오후부터 다시 참여하여 공연 준비를 하고 몇번이고 다시 테스트하며 공연 시간만을 기다렸던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 공연이 시작하고 모든 페이지가 큰 문제 없이 진행되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순식간에 10팀의 공연이 끝나고 성공적으로 마무리 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 시상 후에 훈훈한 음악이 나오면서 우리에게 감사인사를 해주셨는데 개발하는 동안 힘들었던 순간들이 주마등처럼 스쳤습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 가장 행복했던 순간으로 손 꼽을 수 있을 정도로 강렬한 기억이었습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;글을 마치며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 조금 부실하게 글이 적어졌는데 광탈페가 워낙 좀 급하고 바로바로 이루어져 문서화가 되어있는 것이 많이 없어 이렇게 정신 없고 정리 안된 글이 나온 것 같습니다ㅠㅠㅠ 그래도 저에게는 최고의 경험이었어서 이렇게 아쉬워 글로 남기게 되었습니다 제 좋은 경험을 읽어주셔서 감사합니다&lt;/p&gt;</description>
      <category>회고록</category>
      <category>FRONT</category>
      <category>frontend</category>
      <category>Study</category>
      <category>개발</category>
      <category>개발자</category>
      <category>광주</category>
      <category>광주탈렌트페스티벌</category>
      <category>광탈페</category>
      <category>회고</category>
      <category>회고록</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/70</guid>
      <comments>https://baeougi.tistory.com/70#entry70comment</comments>
      <pubDate>Sat, 4 Oct 2025 23:41:49 +0900</pubDate>
    </item>
    <item>
      <title>우당탕탕 App store 배포 일기.......</title>
      <link>https://baeougi.tistory.com/69</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 제가 광산 어플을 배포하면서 진짜 너무 힘든 일을 많이 겪어서 이렇게 글을 적게 되었습니다.....&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;진짜 배포 하면서 멘탈 탈탈 가루 났습니다..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m9t59/btsQMLrpixL/5PmGtMViB8QRckzLIUGoC0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m9t59/btsQMLrpixL/5PmGtMViB8QRckzLIUGoC0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m9t59/btsQMLrpixL/5PmGtMViB8QRckzLIUGoC0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm9t59%2FbtsQMLrpixL%2F5PmGtMViB8QRckzLIUGoC0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;401&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;첫 어플 심사 결과&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 어플 심사를 보낸 건 학교 선배님의 계정을 빌려서 시민화폐광산이라는 외주 받은 앱을 배포하려고 했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 4~5번 정도 심사에 탈락 했었습니다&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. test flight&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1614&quot; data-origin-height=&quot;1132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3GaJs/btsQPGPLZIm/S3OT8gk5U9fHqq91QYJlNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3GaJs/btsQPGPLZIm/S3OT8gk5U9fHqq91QYJlNk/img.png&quot; data-alt=&quot;test flight&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3GaJs/btsQPGPLZIm/S3OT8gk5U9fHqq91QYJlNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3GaJs%2FbtsQPGPLZIm%2FS3OT8gk5U9fHqq91QYJlNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1614&quot; height=&quot;1132&quot; data-origin-width=&quot;1614&quot; data-origin-height=&quot;1132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;test flight&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 어플을 계속 빌드한 후 test flight에 올리려고 몇번씩이나 시도 했는데 계속 실패하는게 반복 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러로그 이런 것도 없어서 몇 번이나 헤매고 있었는데 애플 에러로그는 이메일로 온다는 사실을 뒤늦게 깨달아 많은 시간을 낭비 했던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 여기서 탈락한 이유는 저희 어플이 이미지를 사용하는데 이미지를 사용하기 전에 동의 여부를 체크해야 하는데 그 과정이 빠져서 계속 실패했었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 바로 고치니 test flight가 올라가고 앱 심사를 보낼 수 있는 상태가 되었습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 서버 error&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rJmqI/btsQQnidGNi/mIEKPREw2IWDR67RpwRMqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rJmqI/btsQQnidGNi/mIEKPREw2IWDR67RpwRMqk/img.png&quot; data-origin-width=&quot;1808&quot; data-origin-height=&quot;2144&quot; data-is-animation=&quot;false&quot; width=&quot;486&quot; data-widthpercent=&quot;54.82&quot; style=&quot;width: 54.1853%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rJmqI/btsQQnidGNi/mIEKPREw2IWDR67RpwRMqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrJmqI%2FbtsQQnidGNi%2FmIEKPREw2IWDR67RpwRMqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1808&quot; height=&quot;2144&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bblJ4G/btsQOmdRhYs/n9VNWMeAIsfuES7OWBvgG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bblJ4G/btsQOmdRhYs/n9VNWMeAIsfuES7OWBvgG1/img.png&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;2360&quot; data-is-animation=&quot;false&quot; style=&quot;width: 44.6519%;&quot; data-widthpercent=&quot;45.18&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bblJ4G/btsQOmdRhYs/n9VNWMeAIsfuES7OWBvgG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbblJ4G%2FbtsQOmdRhYs%2Fn9VNWMeAIsfuES7OWBvgG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1640&quot; height=&quot;2360&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째는 저희가 AWS에서 저희 학교서버로 이전하고 있는 상황에 어플 심사가 진행되어서 500이 뜨면서 로그인 실패했다는 답변이 돌아왔습니다 완벽하게 서버 이전 후 다시 심사를 올리니 이것에 대한 오류는 돌아오지 않았습니다&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3. 회원가입&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번째는 회원가입을 테스트할 때 인증번호를 입력해야하는데 그걸 테스트하기 힘들다는 식으로 메일이 와서 인증번호를 잠깐동안&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;123456만 입력해도 통과되게 풀어놨습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 저작권&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2552&quot; data-origin-height=&quot;884&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdmSJE/btsQOESLn75/Ca3cmTeCoDsrLdqrGTYUYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdmSJE/btsQOESLn75/Ca3cmTeCoDsrLdqrGTYUYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdmSJE/btsQOESLn75/Ca3cmTeCoDsrLdqrGTYUYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdmSJE%2FbtsQOESLn75%2FCa3cmTeCoDsrLdqrGTYUYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2552&quot; height=&quot;884&quot; data-origin-width=&quot;2552&quot; data-origin-height=&quot;884&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 큰 가장 문제였습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 광산구의 사칭이 아님을 증명해야 한다고 와서 간단한 서류를 보냈었는데 다시 저런 메일이 돌아왔습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인 계정을 이용하면 안되고 조직으로서 apple developer program을 다시 등록해야 한다는 답변이었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 답변을 보고 저희는 법인 등록 계정을 만들기 시작했습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;애플 계정 생성&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2300&quot; data-origin-height=&quot;4196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pkuOW/btsQM0CPwsC/5CigHdIWa1sJTdI0um20lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pkuOW/btsQM0CPwsC/5CigHdIWa1sJTdI0um20lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pkuOW/btsQM0CPwsC/5CigHdIWa1sJTdI0um20lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpkuOW%2FbtsQM0CPwsC%2F5CigHdIWa1sJTdI0um20lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;750&quot; data-origin-width=&quot;2300&quot; data-origin-height=&quot;4196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 법인 계정을 등록하는 방법 밖에 없다고 결론을 내어서 광산구 apple 법인계정을 만들기 시작했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음해보는 것이라 계정 만드는 것부터 쉽지 않았던거 같습니다 처음에 계정을 만들어주라고 핸드북과 함께 관계자 분들에게 요구를 했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 연령대가 높으신 분들이라 모르셔서 제가 모든 정보를 받고 만들기 시작했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 핸드북을 보면서 만드니 그리 어렵진 않았던거 같습니다 이 부분은 굉장히 수월하게 넘어갔습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://support.guidebook.com/hc/ko/articles/360000228487-Apple-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EA%B3%84%EC%A0%95-%EB%A7%8C%EB%93%A4%EA%B8%B0-Apple-Developer-Account&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://support.guidebook.com/hc/ko/articles/360000228487-Apple-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EA%B3%84%EC%A0%95-%EB%A7%8C%EB%93%A4%EA%B8%B0-Apple-Developer-Account&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;법인 apple developer 계정 구매&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 계정을 만들었고 또 여러 정보들을 입력하고 법인 apple developer 구매 과정을 밟기 시작했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 하자마자..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b50w5z/btsQQmw4V35/ry56gLH0h7zv3YTHaL5FwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b50w5z/btsQQmw4V35/ry56gLH0h7zv3YTHaL5FwK/img.png&quot; data-origin-width=&quot;2468&quot; data-origin-height=&quot;3256&quot; data-is-animation=&quot;false&quot; width=&quot;499&quot; data-widthpercent=&quot;54.36&quot; style=&quot;width: 53.7291%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b50w5z/btsQQmw4V35/ry56gLH0h7zv3YTHaL5FwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb50w5z%2FbtsQQmw4V35%2Fry56gLH0h7zv3YTHaL5FwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2468&quot; height=&quot;3256&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHAlYm/btsQN3MHKTA/XdBeX4MCdKfu6f8xec8tG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHAlYm/btsQN3MHKTA/XdBeX4MCdKfu6f8xec8tG0/img.png&quot; data-origin-width=&quot;525&quot; data-origin-height=&quot;825&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.1081%;&quot; data-widthpercent=&quot;45.64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHAlYm/btsQN3MHKTA/XdBeX4MCdKfu6f8xec8tG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHAlYm%2FbtsQN3MHKTA%2FXdBeX4MCdKfu6f8xec8tG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;525&quot; height=&quot;825&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 알 수 없는 오류가 발생하였습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 아무 메일도 오지 않았고 애플에 문의까지 하게 되었습니다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문의 결과 현재 문제 상황은 제 맥북에 로그인된 계정과 시도하려는 애플 계정이 일치해야 다음 단계를 진행할 수 있다는 것이었습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 그래서 제 계정을 로그아웃하지 않고 하기 위해 학교에서 맥북을 새로 대여까지 하였습니다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 진행하니 다음 단계로 넘어갈 수 있게 되었는데 또 문제가 발생했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;법인계정으로 등록하려면 DUNS 번호가 필요했습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DUNS 번호를 발급받기 위해서는 밑에서 발급 받으시면 됩니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://support.dnb.com/?CUST=APPLEDEV&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://support.dnb.com/?CUST=APPLEDEV&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발급 번호는 2~3일 후에 이메일로 받았던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DUNS 번호를 발급 받고 바로 재시도 해봤지만 일치하지 않는다는 경고 문구가 뜨면서 실패했습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이유는 DUNS 번호를 발급받고 얼마되지 않은 상태면 가끔 그렇게 뜬다고 하더라구요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 같은 경우 3일 정도 기다리니 다음 단계로 넘어갈 수 있었습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DUNS 번호 발급할 때 입력한 정보와 똑같은 정보를 입력하고 마지막 이메일이 왔습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;1188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbaOwp/btsQODsZV4l/oakayc1Wxkq8iHAP62K951/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbaOwp/btsQODsZV4l/oakayc1Wxkq8iHAP62K951/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbaOwp/btsQODsZV4l/oakayc1Wxkq8iHAP62K951/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbaOwp%2FbtsQODsZV4l%2Foakayc1Wxkq8iHAP62K951%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;499&quot; height=&quot;569&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;1188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 여러 서류들을 저 링크에 첨부하니 결제할 수 있는 상태가 되었습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;또 다시 앱 심사...&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;글을 마치며&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AA2mu/btsQOiblzlI/M0lOyclVXnCXPCHfCLKd01/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AA2mu/btsQOiblzlI/M0lOyclVXnCXPCHfCLKd01/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AA2mu/btsQOiblzlI/M0lOyclVXnCXPCHfCLKd01/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAA2mu%2FbtsQOiblzlI%2FM0lOyclVXnCXPCHfCLKd01%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;336&quot; height=&quot;336&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 엄청난 여정이 있었습니다.. 글은 굉장히 짧아보이지만 이 과정을 1-2달에 거쳐서 한거 같습니다.. 이 과정 거치면서 진짜 스트레스도 많이 받은거 같았는데 그래도 한 번씩 통과 될 때마다 말로 표현 못할 엄청난 짜릿함을 느꼈던거 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 단계를 할 때마다 1-2일은 무조건 대기 해야해서 너무 지쳤던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 글에 다 담지 못했지만 애플과 전화 2번, 메일 문의 3번정도는 했던거 같습니다...(제발 친절하게 알려주세요..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힘들었지만 지금 생각하면 너무 웃긴거 같습니다..&lt;/p&gt;</description>
      <category>회고록</category>
      <category>app store</category>
      <category>expo</category>
      <category>Fe</category>
      <category>ios</category>
      <category>rn</category>
      <category>개발</category>
      <category>배포</category>
      <category>심사</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/69</guid>
      <comments>https://baeougi.tistory.com/69#entry69comment</comments>
      <pubDate>Thu, 25 Sep 2025 16:03:38 +0900</pubDate>
    </item>
    <item>
      <title>Redis 사용기</title>
      <link>https://baeougi.tistory.com/68</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 제가 redis를 사용하게 된 계기와 어떻게 사용했는지 또 redis는 무엇인지에 대하여 글을 적게 되었습니다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Redis란?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPs88P/btsQhrHk8nt/vnOuMuCGBRPCkLf2PlNnM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPs88P/btsQhrHk8nt/vnOuMuCGBRPCkLf2PlNnM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPs88P/btsQhrHk8nt/vnOuMuCGBRPCkLf2PlNnM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPs88P%2FbtsQhrHk8nt%2FvnOuMuCGBRPCkLf2PlNnM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;353&quot; height=&quot;235&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redis는 Remote(원격)에 위치하고 프로세스로 존재하는 In-Memory 기반의 Dictionary(key-value) 구조 데이터 관리 Server 시스템입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 고속 읽기와 쓰기에 최적화 되어 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리에서 데이터를 처리하기 때문에 작업 속도가 빠릅니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 프로그래밍 언어 프레임워크에 대한 API를 폭 넓게 지원합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;In-Memory db&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;디스크나 SSD가 아닌 컴퓨터의 주 메모리(RAM)에 데이터를 저장하고 관리하는 데이터베이스&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;캐시의 구조 패턴&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Look aside cache&lt;/b&gt;: 캐시를 한 번 접근 하여 데이터 여부를 확인 후 있다면 캐시의 데이터를 사용하고 없으면 실제 DB 또는 API를 호출합니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Write Back&lt;/b&gt;: insert 쿼리를 일일이 날리지 않고 한꺼번에 배치 처리하기 이해 사용됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 이 팀 소개를 구현하면서 총 두 가지 문제가 있었는데 하나씩 말씀 드리겠습니다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CORS&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WIkux/btsQmfZqhjX/F15gJhk4iZaKkw90sLXcT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WIkux/btsQmfZqhjX/F15gJhk4iZaKkw90sLXcT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WIkux/btsQmfZqhjX/F15gJhk4iZaKkw90sLXcT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWIkux%2FbtsQmfZqhjX%2FF15gJhk4iZaKkw90sLXcT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;1000&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브에 요청을 보낼 때 처음에는 CORS가 터져서 어떻게 해결을 했냐면 next.js에서 제공하는 기능인 route handler 기능을 이용해서 프록시로 우회하여 요청을 처음 보내는데 성공 했습니다&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밑에는 코드와 제가 route handler를 학습할 때 적었던 글입니다&lt;/p&gt;
&lt;pre id=&quot;code_1756962898866&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NextResponse } from 'next/server';


export async function GET(
  { params }: { params: { id: string } }
) {
  try {
    const { id } = params;

    const githubResponse = await fetch(`https://api.github.com/users/${encodeURIComponent(id)}`, {
      headers: {
        'Accept': 'application/vnd.github.v3+json',
        'User-Agent': 'Gwangju-talent-festival-Client',
      },
    });

    if (!githubResponse.ok) {
      if (githubResponse.status === 404) {
        return NextResponse.json(
          { error: 'not found' },
          { status: 404 }
        );
      }

      return NextResponse.json(
        { error: 'failed to fetch' },
        { status: githubResponse.status }
      );
    }

    const githubData = await githubResponse.json();

    return NextResponse.json(githubData);
  } catch (error) {
    console.error(error);
    return NextResponse.json(
      { error: 'internal server error' },
      { status: 500 }
    );
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://baeougi.tistory.com/56&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://baeougi.tistory.com/56&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1756962975815&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;next.js route handler에 대해서 알아보자&quot; data-og-description=&quot;오늘은 최근에 적용해본 next.js에서 제공하는 route handler라는 기능에 대해서 글을 써보려고 합니다!! route handler란?next.js에서 제공하는 기능 중 하나로 특정 경로에 대한 사용자 정의 요청 처리기(c&quot; data-og-host=&quot;baeougi.tistory.com&quot; data-og-source-url=&quot;https://baeougi.tistory.com/56&quot; data-og-url=&quot;https://baeougi.tistory.com/56&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/LhONY/hyZGZfvaQs/LqUuUQ0lU2mb8L8VcKM5Dk/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/bQL8xH/hyZIP4dNI8/WHg8zz9O47P5pdkKV6DA11/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/bwltYE/hyZIY7VBdh/7PchkQ4Q8N6jnL7b18F810/img.jpg?width=1080&amp;amp;height=1440&amp;amp;face=0_0_1080_1440&quot;&gt;&lt;a href=&quot;https://baeougi.tistory.com/56&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://baeougi.tistory.com/56&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/LhONY/hyZGZfvaQs/LqUuUQ0lU2mb8L8VcKM5Dk/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/bQL8xH/hyZIP4dNI8/WHg8zz9O47P5pdkKV6DA11/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/bwltYE/hyZIY7VBdh/7PchkQ4Q8N6jnL7b18F810/img.jpg?width=1080&amp;amp;height=1440&amp;amp;face=0_0_1080_1440');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;next.js route handler에 대해서 알아보자&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 최근에 적용해본 next.js에서 제공하는 route handler라는 기능에 대해서 글을 써보려고 합니다!! route handler란?next.js에서 제공하는 기능 중 하나로 특정 경로에 대한 사용자 정의 요청 처리기(c&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;baeougi.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;요청 횟수 제한&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;817&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WEPVL/btsQkUOn0Z3/myMwtKXB8sI1LbYQSDDcS1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WEPVL/btsQkUOn0Z3/myMwtKXB8sI1LbYQSDDcS1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WEPVL/btsQkUOn0Z3/myMwtKXB8sI1LbYQSDDcS1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWEPVL%2FbtsQkUOn0Z3%2FmyMwtKXB8sI1LbYQSDDcS1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;564&quot; height=&quot;360&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;817&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 깃허브로 토큰을 발급 받아서 하는 요청의 제한 수가 1일 5000회로 제한되어 있었는데 이 요청수가 너무 부족하여서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결 방법을 고민하다가 redis를 선택하게 되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적인 흐름을 말씀 해드리겠습니다&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자가 접속하면 캐시가 있는지 확인&lt;/li&gt;
&lt;li&gt;없다면 깃허브에 요청을 다시 전송&lt;/li&gt;
&lt;li&gt;있다면 캐시된 데이터를 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 코드와 함께 설명드리겠습니다&lt;/p&gt;
&lt;pre id=&quot;code_1756985067687&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// redis.ts

import Redis, { type Redis as RedisType } from &quot;ioredis&quot;;

declare global {
  var _redis: RedisType | undefined;
}

function buildUrl(): string {
  if (process.env.REDIS_URL &amp;amp;&amp;amp; process.env.REDIS_URL.trim().length &amp;gt; 0) {
    return process.env.REDIS_URL.trim();
  }

  const host = process.env.REDIS_HOST!;
  const port = process.env.REDIS_PORT!;
  const password = process.env.REDIS_PASSWORD ?? &quot;&quot;;

  const useTLS = process.env.REDIS_TLS === &quot;1&quot; || process.env.REDIS_TLS?.toLowerCase() === &quot;true&quot;;

  const protocol = useTLS ? &quot;rediss&quot; : &quot;redis&quot;;
  const passEnc = encodeURIComponent(password);

  return `${protocol}://default:${passEnc}@${host}:${port}`;
}

function createRedis(): RedisType {
  const url = buildUrl();
  const isTLS = url.startsWith(&quot;rediss://&quot;);
  return new Redis(url, {
    ...(isTLS ? { tls: {} } : {}),
    connectTimeout: 10_000,
    maxRetriesPerRequest: 2,
    retryStrategy: (times: number) =&amp;gt; Math.min(times * 200, 2000),
  });
}

export const redis = global._redis ?? createRedis();
if (!global._redis) global._redis = redis;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1756986708851&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 수정된 route.ts

import { redis } from &quot;@/shared/lib/redis&quot;;
import { NextResponse } from &quot;next/server&quot;;

const KEY = (id: string) =&amp;gt; `gh:user:${id}`;
const TTL_SECONDS = 60 * 60 * 24;

export async function GET(_request: Request, { params }: { params: Promise&amp;lt;{ id: string }&amp;gt; }) {
  const { id } = await params;

  let cached: string | null = null;
  try {
    cached = await redis.get(KEY(id));
  } catch (e) {
    throw e;
  }
  if (cached) {
    return new NextResponse(cached, {
      status: 200,
      headers: { &quot;Content-Type&quot;: &quot;application/json&quot;, &quot;X-Cache&quot;: &quot;HIT&quot; },
    });
  }

  const gh = await fetch(`https://api.github.com/users/${encodeURIComponent(id)}`, {
    headers: {
      Accept: &quot;application/vnd.github.v3+json&quot;,
      &quot;User-Agent&quot;: &quot;gwangtalpe-client&quot;,
      Authorization: `Bearer ${process.env.GITHUB_TOKEN ?? &quot;&quot;}`,
    },
    cache: &quot;no-store&quot;,
  });

  if (!gh.ok) {
    if (gh.status === 404) {
      return NextResponse.json({ error: &quot;not found&quot; }, { status: 404 });
    }
    return NextResponse.json({ error: &quot;failed to fetch&quot; }, { status: gh.status });
  }

  const data = await gh.json();

  try {
    await redis.set(KEY(id), JSON.stringify(data), &quot;EX&quot;, TTL_SECONDS);
  } catch (error) {
    throw error;
  }

  return NextResponse.json(data, { status: 200, headers: { &quot;X-Cache&quot;: &quot;MISS&quot; } });
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;글을 마치며..&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 redis에 대해서 알아보았는데 처음 해보는 것이라 처음에 자신이 없었는데 하고나서 되니 정말 기분이 좋고 뿌듯 했던거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러분들도 꼭 무엇이든 도전하시면 좋을거 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 읽어주셔서 감사합니다&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;046&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/046.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/046.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>라이브러리</category>
      <category>REDIS</category>
      <category>개발</category>
      <author>ougi</author>
      <guid isPermaLink="true">https://baeougi.tistory.com/68</guid>
      <comments>https://baeougi.tistory.com/68#entry68comment</comments>
      <pubDate>Thu, 4 Sep 2025 21:05:36 +0900</pubDate>
    </item>
  </channel>
</rss>