<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Next.js on 오늘도 개발을 한다.</title>
    <link>https://cloudsoswift.github.io/tags/next.js/</link>
    <description>오늘도 개발을 한다. (Next.js)</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>ko-kr</language>
    <lastBuildDate>Mon, 08 Jun 2026 08:04:15 +0900</lastBuildDate>
    
    <atom:link href="https://cloudsoswift.github.io/tags/next.js/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>[podoR] 2. 프로젝트 첫 주차에 알게된 점들 (w. SpEL, Hydration Mismatch, 이벤트 재타게팅)</title>
      <link>https://cloudsoswift.github.io/post/develop/toy-project/podor/02-knowledge-in-first-week/</link>
      <pubDate>Mon, 08 Jun 2026 08:04:15 +0900</pubDate>
      
      <guid>https://cloudsoswift.github.io/post/develop/toy-project/podor/02-knowledge-in-first-week/</guid>
      <description>&lt;p&gt;프로젝트 개발을 진행하는 첫 한 주동안, 새롭게 배운 점들을 공유하고자 한다.&lt;/p&gt;
&lt;h2 id=&#34;spring-관련&#34; &gt;Spring 관련
&lt;span&gt;
    &lt;a href=&#34;#spring-%ea%b4%80%eb%a0%a8&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;application.yml의 &lt;code&gt;server.servlet.contextPath&lt;/code&gt; 에 특정 URL을 설정하면, 해당 URL이 prefix처럼 동작&lt;/li&gt;
&lt;li&gt;Spring Security의 기본 redirect uri 구조는 &lt;code&gt;${URL}/login/oauth2/code/${플랫폼}&lt;/code&gt;임&lt;/li&gt;
&lt;li&gt;Spring Security 6 이후로(정확히는 5.5인듯? CLIENT_SECRET_POST가 5.5부터 나옴) &lt;code&gt;spring.security.oauth2.client.registration.${플랫폼}.client-authentication-method&lt;/code&gt;에 &lt;code&gt;POST&lt;/code&gt; 대신 &lt;code&gt;client_secret_post&lt;/code&gt;를 사용해야 함.&lt;/li&gt;
&lt;li&gt;Spring에서 static &lt;code&gt;log&lt;/code&gt;(logger객체)를 통해 로그를 찍기 위해서는, 이를 사용할 컨트롤러에 &lt;code&gt;@log4j&lt;/code&gt;, &lt;code&gt;@Slf4j&lt;/code&gt;와 같은 lombok의 애너테이션을 달아주면 &lt;code&gt;log&lt;/code&gt; 객체를 사용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;spelspring-expression-language&#34; &gt;SpEL(Spring Expression Language)
&lt;span&gt;
    &lt;a href=&#34;#spelspring-expression-language&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 1. XML based
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;bean id&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;numberGuess&amp;#34;&lt;/span&gt; class&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;org.spring.samples.NumberGuess&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;property name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;randomNumber&amp;#34;&lt;/span&gt; value&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#{ T(java.lang.Math).random() * 100.0 }&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;!--&lt;/span&gt; other properties &lt;span style=&#34;color:#f92672&#34;&gt;--&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/&lt;/span&gt;bean&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 2. Annotation based
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FieldValueTestBean&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Value&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#{ systemProperties[&amp;#39;user.region&amp;#39;] }&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; String defaultLocale&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setDefaultLocale&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;String defaultLocale&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;defaultLocale&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; defaultLocale&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;getDefaultLocale&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;defaultLocale&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.spring.io/spring-framework/docs/3.0.x/reference/expressions.html&#34;&gt;6. Spring Expression Language (SpEL)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;런타임 시 &lt;code&gt;객체 그래프(object graph)&lt;/code&gt;를 쿼리하고 조작할 수 있는 표현식 언어&lt;/li&gt;
&lt;li&gt;&lt;code&gt;기술 중립적인(agnostic) API&lt;/code&gt;를 기반으로 하여, OGNL, MVEL, JBoss EL 등 다른 표현식 언어 구현체들과 &lt;code&gt;통합(integrate)&lt;/code&gt;할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;XML&lt;/code&gt; 및 &lt;code&gt;애너테이션&lt;/code&gt; 모두에서 사용 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;springsecurity--oauth2-관련&#34; &gt;SpringSecurity / OAuth2 관련
&lt;span&gt;
    &lt;a href=&#34;#springsecurity--oauth2-%ea%b4%80%eb%a0%a8&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OAuth2User&lt;/code&gt; : OAuth2 로그인 후 인증된 사용자의 정보를 담는 인터페이스로, &lt;code&gt;Map&amp;lt;String, Object&amp;gt;&lt;/code&gt; 형태의 &lt;code&gt;Attribute&lt;/code&gt;로 사용자 정보를, &lt;code&gt;String&lt;/code&gt; 형태의 &lt;code&gt;Name&lt;/code&gt;으로 식별자를 가짐(권한 목록인 &lt;code&gt;getAuthorities&lt;/code&gt;도 있음)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@EnableMethodSecurity&lt;/code&gt;(구 &lt;code&gt;@EnableGlobalMethodSecurity&lt;/code&gt;): &lt;code&gt;메서드 수준&lt;/code&gt;에서의 권한 모델링
&lt;ul&gt;
&lt;li&gt;만약, 특정 도메인에 관한 모든 작업(ex. &lt;code&gt;/{도메인}/{자원ID}&lt;/code&gt;)이 권한이 필요하다면, &lt;code&gt;SecurityFilterChain&lt;/code&gt;에서 &lt;code&gt;authorizeHttpRequests(... authorize .requestMatchers(&amp;quot;/endpoint&amp;quot;).hasAuthority(&amp;quot;USER&amp;quot;))&lt;/code&gt; 와 같은 형태로 &lt;code&gt;요청 기반&lt;/code&gt;의 권한 모델링 하면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;fe-관련&#34; &gt;FE 관련
&lt;span&gt;
    &lt;a href=&#34;#fe-%ea%b4%80%eb%a0%a8&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;h3 id=&#34;next-관련&#34; &gt;Next 관련
&lt;span&gt;
    &lt;a href=&#34;#next-%ea%b4%80%eb%a0%a8&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;client components&lt;/code&gt;&lt;/strong&gt; vs &lt;strong&gt;&lt;code&gt;server components&lt;/code&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;client components&lt;/code&gt;를 사용해야 할 때
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;state&lt;/code&gt; 또는 &lt;code&gt;이벤트 핸들러&lt;/code&gt;(ex. &lt;code&gt;onClick&lt;/code&gt;, &lt;code&gt;onChange&lt;/code&gt;)가 필요할 때&lt;/li&gt;
&lt;li&gt;&lt;code&gt;생애주기 로직&lt;/code&gt;(ex. &lt;code&gt;useEffect&lt;/code&gt;)을 사용해야 할 때&lt;/li&gt;
&lt;li&gt;&lt;code&gt;브라우저단-전용 API&lt;/code&gt;(ex. &lt;code&gt;localStorage&lt;/code&gt;, &lt;code&gt;window&lt;/code&gt;, &amp;hellip;)가 필요할 때&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Custom Hooks&lt;/code&gt;가 필요할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;server components&lt;/code&gt;를 사용해야 할 때
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;데이터 소스와 가까이 위치한&lt;/em&gt; &lt;code&gt;DB&lt;/code&gt; 또는 &lt;code&gt;API&lt;/code&gt;로부터 데이터를 &lt;code&gt;fetch&lt;/code&gt; 해야할 때&lt;/li&gt;
&lt;li&gt;&lt;code&gt;API 키&lt;/code&gt;, &lt;code&gt;토큰&lt;/code&gt; 등 &lt;strong&gt;&lt;code&gt;비밀 정보&lt;/code&gt;&lt;/strong&gt; 를 &lt;em&gt;client에 노출하지 않고&lt;/em&gt; 사용해야 할 때&lt;/li&gt;
&lt;li&gt;브라우저로 전송되는 &lt;strong&gt;Javascript 양을 줄여야 할 때&lt;/strong&gt; (즉, 미리 데이터를 HTML에 박아놔서 그걸 렌더링하는 스크립트를 줄여야 할 때)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FCP(최초 콘텐츠풀 페인트)&lt;/code&gt;를 개선하고, 콘텐츠를 클라이언트에 &lt;code&gt;점진적으로 전송(stream)&lt;/code&gt;해야 할 때
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FCP&lt;/code&gt;: 브라우저가 &lt;code&gt;DOM 콘텐츠&lt;/code&gt;의 &lt;strong&gt;가장 첫 조각(비트)를 렌더링&lt;/strong&gt;하여, 사용자에게 &amp;lsquo;페이지가 실제로 로드되고 있음&amp;rsquo;을 인식시키는데 &lt;strong&gt;걸리는 시간&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;서버 측
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;server component&lt;/code&gt;는 &lt;code&gt;RSC Payload(React Server Component Payload)&lt;/code&gt;라는 특수한 데이터 형식으로 렌더링
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RSC Payload&lt;/code&gt;: 렌더링된 &lt;code&gt;Server Component&lt;/code&gt; 트리를 압축된 Binary 형식으로 표현한 것으로, 클라이언트 측 React에서 브라우저 DOM 업데이트 하는데 사용
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;server component&lt;/code&gt; 렌더링 결과&lt;/li&gt;
&lt;li&gt;&lt;code&gt;client component&lt;/code&gt;가 &lt;em&gt;렌더링 되어야 할 위치&lt;/em&gt; &lt;code&gt;자리표시자(Placeholder)&lt;/code&gt; 및 &lt;code&gt;해당 Javascript 파일에 대한 참조&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;server component&lt;/code&gt; -&amp;gt; &lt;code&gt;client component&lt;/code&gt; 측으로 전달된 모든 &lt;code&gt;props&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;클라이언트 컴포넌트&lt;/code&gt;와 &lt;code&gt;RSC Payload&lt;/code&gt;는 HTML을 사전-렌더링 하는데 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;클라이언트 측
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HTML&lt;/code&gt;을 사용하여 해당 라우트의 &lt;code&gt;비-상호작용 프리뷰&lt;/code&gt;를 즉시 표시&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RSC Payload&lt;/code&gt;를 사용해 &lt;code&gt;Client&lt;/code&gt; 및 &lt;code&gt;Server component&lt;/code&gt; 트리를 동기화&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Javascript&lt;/code&gt;를 사용해 &lt;code&gt;Client Component&lt;/code&gt;를 Hydrate하고, 상호작용 가능하도록 만듦&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;hydration 불일치&lt;/code&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Zustand persist와 같이, &lt;em&gt;&lt;code&gt;브라우저 Storage&lt;/code&gt;에서 데이터를 불러와&lt;/em&gt; 이를 바탕으로 화면을 렌더링하는 경우
&lt;ol&gt;
&lt;li&gt;서버에서 렌더링하여 보낸 HTML 화면&lt;/li&gt;
&lt;li&gt;클라이언트에서 HTML을 받아와 React 코드 실행해 렌더링 (&lt;code&gt;Hydration&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;위 두가지 화면이 불일치하는, &lt;strong&gt;&lt;code&gt;Hydration Mismatch (하이드레이션 에러)&lt;/code&gt;&lt;/strong&gt; 문제가 발생하게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이를 막기 위해, &lt;code&gt;마운트 가드(Mount Guard)&lt;/code&gt;라는 패턴을 사용
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;브라우저에 화면이 완전히 붙을 때(Mount)까지는&lt;/em&gt; 서버와 똑같이 &amp;lsquo;&lt;strong&gt;기본 상태&lt;/strong&gt;(&lt;code&gt;빈 화면&lt;/code&gt;이나 &lt;code&gt;스켈레톤 UI&lt;/code&gt;)&amp;lsquo;를 보여주고, 브라우저 로드가 끝난 직후에 스토리지를 읽은 진짜 상태를 보여주는 방식&lt;/li&gt;
&lt;li&gt;마운트 가드를 페이지 전체에 적용할 경우, SEO가 불가능하므로, &lt;em&gt;하이드레이션이 이뤄지는&lt;/em&gt; &lt;code&gt;부분 컴포넌트&lt;/code&gt;에 대해서만 마운트 가드를 씌움&lt;/li&gt;
&lt;li&gt;또한, 인가, 권한 등이 필요한 페이지(ex. 마이 페이지, 결제 내역 등)의 경우 애초에 &lt;em&gt;SEO가 필요 없으므로&lt;/em&gt; &lt;code&gt;마운트 가드&lt;/code&gt;를 &lt;code&gt;페이지 전체&lt;/code&gt;에 씌워도 상관 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;만약, 서버 사이드에서, &lt;em&gt;클라이언트 측 데이터를 바탕으로&lt;/em&gt; Hydration된 HTML을 만들어야 한다면 요청 헤더(및 쿠키)를 통해 필요한 데이터를 전송하고, 그를 바탕으로 렌더링하게 해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;런타임&lt;/code&gt;&lt;/strong&gt; 에 &lt;code&gt;환경변수 주입&lt;/code&gt;하기
&lt;ul&gt;
&lt;li&gt;빌드 타임에 환경변수를 주입한다면?
&lt;ul&gt;
&lt;li&gt;환경변수 변동 생길경우, 환경별(Dev, Prod, &amp;hellip;)로 빌드 매번 다시 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Client-side&lt;/code&gt; / &lt;code&gt;Server-side&lt;/code&gt;에 따라 환경 변수 구분 필요
&lt;ul&gt;
&lt;li&gt;Server-side에서 필요한 민감정보는 Client 측에 노출되지 않아야 하므로, &lt;code&gt;Client-side&lt;/code&gt; / &lt;code&gt;Server-side&lt;/code&gt;에서 필요한 환경변수를 구분해서 저장하는것이 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;js--html-관련&#34; &gt;JS / HTML 관련
&lt;span&gt;
    &lt;a href=&#34;#js--html-%ea%b4%80%eb%a0%a8&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;elem.setPointerCapture(pointerId)&lt;/code&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pointerId&lt;/code&gt;를 갖는 이벤트를 &lt;code&gt;elem&lt;/code&gt;에 바인딩
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pointerId&lt;/code&gt;: &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent&#34;&gt;&lt;code&gt;PointerEvent&lt;/code&gt;&lt;/a&gt;이벤트를 발생시킨 포인터에 할당된 식별자로, 포인팅 장치에 대한 고유 식별자를 뜻함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이렇게 하면, 동일한 &lt;code&gt;pointerId&lt;/code&gt;를 갖는 모든 포인터 이벤트는, 실제 발생 위치와 상관없이 대상으로 &lt;code&gt;elem&lt;/code&gt;을 가짐(즉, &lt;code&gt;elem&lt;/code&gt;에서 일어난 것처럼 처리)&lt;/li&gt;
&lt;li&gt;주로 요소에 대한 드래그를 놓치지 않기 위해 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;이벤트 재타게팅&lt;/code&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Javascript&lt;/code&gt;에는 두 가지 종류의 &lt;code&gt;이벤트 재타게팅&lt;/code&gt;이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;**마우스 이벤트**의 타겟 설정 규칙&lt;/code&gt;으로 인한 &lt;code&gt;재타겟팅&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;브라우저가 클릭,더블 클릭과 같은 이벤트를 &lt;strong&gt;온전히 인식&lt;/strong&gt;하려면, 마우스를 &lt;strong&gt;누를 때&lt;/strong&gt;(&lt;code&gt;pointerdown&lt;/code&gt;)와 &lt;strong&gt;뗄 때&lt;/strong&gt;(&lt;code&gt;pointerup&lt;/code&gt;)의 &lt;strong&gt;&lt;code&gt;target&lt;/code&gt;이 같아야 함&lt;/strong&gt;.
&lt;ul&gt;
&lt;li&gt;만약 캡처링 등의 문제로 둘의 target이 달라질 경우, 브라우저는 &amp;ldquo;두 요소의 가장 가까운 공통 조상에게 이벤트를 전달한다&amp;quot;라는 규칙을 따름&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// 1. W3C의 Pointer Events에 대한 Working Draft
Each implementation will determine the appropriate hysteresis tolerance, but in general SHOULD fire click and dblclick events when the event target of the associated mousedown and mouseup events is the same element with no mouseout or mouseleave events intervening, and SHOULD fire click and dblclick events on **the nearest common inclusive ancestor** when the associated mousedown and mouseup event targets are different.
(각 구현체는 적절한 히스테리시스 허용 오차(흔들림 등의 이유로 발생한, 마우스를 누르고 떼는 위치의 차이)를 결정하지만, 일반적으로 `mousedown` 및 `mouseup` 이벤트의 대상이, `mouseout` 또는 `mouseleave` 이벤트가 개입되지 않은 상태에서, 그 둘이 동일 요소일 경우 `click` 및 `dblclick` 이벤트를 발생시켜야 한다.
또한, `mousedown` 및 `mouseup` 이벤트의 대상이 서로 다를 경우 **가장 가까운 공통 상위 조상 요소**에서 `click` 및 `dblclick` 이벤트를 발생시켜야 한다.)
출처: [Pointer Events](https://www.w3.org/TR/pointerevents/#mouse-event-order)
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// 2. whatwg의 DOM 스펙
To retarget an object A against an object B, repeat these steps until they return an object:

If one of the following is true

A is not a node (A가 노드가 아니거나)
A’s root is not a shadow root (A의 루트가 Shadow root가 아니거나)
B is a node and A’s root is a shadow-including inclusive ancestor of B (B가 노드이고, A의 루트가 B의 shadow를 포함하는 포괄적인 조상인 경우)
then return A. (A를 반환한다)

Set A to A’s root’s host. (A를 A의 루트의 호스트로 설정한다)
[DOM Standard](https://dom.spec.whatwg.org/#retarget)
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Web_components&#34;&gt;&lt;code&gt;Web Components&lt;/code&gt;&lt;/a&gt;에서의 &lt;code&gt;이벤트 재타게팅&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Web Components&lt;/code&gt;: HTML상에서 &lt;strong&gt;재사용가능한&lt;/strong&gt; &lt;code&gt;커스텀 UI&lt;/code&gt;를 생성 및 활용할 수 있도록 돕는 기술의 집합
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Custom Element&lt;/code&gt;: 사용자 정의 요소 및 그들의 동작을 정의할 수 있게 해주는 Javascript API 모음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Shadow DOM&lt;/code&gt;: 요소에 캡슐화된 &lt;code&gt;Shadow DOM 트리&lt;/code&gt;를 연결 및 제어하기 위한 Javascript API 모음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HTML Templates&lt;/code&gt;: &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; 및 &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; 요소를 통해 페이지에 표시되지 않은 마크업 템플릿을 작성할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;그 중, &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM&#34;&gt;&lt;code&gt;Shadow DOM&lt;/code&gt;&lt;/a&gt;이 이 &lt;code&gt;이벤트 재타게팅&lt;/code&gt;과 관련 있음
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;커스텀 엘리먼트&lt;/code&gt;의 중요 특징 중 하나인 &lt;strong&gt;&lt;code&gt;캡슐화&lt;/code&gt;&lt;/strong&gt; 를 지키기 위해, 페이지 내 코드가 &lt;code&gt;커스텀 엘리먼트&lt;/code&gt;의 내부 구현을 수정해 손상시키지 않도록 해야 함.&lt;/li&gt;
&lt;li&gt;이때, &lt;code&gt;Shadow DOM&lt;/code&gt;을 사용하면, 요소를 &lt;em&gt;DOM 트리에 연결하되&lt;/em&gt;, 트리의 내부구조는 페이지 내 Javascript 및 CSS 코드로부터 숨길 수 있음.
&lt;ul&gt;
&lt;li&gt;&lt;img src=&#34;shadow-dom-tree.png&#34; alt=&#34;&#34;&gt;&lt;/li&gt;
&lt;li&gt;즉, DOM 트리에는 &lt;code&gt;shadow host&lt;/code&gt;만 드러나있고, &lt;code&gt;shadow host&lt;/code&gt;를 &lt;code&gt;root&lt;/code&gt;로 하는 &lt;code&gt;Shadow DOM 트리&lt;/code&gt;는 숨겨져 있는 형태임. (추후 렌더링시에는 합쳐짐)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하지만 이렇게 해도, &lt;code&gt;Shadow DOM 트리&lt;/code&gt; 내부 요소에서 발생한 이벤트가 &lt;code&gt;버블링&lt;/code&gt; 될 경우, &lt;code&gt;Shadow DOM 트리&lt;/code&gt; 외부 요소가 이들의 존재를 알 수 있음.
&lt;ul&gt;
&lt;li&gt;따라서, 이를 막고자 &lt;code&gt;Shadow DOM 트리&lt;/code&gt; 내부에서 발생한 이벤트가 버블링되어 상위로 전달될 때, &lt;code&gt;Shadow DOM Boundary&lt;/code&gt;를 넘으면 &lt;code&gt;Event.target&lt;/code&gt;의 값이 리스너의 스코프에 맞춰 변경됨.
&lt;ul&gt;
&lt;li&gt;즉, 상위 요소의 리스너의 스코프에서는 &lt;code&gt;Shadow DOM 트리&lt;/code&gt; 내부 요소를 알 수 없으므로, &lt;code&gt;Shadow DOM 트리&lt;/code&gt;에서 유일하게 외부에 노출된 요소인 &lt;code&gt;shadow host&lt;/code&gt;로 target이 변경됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이를 &lt;code&gt;이벤트 재타게팅&lt;/code&gt;이라고 함.&lt;/li&gt;
&lt;li&gt;이러한 &lt;code&gt;이벤트 재타게팅&lt;/code&gt;의 대표적인 예시가 &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; 요소임
&lt;ul&gt;
&lt;li&gt;DOM에서는 &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; 요소만 보이지만, &lt;em&gt;실제로 렌더링 될때는&lt;/em&gt; 비디오 재생에 필요한 &lt;strong&gt;일련의 버튼 및 제어용 UI&lt;/strong&gt;들이 포함되어 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mocking-관련&#34; &gt;Mocking 관련
&lt;span&gt;
    &lt;a href=&#34;#mocking-%ea%b4%80%eb%a0%a8&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Service Worker파일(mswServiceWorker.js)의 경우, 브라우저단에서 직접 접근해 등록하는 파일이므로 정적 서빙이 필요함
&lt;ul&gt;
&lt;li&gt;그래서 &lt;code&gt;public/&lt;/code&gt; 폴더에 넣음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker&lt;/code&gt;와 &lt;code&gt;server&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;worker&lt;/code&gt;(&lt;code&gt;setupWorker&lt;/code&gt;): &lt;code&gt;클라이언트-워커 통신 채널&lt;/code&gt;을 준비하여, 브라우저단에서의 API Mocking을 가능하도록 함&lt;/li&gt;
&lt;li&gt;&lt;code&gt;server&lt;/code&gt;(&lt;code&gt;setupServer&lt;/code&gt;): 서비스 워커가 실행될 수 없는 &lt;code&gt;Node.js&lt;/code&gt; 환경에서의 동일한 요청 핸들러를 적용하기 위한 브릿지
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http&lt;/code&gt;와 같은 표준 요청 모듈을 확장해, 외부로 전송되는 요청에 반응(react)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Node.js&lt;/code&gt;환경 기반이므로 &lt;code&gt;location&lt;/code&gt;, &lt;code&gt;localStorage&lt;/code&gt;와 같은 브라우저 전용 API는 사용할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;db-관련&#34; &gt;DB 관련
&lt;span&gt;
    &lt;a href=&#34;#db-%ea%b4%80%eb%a0%a8&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h2&gt;&lt;h3 id=&#34;postgresql&#34; &gt;PostgreSQL
&lt;span&gt;
    &lt;a href=&#34;#postgresql&#34;&gt;
        &lt;svg viewBox=&#34;0 0 28 23&#34; height=&#34;100%&#34; width=&#34;19&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path d=&#34;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;path d=&#34;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&#34; fill=&#34;none&#34; stroke-linecap=&#34;round&#34; stroke-miterlimit=&#34;10&#34; stroke-width=&#34;2&#34;/&gt;&lt;/svg&gt;
    &lt;/a&gt;
&lt;/span&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://develop-tracking.tistory.com/entry/PostgreSQL-%ED%8C%8C%ED%8B%B0%EC%85%94%EB%8B%9D-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EB%B3%B5%ED%95%A9-PK-bigserial%EC%9D%98-%ED%95%A8%EC%A0%95-1100%EA%B1%B4%EC%9D%98-%EC%A4%91%EB%B3%B5-%ED%82%A4-%EC%9E%A5%EC%95%A0-%EB%B6%84%EC%84%9D%EA%B3%BC-%EB%B3%B5%EA%B5%AC&#34;&gt;PostgreSQL 파티셔닝 환경에서 복합 PK + bigserial의 함정: 1,100건의 중복 키 장애 분석과 복구&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;PK(A, B) (복합 키) != B가 유일하다
&lt;ul&gt;
&lt;li&gt;BigSerial과 조합시 중복 가능성 존재&lt;/li&gt;
&lt;li&gt;가령, (시간, BS)를 복합키로 잡았을 경우, BS 값이 파티셔닝, 캐시 동시 참조 등의 이유로 인해 중복될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;파티션 키는 PK의 일부일 필요가 없다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
