<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Roopretelcham</title>
    <link>https://rutel.tistory.com/</link>
    <description>프로그래밍, 음악, 게임에 대해 다룹니다.</description>
    <language>ko</language>
    <pubDate>Sat, 30 May 2026 16:04:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>RuTel</managingEditor>
    <image>
      <title>Roopretelcham</title>
      <url>https://tistory1.daumcdn.net/tistory/2025400/attach/8278943d5f904a12b8347768e5779707</url>
      <link>https://rutel.tistory.com</link>
    </image>
    <item>
      <title>기업엔지니어가 하는 일, 장단점 정리</title>
      <link>https://rutel.tistory.com/435</link>
      <description>&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://youtu.be/jVw3Khxeluk?si=n7cLIuq0EY66m_h2&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/jVw3Khxeluk?si=n7cLIuq0EY66m_h2&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=jVw3Khxeluk&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/Lnw16/hyZNlpM0mI/mvqK6HyKwQsAor9o8lTJK1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=218_116_334_244,https://scrap.kakaocdn.net/dn/cjBsie/hyZNn8WIEQ/kcuNohoe92frZXWdpD1OKk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=218_116_334_244&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;【情シス部門の一人親方】ほぼ未整備だった社内ITシステムに革命を起こした方法とは！？【コ&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/jVw3Khxeluk&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&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;참고 사이트 :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://qiita.com/Conabuku/items/d077ef0b19845f29ebc7&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://qiita.com/Conabuku/items/d077ef0b19845f29ebc7&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1762870856408&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;コーポレートエンジニアのキャリア形成論 - Qiita&quot; data-og-description=&quot;サマリー この記事は、コーポレートエンジニアという職種に触れ、彼らが日々直面する挑戦、不安、そして、成長の機会を考えることにします。。コーポレートエンジニアリングの世界は、&quot; data-og-host=&quot;qiita.com&quot; data-og-source-url=&quot;https://qiita.com/Conabuku/items/d077ef0b19845f29ebc7&quot; data-og-url=&quot;https://qiita.com/Conabuku/items/d077ef0b19845f29ebc7&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ERrcT/hyZNpeCOpi/aWX7bS7j75unaeeNBA61f1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://qiita.com/Conabuku/items/d077ef0b19845f29ebc7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://qiita.com/Conabuku/items/d077ef0b19845f29ebc7&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ERrcT/hyZNpeCOpi/aWX7bS7j75unaeeNBA61f1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;コーポレートエンジニアのキャリア形成論 - Qiita&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;qiita.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;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;1&quot; 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;b&gt;코퍼레이트 엔지니어&lt;/b&gt;는 '회사 비즈니스 전략과 IT를 연결하는 전문가'&lt;/li&gt;
&lt;li&gt;주요 역할: 사내 시스템(네트워크, 서버, 업무시스템 등) 설계, 운영, 관리, 비즈니스 프로세스 개선(자동화, 효율화)으로 조직 성장&amp;middot;경쟁력 강화&lt;/li&gt;
&lt;li&gt;단순 기술자에 머무르지 않고 &quot;비즈니스의 심장부&quot;에 관여, 기술적 시각과 경영적 시각을 지도력 있게 융합해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;2&quot; data-ke-size=&quot;size26&quot;&gt;2. 커리어에서 마주치는 현실과 불안&lt;/h2&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;사내 고유 업무‧시스템을 오래 다루면 그 경험이 &quot;특정 회사&amp;middot;도메인에만 국한&quot;&lt;/li&gt;
&lt;li&gt;외부 SI, 개발 쪽 전문가처럼 다양한 프로젝트/기술을 직접 체험하기 어려움&lt;/li&gt;
&lt;li&gt;최신 기술 도입&amp;middot;교육은 예산, 업무환경상 늦어지는 경우 잦음&lt;/li&gt;
&lt;li&gt;일 자체가 '사내 안정/운영'에 치중하여 신기술/혁신 영역에 뒤처지기 쉬움&lt;/li&gt;
&lt;li&gt;업무가 한정돼서 &quot;스스로 성장하는 느낌이 약하다&quot;는 고민 흔함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;3. 코퍼레이트 엔지니어의 해법&amp;middot;마인드&amp;middot;강점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그럼에도 불구하고, 기업 내 IT 핵심으로서 비즈니스 전략 달성에 직접적인 '영향력'과 '주도권'을 가질 수 있음&lt;/li&gt;
&lt;li&gt;&quot;업무 프로세스 이해&quot;와 &quot;조직横断 커뮤니케이션&quot;에서 얻는 경험은 어디서도 대체 불가&lt;/li&gt;
&lt;li&gt;엔지니어로서 갖추어야 할 주요 7대 스킬:&lt;br /&gt;① 벤더 관리 ② 시스템&amp;middot;소프트웨어 운영 ③ 정보보안 ④ 인프라 설계/관리 ⑤ 데이터 분석基반 ⑥ 세일즈(설득) 스킬 ⑦ 커뮤니케이션&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기술력만 Important하지 않음!&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회사 내에서 의사결정권자(비IT조직 포함)와 협업/설득하는 역량&lt;/li&gt;
&lt;li&gt;개선안 제시부터 실제 정착까지 추진하는 실행력과 문제해결 능력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;4. 기타(주요 비교, 문제의식)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SIer, 외부 전문개발자와 비교해 '유연성/스킬 업데이트'에 제약이 많으나, 반대로 &quot;현장과 밀착&quot;‧&quot;조직 내 영향 증대&quot;라는 독자적 가치&amp;middot;경로가 있음&lt;/li&gt;
&lt;li&gt;시장에서의 최신 기술 습득이 어렵지만, 반대로 비즈니스 중심의 IT 리더&amp;middot;관리직으로 커리어 전환 가능성이 높음&lt;/li&gt;
&lt;li&gt;여러 부서, 현장과 교류하면서 인적 자산, 사업 프로세스에 대한 총체적 이해가 커지는 것이 큰 장점&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;&quot; 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;코퍼레이트 엔지니어는 단순한 IT 잡무 담당자가 아닌, &quot;비즈니스와 IT의 가교&quot;&lt;/li&gt;
&lt;li&gt;단점: 기술적으로는 좁아질 수 있지만, 조직 내 실질 영향력&amp;middot;리더십, 종합적 비즈니스 추진 경험이 쌓임&lt;/li&gt;
&lt;li&gt;IT 베이스 + 문제해결능력 + 커뮤니케이션/리더십을 바탕으로 회사 내에서 '기술을 통한 변화'를 주도할 수 있다면 특별한 가치를 가질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;&quot; 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;헬프데스크 역할: 사내 직원들의 문의에 대응
&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;PC 관련 모든 트러블(고장, 오류, 소프트웨어 문제 등) 대응&lt;/li&gt;
&lt;li&gt;소프트웨어나 시스템, 기기 사용법 안내&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;키팅: 신규 입사자 PC 설정, 장비 세팅&amp;middot;배포&lt;/li&gt;
&lt;li&gt;시스템 보수&amp;middot;운영: 네트워크, 서버, IT장비 정상작동 점검&amp;middot;간단한 유지관리&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;&quot; 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;프로젝트 로드맵 작성: IT 관련 신규 프로젝트(시스템 개편, 자동화 등) 계획 수립&lt;/li&gt;
&lt;li&gt;정보수집: 최신 IT, 보안, AI, SaaS 트렌드 파악 및 관련 정보 분석&lt;/li&gt;
&lt;li&gt;최신 툴/서비스 도입: 사내에 필요하다고 판단되는 새로운 서비스(AI, SaaS, 보안 시스템 등) 도입 검토 및 적용&lt;/li&gt;
&lt;li&gt;기존 업무의 정보화: 기존 사무 프로세스, 시스템을 효율적으로 바꿀 수 있도록 정보화 진행&lt;/li&gt;
&lt;li&gt;외부 벤더와의 미팅: 장비/시스템 공급사 등 외부 전문가와 협업, 기술 상담, 네고 등&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&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;단기(일상)는 '잡무'와 사내 IT서포트(문제 해결, PC 설정, 사용법 안내)가 주 업무&lt;/li&gt;
&lt;li&gt;장기적으로는 회사 전반의 IT 환경 개선, 새로운 서비스 도입, 효율화, 외부 협력 등 조금 더 &quot;주도적&quot;인 변화 업무가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</description>
      <category>Study</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/435</guid>
      <comments>https://rutel.tistory.com/435#entry435comment</comments>
      <pubDate>Tue, 11 Nov 2025 23:23:40 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt3] i18n 을 통한 사이트 현지화 적용</title>
      <link>https://rutel.tistory.com/434</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  i18n은 국제화 프레임워크로서 다양한 프레임워크나 플랫폼에서 활용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 웹사이트 : &lt;a href=&quot;https://www.i18next.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.i18next.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757658509236&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;Introduction | i18next documentation&quot; data-og-description=&quot;&quot; data-og-host=&quot;www.i18next.com&quot; data-og-source-url=&quot;https://www.i18next.com/&quot; data-og-url=&quot;https://www.i18next.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cawOca/hyZI4nn2VN/4LQu23i55YHTX04PuPyMZK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/Z848n/hyZI324hMK/5TzIikbTZ9bKcvKKMwy3c1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.i18next.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.i18next.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cawOca/hyZI4nn2VN/4LQu23i55YHTX04PuPyMZK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/Z848n/hyZI324hMK/5TzIikbTZ9bKcvKKMwy3c1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;Introduction | i18next documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.i18next.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 해당 프레임워크를 &lt;b&gt;Nuxt3&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;image.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mngMX/btsQxrGa3LO/OHyxAjo84UdkCjsl38PyM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mngMX/btsQxrGa3LO/OHyxAjo84UdkCjsl38PyM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mngMX/btsQxrGa3LO/OHyxAjo84UdkCjsl38PyM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmngMX%2FbtsQxrGa3LO%2FOHyxAjo84UdkCjsl38PyM1%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;768&quot; height=&quot;439&quot; data-filename=&quot;image.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#library&quot;&gt;필요 라이브러리 설치&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#googleapi&quot;&gt;구글 시트 API 사용 설정&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#structure&quot;&gt;프로젝트 기본 구조화&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#example&quot;&gt;프론트엔드 현지화 예시&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;library&quot; data-ke-size=&quot;size26&quot;&gt;필요 라이브러리 설치&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Front-end&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다국어 처리 프레임워크 i18n
&lt;pre class=&quot;llvm&quot;&gt;&lt;code&gt;npx nuxi@latest module add i18n&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;구글 인증
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;yarn add google-auth-library&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;구글 스프레드시트
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;yarn add google-spreadsheet&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;googleapi&quot; data-ke-size=&quot;size26&quot;&gt;구글 시트 API 사용 설정&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://console.cloud.google.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구글 클라우드 콘솔&lt;/a&gt; 에서 프로젝트 생성&lt;/li&gt;
&lt;li&gt;Google Sheets API 검색 후 사용 설정&lt;/li&gt;
&lt;li&gt;API/서비스 세부정보에서 &lt;b&gt;사용자 인증정보 만들기&lt;/b&gt; &amp;rarr; 서비스 계정 생성&lt;/li&gt;
&lt;li&gt;계정 클릭 &amp;rarr; &quot;키&quot; 탭 &amp;rarr; 새 키 생성 &amp;rarr; JSON 다운로드&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Read and write Google Sheets data.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wq6nk/btsQyA3fWyx/8jL6xnySNGJjIuEObUWEdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wq6nk/btsQyA3fWyx/8jL6xnySNGJjIuEObUWEdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wq6nk/btsQyA3fWyx/8jL6xnySNGJjIuEObUWEdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWq6nk%2FbtsQyA3fWyx%2F8jL6xnySNGJjIuEObUWEdK%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;572&quot; height=&quot;271&quot; data-filename=&quot;Read and write Google Sheets data.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;service-account@liahnson.jiam.gserviceaccour.png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9IAbo/btsQvOaVGDL/8Jf5Tyd1hKdQ5SKG9gU5NK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9IAbo/btsQvOaVGDL/8Jf5Tyd1hKdQ5SKG9gU5NK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9IAbo/btsQvOaVGDL/8Jf5Tyd1hKdQ5SKG9gU5NK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9IAbo%2FbtsQvOaVGDL%2F8Jf5Tyd1hKdQ5SKG9gU5NK%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;512&quot; height=&quot;467&quot; data-filename=&quot;service-account@liahnson.jiam.gserviceaccour.png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;사용자 인증 정보.png&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BfxIP/btsQu5cXVXx/Y8z0ChNdr957pVxKcZMsa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BfxIP/btsQu5cXVXx/Y8z0ChNdr957pVxKcZMsa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BfxIP/btsQu5cXVXx/Y8z0ChNdr957pVxKcZMsa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBfxIP%2FbtsQu5cXVXx%2FY8z0ChNdr957pVxKcZMsa0%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;826&quot; height=&quot;357&quot; data-filename=&quot;사용자 인증 정보.png&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;service-account@liahnson.jiam.gserviceaccour (1).png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t4h2s/btsQxsSCVv4/ZcJzGBwQidQ9dUpExwgrk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t4h2s/btsQxsSCVv4/ZcJzGBwQidQ9dUpExwgrk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t4h2s/btsQxsSCVv4/ZcJzGBwQidQ9dUpExwgrk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft4h2s%2FbtsQxsSCVv4%2FZcJzGBwQidQ9dUpExwgrk0%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;512&quot; height=&quot;467&quot; data-filename=&quot;service-account@liahnson.jiam.gserviceaccour (1).png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 JSON:&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;type&quot;: &quot;service_account&quot;,
  &quot;project_id&quot;: &quot;liahnson&quot;,
  &quot;private_key&quot;: &quot;-----BEGIN PRIVATE KEY-----\ntesttesttest\n&amp;mdash;&amp;mdash;END PRIVATE KEY-----\n&quot;,
  &quot;client_email&quot;: &quot;service-account@test.iam.gserviceaccount.com&quot;,
  &quot;client_id&quot;: &quot;1234&quot;,
  &quot;token_uri&quot;: &quot;https://oauth2.googleapis.com/token&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;structure&quot; 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;&lt;code&gt;locales&lt;/code&gt; 폴더 생성&lt;/li&gt;
&lt;li&gt;다운받은 JSON 파일을 &lt;code&gt;credentials.json&lt;/code&gt; 으로 이름 변경 &amp;rarr; &lt;code&gt;locales&lt;/code&gt; 폴더에 위치&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sync.js&lt;/code&gt; 파일 작성 (구글시트 &amp;harr; JSON 동기화)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;sync.js 예제&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 모듈 및 전역 변수 선언
const { GoogleSpreadsheet } = require('google-spreadsheet');
const { JWT } = require('google-auth-library');
const credentials = require('./credentials.json'); // 서비스 계정 인증 파일 경로
const fs = require('fs');
const path = require('path'); // 경로 조작을 위한 모듈 추가
const _ = require('lodash');

// 전역 설정
const localesPath = 'locales';
const lngs = ['ko', 'en']; // 언어 목록
const spreadsheetDocId = 'doc_id_test';
const fileNm = 'translation';

// Google API 인증
const serviceAccountAuth = new JWT({
    email: credentials.client_email,
    key: credentials.private_key,
    scopes: ['&amp;lt;https://www.googleapis.com/auth/spreadsheets&amp;gt;'],
});

// 스프레드시트 로드 함수
async function loadSpreadsheet() {
    console.info(
        '\\u001B[32m',
        '=====================================================================================================================\\n',
        `(\\u001B[34mhttps://docs.google.com/spreadsheets/d/${spreadsheetDocId}/#gid=0\\u001B[0m)\\n`,
        '=====================================================================================================================',
        '\\u001B[0m'
    );

    const doc = new GoogleSpreadsheet(spreadsheetDocId, serviceAccountAuth);
    await doc.loadInfo(); // 문서 정보 로드
    return doc;
}

// 시트 데이터 매핑 함수
async function makeTranslationsMapFromSheet(sheet, lngsMap) {
    if (!sheet) {
        console.error('Sheet not found');
        return lngsMap;
    }

    const rows = await sheet.getRows();

    rows.forEach((row) =&amp;gt; {
        const combinedKey = row._rawData[5]; // Combined key는 해당 위치에 있다고 가정

        if (combinedKey) {
            lngs.forEach((lang, langIndex) =&amp;gt; {
                let translation = row._rawData[langIndex + 3]; // ko, en 필드에 접근

                if (translation) {
                    translation = translation.replace(/\\\\n/g, '\\n'); // 이스케이프된 \\n 변환
                    _.set(lngsMap, `${lang}.${combinedKey}`, translation);
                } else {
                    console.warn(`No translation found for ${lang} in row with combined key: ${combinedKey}`);
                }
            });
        }
    });

    return lngsMap;
}

// JSON 파일로 저장 함수
function saveTranslationsToFile(lngsMap) {
    lngs.forEach((lng) =&amp;gt; {
        const localeJsonFilePath = path.join(__dirname, `${lng}.json`);
        const jsonString = JSON.stringify(lngsMap[lng] || {}, null, 2); // JSON 포맷으로 저장

        fs.writeFile(localeJsonFilePath, jsonString, 'utf8', (err) =&amp;gt; {
            if (err) {
                throw err;
            }
            console.log(`File written successfully: ${localeJsonFilePath}`);
        });
    });
}

// 메인 업데이트 함수
async function updateJsonFromSheet() {
    const doc = await loadSpreadsheet();

    let lngsMap = lngs.reduce((acc, lng) =&amp;gt; {
        acc[lng] = {}; // 언어별 빈 객체 초기화
        return acc;
    }, {});

    for (const sheet of doc.sheetsByIndex) {
        console.log(`Processing sheet: ${sheet.title}`);
        lngsMap = await makeTranslationsMapFromSheet(sheet, lngsMap);
    }

    saveTranslationsToFile(lngsMap);
}

// 함수 실행
updateJsonFromSheet();

// 모듈 내보내기
module.exports = {
    localesPath,
    lngs,
    loadSpreadsheet,
    updateJsonFromSheet,
    fileNm,
};&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 data-tt=&quot;{&amp;quot;paragraphStyle&amp;quot;:{&amp;quot;alignment&amp;quot;:4,&amp;quot;writingDirection&amp;quot;:1}}&quot;&gt;위 스크립트에 맞춰 아래와 같은 구조로 구글 시트를 작성한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; min-width: 600px; text-align: center;&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background: #fafbfc;&quot;&gt;
&lt;th&gt;페이지명&lt;/th&gt;
&lt;th&gt;대상&lt;/th&gt;
&lt;th&gt;원문&lt;/th&gt;
&lt;th&gt;Key(N)&lt;/th&gt;
&lt;th&gt;ko&lt;br /&gt;(한글번역)&lt;/th&gt;
&lt;th&gt;en&lt;br /&gt;(영문번역)&lt;/th&gt;
&lt;th&gt;combinedKey &lt;br /&gt;(key1 + 2 + 3)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Home&lt;/td&gt;
&lt;td&gt;버튼&lt;/td&gt;
&lt;td&gt;Login&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;로그인&lt;/td&gt;
&lt;td&gt;Login&lt;/td&gt;
&lt;td&gt;home.button.login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Home&lt;/td&gt;
&lt;td&gt;메뉴&lt;/td&gt;
&lt;td&gt;My Page&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;마이페이지&lt;/td&gt;
&lt;td&gt;My Page&lt;/td&gt;
&lt;td&gt;home.menu.mypage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manager&lt;/td&gt;
&lt;td&gt;타이틀&lt;/td&gt;
&lt;td&gt;Main Manager&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;메인관리자&lt;/td&gt;
&lt;td&gt;Main Manager&lt;/td&gt;
&lt;td&gt;manager.title.main&lt;/td&gt;
&lt;/tr&gt;
&lt;!-- 필요한 만큼 행 추가 --&gt;&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-tt=&quot;{&amp;quot;paragraphStyle&amp;quot;:{&amp;quot;alignment&amp;quot;:4,&amp;quot;writingDirection&amp;quot;:1}}&quot;&gt;페이지명, 대상, 원문, key1,2,3 : 사용자가 참고하기 위한 데이터 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-tt-replacement=&quot;true&quot; data-tt=&quot;{&amp;quot;paragraphStyle&amp;quot;:{&amp;quot;alignment&amp;quot;:4,&amp;quot;writingDirection&amp;quot;:1}}&quot;&gt;실질적으론 아래의 값이 번역에 사용된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-tt=&quot;{&amp;quot;paragraphStyle&amp;quot;:{&amp;quot;alignment&amp;quot;:4,&amp;quot;writingDirection&amp;quot;:1}}&quot;&gt;ko : 한글번역 데이터 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-tt=&quot;{&amp;quot;paragraphStyle&amp;quot;:{&amp;quot;alignment&amp;quot;:4,&amp;quot;writingDirection&amp;quot;:1}}&quot;&gt;en : 영문번역 데이터 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-tt=&quot;{&amp;quot;paragraphStyle&amp;quot;:{&amp;quot;alignment&amp;quot;:4,&amp;quot;writingDirection&amp;quot;:1}}&quot;&gt;key : i18n 에서 참고하는 키 값 (위 스크립트의 combinedKey에 해당)&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 data-tt=&quot;{&amp;quot;paragraphStyle&amp;quot;:{&amp;quot;alignment&amp;quot;:4}}&quot;&gt;그럼 작성한 sync.js 스크립트를 실행하면 아래와 같이 현지화 파일이 생성 혹은 갱신될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image (1).png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvHytt/btsQyoPozwk/kj9ZBMqhxTpQPYoGNFzdu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvHytt/btsQyoPozwk/kj9ZBMqhxTpQPYoGNFzdu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvHytt/btsQyoPozwk/kj9ZBMqhxTpQPYoGNFzdu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvHytt%2FbtsQyoPozwk%2Fkj9ZBMqhxTpQPYoGNFzdu0%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;152&quot; data-filename=&quot;image (1).png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;빌드 시에 현지화 데이터 업데이트 및 빌드를 같이 진행하려면 아래와 같이 스크립트를 작성하면 될 것이다.&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;package.json script 예시&lt;/h3&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;&quot;scripts&quot;: {
  &quot;build&quot;: &quot;npm run lang:sync &amp;amp;&amp;amp; nuxt build&quot;,
  &quot;lang:sync&quot;: &quot;node ./locales/sync.js&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;example&quot; data-ke-size=&quot;size26&quot;&gt;프론트엔드 현지화 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿에서는 &lt;code&gt;$t('key')&lt;/code&gt;, 스크립트에서는 &lt;code&gt;t('key')&lt;/code&gt;로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-tt=&quot;{&amp;quot;paragraphStyle&amp;quot;:{&amp;quot;alignment&amp;quot;:4,&amp;quot;writingDirection&amp;quot;:1}}&quot;&gt;언어 변경 시에는 반드시 setLocale 함수를 호출하여 변경하도록 한다. &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;/p&gt;
&lt;pre id=&quot;code_1757658218941&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{{ $t(mobileTitle) }}&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_1757658280217&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    $alert(t('client.common.passwordHasBeenModified'));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;layout/manager.vue&lt;/h3&gt;
&lt;pre id=&quot;code_1757658426092&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;div id=&quot;manager&quot;&amp;gt;
	    &amp;lt;span&amp;gt;{{ $t(mobileTitle) }}&amp;lt;/span&amp;gt;
	  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;const { setLocale, t } = useI18n();
const mainStore = useMainStore();

const selectedLanguage = computed({
  get: () =&amp;gt; mainStore.lang,
  set: (value) =&amp;gt; {
    mainStore.setLang(value);
    setLocale(value);
    document.documentElement.lang = value;
  }
});

const mobileTitle = computed(() =&amp;gt; {
  switch (route.path) {
    case '/manager/home':
      return 'manager.home.Home';
  }
});

const updatePassword = async () =&amp;gt; {
  try {
    await useCustomFetch.put(&quot;/common/password&quot;, { body: { newPassword, target, email } });
    $alert(t('client.common.passwordHasBeenModified'));
  } catch (e) {
    $toastError(e.message || t('common.toastError.An error occurred while processing the request'));
  }
};
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Web Develop/Frameworks and Libraries</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/434</guid>
      <comments>https://rutel.tistory.com/434#entry434comment</comments>
      <pubDate>Fri, 12 Sep 2025 15:15:23 +0900</pubDate>
    </item>
    <item>
      <title>[AWS S3] 접근 정책 수정</title>
      <link>https://rutel.tistory.com/432</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IAM &amp;gt; 사용자 &amp;gt; [특정사용자] 선택&lt;/li&gt;
&lt;li&gt;권한정책에서 정책 이름 클릭&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doY2dh/btsHNfAs6pO/BmsbMTWdZ4YdNexftT6xxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doY2dh/btsHNfAs6pO/BmsbMTWdZ4YdNexftT6xxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doY2dh/btsHNfAs6pO/BmsbMTWdZ4YdNexftT6xxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoY2dh%2FbtsHNfAs6pO%2FBmsbMTWdZ4YdNexftT6xxK%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;1578&quot; height=&quot;656&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;656&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 정책에 정의된 권한 &amp;gt; 편집&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2734&quot; data-origin-height=&quot;754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/emaNv0/btsHMwpc5O4/wyLBf4uWb0IRh4virg3xnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/emaNv0/btsHMwpc5O4/wyLBf4uWb0IRh4virg3xnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/emaNv0/btsHMwpc5O4/wyLBf4uWb0IRh4virg3xnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FemaNv0%2FbtsHMwpc5O4%2FwyLBf4uWb0IRh4virg3xnk%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;2734&quot; height=&quot;754&quot; data-origin-width=&quot;2734&quot; data-origin-height=&quot;754&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1716202109248&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;Version&quot;: &quot;2012-10-17&quot;,
	&quot;Statement&quot;: [
		{
			&quot;Effect&quot;: &quot;Allow&quot;,
			&quot;Action&quot;: [
				&quot;s3:*&quot;,
				&quot;s3-object-lambda:*&quot;
			],
			&quot;Resource&quot;: &quot;*&quot;,
			&quot;Condition&quot;: {
				&quot;IpAddressIfExists&quot;: {
					&quot;aws:SourceIp&quot;: [
						&quot;11.11.111.111/32&quot;
					]
				},
				&quot;StringEqualsIfExists&quot;: {
					&quot;aws:SourceVpc&quot;: [
						&quot;vpc-e727fc89&quot;
					]
				}
			}
		},
		{
			&quot;Effect&quot;: &quot;Allow&quot;,
			&quot;Action&quot;: [
				&quot;s3:*&quot;,
				&quot;s3-object-lambda:*&quot;
			],
			&quot;Resource&quot;: &quot;*&quot;,
			&quot;Condition&quot;: {
				&quot;IpAddress&quot;: {
					&quot;aws:SourceIp&quot;: [
						&quot;111.11.11.252/32&quot;,
					]
				}
			}
		}
	]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 SourceIp를 추가한 다음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 &amp;gt; 변경사항 저장을 눌러 업데이트 한다.&lt;/p&gt;</description>
      <category>Infrastructure</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/432</guid>
      <comments>https://rutel.tistory.com/432#entry432comment</comments>
      <pubDate>Mon, 20 May 2024 19:48:45 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] EC2 &amp;gt; Amazon Linux 볼륨 크기 늘리기</title>
      <link>https://rutel.tistory.com/431</link>
      <description>&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;Amazon EBS 볼륨&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- Amazon EC2 인스턴스에 연결하는 스토리지 볼륨&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 진행 전에 볼륨을 늘릴 순 있어도 줄일 수 없다는 것에 유의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 볼륨 크기 증가 시 비용 계산은 아래 참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/ebs/pricing/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://aws.amazon.com/ko/ebs/pricing/&lt;/a&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;1. EC2 인스턴스 목록에서 인스턴스 ID 클릭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 스토리지 탭에서 볼륨 ID 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-14 오후 2.42.45.png&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQx6hr/btsHo39gXS1/shPKPdfcBuBJxDniz2xkFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQx6hr/btsHo39gXS1/shPKPdfcBuBJxDniz2xkFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQx6hr/btsHo39gXS1/shPKPdfcBuBJxDniz2xkFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQx6hr%2FbtsHo39gXS1%2FshPKPdfcBuBJxDniz2xkFK%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;655&quot; height=&quot;324&quot; data-filename=&quot;스크린샷 2024-05-14 오후 2.42.45.png&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 작업 &amp;gt; 볼륨 수정 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-14 오후 2.43.15.png&quot; data-origin-width=&quot;1563&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n9oPx/btsHnVjHNx3/3H4a2S2wI9wKzXuQvtatKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n9oPx/btsHnVjHNx3/3H4a2S2wI9wKzXuQvtatKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n9oPx/btsHnVjHNx3/3H4a2S2wI9wKzXuQvtatKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn9oPx%2FbtsHnVjHNx3%2F3H4a2S2wI9wKzXuQvtatKk%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;1563&quot; height=&quot;221&quot; data-filename=&quot;스크린샷 2024-05-14 오후 2.43.15.png&quot; data-origin-width=&quot;1563&quot; data-origin-height=&quot;221&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 크기 정보 수정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-05-14 오후 2.43.40.png&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blGdjh/btsHqkBWzc2/FKGyGfh6h2tRJrKRh46sg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blGdjh/btsHqkBWzc2/FKGyGfh6h2tRJrKRh46sg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blGdjh/btsHqkBWzc2/FKGyGfh6h2tRJrKRh46sg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblGdjh%2FbtsHqkBWzc2%2FFKGyGfh6h2tRJrKRh46sg1%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;569&quot; height=&quot;410&quot; data-filename=&quot;스크린샷 2024-05-14 오후 2.43.40.png&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 일정시간 지난 후 인스턴스에 연결해 파티션 확인&lt;/p&gt;
&lt;pre id=&quot;code_1715665500239&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; lsblk&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;6.　파티션 확장&lt;/p&gt;
&lt;pre id=&quot;code_1716909866194&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; sudo growpart /dev/xvda 1&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;7. 파일 시스템 유형 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* XFS filesystem data와 같이 유형이 표시된다.&lt;/p&gt;
&lt;pre id=&quot;code_1716909914778&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo file -s /dev/xvda1&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;7. 파일시스템 확장 (위에서 확인한 시스템 유형에 따라)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7-1. ext4의 경우&lt;/p&gt;
&lt;pre id=&quot;code_1716909999677&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; sudo resize2fs /dev/xvda1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7-2. xfs의 경우&lt;/p&gt;
&lt;pre id=&quot;code_1715665786306&quot; class=&quot;nginx&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;  sudo xfs_growfs&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;8. 확장된 크기 확인&lt;/p&gt;
&lt;pre id=&quot;code_1716910054211&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df -h&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;참고 :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/ebs/latest/userguide/recognize-expanded-volume-linux.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.aws.amazon.com/ko_kr/ebs/latest/userguide/recognize-expanded-volume-linux.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715665814253&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;EBS 볼륨 크기 조정 후 파일 시스템 확장 - Amazon EBS&quot; data-og-description=&quot;다음과 같은 지침에서는 Linux용 XFS 및 Ext4 파일 시스템을 확장하는 프로세스를 안내합니다. 다른 파일 시스템을 확장하는 방법에 대한 자세한 내용은 해당 설명서를 참조하세요.&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/ebs/latest/userguide/recognize-expanded-volume-linux.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/ebs/latest/userguide/recognize-expanded-volume-linux.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/daIp79/hyV56vfDOm/iIhkiNKZvIJcghKQhGjVkk/img.png?width=880&amp;amp;height=800&amp;amp;face=0_0_880_800,https://scrap.kakaocdn.net/dn/hbLv9/hyV578Ldy3/4KQOAHh3ryaH8yxAxGfuUk/img.png?width=880&amp;amp;height=800&amp;amp;face=0_0_880_800,https://scrap.kakaocdn.net/dn/cD68zA/hyV2s03svm/vysKJ2xE7vssWkOn4Ss9ok/img.png?width=640&amp;amp;height=452&amp;amp;face=0_0_640_452&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/ebs/latest/userguide/recognize-expanded-volume-linux.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/ebs/latest/userguide/recognize-expanded-volume-linux.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/daIp79/hyV56vfDOm/iIhkiNKZvIJcghKQhGjVkk/img.png?width=880&amp;amp;height=800&amp;amp;face=0_0_880_800,https://scrap.kakaocdn.net/dn/hbLv9/hyV578Ldy3/4KQOAHh3ryaH8yxAxGfuUk/img.png?width=880&amp;amp;height=800&amp;amp;face=0_0_880_800,https://scrap.kakaocdn.net/dn/cD68zA/hyV2s03svm/vysKJ2xE7vssWkOn4Ss9ok/img.png?width=640&amp;amp;height=452&amp;amp;face=0_0_640_452');&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;EBS 볼륨 크기 조정 후 파일 시스템 확장 - Amazon EBS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;다음과 같은 지침에서는 Linux용 XFS 및 Ext4 파일 시스템을 확장하는 프로세스를 안내합니다. 다른 파일 시스템을 확장하는 방법에 대한 자세한 내용은 해당 설명서를 참조하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Infrastructure</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/431</guid>
      <comments>https://rutel.tistory.com/431#entry431comment</comments>
      <pubDate>Tue, 14 May 2024 14:49:55 +0900</pubDate>
    </item>
    <item>
      <title>[Vue3] ref와 reactive 차이</title>
      <link>https://rutel.tistory.com/429</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;반응형 데이터를 만들기 위한 함수&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ref&lt;/h2&gt;
&lt;pre id=&quot;code_1712126280035&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;
import { ref } from 'vue'

let id = 0

const newTodo = ref('')
const hideCompleted = ref(false)
const todos = ref([
  { id: id++, text: 'HTML 배우기', done: true },
  { id: id++, text: 'JavaScript 배우기', done: true },
  { id: id++, text: 'Vue 배우기', done: false }
])&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;사용 대상&lt;/b&gt;: 모든 종류의 값 (기본 데이터 타입 또는 객체/배열).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;접근 방법&lt;/b&gt;: .value 속성을 통해 값에 접근하고 변경합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주요 특징&lt;/b&gt;: 기본 데이터 타입(예: 문자열, 숫자, 불리언)에 반응성을 부여할 수 있으며, 객체나 배열에도 사용 가능하지만, 단일 값에 대한 반응성을 관리하는 데 주로 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;reactive&lt;/h3&gt;
&lt;pre id=&quot;code_1712126300084&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup&amp;gt;
import { reactive } from 'vue'

let id = 0

const state = reactive({
  newTodo: '',
  hideCompleted: false,
  todos: [
    { id: id++, text: 'HTML 배우기', done: true },
    { id: id++, text: 'JavaScript 배우기', done: true },
    { id: id++, text: 'Vue 배우기', done: false }
  ]
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;사용 대상&lt;/b&gt;: 객체나 배열.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;접근 방법&lt;/b&gt;: .value 속성 없이 객체나 배열 내부의 속성에 직접 접근합니다.&lt;/li&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;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;reactive 사용의 이점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;직관적인 접근과 수정&lt;/b&gt;: reactive 객체의 속성에 접근하거나 수정할 때, .value를 사용할 필요가 없습니다. 이는 코드를 좀 더 직관적으로 만들고, 일반 JavaScript 객체와 동일한 방식으로 작업할 수 있게 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중첩된 반응성&lt;/b&gt;: reactive를 사용하면, 객체 내의 중첩된 속성도 자동으로 반응성이 적용됩니다. 따라서 객체 내부 구조가 복잡해지거나 중첩된 경우에도, 별도의 처리 없이 모든 레벨에서 반응성을 유지할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코드 조직&lt;/b&gt;: 여러 반응형 데이터를 하나의 reactive 객체에 그룹화하여 관리할 수 있습니다. 이는 관련 데이터와 로직을 함께 묶어서 관리하기 편리하게 해줍니다, 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;선택 기준&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 타입(문자열, 숫자, 불리언 등)에 대한 반응성이 필요한 경우, 또는 Vue 템플릿에서 직접 참조되는 단일 변수에 대해서는 ref를 사용하는 것이 좋습니다.&lt;/li&gt;
&lt;li&gt;객체나 배열과 같은 복합적인 데이터 구조에 대해 반응성을 제공하고, 중첩된 데이터 구조를 다루거나 여러 관련 데이터를 함께 관리해야 하는 경우 reactive를 사용하는 것이 더 적합할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web Develop/Frameworks and Libraries</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/429</guid>
      <comments>https://rutel.tistory.com/429#entry429comment</comments>
      <pubDate>Wed, 3 Apr 2024 15:39:03 +0900</pubDate>
    </item>
    <item>
      <title>[Vue3]  Composition API</title>
      <link>https://rutel.tistory.com/428</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;전통적인 Options API&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue에서의 스크립트 구현은 크게 두가지 방식이 있다. 전통적인 Options API와 Composition API이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 Options API&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;django&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;input v-model=&quot;newTodo&quot; @keyup.enter=&quot;addTodo&quot;&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;li v-for=&quot;todo in todos&quot; :key=&quot;todo.id&quot;&amp;gt;
        {{ todo.text }}
      &amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
  data() {
    return {
      newTodo: '',
      todos: [],
      nextId: 0
    }
  },
  methods: {
    addTodo() {
      this.todos.push({ id: this.nextId++, text: this.newTodo });
      this.newTodo = ''; // 입력 필드 초기화
    }
  }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Composition API&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Vue 3의 Composition API는 컴포넌트 로직을 구성하는 새로운 방법을 제공합니다. 이 API의 도입은 Vue 애플리케이션을 설계하고 개발하는 방식에 근본적인 변화를 가져왔습니다. Composition API의 특징과 장점은 다음과 같습니다:&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;반응형 상태 정의&lt;/b&gt;: &lt;code&gt;ref&lt;/code&gt;와 &lt;code&gt;reactive&lt;/code&gt; 함수를 사용하여 반응형 상태를 선언적으로 정의할 수 있습니다. 이 상태들은 컴포넌트의 템플릿에서 직접 사용될 수 있으며, 상태 변경 시 자동으로 화면을 업데이트합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;setup&lt;/code&gt; 함수&lt;/b&gt;: 컴포넌트의 반응형 상태, 계산된 속성, 메서드 등 모든 로직을 &lt;code&gt;setup&lt;/code&gt; 함수 내에 정의합니다. &lt;code&gt;setup&lt;/code&gt; 함수는 컴포넌트의 옵션/라이프사이클 훅보다 먼저 실행되며, 여기에서 정의된 모든 값과 함수는 템플릿에서 직접 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;함수 기반의 구성&lt;/b&gt;: 로직을 재사용 가능한 함수로 캡슐화하고 조합하여 컴포넌트를 구성할 수 있습니다. 이러한 접근 방식은 컴포넌트 간에 코드를 재사용하고 조합하기 쉽게 만듭니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;로직의 재사용 및 조직화&lt;/b&gt;: Composition API를 사용하면 로직을 기능별로 구성하고 필요한 곳에서 재사용할 수 있습니다. 이는 코드의 중복을 줄이고, 프로젝트의 유지보수성을 향상시킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유연성&lt;/b&gt;: 컴포넌트의 로직을 더 유연하게 조직할 수 있습니다. 예를 들어, 관련된 모든 반응형 상태와 함수를 함께 그룹화하여 관리할 수 있으며, 이는 컴포넌트의 가독성을 크게 향상시킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타입스크립트와의 호환성&lt;/b&gt;: Composition API는 타입스크립트와 더욱 잘 호환됩니다. &lt;code&gt;setup&lt;/code&gt; 함수 내에서 정의된 상태와 함수에 타입을 적용하기 쉬워, 타입스크립트를 사용하는 프로젝트에서 타입 안정성과 개발 경험을 향상시킬 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응집력 있는 코드 베이스&lt;/b&gt;: 기능별로 로직을 그룹화하고 재사용할 수 있기 때문에, 관련 로직이 물리적으로 가까운 위치에 있게 됩니다. 이는 응집력 있는 코드 베이스를 유지하는 데 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;더 나은 성능&lt;/b&gt;: Composition API를 사용하면 필요한 로직만을 정확히 구성하여 사용할 수 있기 때문에, 불필요한 로직의 실행을 최소화할 수 있습니다. 이는 애플리케이션의 성능을 최적화하는 데 기여할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Composition API는 Vue 애플리케이션을 개발할 때 더 큰 유연성과 향상된 코드 재사용성을 제공합니다. 이는 특히 대규모 애플리케이션 또는 복잡한 컴포넌트 구조를 가진 프로젝&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트에서 그 장점이 두드러집니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Vue 3 초기 버전에서의 Composition API 사용 예시&lt;/h3&gt;
&lt;pre class=&quot;django&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;input v-model=&quot;newTodo&quot; @keyup.enter=&quot;addTodo&quot; /&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;li v-for=&quot;todo in todos&quot; :key=&quot;todo.id&quot;&amp;gt;{{ todo.text }}&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import { ref } from 'vue';

export default {
  setup() {
    const newTodo = ref('');
    const todos = ref([]);

    const addTodo = () =&amp;gt; {
      todos.value.push({ id: todos.value.length + 1, text: newTodo.value });
      newTodo.value = '';
    };

    return { newTodo, todos, addTodo };
  }
};
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue 3 초기 버전에서 Composition API를 사용할 때는 setup 함수 내에서 컴포넌트의 반응형 상태, 계산된 속성, 메서드 등을 정의하고, 필요한 값들을 객체로 반환하여 템플릿에서 사용할 수 있도록 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Vue 3.2 이후에서의 &amp;lt;script setup&amp;gt; 구문 사용 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Vue 3.2부터 도입된 &lt;/span&gt;&amp;lt;script setup&amp;gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt; 구문을 사용하면, &lt;/span&gt;setup&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt; 함수 내에서 반환 과정 없이 직접 변수와 함수를 정의할 수 있으며, 이들은 자동으로 템플릿에서 사용 가능해집니다. 이로 인해 코드가 더욱 간결하고 선언적으로 변화했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1712124789796&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;input v-model=&quot;newTodo&quot; @keyup.enter=&quot;addTodo&quot; /&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;li v-for=&quot;todo in todos&quot; :key=&quot;todo.id&quot;&amp;gt;{{ todo.text }}&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import { ref } from 'vue';

const newTodo = ref('');
const todos = ref([]);

const addTodo = () =&amp;gt; {
  todos.value.push({ id: todos.value.length + 1, text: newTodo.value });
  newTodo.value = '';
};
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;주요 차이점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;코드 간결성&lt;/b&gt;: &amp;lt;script setup&amp;gt; 구문을 사용하면, 컴포넌트의 로직을 더욱 간결하게 작성할 수 있습니다. setup 함수 내에서 반환 과정 없이 모든 로직을 정의할 수 있으며, 이는 코드의 가독성과 유지보수성을 크게 향상시킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동 import 추론&lt;/b&gt;: &amp;lt;script setup&amp;gt;은 IDE와 도구에서 더 나은 타입 추론과 자동 완성을 제공합니다. 또한, Vue 컴파일러는 &amp;lt;script setup&amp;gt; 내에서 사용된 Vue API를 자동으로 감지하여 필요한 코드를 자동으로 import 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴포넌트 정의의 선언적 표현&lt;/b&gt;: &amp;lt;script setup&amp;gt; 구문은 컴포넌트의 정의를 더 선언적으로 만들어 줍니다. 이는 Vue 컴포넌트의 구조와 로직을 더 명확하게 표현할 수 있게 해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;lt;script setup&amp;gt; 구문은 Vue 3.2 이상에서 Composition API를 사용하는 새로운 표준이 되었으며, 많은 개발자들이 이 새로운 패턴을 선호하고 있습니다.&lt;/p&gt;</description>
      <category>Web Develop/Frameworks and Libraries</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/428</guid>
      <comments>https://rutel.tistory.com/428#entry428comment</comments>
      <pubDate>Wed, 3 Apr 2024 15:13:34 +0900</pubDate>
    </item>
    <item>
      <title>핸들러(handler)와 콜백 함수(callback function)의 차이</title>
      <link>https://rutel.tistory.com/427</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;콜백 함수 (Callback Function)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 콜백 함수는 다른 함수에 인자로 전달되는 함수입니다. 이 함수는 외부 함수의 내부 로직에 의해 특정 시점에 호출됩니다. 콜백 함수는 비동기 처리, 이벤트 리스너 등록, 고차 함수(higher-order function)에서 자주 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;용도&lt;/b&gt;: 콜백 함수는 비동기 작업의 결과를 처리하거나, 특정 이벤트가 발생했을 때 수행할 작업을 정의하는 데 사용됩니다. 예를 들어, 서버로부터 데이터를 요청하고 그 데이터가 도착했을 때 실행될 함수, 또는 사용자가 버튼을 클릭했을 때 실행될 함수 등이 콜백 함수로 사용될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시&lt;/b&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1712120764118&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// setTimeout 함수에 전달된 익명 함수는 콜백 함수입니다.
setTimeout(() =&amp;gt; {
    console.log(&quot;1초 후에 실행됩니다.&quot;);
}, 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;핸들러 (Handler)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 핸들러는 특정 이벤트나 조건에 대응하여 실행되도록 지정된 함수를 의미합니다. 이 용어는 주로 이벤트 처리와 관련된 맥락에서 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;용도&lt;/b&gt;: 이벤트 핸들러는 사용자의 입력, 시스템 이벤트, 네트워크 응답 등 다양한 이벤트에 반응하기 위해 사용됩니다. 웹 개발에서는 DOM 이벤트(클릭, 키보드 입력 등)를 처리하는 함수를 이벤트 핸들러라고 부릅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&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;pre id=&quot;code_1712120842050&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- HTML에서 버튼 클릭 이벤트에 대한 핸들러를 정의합니다. --&amp;gt;
&amp;lt;button onclick=&quot;alert('클릭됨!')&quot;&amp;gt;클릭하세요&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1712120869029&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// JavaScript에서 이벤트 리스너를 추가하는 방식으로 핸들러를 지정할 수 있습니다.
document.getElementById(&quot;myButton&quot;).addEventListener(&quot;click&quot;, function() {
    alert(&quot;버튼이 클릭되었습니다.&quot;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;요약하자면, 콜백 함수는 넓은 의미에서 다른 함수의 실행 완료, 비동기 작업의 완료 등 다양한 상황에서 호출되도록 예정된 모든 함수를 말하며, 핸들러는 특히 이벤트 처리와 관련된 맥락에서 사용되는 용어입니다. 따라서 모든 이벤트 핸들러는 콜백 함수의 한 형태라고 볼 수 있지만, 모든 콜백 함수가 이벤트 핸들러는 아닙니다.&lt;/p&gt;</description>
      <category>Mobile App Develop</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/427</guid>
      <comments>https://rutel.tistory.com/427#entry427comment</comments>
      <pubDate>Wed, 3 Apr 2024 14:07:55 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] Proxy</title>
      <link>https://rutel.tistory.com/426</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Proxy : 대리&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy는 JavaScript에서 객체의 기본 동작(예: 속성 접근, 할당, 열거, 함수 호출 등)을 사용자 정의 동작으로 가로채서(trap) 조작할 수 있게 해주는 기능입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 객체에 대한 작업을 가로채서 그 작업이 수행되기 전, 수행된 후, 또는 작업을 완전히 대체하여 추가적인 로직을 실행할 수 있게 해줍니다. 이런 특징 때문에 Proxy는 다양한 고급 작업과 패턴에 유용하게 사용될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1712112984431&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const target = {
  message1: &quot;hello&quot;,
  message2: &quot;everyone&quot;,
};

const handler1 = {};

const proxy1 = new Proxy(target, handler1);

proxy1.message1 = 'hi';
console.log('target', target);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드에서 target의 message1 속성의 값은 hi로 변경되게 된다.&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;아래 예제를 통해 Proxy로 할 수 있는 다양한 가능성을 살펴보겠다.&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 속성 읽기 접근 제어&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성을 읽을 때마다 로그를 출력하도록 합니다. get은 속성값을 가져오기 위한 trap(가로채기)이다.&lt;/p&gt;
&lt;pre id=&quot;code_1712113122279&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(...)
const handler1 = {
  get(target, prop, receiver) {
    console.log(`속성 '${prop}'에 접근함`);
    return Reflect.get(...arguments);
  }
};

const proxy1 = new Proxy(target, handler1);

console.log(proxy1.message1); // 속성 'message1'에 접근함 -&amp;gt; hello
console.log(proxy1.message2); // 속성 'message2'에 접근함 -&amp;gt; everyone&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy는 반드시 new 키워드로만 생성가능하다.&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;background-color: #ffffff; color: #0d0d0d; font-size: 1.44em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;2. 속성 쓰기 접근 제어&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성에 값을 할당할 때 유효성 검사를 추가합니다. 예를 들어, message1에는 오직 문자열만 할당될 수 있게 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1712118373057&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(...)
const handler1 = {
    set(target, prop, value) {
        if (prop === &quot;message1&quot; &amp;amp;&amp;amp; typeof value !== &quot;string&quot;) {
            throw new Error(&quot;message1은 문자열이어야 합니다.&quot;);
        }
        target[prop] = value;
        return true; // 성공적으로 값을 할당했음을 나타냄
    }
};

const proxy1 = new Proxy(target, handler1);

proxy1.message1 = &quot;안녕하세요&quot;; // 성공
try {
    proxy1.message1 = 123; // Error: message1은 문자열이어야 합니다.
} catch (e) {
    console.error(e.message);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. 속성 존재 여부 확인&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;객체에 특정 속성이 있는지 확인할 때마다 로그를 출력합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1712118433806&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const handler1 = {
  has(target, prop) {
    console.log(`${prop} 속성이 객체에 존재하는지 확인`);
    return prop in target;
  }
};

const proxy1 = new Proxy(target, handler1);

console.log('message1' in proxy1); // message1 속성이 객체에 존재하는지 확인 -&amp;gt; true
console.log('message3' in proxy1); // message3 속성이 객체에 존재하는지 확인 -&amp;gt; false&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;이외에도 다양한 Handler Function을 통해 객체의 기본동작을 정의하고 유연하게 사용할 수 있다.&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;Proxy생성자와 Handler Function에 대해서는 다음 문서를 참고&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1712118493638&quot; style=&quot;color: #333333; text-align: start;&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Pxl2l/hyVJTpKBQD/eihpAIMv8pyTnGIIcwjGp1/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot; data-og-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy&quot; data-og-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-description=&quot;The Proxy() constructor creates Proxy objects.&quot; data-og-title=&quot;Proxy() constructor - JavaScript | MDN&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://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy&quot; data-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Pxl2l/hyVJTpKBQD/eihpAIMv8pyTnGIIcwjGp1/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Proxy() constructor - JavaScript | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;The Proxy() constructor creates Proxy objects.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Study/JavaScript</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/426</guid>
      <comments>https://rutel.tistory.com/426#entry426comment</comments>
      <pubDate>Wed, 3 Apr 2024 13:28:59 +0900</pubDate>
    </item>
    <item>
      <title>[AWS Linux] Git Action Runner에서 Dotnet Core 6 Error발생 시</title>
      <link>https://rutel.tistory.com/425</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 리눅스 환경에 CI &amp;amp; CD를 적용하는데&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;pre id=&quot;code_1710136092520&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Libicu's dependencies is missing for Dotnet Core 6.0
Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 6.0 dependencies.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 AWS Linuxt는 X64 아키텍처라곤 하나 위에서 알려주는 .sh 파일 실행만으론 의존성이 해결되지 않는다.&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;pre id=&quot;code_1710136135337&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo yum install perl-Digest-SHA -y

sudo yum install libicu -y&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;이후에 ./config.sh를 실행하면 정상적으로 GitHub의 액션런너와 연결이 되고 설정과정을 진행할 수 있게 된다.&lt;/p&gt;</description>
      <category>Infrastructure</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/425</guid>
      <comments>https://rutel.tistory.com/425#entry425comment</comments>
      <pubDate>Mon, 11 Mar 2024 14:50:40 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt.js + Node.js] 백엔드에서 업로드한 정적파일을 프론트에서 참조하기</title>
      <link>https://rutel.tistory.com/424</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드에서 이미지 파일을 static 폴더에 올렸다면 일반적으로는 프론트에서 참조할 수가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 express는 이미지 파일과 같은 정적 파일들을 쉽게 참조하여 반환할 수 있는 메소드를 제공한다.&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;| Back-end&lt;/p&gt;
&lt;pre id=&quot;code_1697954702266&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.use('/static', express.static(path.join(__dirname, 'static')));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;express.static 메소드는 node프로세스가 실행되는 path에 따라 상대적이므로 위와 같이 환경변수인 __dirname을 써서 디렉토리명을 지정해줄 수 있다. node 프로세스가 실행되는 같은 경로의 static 폴더를 참조한다.&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;그러면 아래와 같이 참조했을 때 백엔드의 static 디렉토리내의 모든 파일을 참조할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http://localhost:3000/api/static/images/mt/resize-1697954077172.jpg&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;| Front-end&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 nuxt.config.js를 수정하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api라는 경로로 들어왔을 때 경로를 다시 쓰기해주도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1697955075528&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; axios: {
        proxy: true,
        prefix: '/api'
    },

    proxy: {
        '/api': { target: process.env.AXIOS_BASE_URL, pathRewrite: { '^/api/': '/' } },
    },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[프론트 .env 폴더에 정의된 api 주소]&lt;/p&gt;
&lt;pre id=&quot;code_1697955116363&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;AXIOS_BASE_URL=http://127.0.0.1:10072&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;만약 DB에 저장된 path과 다음과 같다면 프론트의 메소드나 computed 속성으로 경로를 반환하면 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static/images/mt/resize-1697954077178.jpg&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697955003498&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  getImageUrl(img) {
            if (img.path &amp;amp;&amp;amp; img.path.includes('static/images')) {
                return '/api/' + img.path;
            }
            return URL.createObjectURL(img);
        },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 백엔드에서 굳이 파일객체를 리턴한다는지 리소스가 많이들고 비효율적인 방법을 쓰지않고도 쉽게 리소스를 참조할 수 있게 된다.&lt;/p&gt;</description>
      <category>Web Develop/Frameworks and Libraries</category>
      <author>RuTel</author>
      <guid isPermaLink="true">https://rutel.tistory.com/424</guid>
      <comments>https://rutel.tistory.com/424#entry424comment</comments>
      <pubDate>Sun, 22 Oct 2023 15:13:43 +0900</pubDate>
    </item>
  </channel>
</rss>