<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>이나당</title>
    <link>https://h-owo-ld.tistory.com/</link>
    <description>농담곰 덕질하는 FE ╰(*&amp;deg;▽&amp;deg;*)╯

https://www.github.com/Ina-dang</description>
    <language>ko</language>
    <pubDate>Wed, 20 May 2026 03:17:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>이나당</managingEditor>
    <image>
      <title>이나당</title>
      <url>https://tistory1.daumcdn.net/tistory/5061156/attach/cb8079222f1b4c12a36b4b7b82908c89</url>
      <link>https://h-owo-ld.tistory.com</link>
    </image>
    <item>
      <title>연초에 봤던 프론트엔드 면접 후기 2곳</title>
      <link>https://h-owo-ld.tistory.com/375</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;144295863.png&quot; data-origin-width=&quot;169&quot; data-origin-height=&quot;169&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAimqG/dJMb99TT2rj/EBA9OJikXAdvVyPAoG9vU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAimqG/dJMb99TT2rj/EBA9OJikXAdvVyPAoG9vU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAimqG/dJMb99TT2rj/EBA9OJikXAdvVyPAoG9vU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAimqG%2FdJMb99TT2rj%2FEBA9OJikXAdvVyPAoG9vU1%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;169&quot; height=&quot;169&quot; data-filename=&quot;144295863.png&quot; data-origin-width=&quot;169&quot; data-origin-height=&quot;169&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;회사 1 후기&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 분위기였나&lt;/b&gt;&lt;/h2&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;면접 질문순서&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1분자기소개&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;현재 팀 개발인원&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팀장1 팀원4&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;회사에서 사용중인 언어, 라이브러리, 환경 등&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Swift, Kotlin, React-Native, Java, Spring Boot, JSP, FreeMarker, JavaScript, TypeScript, jQuery, React, Next, Nest, Express, Linux, Windows, Mac&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;온프레미스환경에서 운영장애생길 때 대처방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VPN, VDI, 리모트뷰, 쉘, 직접 방문 등 병원마다 접속 방식이 전부 달라서 상황마다 다르게 대응한다.&lt;/li&gt;
&lt;li&gt;대부분은 브라우저 로그나 서버 로그를 먼저 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;하고있는 서비스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-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;li&gt;제약 사전심사&lt;/li&gt;
&lt;li&gt;등등&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로그인 구성방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서비스 성격에 따라 다르게 구성했다.&lt;br /&gt;- 알림톡은 단순 정보 확인 형태&lt;br /&gt;- 관리자 페이지는 JWT 기반 인증&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;레거시였던 자바&amp;amp;제이쿼리 고도화 작업을 어떤순서로 진행했는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 먼저 기존 서비스가 정상 동작하는 것을 1차 목표로 잡았다.&lt;/li&gt;
&lt;li&gt;이후 소스를 분석 &amp;amp; 병원 측과 기능 확인을 병행하면서 작업했다.&lt;/li&gt;
&lt;li&gt;화면은 웹뷰 기반이었지만 최대한 네이티브 앱 같은 느낌이 나도록 신경 썼다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;고도화작업 인원분배는 어떻게 했는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;백1 프론트1 디자인1 기획자없음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;고도화 진행중 레거시와 고도화가 혼재되어있을때 충돌은 어떻게 해결했는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 JAR 기반 서비스는 기존 URL을 유지하고, 고도화 버전은 병원에서 발급받은 임시 URL로 병행 운영했다.&lt;/li&gt;
&lt;li&gt;안정화 이후 기존 URL을 React 기반 서비스로 전환했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;카카오 브라우저에서 디바이스간 이슈사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디바이스 환경별 스타일 차이 정도는 있었지만 치명적인 문제는 거의 없었다고 답변하고 다만 외부 브라우저로 열렸을 때 스토리지 값이 유지되지 않아 흰 화면이 뜨는 경우는 가끔 있었다고 했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;중간에서 커뮤니케이션한다는게 병원과 협의한다는 건지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순 기술 작업만 한 게 아니라 일정 조율이나 부서 간 협의도 많이 했다고 설명. 팀원들이 힘들어할 때 중간에서 조율하기도 했고, 병원 측이나 타 부서와의 소통도 담당했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비전공자로서 개발할때 허들은 없었는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;본인 입사 후 2주뒤에 입사한 분이 어릴때부터 개발을 하신분이라 전팀장님한테 비교를 많이받았다. 그래서 퇴근하고서도 개인 공부에 엄청 시간투자를 많이했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;신규개발시 공통 환경이라던지 기본구조 작업을 했다고 했는데 자세히 설명좀&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-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;li&gt;이후 입사자는 코드 적응 속도가 확실히 빨라졌다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스토리북 만드는 리소스도 꽤 들었을텐데&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잠깐 프로젝트가 딜레이 된 시점이 마침 생겨서 그때 호다닥 작업했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;멀티레포지토리인지 모노레포인지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;멀티 레포지토리라고 답변했다. 병원마다 서버 환경이나 요구사항, 버전이 전부 달라서 모노레포로 운영하기는 어렵다고 설명했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스토리북 이나 컨벤션이 효과가 있었나&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신규 입사자분들이 회사 코드 적응하는 데 확실히 도움이 됐다고 답변했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SI같은 느낌인가&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SI 성격은 있지만 유지보수도 대부분 직접 한다고 설명했다. 몇몇 외주를 제외하면 운영도 계속 담당한다고 답변했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리액트를 고도화 해본적이 있나&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 자바 기반 네이티브 앱 구조를 점진적으로 개선하면서, 네이티브 영역은 최소화하고 UI 영역은 React 기반 웹뷰로 전환하는 작업을 주로 하고 있다. React 자체를 고도화한 경험은 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;느낀 점&lt;/b&gt;&lt;/h2&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;단순 React보다 &amp;ldquo;실제 운영 가능 여부&amp;rdquo;를 많이 물어봄&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;&lt;b&gt;회사 2 후기&lt;/b&gt;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 분위기였나&lt;/b&gt;&lt;/h2&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;CS + 운영 + 협업 같이 물어봄&lt;/li&gt;
&lt;li&gt;AI 활용 여부도 질문함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;기억나는 질문들&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1분 자기소개&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지금 회사 이직사유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;크게 두 가지 이유가 있다. 하나는 회사의 경영 방향이 제가 중요하게 생각하는 개발 가치와 점점 멀어졌다는 점이고, 다른 하나는 팀 운영 구조 변화로 인해 개발에 집중하기 어려운 환경이 되었다는 점이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;좀더 자세하게 설명해줄 수 있나. 회사 관련&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매출이 입사후로 계속 줄어들다보니 경영에서 단기적인 영업 성과를 더 중요하게 보기 시작했고, 기능 자체보다는 보여지는 부분 위주로 영업을 하려한다... 가장 큰 포인트는 '있는 기능이 아닌데 있는것처럼 포장'을 해서 디자인만 예쁘게하려는 기획을 하고있어서 빤스런 하려한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;회사가 당장 그렇게 하라하면 어떡할거냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래서 지금 나가려고 알아보는거다. 만드는 입장으로서 중요하게 생각하는게 성취감과 정직함이라고 생각한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;우리회사 서비스 써봤냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;홈페이지 사업 소개와 유튜브 영상은 확인했지만 실제 서비스 사용까지는 못했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지금 회사에서 하는 서비스가 자사서비스인가 아니면 모듈만 만들어서 거기에 설치하는 에이전시같은 사업인가&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;알림톡은 SI 성격이 강하고, 키오스크는 솔루션 느낌이다.&lt;/li&gt;
&lt;li&gt;키오스크는 내부망에서만 동작하기 때문에 방문해서 직접 설치 진행한다.&lt;/li&gt;
&lt;li&gt;모바일 서비스는 병원 서버에 배포하는데 방문/비방문 나뉘어져있고 SI 성격이지만 유지보수까지 담당한다고 답변했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;본인이 진행한 프로젝트중 가장 잘했다 싶은 프로젝트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회사 1에서도 이야기했던 병원 고도화 프로젝트를 이야기. 기존 서비스에서 작동하던 기능들을 최대한 똑같이 유지하는 것을 우선 목표로 잡았고, 병원 측과 기능 확인을 병행하면서 작업했다. (이전 문서가 없어서 병원도 정확히 어떤기능인지 모름)&lt;/li&gt;
&lt;li&gt;웹뷰 기반이지만 최대한 네이티브 앱 느낌이 나도록 신경 썼다고 답변했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리덕스 툴킷, 리액트쿼리같은거 여러가지 썼는데 어떻게 선택하고 쓰게된건지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입사 당시에는 Redux를 사용 중이었는데 보일러플레이트가 너무 많다고 느껴 RTK 도입을 제안했다고 설명했다. 팀장님이 새로운 기술 제안에 열려 있는 편이어서 비교적 자연스럽게 도입할 수 있었다.&lt;/li&gt;
&lt;li&gt;이후 신규 인력이 React Query에 익숙했고, 프로젝트 특성상 서버 상태 관리에 더 적합하다고 판단해 팀장과 협의 후 React Query를 도입했다.&lt;/li&gt;
&lt;li&gt;팀원, 프로젝트 성격에 따라 선택했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;근데 전역을 사용할 일이 많이 없나요&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-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;h3 data-ke-size=&quot;size23&quot;&gt;깃플로우는 어케하게됨&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전에 다 나가버린사람들이 깃관리를 안하고있었고 남아있던 전팀장님이 새로 팀빌딩 하면서 깃플로우 하자해서 같이 이야기하다가 깃플로우로 하게됐다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;차트는 뭐뭐 썼는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입사 초반에는 npm trends를 봤을 때 chart.js가 가장 많이 쓰이는것같아서 그걸 썼었다. 대부분 곡선이나 막대 간단한 차트만 보여주는거라 어려운차트가 필요없어서 그걸쓰다가 사전심사때는 차트가 조금 스크롤도필요하고 커스텀이 필요해져서 찾아보니 rechart.js가 커스텀이 좋다해서 그걸 쓰게됐다.&lt;/li&gt;
&lt;li&gt;근데 사실 전팀장님 개발 철칙이 만들수있으면 굳이 라이브러리 쓰지마라고해서 범위 달력이나 몇 몇 차트는 직접 만들었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다국어 처리도 한것같은데 그건 어떻게 처리했는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존성을 최소화하기 위해 직접 구현되어있다.&lt;/li&gt;
&lt;li&gt;브라우저의 userAgent &lt;i&gt;(navigator.language인데 userAgent라고 잘못말함 샤갈ㅠ 디바이스랑 언어체크 붙여서 같이해서 순간 헷갈림)&lt;/i&gt; 값을 기반으로 언어를 분기하고, 병원에서 제공한 다국어 엑셀 데이터를 JSON으로 변환해 관리했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그러면 다국어를 번역하는 사람한테 엑셀같은거로 받나&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그렇다. 모병원같은경우는 7개국어까지하는데 그경우 병원에서 &amp;lsquo;안녕하세요&amp;rsquo;에 맞는 부분의 각 언어별로 문서를 제공해준다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a href=&quot;http://quill.js&quot;&gt;quill.js&lt;/a&gt;는 어디까지, 어쩌다 사용하게된건지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에디터 비교하면서 quill.js까지 선택하게된 히스토리(Toast UI, Wysiwyg...) 설명했다.&lt;/li&gt;
&lt;li&gt;많이쓰지는 않고 에디터에 사진첨부, 글씨체, 굵기, 정렬, 색상 이정도까지만 옵션에 넣었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;pg 구축은 어떤식으로 하는지, api로 하는지 모듈로 하는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pg 업체마다 다른데 어디는 자바 jsp밖에 없다하면 jsp를 저희는 프리마커를 쓰고있기때문에 프리마커템플릿엔진에 맞춰서 바꿔서 작업하고, 만약 js가 있다하면 js api쓸수있으면 거기다가 api 주고받는걸로 하는데 어디는 jsoup으로 해야한대서 그걸 사용하기도 하고 pg사마다 다 각각 다르다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;백엔드랑 api형식의 문서를 프론트에서 작성해보신건가요? 아니면 보통 그렇게 하시나요?&lt;/h3&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;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그럼 그대로 해주나요?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그럴때도 있고 추가하고싶은게있으면 추가하기도하고 일단 초안문서를 프론트에서 만들면 그때부터 백엔드랑 협의했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;KIMS 시스템에서 응답받은 HTML 데이터를 파싱하여 화면에 동적으로 데이터 추가 &amp;lt;- 이걸 좀더 자세히 설명해달라&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;KIMS 의약 정보 페이지에서 HTML 데이터를 받아온 뒤, 특정 div/class 기준으로 필요한 데이터를 추출해 화면 구조에 맞게 재가공했다고 설명했다.&lt;/li&gt;
&lt;li&gt;기존 HTML 구조를 그대로 쓰기보다는 필요한 데이터만 다시 조립해서 사용했다고 답변했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;lighthouse를 사용해서 성능 개선한게있다는데 자세히 설명해달라&lt;/h3&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;다만 분석 과정에서 MUI 번들 크기가 상당히 큰 것을 확인했고, 이후 프로젝트에서는 MUI를 사용하지않고 프로젝트를 템플릿화 + 기본 html태그를 사용한 스토리북 제작 하여 불필요한 사용을 줄이고 있다고 답변했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리액트-윈도우는 왜썼는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기에는 데이터 양을 예측하지 못해 단순 렌더링으로 구현했는데, 실제 운영 환경에서 데이터가 많아지면서 렉이 발생했다.&lt;/li&gt;
&lt;li&gt;이후 화면에 필요한 요소만 렌더링하도록 react-window를 도입했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스토리북 도입을 주도했냐, 왜했냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ㄹㄹ이가 맘대로해놔서 1번회사 때 말한대로&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그럼 그 작업하는분은 진짜로 컨벤션을 몰라서 그런거냐 본인의 확고한 뭔가가 있어서 그랬던거냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개인 스타일이 강한 부분도 있었던 것 같다고 답변했다.&lt;/li&gt;
&lt;li&gt;다만 당시에는 명확한 규칙 자체가 부족했던 것도 사실이라 이후 팀원들과 협의해 컨벤션을 정리했다고 설명했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨벤션 생긴 이후로는 잘 따르냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그도 노력중이다. 그리고 중간중간 팀원들이 이제 그의 커밋을 확인했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨벤션 사실 모르면 물어보면서 해야하는거 아니냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웃음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;병원의 로그인서비스 어떻게 구축하는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아까 회사1에서 말한대로&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;액세스토큰이랑 리프레시토큰 어떻게저장하는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액세스 토큰은 Header 리프레시 토큰은 Cookie&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리액트에서 키가 중요하다고 하는데 왜 그게 중요하냐, 키를 잘못쓰면 무슨문제가 생기냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열 렌더링 시 index를 key로 사용할 경우 순서 변경 시 문제가 생길 수 있다는 것은 알고 있어서 항상 고유한 값을 사용하려고 했다.&lt;/li&gt;
&lt;li&gt;항상 데이터중에 프라이머리한걸로 쓰려고했다. 안된다고 들어서 한번도 쓴적이없다. 그 이유는 잘모르겠다 죄송하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;React는 리스트를 렌더링할 때 `key` 값을 기준으로 어떤 요소가 변경됐는지 비교한다.

만약 index를 key로 사용하면:

- 리스트 순서가 변경되거나
- 중간 요소가 추가/삭제될 때

React가 기존 요소를 잘못 재사용할 수 있다.

그 결과:

- input 값이 꼬이거나
- 잘못된 컴포넌트가 유지되거나
- 불필요한 리렌더링이 발생할 수 있다.

그래서 가능하면 DB id 같은 고유한 값을 key로 사용하는 것이 좋다.&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;병원에서 운영할때 cors문제생기냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분 병원 환경은 운영 서버에 바로 배포하는 구조였고, 프론트와 백엔드 도메인이 같은 경우가 많아서 CORS 문제가 거의 없었다고 설명했다.&lt;/li&gt;
&lt;li&gt;포트 차이로 문제가 생기는 경우에는 nginx 프록시 설정으로 해결했다고 답변했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개발서버없으면 프론트하고 백엔드하고 어떻게 테스트하냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로는 로컬 환경에서 각각 실행해 테스트했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;한 노트북에서 두개 프로젝트 띄운다는거냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그런 경우도 있었고, 상황에 따라 노트북을 따로 사용하기도 했다고 설명했다.&lt;/li&gt;
&lt;li&gt;필요한 경우에는 백엔드에서 프론트 개발용 IP와 포트를 허용하는 방식으로 테스트했다고 답변했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개발서버가 없을수가 있냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개인적으로는 개발 서버가 꼭 필요하다고 생각했다.&lt;/li&gt;
&lt;li&gt;실제로 개발 서버와 병원 DB 환경을 따로 구성해 테스트하고 싶어 생산부 요청도 했지만 현실적으로 지원이 어려웠다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그래서 테스트는 어떻게&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트 환경이 부족했기 때문에 입사 이후에는 Postman이나 MSW 같은 도구 세팅을 더 철저하게 하려고 했다.&lt;/li&gt;
&lt;li&gt;병원 운영 환경은 테스트 데이터조차 없는 경우가 있어서 더욱 중요하다고 느꼈다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;설치는 직접가서 빌드하냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 병원에 방문해 작업하는 경우도 있었다.&lt;/li&gt;
&lt;li&gt;주로 리눅스 환경의 서버가 많았다.&lt;/li&gt;
&lt;li&gt;설치는 실물서버를 받아서 OS설치 - 서버 랙 작업부터 진행하는 경우도 있었고, 가상 서버 환경을 제공받아 Windows Server에 배포한 경험도 있다고 설명했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;디바운스나 쓰로틀링에 대해서 어떻게 아냐 써봤냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;병원에서 번호표 발급이라는게 있는데 그거를 버튼을 막 엄청 눌러서 티켓팅 한다는걸 알게됐다.&lt;/li&gt;
&lt;li&gt;그래서 그 이후론 버튼에 디바운스나 쓰로틀링 넣고있다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리플로우랑 리페인트 차이에 대해서 설명좀&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설명 못함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# Reflow(Layout)

!요소의 크기나 위치가 변경되면서 브라우저가 전체 레이아웃을 다시 계산하는 과정이다.!

예시:
- width/height 변경
- margin 변경
- font-size 변경
- DOM 추가/삭제

=&amp;gt; 비용이 크다.

---

# Repaint

!레이아웃 변화 없이 색상이나 스타일만 다시 그리는 과정이다.!

예시:
- background-color 변경
- color 변경
- visibility 변경

=&amp;gt; Reflow보다 상대적으로 비용이 적다.

---

# Reflow가 발생하면 보통 Repaint도 같이 발생한다.
그래서 애니메이션 작업 시에는:

- width/height 대신
- transform, opacity 같은 속성을 사용하는 것이 성능상 유리하다.&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;병원 관리자 페이지면 엄청 복잡할텐데&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EMR 수준은 아니어서 생각보다 복잡한 시스템은 아니었다.&lt;/li&gt;
&lt;li&gt;대부분 조회 형태 작업이 많았고, 그중에서는 제약 사전심사 프로젝트가 가장 복잡했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사전심사때는 폼관리어케했냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 단위로 컴포넌트를 분리했다고 설명했다.&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&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;개인적으로 props drilling이 깊어지기 시작하면 전역 상태로 관리하는 편이라, 당시에는 상태 관리를 조금 더 철저하게 가져가려고 했다고 설명했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a href=&quot;https://naver.com%EC%9E%85%EB%A0%A5%ED%96%88%EC%9D%84%EB%95%8C&quot;&gt;https://naver.com입력했을때&lt;/a&gt; 화면에 뿌려지기까지과정&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저에서 URL 입력 &amp;rarr; DNS 조회 &amp;rarr; IP 확인 &amp;rarr; 해당 서버 요청 &amp;rarr; HTML/CSS/JS 응답 &amp;rarr; 필요한 경우 추가 API 요청 &amp;rarr; 브라우저 렌더링&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;http 3.0 에 대해서 설명좀&lt;/h3&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;/ul&gt;
&lt;pre id=&quot;code_1778678897739&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HTTP/3?
HTTP/3는 기존 HTTP/1.1, HTTP/2처럼 웹에서 클라이언트와 서버가 데이터를 주고받기 위한
HTTP 프로토콜의 최신 주요 버전.

가장 큰 차이는 기존 HTTP/1.1과 HTTP/2가 TCP 기반으로 동작했던 것과 달리,
HTTP/3는 UDP 기반의 QUIC 프로토콜 위에서 동작한다는 점.

  
---구조 비교
기존:
HTTP -&amp;gt; TCP -&amp;gt; IP

HTTP/3:
HTTP/3 -&amp;gt; QUIC(UDP 기반) -&amp;gt; IP
---

사용이유?
이전 버전에서 HOL Blocking(Head Of Line Blocking):
  TCP 기반 통신에서 하나의 패킷이 손실되면 뒤 요청들도 같이 대기하는 문제
가 발생했었다. 

QUIC은 스트림 단위로 데이터를 처리해 하나의 요청이 늦어져도 다른 요청까지 전부 막히는 현상을 줄여준다.
그래서 연결 속도가 더 빠르고 모바일 네트워크 환경에 강하고 지연 시간이 줄어드는 장점이 있다.

따라서 QUIC(HTTP/3에서 사용하는 통신 프로토콜)을 사용하면 연결 설정 시간이 줄어들고, 
여러 요청을 동시에 처리할 때 하나의 요청 지연이 다른 요청까지 막는 문제를 줄일 수 있음.

추가특징
- UDP 기반
- TLS 암호화 기본 내장
- 연결 재수립 속도가 빠름
- HTTP/3 핵심 기술&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배포할때 백엔드랑 프론트 같이 배포해야할때 어케함&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쉘 두개 켜고 백엔드가 대부분 가벼워서 더 빨리되니까 프론트 스크립트 하고 백엔드 스크립트 해서 배포했는데 아직까지 문제없었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그런거 말고 무중단해야하면&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PM2. 빌드한후에 pm2 restart(reload라 말해야하는데;) 로 했다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1778679002816&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;궁금해서 찾아본 다른 대안

- Nginx Reverse Proxy + Blue-Green 배포
새 버전을 다른 포트나 다른 서버에 먼저 띄운 뒤, Nginx upstream을 새 버전으로 바꾸는 방식

예시)
- 기존 버전: 3000번 포트
- 새 버전: 3001번 포트
- 새 버전 헬스체크
- Nginx가 바라보는 포트를 3001로 변경
- 문제 생기면 다시 3000으로 롤백

- Docker 기반 배포 -&amp;gt; 아마 이 방식을 원하셨던것 같음
Docker 이미지를 새로 빌드하고 새 컨테이너를 띄운 뒤, 정상 확인 후 기존 컨테이너를 내리는 방식.
규모가 커지면 Docker Compose, Kubernetes, Blue-Green, Rolling Update 같은 방식으로 확장.&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장애났을때 프론트는 사실 할수있는게 없을텐데 장애조치를 위해서 할 수 있는 최선 뭐가있냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마침 백엔드분이 지금 휴가중이라서 이번에 배포 시 오류나서 수정해야 하는 백엔드코드들을 확인해서 수정했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;아 풀스택이구나. 질문의도를 바꾼다. 백엔드 장애 대비해서 뭔가 프론트에서 처리하고 있냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;API 응답이 비정상인 경우 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;첫번째 회사를 오래다녔는데 이제 두번째 회사를 선택하면서 어떤스타일이고 어떤회사를 가야겠다 라는게 있는지&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개인적으로는 기획자가 있는 회사에 가보고 싶다. 이전 회사에서는 기획 역할까지 개발팀이 함께 하는 경우가 많았기 때문에, 역할이 조금 더 명확하게 분리된 환경도 경험해보고 싶다.&lt;/li&gt;
&lt;li&gt;추가로 AI 관련 학과에 진학 예정이라(방통대) 회사 안에서 자연스럽게 AI 관련 업무나 흐름을 접할 수 있는 환경에도 관심이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;우리스타트업이라 돈없을수도 있고 당장 돈이없는상황은 아니지만 스타트업이라는게 어떻게될지모르는데&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지금 우리회사도 어떻게 될지 모른다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AI머신러닝 하는 분들이 있긴한데 그 업무를 직접적으로 하는건 아니고 그분의 모델들을 호출하는거라 실망하시는거아니냐&lt;/h3&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;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기술적 갈등이나 의사갈등이 있을때 협의하려고 했지만 안되는 경우도있다. 그럴땐 어떻게하냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개인적으로는 감정이 드러나는 순간 협의가 어려워진다고 생각한다. 그래서 상대방이 감정적으로 나오더라도 최대한 감정을 드러내지 않으려고 하고, 기술 자료나 근거를 중심으로 이야기하려고 한다.&lt;/li&gt;
&lt;li&gt;정말 끝까지 해결되지 않는 경우에는 일단 방향을 맞춰 진행하고, 이후 결과를 통해 다시 논의하는 편이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;근데 만약 상대방이 잘못생각한게아니고 본인이 잘못생각한거였어서 문제안생기면&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그럼 아 그게맞구나 앞으로 그렇게 하면되는구나 생각하고 만다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;팀장님 언급이 좀 잇었는데 본인이 생각하는 팀의 리더는 어떤사람이어야 한다고 생각하냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 의견을 다 수용할 필요는 없지만, 방향을 정리해주고 왜 그 방향이 맞는지 설명해줄 수 있는 사람이 좋은 리더라고 생각한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;업무가 힘들다는 기준이 사람마다 다른데&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일 없을때 힘들다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AI툴 어떻게 사용중이냐&lt;/h3&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;- 회사에서는 지피티 사줘서 지피티쓰고 gemini cli같이쓰고있따
- 집에서는 커서쓰고있다&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;바이브코딩하냐&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(생각 개많았음 바이브코딩하면 안좋게볼까봐 ㅠ) 집에서는 커서 단위별로 해달라고하면 공식문서보다 잘알려줘서 커서로 학습대신하는데 회사에서는 커서 위험하다 생각해서 안씀
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;&amp;gt;&amp;gt; 지금은 바이브코딩없이 못사는 나&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잠깐 지나면 막 쌓이는게 그 중간에 혹시나 확인 못하고 넘어가게될까봐&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;우린 바이브코딩좋아함 우리 ai개많이씀 클로드 비싸서 안쓸꺼면 코덱스라도 꼭 써보셈&lt;/h3&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;- 녜&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;느낀 점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;왜 그렇게 선택했는지&amp;rdquo;를 엄청 중요하게 봄&lt;/li&gt;
&lt;li&gt;모르는 건 솔직하게 말하는 게 낫다고 느낌&lt;/li&gt;
&lt;/ul&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;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;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;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;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;</description>
      <category>일상/일기장</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/375</guid>
      <comments>https://h-owo-ld.tistory.com/375#entry375comment</comments>
      <pubDate>Wed, 13 May 2026 22:09:39 +0900</pubDate>
    </item>
    <item>
      <title>나당쓰의 2026년 1분기 회고</title>
      <link>https://h-owo-ld.tistory.com/374</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;144295863.png&quot; data-origin-width=&quot;169&quot; data-origin-height=&quot;169&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7tnST/dJMcahKw88v/XXYuNrqC9OXAoitPdfWvU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7tnST/dJMcahKw88v/XXYuNrqC9OXAoitPdfWvU0/img.png&quot; data-alt=&quot;옛날 메이플사진을 자꾸 썸네일로 했더니 메이플 좋아한다고 오해해서 조크베어때 만든 이미지를 썸네일 용으로 가져옴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7tnST/dJMcahKw88v/XXYuNrqC9OXAoitPdfWvU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7tnST%2FdJMcahKw88v%2FXXYuNrqC9OXAoitPdfWvU0%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;169&quot; height=&quot;169&quot; data-filename=&quot;144295863.png&quot; data-origin-width=&quot;169&quot; data-origin-height=&quot;169&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;옛날 메이플사진을 자꾸 썸네일로 했더니 메이플 좋아한다고 오해해서 조크베어때 만든 이미지를 썸네일 용으로 가져옴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 2025년 회고 다음글이 바로 2026년 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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;한줄요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 새로운 항해의 2026&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;1분기 전체 요약&lt;/h2&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;잘한점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;어중간하게 미련가지지 않고 퇴사한 것&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 팀장님이랑 마지막 면담이 진짜 레전드 오브 레전드였다. 퇴사면담 하자면서 카페갔더니 대뜸 하는말이 '그래서 어디가는데요?' 로 시작. 이후엔 갑자기 본인 진로상담을 나한테함 (물론 내가 직업상담사 자격이 있고 경험도 있긴한데 나.. 지금.. 내 퇴사 면담이에요)&lt;/li&gt;
&lt;li&gt;3월 23일부터 백수 시작~&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pRy8h/dJMcadOWlcp/0TcIQLqmZ7YHAkr1qu7DmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pRy8h/dJMcadOWlcp/0TcIQLqmZ7YHAkr1qu7DmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pRy8h/dJMcadOWlcp/0TcIQLqmZ7YHAkr1qu7DmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpRy8h%2FdJMcadOWlcp%2F0TcIQLqmZ7YHAkr1qu7DmK%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;1270&quot; height=&quot;520&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&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;1분기에 프로젝트 하나를 마무리 한 것? (1차 오픈해서 주변사람들한테 테스트 받고있당)&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cats.jpg&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n0dOf/dJMcabjtruD/klvMk9bB9XP5K593POKir1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n0dOf/dJMcabjtruD/klvMk9bB9XP5K593POKir1/img.jpg&quot; data-alt=&quot;2학기부터 전공선택 이라 현재는 비워져있는상태 ~.~&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n0dOf/dJMcabjtruD/klvMk9bB9XP5K593POKir1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn0dOf%2FdJMcabjtruD%2FklvMk9bB9XP5K593POKir1%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;784&quot; height=&quot;101&quot; data-filename=&quot;cats.jpg&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;101&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2학기부터 전공선택 이라 현재는 비워져있는상태 ~.~&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;하고싶었던 공부를 시작한 것&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중간고사, 과제기간에 파묻혀 있는 나&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rQNpZ/dJMcacQbSr5/sk4vNPkE8dlyznQfOztzDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rQNpZ/dJMcacQbSr5/sk4vNPkE8dlyznQfOztzDk/img.png&quot; data-alt=&quot;5월부턴 헬스도 등록할거!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rQNpZ/dJMcacQbSr5/sk4vNPkE8dlyznQfOztzDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrQNpZ%2FdJMcacQbSr5%2Fsk4vNPkE8dlyznQfOztzDk%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;497&quot; height=&quot;137&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;5월부턴 헬스도 등록할거!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;건강에 좀더 관심을 가지기 시작한 것&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.jpg&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p5Epp/dJMcaco7OaD/kImdG8s607gwvak9gWja2k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p5Epp/dJMcaco7OaD/kImdG8s607gwvak9gWja2k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p5Epp/dJMcaco7OaD/kImdG8s607gwvak9gWja2k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp5Epp%2FdJMcaco7OaD%2FkImdG8s607gwvak9gWja2k%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;954&quot; height=&quot;589&quot; data-filename=&quot;11.jpg&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;여행을 늘리게 된 것&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3월엔 퇴사한 전직장동료분들 + 다니는 동료분들 이랑 제주도를 다녀왔다!&lt;/li&gt;
&lt;li&gt;4월도 예약완료&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;아쉬운점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;997&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHlsxv/dJMcagLQj3B/eY3LqV2MmX9EGOHRmWZlfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHlsxv/dJMcagLQj3B/eY3LqV2MmX9EGOHRmWZlfk/img.png&quot; data-alt=&quot;추추추추추추천강의&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHlsxv/dJMcagLQj3B/eY3LqV2MmX9EGOHRmWZlfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHlsxv%2FdJMcagLQj3B%2FeY3LqV2MmX9EGOHRmWZlfk%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;997&quot; height=&quot;469&quot; data-origin-width=&quot;997&quot; data-origin-height=&quot;469&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;추추추추추추천강의&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;선행학습이 안되어있어서 학교 공부 따라가기가 너무 버거운 것&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EBS 감사합니다..&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컨디션 관리가 아직도 잘 안돼서 쉽게 지치는점&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실비 야무지게 받고있다~&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;배운 점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;퇴사는 생각보다 별거 없었다. 마지막까지 평생 안주거리를 만들어낸 회사 덕분에 미련또한 1도 없음 ^^.. 퇴사 후에 들려오는 이야기들도 진짜 대박살 썰들이 우수수수 쏟아지고있어서 ㅎㅋㅎㅋ&lt;/li&gt;
&lt;li&gt;혼자 공부할 때는 의지도 중요하지만 체계를 잘 잡아두는게 훨씬 중요한 것 같다.&lt;/li&gt;
&lt;li&gt;프로젝트는 한 삽을 뜨기, 그리고 마무리까지 가져가기 이 두가지가 정말 정말 힘들다.&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2분기 목표&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;학업&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중간고사, 과제 무사히 잘 치르기 (국장 가능할 정도는 하자..)&lt;/li&gt;
&lt;li&gt;EBS 수학, 물리강의 일주일에 3회 이상 듣기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;개발&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구지라지 시작&lt;/li&gt;
&lt;li&gt;에너지트래커 운영하면서 조금씩 홍보하기&lt;/li&gt;
&lt;li&gt;코딩테스트 &amp;amp; 알고리즘 준비하기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;일상&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쉼, 쉼!&lt;/li&gt;
&lt;li&gt;더워지기전에 여행 많이다니기&lt;/li&gt;
&lt;li&gt;본가다녀오기&lt;/li&gt;
&lt;li&gt;마지막주 수요일 문화의날 챙기기&lt;/li&gt;
&lt;li&gt;2분기까지는 돈걱정 안하고 하고싶은거 다 하기&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>일상/일기장</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/374</guid>
      <comments>https://h-owo-ld.tistory.com/374#entry374comment</comments>
      <pubDate>Mon, 6 Apr 2026 18:04:39 +0900</pubDate>
    </item>
    <item>
      <title>감자 개발자의 2025년 회고</title>
      <link>https://h-owo-ld.tistory.com/373</link>
      <description>&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;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bP6LzT/btsORTrU7cM/gwWNB9ayfIST77IXWOgzy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bP6LzT/btsORTrU7cM/gwWNB9ayfIST77IXWOgzy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bP6LzT/btsORTrU7cM/gwWNB9ayfIST77IXWOgzy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbP6LzT%2FbtsORTrU7cM%2FgwWNB9ayfIST77IXWOgzy0%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;500&quot; height=&quot;491&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2022년 11월 1일 현재 회사에 입사 후 드디어 3년이 지났다. 2025년에 경험한 것들을 정리하고 앞으로의 계획을 다시 새겨보는 시간을 가져보려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2025 타임라인&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상반기&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2024년 이어서 진행중인 프로젝트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;- 한방병원 알림톡&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병원측 사정으로 인해 테스트가 밀려서 오픈도 미뤄졌다. 오픈이 미뤄지면서 요구사항등이 자꾸자꾸 나오고, 예외상황들도 더 많아지고 기존에 없던 케이스들도 추가하게되어서 테스트가 더 오래 걸렸다. 그래도 막상 오픈하고나니 오픈 후 첫 달 정도만 로그분석 들어오고 이후에는 운영이슈 0% 기록중. 사용량은 많은데 이슈가 없어서 사용자들이 편하게 쓰고 있다고 생각하니 매우 뿌듯했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;케이스가 복잡한 시나리오가 많아서 README.md랑 JSDoc을 엄청 꼼꼼하게 달아두고 커밋내용도 육하원칙으로 쓰려고 신경을 많이 썼던 프로젝트&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;- EMR 태블릿 앱&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래는 4분기에 개발하고 소스 자체를 인수인계 하기로 한 프로젝트인데, 그 업체에서 운영인력을 구하지못해서 6개월 유지보수 추가 요청을 주셨다. (추가개발도 ㅎ) 회사에서 사용해보지 않던 기능들을 만들어 볼 수 있어서 좋았다. 탭구성이나 화면 형태 외의 html을 만들어서 PDF로 저장하기도하고 구글 북마크처럼 즐겨찾기기능도 만들어보고 재밌었다. 마지막 인수인계때는 회사에서 그동안 문서를 그렇게까지 많이 해본적이 없는데 업체에서 요청한 완료보고 문서들이 많아서 조금 허덕였지만 그래도 무사히 마무리-&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 업체 본부장님이 인수인계끝나고 회식하면서 '그동안 외주할 때 이렇게 쫑파티를 한적이 없는데 정말 잘해줘서 식사자리 마련했다. 본인들의 작업에 자랑스러워 해도된다.'라고 말해주셔서 진짜 ㄹㅇ 완전 감동이었다. 이런 말 한마디마디에 또 에너지를 얻고 일하게 되는것같다. :D&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;size18&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;갑분기. 갑자기 통합관리시스템(환자, 식수, 진료예약, 물리치료 등), 키오스크, 알림톡 기획(!!!!!!!)을 맡게되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 그 병원은 수기, 또는 스프레드시트로 식사와 치료, 그리고 상담예약을 관리하고 있고 CS나 환자관리는 각각의 개인 솔루션업체를 사용하고 있어 원무에서 한 환자를 볼때 4-5개의 창을 봐야하는 불편함이 있다고 하셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 부분을 최대한 1-2개로 줄일 수 있도록 관리시스템을 구축하면서 가장 급한 식수(병원식)관리 키오스크와 알림톡 기획을 같이 맡게되었다. 담당하는 원무선생님이 매우 의욕적이어서 figma도 공부하면서 기획 ppt를 만들었다. 하지만 이후에 아래의 고도화 앱에 투입되면서 기획은 여기까지만 하고 다른분에게 넘어가게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이후에는 팔로업을 가-끔 도와주는 정도로만 관여하게되었고 중간에 해당 프로젝트 담당하던 사람 한 명이 이탈이 있어서 오픈일정에 차질도 생기고 남아있는 팀원이 진짜 힘들어했다. 기능을 3차까지 나눠서 오픈하기로 변경되었는데, 부디 3차까지 잘 마무리 되기를 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;처음엔 이렇게 장차법만 추가였긴한데, 결국 지금(6월 말)은 + 입원수속알림톡, 주차현황 등등등 막 늘어나고 있긴하다 :D ㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 네이티브(Java+Kotlin &amp;amp; Swift), 스프링부트(Java) 로 만들어진 프로젝트를 이번엔 네이티브(Kotlin &amp;amp; Swift)와 리액트(Javascript)로 고도화를 진행하고있다.&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;하지만 이전에는 수납기능이 없고 대부분 전산 + 백엔드와 주고받는 api 기능들이 전부라서 문제가 없었는데.. 외부 업체 연동이 끼니까 이슈가 생기긴해서 네이티브 수정이 좀 있긴 했다. (코쓱) 해당 부분은 별도의 포스팅으로 정리 해두었다。&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1758716240393&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;[React&amp;amp;Kotlin] 웹-네이티브 브리지를 활용한 PG 결제 연동 구조 설계기 - 안드로이드 편&quot; data-og-description=&quot;문제의 시작 현재 회사에서 안드로이드 앱들은 MainActivity에서 WebView를 활용해 React로 개발된 웹 화면을 네이티브 앱 내에 띄워서 표시하고 있다. 이전까지는 대부분 외부업체와의 연동이 없고 병&quot; data-og-host=&quot;h-owo-ld.tistory.com&quot; data-og-source-url=&quot;https://h-owo-ld.tistory.com/370&quot; data-og-url=&quot;https://h-owo-ld.tistory.com/370&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/k91d7/hyZJCkYeh5/4L1UMMXEDHvKPO1IbEYKz0/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/D95jo/hyZJPp7x0o/hJt7KlJ80LOfmJTaW8PsLk/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/bHKktZ/hyZJQCzjan/t517ew7145UrKefUQ8W7j0/img.png?width=918&amp;amp;height=1332&amp;amp;face=0_0_918_1332&quot;&gt;&lt;a href=&quot;https://h-owo-ld.tistory.com/370&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://h-owo-ld.tistory.com/370&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/k91d7/hyZJCkYeh5/4L1UMMXEDHvKPO1IbEYKz0/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/D95jo/hyZJPp7x0o/hJt7KlJ80LOfmJTaW8PsLk/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/bHKktZ/hyZJQCzjan/t517ew7145UrKefUQ8W7j0/img.png?width=918&amp;amp;height=1332&amp;amp;face=0_0_918_1332');&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;[React&amp;amp;Kotlin] 웹-네이티브 브리지를 활용한 PG 결제 연동 구조 설계기 - 안드로이드 편&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;문제의 시작 현재 회사에서 안드로이드 앱들은 MainActivity에서 WebView를 활용해 React로 개발된 웹 화면을 네이티브 앱 내에 띄워서 표시하고 있다. 이전까지는 대부분 외부업체와의 연동이 없고 병&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;h-owo-ld.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1758716255503&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;[React&amp;amp;iOS] 웹-네이티브 브리지를 활용한 PG 결제 연동 구조 설계기 - iOS 편&quot; data-og-description=&quot;문제의 시작현재 회사에서 안드로이드 앱들은 MainActivity에서 WebView를 활용해 웹 화면을 네이티브 앱 내에 띄워서 표시하고 있다. 이전까지는 대부분 외부 연동이 없는 조회 형태라서 특별한 문&quot; data-og-host=&quot;h-owo-ld.tistory.com&quot; data-og-source-url=&quot;https://h-owo-ld.tistory.com/371&quot; data-og-url=&quot;https://h-owo-ld.tistory.com/371&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/W3ulf/hyZJn9Ot5j/W3MxlKwnIoWtMAebL8Dq50/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/Yu9wn/hyZJQP64O3/jfMk3NyTNcT60em3B02MF0/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/cwTlG3/hyZJrqP4aT/Q5CjIGkMPIxOMI7BrY9Tf1/img.png?width=2978&amp;amp;height=1412&amp;amp;face=0_0_2978_1412&quot;&gt;&lt;a href=&quot;https://h-owo-ld.tistory.com/371&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://h-owo-ld.tistory.com/371&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/W3ulf/hyZJn9Ot5j/W3MxlKwnIoWtMAebL8Dq50/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/Yu9wn/hyZJQP64O3/jfMk3NyTNcT60em3B02MF0/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/cwTlG3/hyZJrqP4aT/Q5CjIGkMPIxOMI7BrY9Tf1/img.png?width=2978&amp;amp;height=1412&amp;amp;face=0_0_2978_1412');&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;[React&amp;amp;iOS] 웹-네이티브 브리지를 활용한 PG 결제 연동 구조 설계기 - iOS 편&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;문제의 시작현재 회사에서 안드로이드 앱들은 MainActivity에서 WebView를 활용해 웹 화면을 네이티브 앱 내에 띄워서 표시하고 있다. 이전까지는 대부분 외부 연동이 없는 조회 형태라서 특별한 문&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;h-owo-ld.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;하반기&amp;nbsp;&lt;/h3&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;7월부터 갑자기 매달 병이 터졌다 이석증에 코로나에 감기에 심재성2도화상에 디스크손상에 눈이상에.. 진짜 온몸이 난리가 나서 실비가 없었으면 저축1도못하고 그냥 가난뱅이 될뻔&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;010&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/010.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/010.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 기존 사용중인 병원 알림톡페이지 고도화 및 추가개발 &amp;amp; 외래최적화 LBS(위치기반서비스) 연동지원&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상반기 병원앱 고도화 및 장차법 적용을 끝내고 해당 프로젝트의 연장선으로&amp;nbsp; 기존에 서비스중인 기능 2개 페이지를 최신 알림톡 페이지로 UI를 바꿔주고, 추가 기능들을 넣었다. 알림톡페이지는 다른 병원들에서 많이 했던거라 크게 어렵지 않을 걸로 예상되는데 그중에 마음에 걸리는거라면 다른 알림톡 서비스 업체와 연계해서 공동으로 API를 맞춰야 하는부분이 매끄럽기를 바라는 마음!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외래최적화 LBS는 비콘 연계 서비스로 네이티브에서 해당 서비스를 활성화 해서 병원을 이용하는동안 자동으로 위치에 맞게 푸시알림을 보내주는 서비스다. 해당 부분에서 네이티브 연동 및 푸시알림 종류에 따라 앱 내에 화면이동까지 지원을 해달라는 요청이 있어서 이것도 네이티브랑 웹뷰 모두 수정이 들어갈 예정. 아직 기능이 명확하게 나오지 않아서 대기중이지만 수정된 푸시알림 연동규격을 통해서 네이티브 브릿지로 웹뷰 알림팝업을 띄워주고 앱내 페이지 이동까지 기능구현이 가능한거는 확인완료 한 상태!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11월까지 LBS오픈과 알림톡을 마무리하고 10월에 새로 들어오신 경력직 팀원분에게 인수인계를 했다.&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;b&gt;- 새로운 팀원의 등장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10월 추석이 지나고 새로운 팀원이 들어왔다. 개발기간은 3-4년 정도인 중니어 개발자분이시고 이것저것 해보고 오셨다. 하지만 우리팀은 정말 &quot;이것저것 개발팀&quot;이기 때문에 적응하는데 조금 힘들어하셨다. 이전 회사는 깃도 커밋하려면 상사에게 컨펌받고 서버반영도 해주는분이 따로 있고 QA에 CS에 다 나눠져있는 회사였다하시는데,...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리회사는 모든걸 스스로 해야하기때문에... 게다가 개발서버도 없는 병원도 많구.. 처음적응엔 힘들어하셨지만 12월말인 지금은 꽤나 적응하셔서 반영도 문서보고 척척 해내고 있으시당. 다행쓰&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;- Goodbye 나의 PTSD&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심리상담을 받았다. 서울시 청년 마음지원사업에 선발돼서 상담 6회 지원이었는데, 상담과정중에 상담사분께서 필요한경우 10회까지 연장할 수 있는데 나의 경우 10회까지 연장하면 좋겠다고 해주셔서 총 10회기를 상담받게되었다.&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;상담중에 과거 학교다닐때 당했던 따돌림 상황이랑 전팀장이 가스라이팅 하는상황이 오버랩돼서 PTSD 재경험이 생긴것 같다고 하셨다. 학창시절때 이야기를 웃으면서 할 수 있어서 극복했다. 괜찮다. 라고 생각했는데 아무래도 어릴때 있었던 일은 커서도 꽤나 영향을 지속적으로 주는가보다. 무튼 상담덕분에 PTSD라는것도 인지하고 치료도 받고 다양한 상황에서 대처할 수 있는 방법들도 알게되었다. 담당해주신 상담사분은 인지치료 위주로 진행해주신 것 같았다. 상담받으면서 '음 그게 어떤이유에서 나당씨한테 중요한 부분일까요?'라는 질문이라던지 내 신체반응이나 그때의 상황탐색 그리고 메타인지를 할 수 있게 많이 도와주셨고 상담이 끝난 지금 엄청 많이 해소되어서 회사에서 내 역할에 대한 강박도 많이 줄어들어서 마음이 편해졌다. 우울이 너무 깊은상태라서 아무것도 안하고 싶고 해야하는데 의욕이 없어서 더 스트레스 받는 굴레에 갇혀있었는데 상담사분이 우울이 사라지면서 알아서 원래 기질대로 하고싶은 충동들이나 욕구들이 올라올거라 해주셨는데, 연말인 지금은 해보고 싶은것들이 조오금씩 생각나고 있어서 (회고도 갑자기 생각남 ㅎ) 내년이 기대되게됐다. 앞으로도 어린시절의 환경들이 영향을 줄테지만 그런 상황에서도 나를 지키기위해 꾸준히 숲을보고 메타인지를 하는 시간을 가지라고 조언해주셨다.&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;- 벌써 줄서고있는 2026업무와 회사이사&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;blob&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EASl1/dJMcafyqBm2/GQNe9pVgA2fkJqh4WtKNq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EASl1/dJMcafyqBm2/GQNe9pVgA2fkJqh4WtKNq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EASl1/dJMcafyqBm2/GQNe9pVgA2fkJqh4WtKNq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEASl1%2FdJMcafyqBm2%2FGQNe9pVgA2fkJqh4WtKNq0%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;435&quot; height=&quot;308&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;308&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현팀장님이랑 업무 정리중인데 벌써 2026년 업무가 그득그득 찼다는게 어이가 없&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;b&gt;- 조용히 올라가고 있는 OTT JUMP의 사용자&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;912&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r1vuJ/dJMcadggneC/M1ll2Xf4WhaJMeq0H1Rbqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r1vuJ/dJMcadggneC/M1ll2Xf4WhaJMeq0H1Rbqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r1vuJ/dJMcadggneC/M1ll2Xf4WhaJMeq0H1Rbqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr1vuJ%2FdJMcadggneC%2FM1ll2Xf4WhaJMeq0H1Rbqk%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;912&quot; height=&quot;243&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;243&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;오류문의 메일이 안오고 있어서.. 다들 잘 쓰고 있낭..? 싶기도하고.. 다행이기도하고.. 다들 편하게 썼으면 &amp;lt;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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힘들었던 가스라이팅의 3년 생활이 지나고 전팀장 퇴사와 기막힌 타이밍의 심리상담 덕분에 2026년은 좀더 밝은 분위기로 보낼거라는 기대가 생겨서.. 2026의 회고는 어떨지 궁금하다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p 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;b&gt;내년 회고는 좀더 새롭고 즐거운 이야기들이 많아서 스크롤이 왕창 생겼으면 좋겠다!&lt;/b&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;niniz&quot; data-emoticon-name=&quot;004&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/004.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/niniz/large/004.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>일상/일기장</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/373</guid>
      <comments>https://h-owo-ld.tistory.com/373#entry373comment</comments>
      <pubDate>Tue, 23 Dec 2025 21:06:07 +0900</pubDate>
    </item>
    <item>
      <title>[OTT JUMP] 크롬 웹 스토어 개발자 등록하기 &amp;amp; OTT JUMP 웹스토어 등록 완료!</title>
      <link>https://h-owo-ld.tistory.com/372</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;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;혼자 잘 쓰고 있었는데, 무니도 웨이브 자동 넘기기가 필요하대서 드디어 으쌰으쌰 하면서 크롬 웹스토어 개발자 등록을 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;추가하는김에 네이버멤버십중이라 넷플릭스도 호다닥!&amp;nbsp;&lt;/span&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;figure id=&quot;og_1755518321138&quot; style=&quot;color: #333333; text-align: start;&quot; contenteditable=&quot;false&quot; data-og-image=&quot;&quot; data-og-url=&quot;https://accounts.google.com/v3/signin/identifier?continue=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdevconsole%2Fregister%3Fhl%3Dko&amp;amp;followup=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdevconsole%2Fregister%3Fhl%3Dko&amp;amp;hl=ko&amp;amp;ifkv=AdBytiPYDVS3osyBly967GB0uxlFBc5AgK6tjyRJS4EDXZQe0u-z1wfmuJ0q83GmaD63gN0ZpOA8&amp;amp;passive=1209600&amp;amp;service=chromewebstore&amp;amp;flowName=WebLiteSignIn&amp;amp;flowEntry=ServiceLogin&amp;amp;dsh=S822248425%3A1755517060023929&quot; data-og-source-url=&quot;https://chrome.google.com/webstore/devconsole/register?hl=ko&quot; data-og-host=&quot;accounts.google.com&quot; data-og-description=&quot;로그인 Chrome 웹 스토어로 이동&quot; data-og-title=&quot;Chrome Web Store&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://chrome.google.com/webstore/devconsole/register?hl=ko&quot; data-source-url=&quot;https://chrome.google.com/webstore/devconsole/register?hl=ko&quot;&gt;&lt;br /&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Chrome Web Store&lt;/p&gt;
&lt;p style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;로그인 Chrome 웹 스토어로 이동&lt;/p&gt;
&lt;p style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;accounts.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1071&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tZ4zY/btsPUIQADCy/2WkHvZH6YZkjLBM86wZkzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tZ4zY/btsPUIQADCy/2WkHvZH6YZkjLBM86wZkzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tZ4zY/btsPUIQADCy/2WkHvZH6YZkjLBM86wZkzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtZ4zY%2FbtsPUIQADCy%2F2WkHvZH6YZkjLBM86wZkzk%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;1071&quot; height=&quot;580&quot; data-origin-width=&quot;1071&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&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;카드를 등록하고 돈을 낸다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;등록비용은 $5&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 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;&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;&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;&amp;nbsp;&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/HVIZh/btsPUX010xh/vSXKnTP3ZEiPVrorbSQ7Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HVIZh/btsPUX010xh/vSXKnTP3ZEiPVrorbSQ7Xk/img.png&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;746&quot; data-is-animation=&quot;false&quot; data-filename=&quot;blob&quot; style=&quot;width: 50.4436%; margin-right: 10px;&quot; data-widthpercent=&quot;51.04&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HVIZh/btsPUX010xh/vSXKnTP3ZEiPVrorbSQ7Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHVIZh%2FbtsPUX010xh%2FvSXKnTP3ZEiPVrorbSQ7Xk%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;1215&quot; height=&quot;746&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PmOhS/btsPTP93Vs2/dhKSbN7L7g9mYvKrBokqlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PmOhS/btsPTP93Vs2/dhKSbN7L7g9mYvKrBokqlK/img.png&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;784&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.3936%;&quot; data-widthpercent=&quot;48.96&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PmOhS/btsPTP93Vs2/dhKSbN7L7g9mYvKrBokqlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPmOhS%2FbtsPTP93Vs2%2FdhKSbN7L7g9mYvKrBokqlK%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;1225&quot; height=&quot;784&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;돈내고 들어온 첫화면!&lt;/p&gt;
&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caUDwW/btsPWii0Yp4/jY0KHRcpOKesYPWjPlbzz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caUDwW/btsPWii0Yp4/jY0KHRcpOKesYPWjPlbzz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caUDwW/btsPWii0Yp4/jY0KHRcpOKesYPWjPlbzz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaUDwW%2FbtsPWii0Yp4%2FjY0KHRcpOKesYPWjPlbzz0%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;536&quot; height=&quot;387&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;manifest.json에 경로를 ./을 넣었더니 저렇게 오류가 떴다. 경로에 ./ 를 지울것!&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1227&quot; data-origin-height=&quot;1273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mQiBA/btsPURsKzUx/8ckKUw99KyZ3G559FQxhLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mQiBA/btsPURsKzUx/8ckKUw99KyZ3G559FQxhLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mQiBA/btsPURsKzUx/8ckKUw99KyZ3G559FQxhLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmQiBA%2FbtsPURsKzUx%2F8ckKUw99KyZ3G559FQxhLk%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;1227&quot; height=&quot;1273&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1227&quot; data-origin-height=&quot;1273&quot;/&gt;&lt;/span&gt;&lt;/figure&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;설명을 입력하고 쭉쭉쭉 스토어 리스팅 부분을 적은후에 '초안 저장' 을 눌러준다.&lt;/p&gt;
&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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;701&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3SoQG/btsPUdXbNQl/z9eUlpgoKV9uW65sh1w711/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3SoQG/btsPUdXbNQl/z9eUlpgoKV9uW65sh1w711/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3SoQG/btsPUdXbNQl/z9eUlpgoKV9uW65sh1w711/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3SoQG%2FbtsPUdXbNQl%2Fz9eUlpgoKV9uW65sh1w711%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;915&quot; height=&quot;701&quot; data-origin-width=&quot;915&quot; data-origin-height=&quot;701&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdu1qH/btsPWYkl8ob/tJtjCPWx55tptifzKkg35K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdu1qH/btsPWYkl8ob/tJtjCPWx55tptifzKkg35K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdu1qH/btsPWYkl8ob/tJtjCPWx55tptifzKkg35K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdu1qH%2FbtsPWYkl8ob%2FtJtjCPWx55tptifzKkg35K%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;1179&quot; height=&quot;614&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&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;다 적어주면 제출 할 수 있는 버튼이 활성화된다.&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&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/9i3P7/btsPVlmPULG/A6jNtCdavjSX80A413Qytk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9i3P7/btsPVlmPULG/A6jNtCdavjSX80A413Qytk/img.png&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;513&quot; data-is-animation=&quot;false&quot; style=&quot;width: 36.8191%; margin-right: 10px;&quot; data-widthpercent=&quot;37.25&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9i3P7/btsPVlmPULG/A6jNtCdavjSX80A413Qytk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9i3P7%2FbtsPVlmPULG%2FA6jNtCdavjSX80A413Qytk%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;719&quot; height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpJuIx/btsPXXSt3L5/WvwFuqcxvhLMNWlj3qsADk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpJuIx/btsPXXSt3L5/WvwFuqcxvhLMNWlj3qsADk/img.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;255&quot; data-is-animation=&quot;false&quot; style=&quot;width: 62.0181%;&quot; data-widthpercent=&quot;62.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpJuIx/btsPXXSt3L5/WvwFuqcxvhLMNWlj3qsADk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpJuIx%2FbtsPXXSt3L5%2FWvwFuqcxvhLMNWlj3qsADk%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;602&quot; height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;앱배포때도 항상 자동배포를 안하고 있으므로&lt;/p&gt;
&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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;183&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d580AJ/btsPViQ5Ieu/bjEfKSkftH97yREmMlEZ5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d580AJ/btsPViQ5Ieu/bjEfKSkftH97yREmMlEZ5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d580AJ/btsPViQ5Ieu/bjEfKSkftH97yREmMlEZ5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd580AJ%2FbtsPViQ5Ieu%2FbjEfKSkftH97yREmMlEZ5K%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;938&quot; height=&quot;183&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;183&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;검토 대기 중 (25.08.18)&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;893&quot; data-origin-height=&quot;621&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBRgOP/btsQc30AGpy/vcyfPkHyH9UeNMe10eJuGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBRgOP/btsQc30AGpy/vcyfPkHyH9UeNMe10eJuGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBRgOP/btsQc30AGpy/vcyfPkHyH9UeNMe10eJuGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBRgOP%2FbtsQc30AGpy%2FvcyfPkHyH9UeNMe10eJuGK%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;893&quot; height=&quot;621&quot; data-origin-width=&quot;893&quot; data-origin-height=&quot;621&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;25.08.30&lt;/p&gt;
&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u7rYe/btsQdmFGW48/jJAWezK8R8bQwKQlevOM8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u7rYe/btsQdmFGW48/jJAWezK8R8bQwKQlevOM8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u7rYe/btsQdmFGW48/jJAWezK8R8bQwKQlevOM8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu7rYe%2FbtsQdmFGW48%2FjJAWezK8R8bQwKQlevOM8k%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;448&quot; height=&quot;223&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;814&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQvQ1Y/btsQfAWYaLo/3EvRnAXfKkWoVVuZn9y0f1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQvQ1Y/btsQfAWYaLo/3EvRnAXfKkWoVVuZn9y0f1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQvQ1Y/btsQfAWYaLo/3EvRnAXfKkWoVVuZn9y0f1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQvQ1Y%2FbtsQfAWYaLo%2F3EvRnAXfKkWoVVuZn9y0f1%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;1240&quot; height=&quot;814&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;814&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;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1756553469366&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;OTT JUMP - Chrome 웹 스토어&quot; data-og-description=&quot;OTT 오프닝 건너뛰기랑 다음회차를 자동으로 재생해주는 크롬 확장 프로그램이에요! 현재는 웨이브와 티빙, 그리고 넷플릭스가 가능합니다.&quot; data-og-host=&quot;chromewebstore.google.com&quot; data-og-source-url=&quot;https://chromewebstore.google.com/detail/ott-jump/bfinfconkbehonefppgjgimmeichocig?authuser=0&amp;amp;hl=ko&quot; data-og-url=&quot;https://chromewebstore.google.com/detail/ott-jump/bfinfconkbehonefppgjgimmeichocig&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/epMG7A/hyZGkDEOUm/xMzBHWA5hkINUhrbCvSkr0/img.jpg?width=128&amp;amp;height=128&amp;amp;face=0_0_128_128&quot;&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/ott-jump/bfinfconkbehonefppgjgimmeichocig?authuser=0&amp;amp;hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://chromewebstore.google.com/detail/ott-jump/bfinfconkbehonefppgjgimmeichocig?authuser=0&amp;amp;hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/epMG7A/hyZGkDEOUm/xMzBHWA5hkINUhrbCvSkr0/img.jpg?width=128&amp;amp;height=128&amp;amp;face=0_0_128_128');&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;OTT JUMP - Chrome 웹 스토어&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;OTT 오프닝 건너뛰기랑 다음회차를 자동으로 재생해주는 크롬 확장 프로그램이에요! 현재는 웨이브와 티빙, 그리고 넷플릭스가 가능합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;chromewebstore.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Inafolio</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/372</guid>
      <comments>https://h-owo-ld.tistory.com/372#entry372comment</comments>
      <pubDate>Sat, 30 Aug 2025 18:28:25 +0900</pubDate>
    </item>
    <item>
      <title>[React&amp;amp;iOS] 웹-네이티브 브리지를 활용한 PG 결제 연동 구조 설계기 - iOS 편</title>
      <link>https://h-owo-ld.tistory.com/371</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;문제의 시작&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QSaXn/btsON4ZZSVR/L7lidnGu2gXxta3LT63gok/tfile.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QSaXn/btsON4ZZSVR/L7lidnGu2gXxta3LT63gok/tfile.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QSaXn/btsON4ZZSVR/L7lidnGu2gXxta3LT63gok/tfile.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/QSaXn/btsON4ZZSVR/L7lidnGu2gXxta3LT63gok/tfile.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;426&quot; height=&quot;640&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;현재 회사에서 안드로이드 앱들은 MainActivity에서 WebView를 활용해 웹 화면을 네이티브 앱 내에 띄워서 표시하고 있다. 이전까지는 대부분 외부 연동이 없는 조회 형태라서 특별한 문제가 없었다. 하지만 이번에 결제기능이 추가되면서.. 문제가생겼다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;결제 수단을 선택하고 그대로 프로세스를 진행하지않고 뒤로가기버튼을 선택한 경우, 앱내 웹뷰로 다시 돌아오지 않았다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&amp;nbsp;&lt;/span&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/H2zjT/btsPF6IUAkX/9EimCDkfX2lsK6Iq6HLWZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H2zjT/btsPF6IUAkX/9EimCDkfX2lsK6Iq6HLWZ1/img.png&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;824&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.591%; margin-right: 10px;&quot; data-widthpercent=&quot;56.25&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H2zjT/btsPF6IUAkX/9EimCDkfX2lsK6Iq6HLWZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH2zjT%2FbtsPF6IUAkX%2F9EimCDkfX2lsK6Iq6HLWZ1%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;730&quot; height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TgzI3/btsPEqaJOlN/wULdwD7BzQMyoJU6NPpbFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TgzI3/btsPEqaJOlN/wULdwD7BzQMyoJU6NPpbFK/img.png&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;1332&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.2462%;&quot; data-widthpercent=&quot;43.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TgzI3/btsPEqaJOlN/wULdwD7BzQMyoJU6NPpbFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTgzI3%2FbtsPEqaJOlN%2FwULdwD7BzQMyoJU6NPpbFK%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;918&quot; height=&quot;1332&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;사담을 좀 하자면.. 최근 회사 상황이 꽤나 정신없다. 기존 팀장님께서 퇴사를 선언하신 뒤 사실상 칩거 상태에 들어가셨고(ㅠ) 이후 월초에 새로 채용된 팀장님도 하루 만에 퇴사를 결정하면서 팀장 자리는 공석이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;현재 팀 구성은 총 4명으로 나, 입사 동기, 2년 차 백엔드 개발자, 신입 프론트엔드 개발자 이렇게만 남아 있는 상황이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;그렇기에 팀장님이 없는 상태에서 의사결정이나 기술 논의가 쉽지 않았다. 특히 문제 해결 과정에서 누군가에게 조언을 받기는 어려운 상황에서 입사 동기와 이야기하던 중 두 가지 해결 방향이 나왔지만 각각 단점이 있어 쉽게 결정할 수 없었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;그러다 문득 평소 자주보는 오픈카톡방이 떠올랐고 고민 끝에 두 군데에 상황을 올려보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;그 중 한 방에서 비슷한 이슈를 겪고 해결한 분의 조언을 받을 수 있었고, 정말 큰 도움이 되었다. (갓...ㅠㅠ)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;조언을 바탕으로 적용한 해결책은 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;개선방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Android 개선방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;안드로이드에서는 MainWebView 외 결제 수단용으로 별도의 자식 WebView(PGWebViewActivity)를 하나 더 만들어 결제요청 시 자식 WebView를 띄우고 뒤로가기 버튼을 누르면 해당 WebView를 닫아 다시 부모 WebView로 돌아올 수 있도록 구성했다. 이 방식으로 팝업 결제 페이지의 흐름을 안정적으로 처리할 수 있었다. 또한 뒤로가기 뿐 아니라 승인까지 진행하는 프로세스 결과도 MainActivity에서 전달받을 수 있는 구조로 개선했다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754040955212&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;[React&amp;amp;Kotlin] 웹-네이티브 브리지를 활용한 PG 결제 연동 구조 설계기 - 안드로이드 편&quot; data-og-description=&quot;문제의 시작 현재 회사에서 안드로이드 앱들은 MainActivity에서 WebView를 활용해 React로 개발된 웹 화면을 네이티브 앱 내에 띄워서 표시하고 있다. 이전까지는 대부분 외부업체와의 연동이 없고 병&quot; data-og-host=&quot;h-owo-ld.tistory.com&quot; data-og-source-url=&quot;https://h-owo-ld.tistory.com/370&quot; data-og-url=&quot;https://h-owo-ld.tistory.com/370&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhhRby/hyZqYPAcEU/Wn30bxAMVk74Dk8Z1PrpbK/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/FJsIa/hyZqQqssmU/o1qswQRQ40YW2Cz5v3jDVk/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/TkVfh/hyZuzHlSCB/4YCmftOptsAF10VZPF2TK1/img.png?width=918&amp;amp;height=1332&amp;amp;face=0_0_918_1332&quot;&gt;&lt;a href=&quot;https://h-owo-ld.tistory.com/370&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://h-owo-ld.tistory.com/370&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhhRby/hyZqYPAcEU/Wn30bxAMVk74Dk8Z1PrpbK/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/FJsIa/hyZqQqssmU/o1qswQRQ40YW2Cz5v3jDVk/img.gif?width=426&amp;amp;height=640&amp;amp;face=0_0_426_640,https://scrap.kakaocdn.net/dn/TkVfh/hyZuzHlSCB/4YCmftOptsAF10VZPF2TK1/img.png?width=918&amp;amp;height=1332&amp;amp;face=0_0_918_1332');&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;[React&amp;amp;Kotlin] 웹-네이티브 브리지를 활용한 PG 결제 연동 구조 설계기 - 안드로이드 편&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;문제의 시작 현재 회사에서 안드로이드 앱들은 MainActivity에서 WebView를 활용해 React로 개발된 웹 화면을 네이티브 앱 내에 띄워서 표시하고 있다. 이전까지는 대부분 외부업체와의 연동이 없고 병&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;h-owo-ld.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;iOS 개선방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;iOS 역시 비슷한 방식으로 자식 WebView를 사용하는 구조이지만 기기 특성상 하드웨어 뒤로가기 버튼이 없기 때문에 상단에 커스텀 뒤로가기 버튼을 별도로 추가해주는 작업을 덧붙였다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;모바일의 갓 핑관님 덕분에 꽤나 복잡했던 결제 플로우 문제를 안정적으로 처리할 수 있었고 무엇보다도 커뮤니티의 힘이 얼마나 큰지를 다시 한 번 느낄 수 있었다.  &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;iOS 개선방법 상세 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;/// ViewController

...
class ViewController: UIViewController,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CLLocationManagerDelegate,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CBCentralManagerDelegate,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WKNavigationDelegate,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WKScriptMessageHandler,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;WKUIDelegate,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PGWebViewControllerDelegate {&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
...
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 결제 시 결제전용 웹뷰를 열도록 하는 브릿지 함수
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case &quot;openPGWebView&quot;:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Logger.log(self, &quot;openPgWebView&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print(&quot;[PRINT DEBUG] openPgWebView message.body: \(String(describing: message.body))&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// JS Bridge로부터 받은 message.body가 String(결제 URL)인지 확인, URL 타입으로 변환 시도
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;guard let link = message.body as? String, let url = URL(string: link) else {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Logger.log(self, &quot;PGWebView: 잘못된 URL \(String(describing: message.body))&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// JS Bridge로부터 받은 message.body가 String(결제 URL)인지 확인, URL 타입으로 변환 시도
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let storyboard = UIStoryboard(name: &quot;Main&quot;, bundle: nil)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if let pgVC = storyboard.instantiateViewController(withIdentifier: &quot;PGWebViewController&quot;) as? PGWebViewController {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 결제 URL 및 delegate(콜백 받을 부모 컨트롤러) 주입
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pgVC.pgUrl = url // 원하는 결제 URL 전달
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pgVC.delegate = self
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 결제창을 UINavigationController로 감싸서 present (상단에 네비게이션바, 뒤로가기 가능)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let nav = UINavigationController(rootViewController: pgVC)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;nav.modalPresentationStyle = .fullScreen // 전체화면 모달로 띄움(iOS 기본은 half-modal이니 꼭 명시)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;present(nav, animated: true)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 결제승인 URL 콜백
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func pgWebViewControllerDidFinish(url:URL){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Logger.log(self, &quot;[PGWebView] 승인 URL 반환:&quot;, url)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 바로 부모 WKWebView에서 페이지 이동!
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;webView.load(URLRequest(url: url))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2978&quot; data-origin-height=&quot;1412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pjNpJ/btsPEMSae6H/r8XMM1KEcakNhPMDufZhJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pjNpJ/btsPEMSae6H/r8XMM1KEcakNhPMDufZhJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pjNpJ/btsPEMSae6H/r8XMM1KEcakNhPMDufZhJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpjNpJ%2FbtsPEMSae6H%2Fr8XMM1KEcakNhPMDufZhJ0%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;2978&quot; height=&quot;1412&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2978&quot; data-origin-height=&quot;1412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;리액트에서 openPGWebView 라는 브릿지메시지를 보내면 해당 메시지 내의 url을 PGWebViewController로 보내준다. 이때 iOS의 경우는 뒤로가기 버튼이 따로없기때문에 별도로 상단에 navigation바에 뒤로가기 버튼을 추가해줬고, iOS에서는 모달이 기본적으로 half로 띄워지기 때문에 명시적으로 풀스크린을 지정해서 전체화면으로 띄우도록 했다.&lt;/span&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;span style=&quot;color: #009a87;&quot;&gt;이후 결제가 성공적으로 완료되면 결제승인 콜백을 통해 부모컨트롤러인 해당 컨트롤러로 승인 URL이 다시 전달된다. 전달받은 URL은 기존의 메인웹뷰에서 다시 로딩되어 웹페이지 흐름이 이어지게 된다.&lt;/span&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;&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;// PGWebViewController
...

/// 결제 전용 WebView의 결과를 콜백받기 위한 프로토콜
protocol PGWebViewControllerDelegate: AnyObject {
    /// 결제 성공 또는 승인 URL이 감지된 경우 호출됨
    func pgWebViewControllerDidFinish(url: URL)
    /// 사용자가 [&amp;lt;-] 뒤로가기/닫기 버튼을 눌러 결제창을 닫은 경우 호출됨
    func pgWebViewControllerDidCancel()
}

/// PG(결제) 전용 웹뷰 컨트롤러
class PGWebViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {
    /// 결제 URL (외부에서 반드시 할당해야 함)
    var pgUrl: URL!
    weak var delegate: PGWebViewControllerDelegate?
    private var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        print(&quot;[PGWebView] viewDidLoad - pgUrl:&quot;, pgUrl ?? &quot;nil&quot;)
        
        // WebView 환경설정: JS, 여러창 등 활성화
        let config = WKWebViewConfiguration()
        config.preferences.javaScriptEnabled = true
        config.preferences.javaScriptCanOpenWindowsAutomatically = true
        
        // WebView 인스턴스 생성 및 설정
        webView = WKWebView(frame: self.view.bounds, configuration: config)
        webView.navigationDelegate = self
        webView.uiDelegate = self
        webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        self.view.addSubview(webView)

        // 결제 URL 로드
        if let url = pgUrl {
            print(&quot;[PGWebView] loading URL:&quot;, url)
            webView.load(URLRequest(url: url))
        } else {
            print(&quot;[PGWebView] pgUrl is nil, cannot load webview&quot;)
        }

        print(&quot;[PGWebView] NavigationController?&quot;, navigationController != nil)
        print(&quot;[PGWebView] parent:&quot;, parent ?? &quot;nil&quot;)
    }
    
    /// 상단 네비게이션 바의 [&amp;lt;-] 버튼 (Left bar button items)
    @IBAction func didTapBack(_ sender: Any) {
        delegate?.pgWebViewControllerDidCancel()
        dismiss(animated: true)
    }

    /// 네비게이션 이벤트 감지(결제 승인/에러/카드앱 딥링크 등 처리)
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -&amp;gt; Void) {
        guard let url = navigationAction.request.url else {
            print(&quot;[PGWebView] navigationAction: url is nil&quot;)
            decisionHandler(.allow)
            return
        }
        print(&quot;[PGWebView] navigating to:&quot;, url)

        // 결제 승인/에러 리턴 URL 감지
        if url.absoluteString.contains(&quot;/approval&quot;) {
            print(&quot;[PGWebView] approval detected, dismissing&quot;)
            delegate?.pgWebViewControllerDidFinish(url: url)
            self.dismiss(animated: true)
            decisionHandler(.cancel)
            return
        }

        // 카드/간편결제/은행 앱 등 외부앱 연동 스킴 감지시, 시스템으로 오픈
        if let scheme = url.scheme, paymentSchemes.contains(scheme) {
            print(&quot;[PGWebView] open external scheme:&quot;, scheme)
            UIApplication.shared.open(url)
            decisionHandler(.cancel)
            return
        }

        // 그 외는 웹뷰 기본동작
        decisionHandler(.allow)
    }
    ...
    
}

...&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;&lt;span style=&quot;color: #009a87;&quot;&gt;리액트에서 요청하면 메인을 거쳐 열리는 결제 웹뷰 페이지 컨트롤러다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;해당 컨트롤러에서는 외부로부터 전달받은 결제 URL을 로딩하고 결제 흐름중 발생하는 승인 완료나 간편결제 같은 외부 앱 호출 같은 이벤트를 감지해서 처리하게 된다.&amp;nbsp;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;리액트에서 사용한 브릿지코드&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1754041382003&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 모바일 네이티브의 `openPGWebView` 메서드 호출.
 *
 * @method openPGWebView
 * @param {String} link pg호출을 위해 별도의 웹뷰를 띄우는 URL.
 */
const openPGWebView = (link) =&amp;gt; {
  if (mobile.isMobile) {
    if (mobile.isAndroid) {
      if (window?.androidWebBridge?.openPGWebView) {
        window.androidWebBridge.openPGWebView(link)
      } else {
        window.open(link)
      }
    } else if (mobile.isIOS) {
      if (window?.webkit?.messageHandlers?.openPGWebView) {
        window.webkit.messageHandlers.openPGWebView.postMessage(link)
      } else {
        window.open(link)
      }
    }
  } else {
    window.open(link)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;결과&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qGfht/btsONAESRX7/SuCPXjHlrHF99jdROFqecK/tfile.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qGfht/btsONAESRX7/SuCPXjHlrHF99jdROFqecK/tfile.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qGfht/btsONAESRX7/SuCPXjHlrHF99jdROFqecK/tfile.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/qGfht/btsONAESRX7/SuCPXjHlrHF99jdROFqecK/tfile.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;426&quot; height=&quot;640&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;이제 뒤로가기 버튼을 눌러도 다시 원래 페이지로 복귀가 자연스럽게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;결제 시나리오 완료후에도 메인 뷰로 승인결과를 URL에 담아서 가져오게되었다.&lt;/span&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;figure style=&quot;color: #333333; text-align: center;&quot; contenteditable=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/012.gif&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-name=&quot;012&quot; data-emoticon-type=&quot;friends1&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;emoticon&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/012.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;동기랑 다음에는 앱개발 하게되면 RN를 진지하게 고려해보자는 이야기를 했다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Error note</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/371</guid>
      <comments>https://h-owo-ld.tistory.com/371#entry371comment</comments>
      <pubDate>Fri, 1 Aug 2025 18:54:20 +0900</pubDate>
    </item>
    <item>
      <title>[React&amp;amp;Kotlin] 웹-네이티브 브리지를 활용한 PG 결제 연동 구조 설계기 - 안드로이드 편</title>
      <link>https://h-owo-ld.tistory.com/370</link>
      <description>&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;426&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cacNgT/btsON9UbGk6/XXK172OSAQzbKnsfYkHrEk/tfile.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cacNgT/btsON9UbGk6/XXK172OSAQzbKnsfYkHrEk/tfile.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cacNgT/btsON9UbGk6/XXK172OSAQzbKnsfYkHrEk/tfile.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cacNgT/btsON9UbGk6/XXK172OSAQzbKnsfYkHrEk/tfile.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;426&quot; height=&quot;640&quot; data-origin-width=&quot;426&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 회사에서 안드로이드 앱들은 MainActivity에서 WebView를 활용해 React로 개발된 웹 화면을 네이티브 앱 내에 띄워서 표시하고 있다. 이전까지는 대부분 외부업체와의 연동이 없고 병원 전산팀과 연동하는 형태라서 특별한 문제가 없었다. 하지만 이번에 결제기능이 추가되면서.. 문제가생겼다.&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;결제 수단을 선택하고 그대로 프로세스를 진행하지않고 뒤로가기버튼을 선택한 경우, 앱내 웹뷰로 다시 돌아오지 않았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;pre id=&quot;code_1750658360764&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    override fun onBackPressed() {
        Logger.debug()

        webView.evaluateJavascript(&quot;historyBack();&quot;) {
            if (it?.toString() == &quot;1&quot;) {
                super.onBackPressed()
            }
        }
    }&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;뒤로가기&amp;nbsp;버튼을&amp;nbsp;눌렀을&amp;nbsp;때&amp;nbsp;WebView에서는&amp;nbsp;historyBack()&amp;nbsp;자바스크립트&amp;nbsp;함수를&amp;nbsp;실행하고&amp;nbsp;그&amp;nbsp;리턴값에&amp;nbsp;따라&amp;nbsp;동작을&amp;nbsp;분기하도록&amp;nbsp;구성되어&amp;nbsp;있다.&amp;nbsp;하지만&amp;nbsp;수납&amp;nbsp;페이지처럼&amp;nbsp;외부에서&amp;nbsp;호출된&amp;nbsp;URL의&amp;nbsp;경우&amp;nbsp;해당&amp;nbsp;함수(historyBack)가&amp;nbsp;정의되어&amp;nbsp;있지&amp;nbsp;않기&amp;nbsp;때문에&amp;nbsp;함수&amp;nbsp;실행&amp;nbsp;시&amp;nbsp;웹&amp;nbsp;디버깅&amp;nbsp;콘솔에&amp;nbsp;&quot;함수가&amp;nbsp;존재하지&amp;nbsp;않는다&quot;는&amp;nbsp;오류가&amp;nbsp;출력되며&amp;nbsp;뒤로가기가&amp;nbsp;정상적으로&amp;nbsp;동작하지&amp;nbsp;않는&amp;nbsp;문제가&amp;nbsp;발생하게&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;&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;&amp;nbsp;&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/bhxHPa/btsON7PONGw/dO3muIz9YPUm0V5NlkrhbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhxHPa/btsON7PONGw/dO3muIz9YPUm0V5NlkrhbK/img.png&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;824&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.591%; margin-right: 10px;&quot; data-widthpercent=&quot;56.25&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhxHPa/btsON7PONGw/dO3muIz9YPUm0V5NlkrhbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhxHPa%2FbtsON7PONGw%2FdO3muIz9YPUm0V5NlkrhbK%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;730&quot; height=&quot;824&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci4sBE/btsOLEhvSFI/QNGQdhNP45fTXgdgKlRUSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci4sBE/btsOLEhvSFI/QNGQdhNP45fTXgdgKlRUSK/img.png&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;1332&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.2462%;&quot; data-widthpercent=&quot;43.75&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci4sBE/btsOLEhvSFI/QNGQdhNP45fTXgdgKlRUSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci4sBE%2FbtsOLEhvSFI%2FQNGQdhNP45fTXgdgKlRUSK%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;918&quot; height=&quot;1332&quot;/&gt;&lt;/span&gt;&lt;/div&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 팀 구성은 총 4명으로 나, 입사 동기, 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;그러다 문득 평소 자주보는 오픈카톡방이 떠올랐고 고민 끝에 두 군데에 상황을 올려보았다.&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개선방법&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Android 개선방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드에서는 MainWebView 외 결제 수단용으로 별도의 자식 WebView(PGWebViewActivity)를 하나 더 만들어 결제요청 시 자식 WebView를 띄우고 뒤로가기 버튼을 누르면 해당 WebView를 닫아 다시 부모 WebView로 돌아올 수 있도록 구성했다. 이 방식으로 팝업 결제 페이지의 흐름을 안정적으로 처리할 수 있었다. 또한 뒤로가기 뿐 아니라 승인까지 진행하는 프로세스 결과도 MainActivity에서 전달받을 수 있는 구조로 개선했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;iOS 개선방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iOS 역시 비슷한 방식으로 자식 WebView를 사용하는 구조이지만 기기 특성상 하드웨어 뒤로가기 버튼이 없기 때문에 상단에 커스텀 뒤로가기 버튼을 별도로 추가해주는 작업을 덧붙였다. (iOS 관련 내용은 따로 포스팅할 예정)&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;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;안드로이드 개선방법 상세 코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1750659835664&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// MainActivity.kt
... 
class MainActivity : AppCompatActivity()  {
     private val pgLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -&amp;gt;
        if (result.resultCode == Activity.RESULT_OK) {
            val approvalUrl = result.data?.getStringExtra(&quot;approval_url&quot;)
            Logger.debug(&quot;PG 승인 URL 받음: $approvalUrl&quot;)
            if (!approvalUrl.isNullOrEmpty()) {
                webView.loadUrl(approvalUrl)
            }
        }
    }
...
    inner class WebBridgeClass {
   		@JavascriptInterface
        fun openPGWebView(url:String){
            Logger.debug(&quot; openPGWebView: $url&quot;)
            val intent = Intent(this@MainActivity, PGWebViewActivity::class.java)
            intent.putExtra(&quot;pg_url&quot;,url)
            Logger.debug(&quot; PGWebViewActivity onCreate() called!!!&quot;)

            (this@MainActivity as MainActivity).pgLauncher.launch(intent)
        }
...&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;아래의&amp;nbsp;WebBridgeClass&amp;nbsp;안의&amp;nbsp;openPGWebView함수를&amp;nbsp;통해&amp;nbsp;웹에서&amp;nbsp;PG&amp;nbsp;결제&amp;nbsp;URL을&amp;nbsp;넘기면&amp;nbsp;안드로이드에서&amp;nbsp;해당&amp;nbsp;URL을&amp;nbsp;Intent로&amp;nbsp;감싸서&amp;nbsp;PGWebViewActivity로&amp;nbsp;이동하도록&amp;nbsp;구현하는&amp;nbsp;웹-네이티브&amp;nbsp;연동&amp;nbsp;브리지를&amp;nbsp;추가해줬다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결제는&amp;nbsp;외부&amp;nbsp;PG사&amp;nbsp;페이지로&amp;nbsp;이동하게&amp;nbsp;되므로&amp;nbsp;이후&amp;nbsp;결제가&amp;nbsp;끝나면&amp;nbsp;PGWebViewActivity에서&amp;nbsp;MainActivity에&amp;nbsp;선언된&amp;nbsp;ActivityResultLauncher를&amp;nbsp;통해&amp;nbsp;결제&amp;nbsp;결과를&amp;nbsp;받아오는&amp;nbsp;구조를&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;&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1750659605378&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// PGWebViewActivity.kt
...

class PGWebViewActivity : AppCompatActivity() {
    private lateinit var webView: WebView

    @SuppressLint(&quot;SetJavaScriptEnabled&quot;, &quot;MissingInflatedId&quot;)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_pgwebview)

        // (1) Lollipop 이하 호환용 - 쿠키 동기화 매니저 초기화
        @Suppress(&quot;DEPRECATION&quot;)
        CookieSyncManager.createInstance(this)

        // (2) Safe Area 대응 (상단/하단 시스템 영역 패딩 적용)
        val webviewContainer = findViewById&amp;lt;FrameLayout&amp;gt;(R.id.webviewContainer2)
        ViewCompat.setOnApplyWindowInsetsListener(webviewContainer) { v, insets -&amp;gt;
            val sysInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(0, sysInsets.top, 0, sysInsets.bottom)
            insets
        }

        // (3) Android 11(R) 이상에서 전체화면 표시 설정
        if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.R) {
            window.setDecorFitsSystemWindows(false)
        }

        // (4) 상태바 배경색/아이콘 색상 설정 (화이트 배경 + 다크 아이콘)
        if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.M) {
            window.statusBarColor = Color.WHITE
            window.decorView.systemUiVisibility =
                window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
        }

        // (5) PG 결제 페이지 URL 인텐트로 전달받기
        val pgUrl = intent.getStringExtra(&quot;pg_url&quot;)
        Logger.debug(&quot; pgUrl: $pgUrl&quot;)

        // (6) WebView 초기 설정
        webView = findViewById(R.id.pgWebView)
        webView.settings.javaScriptEnabled = true // 자바스크립트 허용
        webView.settings.setSupportMultipleWindows(true) // 다중창 지원
        webView.settings.javaScriptCanOpenWindowsAutomatically = true // JS에서 window.open 허용
        webView.settings.domStorageEnabled = true // localStorage 등 DOM 스토리지 허용

        // (7) Third-party 쿠키 허용 (PG 결제 시 필수)
        if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.LOLLIPOP) {
            CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true)
        }

        // (8) WebViewClient 설정 - URL 제어 및 외부앱/마켓 호출 처리
        webView.webViewClient = object : WebViewClient() {

            @Deprecated(&quot;Deprecated in Java&quot;)
            @Suppress(&quot;DEPRECATION&quot;)
            override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
                val url = request?.url.toString()
                Logger.debug(&quot; [shouldOverrideUrlLoading] url=$url&quot;)

                // (8-1) 결제 승인 URL 처리
                if (url.contains(&quot;/approval&quot;)) {
                    val resultIntent = Intent()
                    resultIntent.putExtra(&quot;approval_url&quot;, url)
                    setResult(RESULT_OK, resultIntent)
                    finish()
                    return true
                }

                // (8-2) 전화 연결 처리
                if (url.startsWith(&quot;tel:&quot;)) {
                    startActivity(Intent(Intent.ACTION_DIAL, url.toUri()))
                    return true
                }

                // (8-3) 외부 앱 호출/마켓 이동 처리
                if (!URLUtil.isNetworkUrl(url) &amp;amp;&amp;amp; !URLUtil.isJavaScriptUrl(url)) {
                    try {
                        val uri = Uri.parse(url)
                        if (uri.scheme == &quot;intent&quot;) {
                            return startSchemeIntent(url)
                        } else {
                            startActivity(Intent(Intent.ACTION_VIEW, uri))
                            return true
                        }
                    } catch (e: Exception) {
                        return false
                    }
                }

                // (8-4) 기본 WebView 처리
                return false
            }

            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                super.onPageStarted(view, url, favicon)
                Logger.debug(&quot; onPageStarted: $url&quot;)
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                Logger.debug(&quot; onPageFinished: $url&quot;)
            }
        }

        // (9) 팝업 등 지원을 위한 WebChromeClient 등록
        webView.webChromeClient = WebChromeClient()

        // (10) PG 결제 페이지 로딩 시작
        if (!pgUrl.isNullOrEmpty()) {
            webView.loadUrl(pgUrl)
        }
    }

    // (11) intent:// 스킴 처리 메서드 (앱 호출 or 마켓 fallback)
    private fun startSchemeIntent(url: String): Boolean {
        return try {
            val schemeIntent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME)
            try {
                startActivity(schemeIntent)
                true
            } catch (e: ActivityNotFoundException) {
                val packageName = schemeIntent.`package`
                if (!packageName.isNullOrEmpty()) {
                    startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(&quot;market://details?id=$packageName&quot;)))
                    true
                } else {
                    false
                }
            }
        } catch (e: URISyntaxException) {
            false
        }
    }

...

    // (14) 백버튼 &amp;rarr; 결제 취소 처리
    @Deprecated(&quot;Deprecated in Java&quot;)
    @Suppress(&quot;DEPRECATION&quot;, &quot;MissingSuperCall&quot;)
    override fun onBackPressed() {
        setResult(RESULT_CANCELED)
        finish()
    }
}&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;PGWebViewActivity는 결제에 필요한 PG URL을 인텐트로 전달받아서 화면이 표시된다.&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;b&gt;1. /approval 등의 URL 탐지 시 setResult(RESULT_OK)와 함께 부모 액티비티에 복귀&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. intent://, ispmobile:// 등 다양한 스킴 처리 및 마켓 fallback 로직을 추가&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;OneUI 7.0부터는 상단, 하단 시스템 영역(노치, 소프트 키 등)에 대응이 필요해서 safe-area 패딩을 적용했고, Android 11 이상에서는 status/navigation bar가 화면 위에 그려지도록 window 설정을 추가했다. 이대로 했더니 시계가 다크모드에서는 제대로 안보이는 이슈가 생겨서 상태바 배경도 흰색으로 바꾸고 아이콘이랑 글씨는 검정색으로 바꿔서 가독성을 높였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 코드 개선의 시작이었던.. 백버튼을 누르면 setResult(RESULT_CANCELED)로 결제 취소 결과를 돌려주고 액티비티를 종료하도록했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1750661186998&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// activity_pgwebview.xml
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    tools:context=&quot;.PGWebViewActivity&quot;&amp;gt;

    &amp;lt;FrameLayout
        android:id=&quot;@+id/webviewContainer2&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;&amp;gt;

        &amp;lt;WebView
            android:id=&quot;@+id/pgWebView&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;match_parent&quot; /&amp;gt;

    &amp;lt;/FrameLayout&amp;gt;

&amp;lt;/androidx.coordinatorlayout.widget.CoordinatorLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;activity_pgwebview.xml은 결제 전용 WebView 레이아웃을 위한 XML로 레이아웃 형태는 MainActivity와 똑같이 배치했다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리액트에서 사용한 브릿지코드&lt;/h3&gt;
&lt;pre id=&quot;code_1750754103011&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 모바일 네이티브의 `openPGWebView` 메서드 호출.
 *
 * @method openPGWebView
 * @param {String} link pg호출을 위해 별도의 웹뷰를 띄우는 URL.
 */
const openPGWebView = (link) =&amp;gt; {
  if (mobile.isMobile) {
    if (mobile.isAndroid) {
      if (window?.androidWebBridge?.openPGWebView) {
        window.androidWebBridge.openPGWebView(link)
      } else {
        window.open(link)
      }
    } else if (mobile.isIOS) {
      if (window?.webkit?.messageHandlers?.openPGWebView) {
        window.webkit.messageHandlers.openPGWebView.postMessage(link)
      } else {
        window.open(link)
      }
    }
  } else {
    window.open(link)
  }
}&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;style2&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwDBxh/btsONbrDtCv/WUNJgfvdrwaskKGZoMRgwk/tfile.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwDBxh/btsONbrDtCv/WUNJgfvdrwaskKGZoMRgwk/tfile.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwDBxh/btsONbrDtCv/WUNJgfvdrwaskKGZoMRgwk/tfile.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cwDBxh/btsONbrDtCv/WUNJgfvdrwaskKGZoMRgwk/tfile.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;426&quot; height=&quot;640&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&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;결제 시나리오 완료후에도 MainActivity로 승인결과를 URL에 담아서 가져오게되었다.&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;&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;&amp;nbsp;&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;012&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/012.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/012.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;동기랑 다음에는 앱개발 하게되면 RN를 진지하게 고려해보자는 이야기를 했다.&lt;/p&gt;</description>
      <category>개발/Error note</category>
      <category>Kotlin</category>
      <category>react</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/370</guid>
      <comments>https://h-owo-ld.tistory.com/370#entry370comment</comments>
      <pubDate>Tue, 24 Jun 2025 17:35:41 +0900</pubDate>
    </item>
    <item>
      <title>[React] 25.04 기준 신규버전 카카오페이 연동하기</title>
      <link>https://h-owo-ld.tistory.com/369</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;새로 하는 프로젝트에 카카오페이가 들어가게 됐다. 기존에 했던거 복붙 하려했는데, 문서 읽어보니 카카오 디벨로퍼스에서 카카오페이 디벨로퍼스로 빠지면서 결제 API연동 방식 신규버전이 생긴것 같았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1938&quot; data-origin-height=&quot;1514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cl1qu7/btsNxqwLmoP/xcpN53Y8p47phgaEdQ6I1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cl1qu7/btsNxqwLmoP/xcpN53Y8p47phgaEdQ6I1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cl1qu7/btsNxqwLmoP/xcpN53Y8p47phgaEdQ6I1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcl1qu7%2FbtsNxqwLmoP%2FxcpN53Y8p47phgaEdQ6I1K%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;1938&quot; height=&quot;1514&quot; data-origin-width=&quot;1938&quot; data-origin-height=&quot;1514&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&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;계정생성&lt;/h2&gt;
&lt;figure id=&quot;og_1745468310831&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;카카오페이 | 개발자센터&quot; data-og-description=&quot;새로운 기회와 가치를 함께 만들어봐요&quot; data-og-host=&quot;developers.kakaopay.com&quot; data-og-source-url=&quot;https://developers.kakaopay.com/&quot; data-og-url=&quot;https://developers.kakaopay.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/8LWk7/hyYIfDLYp7/3pI3Kypf533v4d3BEhOrN1/img.jpg?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://developers.kakaopay.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.kakaopay.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/8LWk7/hyYIfDLYp7/3pI3Kypf533v4d3BEhOrN1/img.jpg?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;카카오페이 | 개발자센터&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;새로운 기회와 가치를 함께 만들어봐요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.kakaopay.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오페이 개발자센터 계정이 없어서 일단 계정부터 만들어줬다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사전등록&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;애플리케이션 등록&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2202&quot; data-origin-height=&quot;1588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l1EFz/btsNw0ygTf3/OZ4RM0NuJJirpoJmyCgRFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l1EFz/btsNw0ygTf3/OZ4RM0NuJJirpoJmyCgRFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l1EFz/btsNw0ygTf3/OZ4RM0NuJJirpoJmyCgRFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl1EFz%2FbtsNw0ygTf3%2FOZ4RM0NuJJirpoJmyCgRFK%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;2202&quot; height=&quot;1588&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2202&quot; data-origin-height=&quot;1588&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Secret key(dev)발급&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1694&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tb3FT/btsOBpwRtZL/eR6Ymogzeds4Y7N39hLVjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tb3FT/btsOBpwRtZL/eR6Ymogzeds4Y7N39hLVjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tb3FT/btsOBpwRtZL/eR6Ymogzeds4Y7N39hLVjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTb3FT%2FbtsOBpwRtZL%2FeR6Ymogzeds4Y7N39hLVjk%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;2500&quot; height=&quot;1694&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;1694&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로 만들어진 애플리케이션을 선택한 후 하단에 Secret key(dev) 발급 버튼을 누른다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;플랫폼등록&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2572&quot; data-origin-height=&quot;1842&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG2tSM/btsNw7RK4SQ/wQ0ZuW9aMkRjpxWs39jOv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG2tSM/btsNw7RK4SQ/wQ0ZuW9aMkRjpxWs39jOv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG2tSM/btsNw7RK4SQ/wQ0ZuW9aMkRjpxWs39jOv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG2tSM%2FbtsNw7RK4SQ%2FwQ0ZuW9aMkRjpxWs39jOv1%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;2572&quot; height=&quot;1842&quot; data-origin-width=&quot;2572&quot; data-origin-height=&quot;1842&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 - 플랫폼에 들어가서 Web부분에 테스트할 주소를 입력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 localhost:3300으로 입력했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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/7DjEG/btsNvbnkxY5/LDMqVMikXUieTVtyxQBg2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7DjEG/btsNvbnkxY5/LDMqVMikXUieTVtyxQBg2k/img.png&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;1242&quot; data-is-animation=&quot;false&quot; style=&quot;width: 20.9838%; margin-right: 10px;&quot; data-widthpercent=&quot;21.23&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7DjEG/btsNvbnkxY5/LDMqVMikXUieTVtyxQBg2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7DjEG%2FbtsNvbnkxY5%2FLDMqVMikXUieTVtyxQBg2k%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;1056&quot; height=&quot;1242&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjfoMI/btsNwWbRNxm/BZv56xjIDkOcRb7hH1N24k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjfoMI/btsNwWbRNxm/BZv56xjIDkOcRb7hH1N24k/img.png&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;220&quot; data-is-animation=&quot;false&quot; style=&quot;width: 77.8534%;&quot; data-widthpercent=&quot;78.77&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjfoMI/btsNwWbRNxm/BZv56xjIDkOcRb7hH1N24k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjfoMI%2FbtsNwWbRNxm%2FBZv56xjIDkOcRb7hH1N24k%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;694&quot; height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;/div&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;* 꼭 http부터 입력해 주어야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1745468809998&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://36.46.31.221 (O)
http://localhost:8080/ (O)
http://127.0.0.1 (O)
https://example (X)
ftp://hello.world (X)
https://example.com/path1 (X) (path, query string, hash 허용하지 않음)
https://https://example.com (X)
https://example.com/path1?key1=value1#hash (X) (path, query string, hash 허용하지 않음)
https://example.com/ (X)
https://*.com (X)&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;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;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;연동하기 (테스트 기준)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결제준비&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;카카오페이&amp;nbsp;결제를&amp;nbsp;시작하기&amp;nbsp;위해&amp;nbsp;결제정보를&amp;nbsp;카카오페이&amp;nbsp;서버에&amp;nbsp;전달하고&amp;nbsp;결제&amp;nbsp;고유번호(TID)와&amp;nbsp;URL을&amp;nbsp;응답받는&amp;nbsp;단계입니다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Secret&amp;nbsp;key를&amp;nbsp;헤더에&amp;nbsp;담아&amp;nbsp;파라미터&amp;nbsp;값들과&amp;nbsp;함께&amp;nbsp;POST로&amp;nbsp;요청합니다.&lt;/li&gt;
&lt;li&gt;요청이 성공하면 응답 바디에 JSON 객체로 다음 단계 진행을 위한 값들을 받습니다.&lt;/li&gt;
&lt;li&gt;서버(Server)는 tid를 저장하고, 클라이언트는 사용자 환경에 맞는 URL로 리다이렉트(redirect)합니다.&lt;/li&gt;
&lt;/ul&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;pre id=&quot;code_1745469523450&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import axios from 'axios'
import { config } from '../../components'
import { log } from '../../tools'

const TestKakaoPage = () =&amp;gt; {
  const { REQUEST_URL, SECTRET_KEY, RETURN_URL } = config.constant.KAKAO
  
  const handleClick = async () =&amp;gt; {
    try {
      const headers = {
        Authorization: 'SECRET_KEY ' + SECRET_KEY,
      }

      const payload = {
        cid: 'TC0ONETIME', // 가맹점코드
        partner_order_id: 'order1234', // 가맹점 주문번호
        partner_user_id: 'YI_SEVERANCE', // 가맹점회원id
        item_name: '초코파이', 
        quantity: 1,
        total_amount: 2200,
        tax_free_amount: 0, 
        approval_url: RETURN_URL, 
        fail_url: RETURN_URL, 
        cancel_url: RETURN_URL,
      }

      log.info('결제 등록 요청에 담긴 payload:', payload)
      
      const response = await axios.post(REQUEST_URL, payload, { headers })
      const mobileURL = config.constant.IS_PRODUCTION
        ? response.data.next_redirect_mobile_url // 사용자 모바일 환경
        : response.data.next_redirect_pc_url // pc 테스트용

      const tid = response.data.tid
      console.log(tid)
      setLocalStorage('tid', JSON.stringify(tid))

      location.href = mobileURL

    } catch (error) {
      log.error('API 호출 오류:: ', error)
    }
  }

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;테스트 Kakao&amp;lt;/h2&amp;gt;
      &amp;lt;button onClick={handleClick}&amp;gt;요청&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

export { TestKakaoPage }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745471637739&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import axios from 'axios'
import { useEffect, useState } from 'react'
import { config } from '../../components'
import { getLocalStorage, hasLocalStorage, queryParamToObject } from '../../tools'

const TestKakaoIngPage = () =&amp;gt; {
  //http://localhost:3300/payment/kakao/ing?pg_token=토큰값
  const param = location.search
  const decodeKey = queryParamToObject(param)
  const { pg_token: pgToken } = decodeKey
  const { APPROVE_URL, PARKING_ADMIN_KEY } = config.constant.KAKAO
  const [status, setStatus] = useState('')
  
  useEffect(() =&amp;gt; {
    if (!pgToken || !hasLocalStorage('tid')) {

      return
    }

    const fetchData = async () =&amp;gt; {
      const headers = {
        Authorization: 'SECRET_KEY ' + PARKING_ADMIN_KEY,
      }

      const payload = {
        cid: 'TC0ONETIME', // 가맹점코드
        tid: getLocalStorage('tid'),
        partner_order_id: 'order1234', // 가맹점 주문번호 
        partner_user_id: 'YI_SEVERANCE', // 가맹점회원id
        pg_token: pgToken,
      }

      const response = await axios.post(APPROVE_URL, payload, { headers })

      setStatus(response.status)
    }

    fetchData()
  }, [decodeKey])

  return (
    &amp;lt;div&amp;gt;
      카카오페이 승인페이지
      {status === 200 &amp;amp;&amp;amp; &amp;lt;p&amp;gt;성공&amp;lt;/p&amp;gt;}
    &amp;lt;/div&amp;gt;
  )
}

export { TestKakaoIngPage }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745471757462&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
*
* https://devtalk.kakao.com/t/msg-authentication-doesn-t-complete-code-701/114140
*카카오페이 테스트 결제 구현 중 발생한 에러 문의 (&amp;ldquo;msg&amp;rdquo;:&amp;ldquo;authentication doesn&amp;rsquo;t complete!&amp;rdquo;,&amp;ldquo;code&amp;rdquo;:-701)
*안녕하세요. 카카오페이 입니다.
*말씀하신 오류의 경우, 사용자인증완료전 승인요청(approve)가 인입되어 발생되는 현상이 맞습니다.
*다만 테스트 CID의 경우, 결제수단 선택후, 비밀번호인증/페이스인증 등이 skip 되어 진행되기때문에,
*내부인증완료 처리진행 approve요청이 들어올경우 드물게 발생하는 현상일 수있습니다.
*운영시에는 발생되지 않는점 참고부탁드립니다.
*감사합니다.
*/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Apr-24-2025 14-12-38.gif&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBTTxR/btsNwYHUNSn/7DxVNbUgjNFXGESGIkq931/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBTTxR/btsNwYHUNSn/7DxVNbUgjNFXGESGIkq931/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBTTxR/btsNwYHUNSn/7DxVNbUgjNFXGESGIkq931/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bBTTxR/btsNwYHUNSn/7DxVNbUgjNFXGESGIkq931/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;670&quot; height=&quot;520&quot; data-filename=&quot;Apr-24-2025 14-12-38.gif&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;520&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;&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;a href=&quot;https://developers.kakaopay.com/docs/getting-started/api-common-guide/prepare&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.kakaopay.com/docs/getting-started/api-common-guide/prepare&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://developers.kakaopay.com/docs/payment/online/single-payment&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.kakaopay.com/docs/payment/online/single-payment&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/Javascript</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/369</guid>
      <comments>https://h-owo-ld.tistory.com/369#entry369comment</comments>
      <pubDate>Fri, 13 Jun 2025 22:20:09 +0900</pubDate>
    </item>
    <item>
      <title>[Javscript/Rechart] x축 스크롤링 추가</title>
      <link>https://h-owo-ld.tistory.com/368</link>
      <description>&lt;pre id=&quot;code_1742369879585&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const CustomTick = (props) =&amp;gt; {
  const { x, y, payload } = props
  const dateParts = payload.value.split('-') // [&quot;2024&quot;, &quot;12&quot;, &quot;15&quot;]

  return (
    &amp;lt;text
      x={x}
      y={y}
      textAnchor=&quot;front&quot;
      fontSize={12}
      letterSpacing={-0.55}
      fontWeight={500}
      fill=&quot;#333&quot;
    &amp;gt;
      &amp;lt;tspan x={x} dy=&quot;12&quot;&amp;gt;
        {dateParts[0]}년
      &amp;lt;/tspan&amp;gt;
      &amp;lt;tspan x={x} dy=&quot;15&quot;&amp;gt;
        {dateParts[1]}월 {dateParts[2]}일
      &amp;lt;/tspan&amp;gt;
    &amp;lt;/text&amp;gt;
  )
}

const StatUsageStatus = ({ value }) =&amp;gt; {
  ...코드생략 
  // x축 간격 조정 (4rem)
  const chartWidth =
    Math.max(chartData?.length * 64, 800) &amp;gt;=
    document?.querySelector('.ChartWrap')?.offsetWidth
      ? Math.max(chartData?.length * 64, 800)
      : '100%'

  return (
    &amp;lt;StatTabPanel value={value} index={0} className=&quot;StatUsageStatus&quot;&amp;gt;
		...코드생략
        &amp;lt;Box className=&quot;ChartBox&quot;&amp;gt;
          &amp;lt;Box className=&quot;ChartContent&quot;&amp;gt;
            &amp;lt;ResponsiveContainer width={chartWidth} height=&quot;100%&quot;&amp;gt;
              &amp;lt;AreaChart
                width={'100%'}
                height={500}
                data={chartData}
                margin={{
                  top: 10,
                  right: 60,
                  left: 0,
                  bottom: 30,
                }}
              &amp;gt;
                {/* ✅ SVG 그라데이션 정의 */}
                &amp;lt;defs&amp;gt;
                  {/* userCount 그래디언트 */}
                  &amp;lt;linearGradient
                    id=&quot;userCountGradient&quot;
                    x1=&quot;0&quot;
                    y1=&quot;0&quot;
                    x2=&quot;0&quot;
                    y2=&quot;1&quot;
                  &amp;gt;
                    &amp;lt;stop offset=&quot;0%&quot; stopColor=&quot;#f1bd44&quot; stopOpacity={0.5} /&amp;gt;
                    &amp;lt;stop offset=&quot;100%&quot; stopColor=&quot;#f1bd44&quot; stopOpacity={0} /&amp;gt;
                  &amp;lt;/linearGradient&amp;gt;
                  &amp;lt;linearGradient
                    id=&quot;preReviewCountGradient&quot;
                    x1=&quot;0&quot;
                    y1=&quot;0&quot;
                    x2=&quot;0&quot;
                    y2=&quot;1&quot;
                  &amp;gt;
                    &amp;lt;stop offset=&quot;0%&quot; stopColor=&quot;#53a9eb&quot; stopOpacity={0.5} /&amp;gt;
                    &amp;lt;stop offset=&quot;100%&quot; stopColor=&quot;#53a9eb&quot; stopOpacity={0} /&amp;gt;
                  &amp;lt;/linearGradient&amp;gt;
                &amp;lt;/defs&amp;gt;
                &amp;lt;CartesianGrid vertical={false} /&amp;gt;
                &amp;lt;XAxis
                  dataKey=&quot;date&quot;
                  interval={0}
                  tick={&amp;lt;CustomTick /&amp;gt;}
                  tickLine={false}
                /&amp;gt;
                &amp;lt;YAxis stroke=&quot;#333&quot; tickLine={false} /&amp;gt;
                &amp;lt;Tooltip /&amp;gt;
                &amp;lt;Area
                  dataKey=&quot;preReviewCount&quot;
                  dot={{ strokeWidth: 2, r: 1 }}
                  fill=&quot;url(#preReviewCountGradient)&quot;
                  name=&quot;테스트수&quot;
                  stroke=&quot;#53a9eb&quot;
                /&amp;gt;
                &amp;lt;Area
                  dataKey=&quot;userCount&quot;
                  dot={{ strokeWidth: 2, r: 1 }}
                  fill=&quot;url(#userCountGradient)&quot;
                  name=&quot;이용자 수&quot;
                  stroke=&quot;#f1bd44&quot;
                /&amp;gt;
              &amp;lt;/AreaChart&amp;gt;
            &amp;lt;/ResponsiveContainer&amp;gt;
          &amp;lt;/Box&amp;gt;
          &amp;lt;Box className=&quot;ChartLegends&quot;&amp;gt;
            &amp;lt;Box className=&quot;ChartLegend&quot;&amp;gt;
              &amp;lt;Box /&amp;gt;
              &amp;lt;T&amp;gt;이용자 수&amp;lt;/T&amp;gt;
            &amp;lt;/Box&amp;gt;
            &amp;lt;Box className=&quot;ChartLegend&quot;&amp;gt;
              &amp;lt;Box /&amp;gt;
              &amp;lt;T&amp;gt;테스트수&amp;lt;/T&amp;gt;
            &amp;lt;/Box&amp;gt;
          &amp;lt;/Box&amp;gt;
        &amp;lt;/Box&amp;gt;
    &amp;lt;/StatTabPanel&amp;gt;
  )
}

export { StatUsageStatus }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btXbss/btsMO8KTXri/aDoDVQJoO2o5hEpvw5JxJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btXbss/btsMO8KTXri/aDoDVQJoO2o5hEpvw5JxJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btXbss/btsMO8KTXri/aDoDVQJoO2o5hEpvw5JxJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtXbss%2FbtsMO8KTXri%2FaDoDVQJoO2o5hEpvw5JxJ1%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;1060&quot; height=&quot;438&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&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: left;&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 전체 가로스크롤 되는 코드였는데, 디자인상으로는 길어지면 y축은 고정이고 x축만 스크롤이 되게 디자인이 나와있어서, 코드를 수정했다. 처음에 어떻게 할지 고민했는데 해당 라이브러리 깃 issue에 비슷한 고민 해결을 올려둔 분이 있어서 참고할 수 있었다.&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;pre id=&quot;code_1742370066707&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const StatUsageStatus = ({ value }) =&amp;gt; {
...코드생략
  return (
    &amp;lt;StatTabPanel value={value} index={0} className=&quot;StatUsageStatus&quot;&amp;gt;
      &amp;lt;Box className=&quot;ChartWrap&quot;&amp;gt;
		... 코드생략
        &amp;lt;Box className=&quot;ChartBox&quot;&amp;gt;
          &amp;lt;Box className=&quot;ChartContent&quot;&amp;gt;
            &amp;lt;Box className=&quot;ChartYAxis&quot;&amp;gt;
              &amp;lt;AreaChart
                width={62}
                height={400}
                data={chartData}
                margin={{
                  top: 10,
                  right: 0,
                  left: 0,
                  bottom: 65,
                }}
              &amp;gt;
                &amp;lt;YAxis stroke=&quot;#333&quot; tickLine={false} /&amp;gt;
                &amp;lt;Area
                  fillOpacity={0}
                  strokeOpacity={0}
                  dataKey=&quot;preReviewCount&quot;
                /&amp;gt;
                &amp;lt;Area fillOpacity={0} strokeOpacity={0} dataKey=&quot;userCount&quot; /&amp;gt;
              &amp;lt;/AreaChart&amp;gt;
            &amp;lt;/Box&amp;gt;
            &amp;lt;Box className=&quot;ChartXAxis&quot;&amp;gt;
              &amp;lt;ResponsiveContainer width={chartWidth} height=&quot;100%&quot;&amp;gt;
                &amp;lt;AreaChart
                  width={'100%'}
                  height={400}
                  data={chartData}
                  margin={{
                    top: 10,
                    right: 60,
                    left: 0,
                    bottom: 30,
                  }}
                &amp;gt;
                  {/* SVG 그라데이션 정의 */}
                  &amp;lt;defs&amp;gt;
                    {/* userCount 그래디언트 */}
                    &amp;lt;linearGradient
                      id=&quot;userCountGradient&quot;
                      x1=&quot;0&quot;
                      y1=&quot;0&quot;
                      x2=&quot;0&quot;
                      y2=&quot;1&quot;
                    &amp;gt;
                      &amp;lt;stop offset=&quot;0%&quot; stopColor=&quot;#f1bd44&quot; stopOpacity={0.5} /&amp;gt;
                      &amp;lt;stop offset=&quot;100%&quot; stopColor=&quot;#f1bd44&quot; stopOpacity={0} /&amp;gt;
                    &amp;lt;/linearGradient&amp;gt;
                    &amp;lt;linearGradient
                      id=&quot;preReviewCountGradient&quot;
                      x1=&quot;0&quot;
                      y1=&quot;0&quot;
                      x2=&quot;0&quot;
                      y2=&quot;1&quot;
                    &amp;gt;
                      &amp;lt;stop offset=&quot;0%&quot; stopColor=&quot;#53a9eb&quot; stopOpacity={0.5} /&amp;gt;
                      &amp;lt;stop offset=&quot;100%&quot; stopColor=&quot;#53a9eb&quot; stopOpacity={0} /&amp;gt;
                    &amp;lt;/linearGradient&amp;gt;
                  &amp;lt;/defs&amp;gt;
                  &amp;lt;CartesianGrid vertical={false} /&amp;gt;
                  &amp;lt;XAxis
                    dataKey=&quot;date&quot;
                    interval={0}
                    tick={&amp;lt;CustomTick /&amp;gt;}
                    tickLine={false}
                  /&amp;gt;
                  &amp;lt;Tooltip /&amp;gt;
                  &amp;lt;Area
                    dataKey=&quot;preReviewCount&quot;
                    dot={{ strokeWidth: 2, r: 1 }}
                    fill=&quot;url(#preReviewCountGradient)&quot;
                    name=&quot;테스트수&quot;
                    stroke=&quot;#53a9eb&quot;
                  /&amp;gt;
                  &amp;lt;Area
                    dataKey=&quot;userCount&quot;
                    dot={{ strokeWidth: 2, r: 1 }}
                    fill=&quot;url(#userCountGradient)&quot;
                    name=&quot;이용자 수&quot;
                    stroke=&quot;#f1bd44&quot;
                  /&amp;gt;
                &amp;lt;/AreaChart&amp;gt;
              &amp;lt;/ResponsiveContainer&amp;gt;
            &amp;lt;/Box&amp;gt;
          &amp;lt;/Box&amp;gt;
          &amp;lt;Box className=&quot;ChartLegends&quot;&amp;gt;
            &amp;lt;Box className=&quot;ChartLegend&quot;&amp;gt;
              &amp;lt;Box /&amp;gt;
              &amp;lt;T&amp;gt;이용자 수&amp;lt;/T&amp;gt;
            &amp;lt;/Box&amp;gt;
            &amp;lt;Box className=&quot;ChartLegend&quot;&amp;gt;
              &amp;lt;Box /&amp;gt;
              &amp;lt;T&amp;gt;테스트수&amp;lt;/T&amp;gt;
            &amp;lt;/Box&amp;gt;
          &amp;lt;/Box&amp;gt;
        &amp;lt;/Box&amp;gt;
      &amp;lt;/Box&amp;gt;
    &amp;lt;/StatTabPanel&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1742370097572&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      // recharts라이브러리 스타일
      .ChartContent {
        display: flex;
        height: dp(400);
        .ChartYAxis {
          width: dp(80);
          height: dp(400);
        }
        .ChartXAxis {
          overflow: hidden;
          overflow-x: auto;
          &amp;amp;::-webkit-scrollbar {
            height: dp(6);
          }

          &amp;amp;::-webkit-scrollbar-thumb {
            border-radius: dp(3);
            background: #aaa;
          }

          &amp;amp;::-webkit-scrollbar-thumb:hover {
            background: #aaa;
          }

          &amp;amp;::-webkit-scrollbar-track {
            background: #eee;
          }
          .recharts-responsive-container {
            .recharts-wrapper {
              .recharts-surface {
                // 차트 내 가로선
                .recharts-cartesian-grid {
                  .recharts-cartesian-grid-horizontal {
                    line {
                      stroke: #ddd;
                      stroke-dasharray: 2 2;
                    }
                  }
                }
                // 차트 내 도트
                .recharts-area {
                  &amp;amp;:first-child {
                    .recharts-area-dots {
                      circle {
                        stroke: #0b7cd3;
                      }
                    }
                  }
                  &amp;amp;:last-child {
                    .recharts-area-dots {
                      circle {
                        stroke: #d3970b;
                      }
                    }
                  }
                }
                // 차트 내 X축
                .recharts-xAxis {
                  .recharts-cartesian-axis-line {
                    stroke: #ddd;
                    stroke-width: dp(1);
                    stroke-dasharray: 2 2;
                  }
                  .recharts-cartesian-axis-ticks {
                    .recharts-cartesian-axis-tick {
                      text-align: left;
                      @include font(500, 12, 20, -0.55);
                    }
                  }
                }
                // 차트 내 Y축
                .recharts-yAxis {
                  .recharts-cartesian-axis-line {
                    stroke: #aaa;
                  }
                  .recharts-cartesian-axis-ticks {
                    @include font(bold, 14, 20);
                  }
                }
              }

              .recharts-tooltip-wrapper {
                .recharts-default-tooltip {
                  padding: dp(5) dp(10) dp(10) !important;
                  .recharts-tooltip-label {
                    @include font(600, 14, 24);
                  }
                  .recharts-tooltip-item-list {
                    .recharts-tooltip-item {
                      padding: 0 !important;
                      span {
                        @include font(bold, 14, 20);
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Y축과 X축을 따로 분리하고 X축만 스크롤이 생기도록 div를 분리했다.&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&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;1070&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nBjd6/btsMO8YrGfX/i9kmlSmNvgYbGCIfFzFr90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nBjd6/btsMO8YrGfX/i9kmlSmNvgYbGCIfFzFr90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nBjd6/btsMO8YrGfX/i9kmlSmNvgYbGCIfFzFr90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnBjd6%2FbtsMO8YrGfX%2Fi9kmlSmNvgYbGCIfFzFr90%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;1070&quot; height=&quot;468&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://recharts.org/en-US/api&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://recharts.org/en-US/api&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://github.com/recharts/recharts/issues/1364#issuecomment-2608588147&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/recharts/recharts/issues/1364#issuecomment-2608588147&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/Javascript</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/368</guid>
      <comments>https://h-owo-ld.tistory.com/368#entry368comment</comments>
      <pubDate>Sat, 3 May 2025 16:57:37 +0900</pubDate>
    </item>
    <item>
      <title>[VSCode] 갑자기 svg파일이 코드가 아닌 미리보기로 보일 때</title>
      <link>https://h-owo-ld.tistory.com/367</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfTaww/btsMyUZQZKE/QsZN6DW1QgkjjHlngyHrB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfTaww/btsMyUZQZKE/QsZN6DW1QgkjjHlngyHrB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfTaww/btsMyUZQZKE/QsZN6DW1QgkjjHlngyHrB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfTaww%2FbtsMyUZQZKE%2FQsZN6DW1QgkjjHlngyHrB1%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;1169&quot; height=&quot;478&quot; data-origin-width=&quot;1169&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&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;갑자기 svg가 코드가 아닌 미리보기로 뜨게됐다.&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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/dkRTiz/btsMyUrWIo2/XFE83rXhCiInsK7LmfMCAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkRTiz/btsMyUrWIo2/XFE83rXhCiInsK7LmfMCAK/img.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;312&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;39.34&quot; style=&quot;width: 38.8846%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkRTiz/btsMyUrWIo2/XFE83rXhCiInsK7LmfMCAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkRTiz%2FbtsMyUrWIo2%2FXFE83rXhCiInsK7LmfMCAK%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;700&quot; height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clAvxm/btsMx67F6sM/ORadUpW6QWBy5s1lpyFJO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clAvxm/btsMx67F6sM/ORadUpW6QWBy5s1lpyFJO0/img.png&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;294&quot; data-is-animation=&quot;false&quot; style=&quot;width: 59.9526%;&quot; data-widthpercent=&quot;60.66&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clAvxm/btsMx67F6sM/ORadUpW6QWBy5s1lpyFJO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclAvxm%2FbtsMx67F6sM%2FORadUpW6QWBy5s1lpyFJO0%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;1017&quot; height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&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;VSCode검색창 열어서 Text Editor모드로 하면 해당 파일을 코드로 볼 수있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; 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;style2&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 나는 모든 svg파일을 코드로 보는걸 원하기때문에 설정을 수정해줬다.&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;b&gt;VSCode 설정 (Ctrl + , 또는 Cmd + ,)&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;1090&quot; data-origin-height=&quot;615&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bspPs4/btsMxGnMQIi/QMFu1n141mPkKYQWjFhQj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bspPs4/btsMxGnMQIi/QMFu1n141mPkKYQWjFhQj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bspPs4/btsMxGnMQIi/QMFu1n141mPkKYQWjFhQj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbspPs4%2FbtsMxGnMQIi%2FQMFu1n141mPkKYQWjFhQj1%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;1090&quot; height=&quot;615&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;615&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;우측상단 JSON으로 열기 &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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fgigi/btsMx6zMHOi/XCDG472gJAbxA0ebbSSMQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fgigi/btsMx6zMHOi/XCDG472gJAbxA0ebbSSMQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fgigi/btsMx6zMHOi/XCDG472gJAbxA0ebbSSMQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFgigi%2FbtsMx6zMHOi%2FXCDG472gJAbxA0ebbSSMQ0%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;203&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아래 코드 추가&lt;/p&gt;
&lt;pre id=&quot;code_1740702484891&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;workbench.editorAssociations&quot;: {
  &quot;*.svg&quot;: &quot;default&quot;
}&lt;/code&gt;&lt;/pre&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvbhjq/btsMyuUFZww/Y2IpiLuDLHc3UkNyrLuAzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvbhjq/btsMyuUFZww/Y2IpiLuDLHc3UkNyrLuAzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvbhjq/btsMyuUFZww/Y2IpiLuDLHc3UkNyrLuAzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdvbhjq%2FbtsMyuUFZww%2FY2IpiLuDLHc3UkNyrLuAzk%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;355&quot; height=&quot;262&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;262&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;</description>
      <category>개발/Install, setting, etc</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/367</guid>
      <comments>https://h-owo-ld.tistory.com/367#entry367comment</comments>
      <pubDate>Sat, 19 Apr 2025 18:04:53 +0900</pubDate>
    </item>
    <item>
      <title>[CSS/SCSS] SCSS에서 CSS 변수 중복 적용 문제 해결하기</title>
      <link>https://h-owo-ld.tistory.com/366</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 프로젝트에서 SCSS를 사용할 때, &lt;span style=&quot;text-align: start;&quot;&gt;common.scss&lt;/span&gt;&amp;nbsp;파일에 CSS 변수도 선언하고 여러 파일에서 불러오는 구조를 만들었다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 CSS 변수가 페이지마다 중복 선언되는 문제가 발생했다.&lt;/p&gt;
&lt;pre id=&quot;code_1741830939094&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 기존의 common.scss
:root {
    --btn-green-border: none;
    --btn-yellow-border: none;
    /* (이런 변수들이 반복됨...) */
}


[data-theme=light]{
...
}

...그외 scss 공통함수들이 있었다&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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/lYgMT/btsMJw46qen/aYlKCPMvjCFkGdmNM1Xk70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYgMT/btsMJw46qen/aYlKCPMvjCFkGdmNM1Xk70/img.png&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;332&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.9654%; margin-right: 10px;&quot; data-widthpercent=&quot;49.54&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYgMT/btsMJw46qen/aYlKCPMvjCFkGdmNM1Xk70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYgMT%2FbtsMJw46qen%2FaYlKCPMvjCFkGdmNM1Xk70%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;274&quot; height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbqBtt/btsMIekdQYV/Y25MmKbO8FAWNNyEZoRQqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbqBtt/btsMIekdQYV/Y25MmKbO8FAWNNyEZoRQqK/img.png&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;345&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.8718%;&quot; data-widthpercent=&quot;50.46&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbqBtt/btsMIekdQYV/Y25MmKbO8FAWNNyEZoRQqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbqBtt%2FbtsMIekdQYV%2FY25MmKbO8FAWNNyEZoRQqK%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;290&quot; height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;원인: SCSS @use의 동작 방식&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SCSS의&amp;nbsp;@use는&amp;nbsp;파일을&amp;nbsp;독립적으로&amp;nbsp;불러와서&amp;nbsp;중복&amp;nbsp;로드를&amp;nbsp;방지하는&amp;nbsp;기능이&amp;nbsp;없다. 그렇기에 어떤 파일에서 @use를 했든 간에, 사용한 곳마다 새롭게 로드가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;br /&gt;시도1&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;그래서 scss안에 css변수들을 global.scss라는 파일로 분리를 해봤지만 문제가 똑같았다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;css와 scss 파일을 분리했으나 중복 문제를 일으킨 원인&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. global.scss파일을 만든후 CSS 변수를 해당 파일로 옮기고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. common.scss에서 @use './global.scss';로 불러오고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3. 개별 스타일 파일(예: patient.page.scss)에서 @use '../common.scss';를 하였다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;결과 =&amp;gt; common.scss가 다시 불러질 때마다 global.scss가 중복 로드됨. === 똑같음&lt;/p&gt;
&lt;figure style=&quot;text-align: center;&quot; contenteditable=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/012.gif&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-name=&quot;012&quot; data-emoticon-type=&quot;friends1&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;emoticon&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/012.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741831072867&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// common.scss에서 global.scss를 사용함 (이러면 중복됨!!!!)
@use './global.scss';

@function dp($n) {
  @return calc($n / 16 * 1rem);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시도1의 파일. 이렇게 하면 common.scss가 불러와질 때마다 결국 global.scss도 함께 불러와지게 된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741831092802&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// patient.page.scss
@use '../common.scss';  // common.scss에서 global.scss를 가져옴 (1번 로드)

// 다른 파일에서도 common.scss를 사용
@use '../common.scss';  // common.scss에서 global.scss를 또 가져옴 (2번 로드)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, common.scss를 여러 SCSS 파일에서 @use하면, global.scss도 중복 로드..&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시도2&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt; global.scss를 딱 한 번만 로드하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;global.scss를 오직 index.scss에서만 한 번 불러오고, common.scss에서 따로 global.scss를 불러오지 않도록 수정했다.&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1741831154656&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// global.scss ( !!어디에서도 @use하지 않음)
:root {
  --base-font-size: 1rem;
  --btn-green-border: none;
  --btn-yellow-border: none;
}

[data-theme='light'] {
  --bg-color: #fff;
}

[data-theme='dark'] {
  --bg-color: #000;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1741831162473&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// common.scss (SCSS 변수와 함수만 포함 위에 @use 사용 X)
@function dp($n) {
  @return calc($n / 16 * 1rem);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1741831170010&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// index.js (여기서만 global.scss를 불러옴)
export * from './common.scss'
export * from './components'
export * from './default.scss'
export * from './global.scss' // 여기에서 한 번만 불러옴
export * from './pages'&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1741831178470&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 개별 페이지 스타일 (patient.page.scss)
@use '../common.scss' as common;

.PatientPage {
  background-color: var(--bg-color);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;global.scss는 index.scss에서 한 번만 불러오므로 더이상 중복 적용되지 않는다.&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;&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;뭔가 해결법이 간단했는데, 생각이 꼬여가지고 굳이 분리한 파일을 다시 @use 해서 가져온 이상한 시도를 했던 경험 @.@&lt;/p&gt;</description>
      <category>개발/HTML, CSS</category>
      <category>CSS</category>
      <category>SCSS</category>
      <author>이나당</author>
      <guid isPermaLink="true">https://h-owo-ld.tistory.com/366</guid>
      <comments>https://h-owo-ld.tistory.com/366#entry366comment</comments>
      <pubDate>Wed, 26 Mar 2025 08:05:42 +0900</pubDate>
    </item>
  </channel>
</rss>