<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Atsushi Miyamoto</title>
    <description>The latest articles on DEV Community by Atsushi Miyamoto (@atsushii).</description>
    <link>https://dev.to/atsushii</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1004371%2F8870c52b-35b4-43b4-a2ab-1d94aaeb2626.jpeg</url>
      <title>DEV Community: Atsushi Miyamoto</title>
      <link>https://dev.to/atsushii</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/atsushii"/>
    <language>en</language>
    <item>
      <title>Quit 9 to 5 to all in on building app by solo</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Sun, 28 Sep 2025 07:22:43 +0000</pubDate>
      <link>https://dev.to/atsushii/quit-9-to-5-to-all-in-on-building-app-by-solo-4hp6</link>
      <guid>https://dev.to/atsushii/quit-9-to-5-to-all-in-on-building-app-by-solo-4hp6</guid>
      <description>&lt;p&gt;hi all,&lt;br&gt;
it’s been a while since i wrote article, this one is just a life update!&lt;/p&gt;

&lt;p&gt;i quit my 9 to 5 job a month ago with $0 MRR, betting everything on building a profitable app as a solo founder.&lt;/p&gt;

&lt;p&gt;this is the biggest decision of my life. i’ve worked as a software engineer for almost 4 and a half years in Japan and Canada. &lt;br&gt;
It was a fun time, but i knew this was what i always wanted since becoming a software engineer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I quit
&lt;/h3&gt;

&lt;p&gt;i’ve always wanted to be free, not working 9 to 5 for someone else, but creating what i want.&lt;br&gt;
and now, with the rise of AI, i believe it’s the best timing ever to bet on the entrepreneurial path.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I’ve been doing for 1 month
&lt;/h3&gt;

&lt;p&gt;for the past month, i’ve been focusing on building and marketing.&lt;br&gt;
i’ve never done marketing before. &lt;br&gt;
it’s not glamorous, but it’s all about small, consistent progress that eventually grows into something bigger.&lt;/p&gt;

&lt;p&gt;i started posting on X daily and gained over 100 new followers.&lt;br&gt;
i posted on Reddit to spread awareness of my app.&lt;br&gt;
i built an anonymous chat app called "One New Friend".&lt;/p&gt;

&lt;p&gt;so far, it has reached 1.5k installs (iOS + Android) and makes $13 MRR. honestly, this is the happiest moment ever for me.&lt;/p&gt;

&lt;p&gt;marketing feels plain at times, but it’s also surprisingly fun.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try my first app
&lt;/h3&gt;

&lt;p&gt;you can check out my app. it’s completely free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apps.apple.com/us/app/one-new-friend/id6747603019?platform=iphone" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.anonymous.oneNweFriend&amp;amp;pcampaignid=web_share" rel="noopener noreferrer"&gt;Android&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What’s next
&lt;/h3&gt;

&lt;p&gt;this journey is just beginning. &lt;/p&gt;

&lt;p&gt;i don’t know if I’ll succeed or fail, but i’m sure the experience will be 100% worth it.&lt;br&gt;
if you’re also planning to walk a similar path, let’s connect!&lt;/p&gt;

&lt;h3&gt;
  
  
  Product Hunt Launch 🎉
&lt;/h3&gt;

&lt;p&gt;almost forgot...&lt;br&gt;
i just launched my app on &lt;a href="https://www.producthunt.com/posts/one-new-friend?utm_source=other&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;it’s a big competition, so if you find my app interesting, i’d really appreciate your support and vote 🙏&lt;/p&gt;

&lt;p&gt;Happy coding!!&lt;/p&gt;

</description>
      <category>indiehacker</category>
      <category>producthunt</category>
      <category>solopreneur</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Implementing Authentication with Clerk in Next.js</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Mon, 14 Oct 2024 08:08:07 +0000</pubDate>
      <link>https://dev.to/atsushii/implementing-authentication-with-clerk-in-nextjs-71a</link>
      <guid>https://dev.to/atsushii/implementing-authentication-with-clerk-in-nextjs-71a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hello! I'm Atsushi, a cloud engineer working at a SaaS company in Tokyo. Recently, I implemented authentication features for my personal AI chatbot project using Clerk, an authentication service. I'd like to share the insights I gained from this experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Clerk?
&lt;/h2&gt;

&lt;p&gt;Clerk is a service that provides embeddable UI components, APIs, and an administrative dashboard for user authentication and management. It supports frontend frameworks like Next.js, React, and Remix.&lt;/p&gt;

&lt;p&gt;In addition to authentication features, Clerk offers UI components that make it easy to implement sign-in and login screens. It also integrates with services like Supabase and Firebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Account Creation
&lt;/h2&gt;

&lt;p&gt;To get started with Clerk:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign up at &lt;a href="https://clerk.com/" rel="noopener noreferrer"&gt;Clerk's website&lt;/a&gt; by clicking the "Get started" button.&lt;/li&gt;
&lt;li&gt;After creating an account, set up your application by providing a name and clicking "Create application".&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Implementing Authentication Screens
&lt;/h2&gt;

&lt;p&gt;Clerk provides UI components that make it easy to implement authentication screens. This guide focuses on implementation with Next.js using the App Router.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Set environment variables in &lt;code&gt;.env.local&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=xxx
   CLERK_SECRET_KEY=xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Set up the Clerk Provider in &lt;code&gt;app/layout.tsx&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ClerkProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@clerk/nextjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jaJP&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@clerk/localizations&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ClerkProvider&lt;/span&gt; &lt;span class="nx"&gt;localization&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;jaJP&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ClerkProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Implement Middleware in &lt;code&gt;middleware.ts&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;clerkMiddleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@clerk/nextjs/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;clerkMiddleware&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;matcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/((?!_next|[^?]*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/(api|trpc)(.*)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;],&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Standard Components
&lt;/h2&gt;

&lt;p&gt;Clerk provides ready-to-use components like &lt;code&gt;&amp;lt;SignUp /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;SignIn /&amp;gt;&lt;/code&gt; that can be easily implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SignUp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@clerk/nextjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SignUp&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom Implementation with React Hook Form
&lt;/h2&gt;

&lt;p&gt;For more control over the form, you can use React Hook Form with Clerk's helpers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a custom hook (&lt;code&gt;useSignInForm&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSignIn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@clerk/nextjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;zodResolver&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hookform/resolvers/zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

   &lt;span class="c1"&gt;// ... (schema and type definitions)&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useSignInForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isLoaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSignIn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="c1"&gt;// ... (form setup and submit handler)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a Form Provider:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSignInForm&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/hooks/sign-in/use-sign-in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SignInFormProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onHandleSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSignInForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

     &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormProvider&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onHandleSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/FormProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create the Form component:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useFormContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LoginForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFormContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
     &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Implement the login page:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SignInFormProvider&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/forms/sign-in/form-provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LoginForm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/forms/sign-in/login-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SignInPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SignInFormProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoginForm&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SignInFormProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Retrieving Authentication Information
&lt;/h2&gt;

&lt;p&gt;To get the user ID after sign-up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;currentUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@clerk/nextjs/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Clerk significantly simplifies the implementation of authentication features.&lt;br&gt;
Its flexibility allows for easy integration with popular tools like React Hook Form and Zod.&lt;br&gt;
However, for Next.js projects, alternatives like Auth.js or Supabase's built-in authentication should also be considered depending on the use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://clerk.com/docs" rel="noopener noreferrer"&gt;Clerk Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://authjs.dev/" rel="noopener noreferrer"&gt;Auth.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>clerk</category>
      <category>authentication</category>
      <category>reacthookform</category>
    </item>
    <item>
      <title>The Journey of Abandoning Ship2Post. Dreams, Challenges, and Lessons</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Sun, 21 Jan 2024 05:40:54 +0000</pubDate>
      <link>https://dev.to/atsushii/the-journey-of-abandoning-ship2post-dreams-challenges-and-lessons-15a0</link>
      <guid>https://dev.to/atsushii/the-journey-of-abandoning-ship2post-dreams-challenges-and-lessons-15a0</guid>
      <description>&lt;p&gt;As a software engineer, harbors the dream of creating their own service, stepping away from the 9 to 5 grind, and achieving financial independence. That dream led me to embark on an ambitious journey with Ship2Post, a project that began in September 2023. Today, with a heavy heart, I must announce that I'm discontinuing my work on this dream project. This blog post is not just a farewell to Ship2Post but a deep dive into the reasons for its sunset and the valuable lessons I learned along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Vision of Ship2Post
&lt;/h2&gt;

&lt;p&gt;Ship2Post was envisioned as a SaaS product designed to revolutionize how indie hackers market their work. The core idea was simple yet: automatically generate engaging tweets based on your GitHub commit messages or PR titles. I aimed to eliminate a significant pain point for indie hackers – the need for effective marketing to ensure their products don't end up unnoticed. The plan was to implement a subscription-based model for monetization, but sometimes, even the most well-thought-out plans encounter unforeseen challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Did I Stumble?
&lt;/h2&gt;

&lt;p&gt;The road to failure is paved with a variety of reasons, but for me, the predominant one was time. The sheer amount of time I invested in Ship2Post eventually led to exhaustion and a loss of motivation. AI-generated tweets, once a novel idea, became commonplace, diminishing the uniqueness of my service. This isn't my first rodeo – I've built and abandoned several projects for similar reasons. It's a simple yet profound realization: spending too much time can drain your passion.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech Behind the Dream
&lt;/h2&gt;

&lt;p&gt;In the world of startups, minimizing expenses is crucial. Here's a glimpse into the tech stack that powered Ship2Post, all within a shoestring budget of just $10, which was my only expense for testing the OpenAI API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chakra-ui.com/" rel="noopener noreferrer"&gt;ChakraUI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://openai.com/blog/openai-api" rel="noopener noreferrer"&gt;OpenAI API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://workers.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare Workers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  System Overview
&lt;/h2&gt;

&lt;p&gt;The architecture of Ship2Post was straightforward. Users would sign up and set up a GitHub Webhook, triggering upon commits or PR merges. These events would prompt Cloudflare Workers (our serverless solution) to generate and store tweets in the Supabase database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflecting on the Journey
&lt;/h2&gt;

&lt;p&gt;Building Ship2Post was an odyssey that tested my limits and taught me invaluable lessons. The primary takeaway is the importance of rapid development and deployment; dwelling too long on a project can be a recipe for lost motivation. Despite my MRR (Monthly Recurring Revenue) still being at zero, I remain committed to my dream of financial freedom through my creations.&lt;/p&gt;

&lt;p&gt;Thank you for joining me on this journey. Your support and readership mean the world to me.&lt;/p&gt;

&lt;h2&gt;
  
  
  P.S. I'm currently soaking up the sun in Cebu, Philippines. If you're around, let's connect and share stories over coffee! 🚀🌴
&lt;/h2&gt;

</description>
      <category>indiehacker</category>
      <category>cloudflare</category>
      <category>supabase</category>
    </item>
    <item>
      <title>Terraform import block to import AWS route53</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Sat, 13 Jan 2024 05:53:11 +0000</pubDate>
      <link>https://dev.to/atsushii/terraform-import-block-to-import-aws-route53-2jb0</link>
      <guid>https://dev.to/atsushii/terraform-import-block-to-import-aws-route53-2jb0</guid>
      <description>&lt;h2&gt;
  
  
  Write import block
&lt;/h2&gt;

&lt;p&gt;Define import block to import exist route53 resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// import.tf
import {
  to = aws_route53_record.example
  id = "{hostedZoneId}_{recordName}_{Type}"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run command
&lt;/h2&gt;

&lt;p&gt;Run tf command to output config to generated_resources.tf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform plan -generate-config-out=generated_resources.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;reference:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.hashicorp.com/terraform/language/import/generating-configuration" rel="noopener noreferrer"&gt;Terraform generating-configuration&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>route53</category>
    </item>
    <item>
      <title>Confused, Aggregate Transaction Boundaries in Domain-Driven Design</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Fri, 01 Dec 2023 13:00:09 +0000</pubDate>
      <link>https://dev.to/atsushii/confused-aggregate-transaction-boundaries-in-domain-driven-design-31a0</link>
      <guid>https://dev.to/atsushii/confused-aggregate-transaction-boundaries-in-domain-driven-design-31a0</guid>
      <description>&lt;h2&gt;
  
  
  What is an Aggregate?
&lt;/h2&gt;

&lt;p&gt;An aggregate is extracted as a unit to maintain invariant conditions and brings order to the operation of objects. It consists of boundaries and a root. The boundary of an aggregate defines what is included in the aggregate. The root of an aggregate is a specific object within it. All external operations on the aggregate are conducted via the aggregate root. By not exposing objects within the aggregate boundary to the outside, the invariant conditions within the aggregate are maintained.&lt;/p&gt;

&lt;p&gt;It is reasonable to consider aggregates as units of the repository&lt;/p&gt;

&lt;p&gt;e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;
&lt;span class="c"&gt;// aggregates&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserRepository&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="n"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Transaction Boundaries
&lt;/h2&gt;

&lt;p&gt;Scope of a Transaction.&lt;/p&gt;

&lt;p&gt;In DDD, it is ideal to consider an aggregate should be the same as a transaction boundary.&lt;/p&gt;

&lt;p&gt;Disadvantages of spanning transactions across aggregates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spanning a transaction across aggregates A and B expresses the start and end of the transaction in the application layer, obscuring the consistency level of each aggregate.&lt;/li&gt;
&lt;li&gt;Technical changes (like ORM or storage changes) necessitate modifications in the use case/domain layer, leading to fragile code.&lt;/li&gt;
&lt;li&gt;Spanning aggregates naturally widens the transaction scope, increasing the likelihood of db locks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;e.g.&lt;/p&gt;

&lt;p&gt;This sample code hides the creation/commit/rollback of tx in infrastructure, but is fragile due to its dependency on the db client in the use case/domain layer. It is sort of anti-pattern. will explain later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Infrastructure layer&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;TransactionRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runner&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Start transaction&lt;/span&gt;
    &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Rollback process&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rollback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Commit process&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Commit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;


&lt;span class="c"&gt;// Usecase layer&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;lessonUseCase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;TransactionSample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Has dependency with db client&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TransactionRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c"&gt;// Transaction processing here&lt;/span&gt;
        &lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;userRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;×××&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;userGroupRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;×××&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In real-world project, Of course, there are many challenging cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;e.g. Creating a User and also wanting to update a Organization etc...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solutions
&lt;/h2&gt;

&lt;h4&gt;
  
  
  1. Merge Aggregates
&lt;/h4&gt;

&lt;p&gt;If crossing aggregates with tx is problematic, merge them together (as seen in some DDD books).&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintains consistency within the aggregate
Disadvantages:&lt;/li&gt;
&lt;li&gt;Larger aggregates might lead to performance issues due to increased db locks

&lt;ul&gt;
&lt;li&gt;Merging different aggregates into one (e.g., A and B into C) complicates the code&lt;/li&gt;
&lt;li&gt;Application logic becomes more infrastructure-dependent. Hard to debug and loos testability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Eventual Consistency
&lt;/h4&gt;

&lt;p&gt;Accept temporary data breaches.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need to change aggregates - Transaction boundaries remain within existing aggregates, keeping the scope narrow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Temporary loss of consistency&lt;/li&gt;
&lt;li&gt;Implementing measures for maintaining consistency can be cumbersome&lt;/li&gt;
&lt;li&gt;Handling failures in mid-process (e.g. queue)

&lt;ul&gt;
&lt;li&gt;e.g. if creating a user succeeds but creating a organization fails, the user might be removed&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Handling failures in recovery&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Transaction Across Aggregates
&lt;/h3&gt;

&lt;p&gt;This is an anti-pattern.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintains consistency&lt;/li&gt;
&lt;li&gt;No need to modify aggregates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fragile to changes&lt;/li&gt;
&lt;li&gt;Wider transaction scope may lead to locks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This post delves into the intricacies of aggregate transaction boundaries within DDD, highlighting the balance between consistency, performance, and system design. Practical solutions and their trade-offs are discussed, providing insights for effective DDD implementation in real-world scenarios.&lt;/p&gt;

&lt;p&gt;Honestly, I am still confused and don't know solution. It is really depends on you and your team.&lt;br&gt;
Also I did not mention about modeling in this time. I think modeling is key factor to find better solution.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>ddd</category>
      <category>go</category>
      <category>transaction</category>
    </item>
    <item>
      <title>Step-by-Step Guide. Hosting Your Application on AWS S3</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Mon, 22 May 2023 05:39:39 +0000</pubDate>
      <link>https://dev.to/atsushii/step-by-step-guide-hosting-your-application-on-aws-s3-2gbj</link>
      <guid>https://dev.to/atsushii/step-by-step-guide-hosting-your-application-on-aws-s3-2gbj</guid>
      <description>&lt;p&gt;Are you considering hosting your Next.js static web application on AWS? If so, this article is for you! In this article, I will walk you through the process of setting up AWS S3 and CloudFront for hosting your Next.js application using Terraform. Additionally, I will explain how to establish a robust CI/CD pipeline to seamlessly deploy your application to AWS. By following this step-by-step guide, you'll gain valuable insights and practical knowledge to efficiently host your Next.js application on AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Why you should consider hosting CloudFront with S3?&lt;br&gt;
Because it significantly reduces latency, ensuring faster content delivery to end-users. Also, this combination can help reduce costs associated with data transfer and it enhances security measures for your content.&lt;br&gt;
Setting up continuous integration and continuous deployment (CI/CD) to deploy your application becomes easier too.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is S3?
&lt;/h2&gt;

&lt;p&gt;AWS provides a storage service called S3, which allows you to store data in the form of objects within buckets. Additionally, S3 can be used to host static websites.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is CloudFront?
&lt;/h2&gt;

&lt;p&gt;CloudFront is a well-known content delivery service, often referred to as a CDN. Its primary function is to efficiently distribute your content to end-users, ensuring fast delivery. One of the main advantages of using CloudFront is that it serves content from edge locations. This means that if your content is already available at an edge location, it can be delivered to users with minimal latency. If the content is not present at an edge location, CloudFront retrieves it from the origin, which in this case would be S3.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's start creating CloudFront and S3 by Terraform!
&lt;/h2&gt;

&lt;p&gt;There are 5 steps to deploy your application on Kubernetes with GitHub Actions and ArgoCD.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup AWS Provider&lt;/li&gt;
&lt;li&gt;Create the S3 bucket&lt;/li&gt;
&lt;li&gt;Create the CloudFront&lt;/li&gt;
&lt;li&gt;Setup CI/CD&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NOTE:&lt;br&gt;
You need to set your aws credential in &lt;code&gt;(~/.aws/credentials)&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Setup AWS Provider
&lt;/h2&gt;

&lt;p&gt;Configure to execute AWS by Terraform&lt;/p&gt;

&lt;p&gt;&amp;lt;/&amp;gt; provider.tf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~&amp;gt; 4.0"
    }
  }
  required_version = "&amp;gt;= 1.0"
}

provider "aws" {
  region = "ap-northeast-1"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Create the S3 bucket
&lt;/h2&gt;

&lt;p&gt;&amp;lt;/&amp;gt; s3.tf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
resource "aws_s3_bucket" "bucket" {
  bucket = test-bucket
}

resource "aws_s3_bucket_cors_configuration" "cors_config" {
  bucket = aws_s3_bucket.bucket.id

  cors_rule {
    allowed_headers = ["*"]
    allowed_methods = ["GET", "POST", "PUT", "DELETE", "HEAD"]
    allowed_origins = ["https://set-origin"]
    expose_headers  = ["ETag"]
    max_age_seconds = 3000
  }
}

resource "aws_s3_bucket_ownership_controls" "example" {
  bucket = aws_s3_bucket.bucket.id
  rule {
    object_ownership = "ObjectWriter"
  }
}

resource "aws_s3_bucket_acl" "acl" {
  depends_on = [aws_s3_bucket_ownership_controls.example]

  bucket = aws_s3_bucket.bucket.id
  acl    = "private"
}

data "aws_iam_policy_document" "policy" {
  statement {
    actions = [
      "s3:GetObject",
    ]

    resources = [
      "${aws_s3_bucket.bucket.arn}/*",
    ]

    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values   = [aws_cloudfront_distribution.this.arn]
    }
  }
}

resource "aws_s3_bucket_policy" "bucket" {
  bucket = aws_s3_bucket.bucket.id
  policy = data.aws_iam_policy_document.policy.json
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;aws_s3_bucket_cors_configuration

&lt;ul&gt;
&lt;li&gt;To enable Cross-Origin Resource Sharing (CORS) and allow loading resources from one domain to interact with resources in a different domain.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;aws_s3_bucket_acl

&lt;ul&gt;
&lt;li&gt;Set private to disable public access.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;aws_iam_policy_document

&lt;ul&gt;
&lt;li&gt;To restrict access to only the &lt;code&gt;s3:GetObject&lt;/code&gt; action from CloudFront and exclude other policies for content delivery.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Create the CloudFront
&lt;/h2&gt;

&lt;p&gt;&amp;lt;/&amp;gt; cloudfront.tf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_cloudfront_origin_access_control" "origin" {
  name                              = "cf-origin-access-control"
  description                       = "access to s3 bucket"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

resource "aws_cloudfront_distribution" "static" {
  default_root_object = "index.html"
  enabled             = true
  price_class         = "PriceClass_200"

  origin {
    domain_name              = aws_s3_bucket.bucket.bucket_regional_domain_name
    origin_id                = "s3-bucket"
    origin_access_control_id = aws_cloudfront_origin_access_control.origin.id
  }

  default_cache_behavior {
    allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods  = ["GET", "HEAD"]

    forwarded_values {
      cookies {
        forward = "none"
      }
      query_string = "false"
    }

    max_ttl                = 86400
    min_ttl                = 0
    target_origin_id       = "s3-bucket"
    viewer_protocol_policy = "redirect-to-https"
  }

  restrictions {
    geo_restriction {
      locations        = []
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;aws_cloudfront_origin_access_control

&lt;ul&gt;
&lt;li&gt;Configure the origin type as S3.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;aws_cloudfront_distribution

&lt;ul&gt;
&lt;li&gt;Create a CloudFront distribution and set the origin to a previously created S3 bucket.&lt;/li&gt;
&lt;li&gt;To use a custom domain with CloudFront, you can configure your domain by setting it in the viewer_certificate section of your CloudFront distribution settings. In this case, you will be using the CloudFront domain for your custom domain setup.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Setup CI/CD
&lt;/h2&gt;

&lt;p&gt;&amp;lt;/&amp;gt; deploy.yaml&lt;/p&gt;

&lt;p&gt;Creating CI/CD using GitHub Actions allows you to automate the build process and upload files to S3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on:
  push:
    branches: [release]

permissions:
  id-token: write
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18]
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: yarn
      - run: yarn
      - run: yarn build
      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: build
          path: dist/
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v3
        with:
          name: build
          path: dist/

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/gha-oidc-role
          aws-region: ap-northeast-1

      - name: Publish
        uses: opspresso/action-s3-sync@master
        env:
          AWS_REGION: ap-northeast-1
          FROM_PATH: dist/
          DEST_PATH: s3://bucket

      - name: Invalidate CF
        uses: chetan/invalidate-cloudfront-action@v2
        env:
          AWS_REGION: ap-northeast-1
          DISTRIBUTION: distributionId
          PATHS: /*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Upload and Download artifact

&lt;ul&gt;
&lt;li&gt;To share data between jobs, you can utilize the &lt;code&gt;actions/upload-artifact@v3&lt;/code&gt; action.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Configure AWS credentials

&lt;ul&gt;
&lt;li&gt;To configure AWS credentials based on your IAM role, you can utilize the &lt;code&gt;aws-actions/configure-aws-credentials@v1-node16&lt;/code&gt; action.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Publish

&lt;ul&gt;
&lt;li&gt;To publish your built file, you can utilize the &lt;code&gt;opspresso action-s3-sync@master&lt;/code&gt; action.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Invalidate CF

&lt;ul&gt;
&lt;li&gt;To remove a file from CloudFront edge caches, you can utilize the &lt;code&gt;chetan/invalidate-cloudfront-action@v2&lt;/code&gt; action.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You have learned how to host and deploy your application using Terraform and GitHub Actions, taking advantage of the managed services provided by AWS such as S3 and CloudFront. With this setup, you can easily manage and scale your application without the need for manual infrastructure management. By following the steps outlined in this article, you can confidently host your application on AWS.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/s3/index.html" rel="noopener noreferrer"&gt;Amazon Simple Storage Service Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html" rel="noopener noreferrer"&gt;Invalidating files - Amazon CloudFront&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cloudfront/index.html" rel="noopener noreferrer"&gt;Amazon CloudFront Documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>cicd</category>
      <category>deploy</category>
      <category>aws</category>
    </item>
    <item>
      <title>Sync Github issue to Jira via GitHub Actions (GHA)</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Sun, 07 May 2023 13:12:31 +0000</pubDate>
      <link>https://dev.to/atsushii/sync-github-issue-to-jira-via-github-actions-gha-5ffb</link>
      <guid>https://dev.to/atsushii/sync-github-issue-to-jira-via-github-actions-gha-5ffb</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I built action to help the OSS maintainer easily manage certain issues on Jira.&lt;/p&gt;

&lt;p&gt;I assume most of the OSS project has a similar process to accept the issue. For instance, if the user creates a new issue then the core maintainer will check the new issue including the content, format, etc.. if the new issue is appropriate the maintainer adds a label as showing accepted.&lt;/p&gt;

&lt;p&gt;I found the problem during this process. &lt;br&gt;
Most OSS maintainers want to manage certain issues such as critical bugs using ticketing software such as Jira however  managing certain issues on Jira can be a time-consuming task. Especially when the OSS is used by many developers. Because a lot of issues can be created by users.&lt;/p&gt;

&lt;p&gt;So I create the action to sync the Github issue to Jira automatically when the maintainer is labeled to issue as accepted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;Maintainer Must-Haves&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/github-issue-sync-2-jira" rel="noopener noreferrer"&gt;https://github.com/marketplace/actions/github-issue-sync-2-jira&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6k32hkecp2f6lskimuj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6k32hkecp2f6lskimuj.png" alt="github-actions-market" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;p&gt;This action helps to sync github issue to Jira automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An example of using a this action is when a label is applied to a GitHub issue, triggering the action to automatically synchronize the issue with Jira.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A custom label can be utilized as a sync/skipping.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Feature
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Sync Github issue to Jira&lt;/li&gt;
&lt;li&gt;A custom acceptance label can be utilized as a synchronization target.&lt;/li&gt;
&lt;li&gt;A custom synced label can be utilized as a synchronization/skipping.&lt;/li&gt;
&lt;li&gt;By applying a custom Jira issue type to a Jira ticket, it can be utilized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The action will first check if the labeled issue exists, then fetch the attached labels to check if the issue is already accepted by the organizer or checked already synced to Jira.&lt;br&gt;
If the already attached synced label, the action will skip the whole process. Otherwise, the action will create a new Jira issue based on the Github issue and send a request to Jira to create a new Jira issue by using Jira rest API.&lt;/p&gt;

&lt;h4&gt;
  
  
  Basic Usage
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sync issues to jira&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;labeled&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;&lt;span class="s"&gt;　# should be set&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;issue-sync&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt; &lt;span class="c1"&gt;# should be set&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sync to Jira&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atsushii/github-issue-to-jira@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github-owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-owner&lt;/span&gt;
          &lt;span class="na"&gt;github-repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;repository-name&lt;/span&gt;
          &lt;span class="na"&gt;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt; &lt;span class="c1"&gt;# read/write authorized token&lt;/span&gt;
          &lt;span class="na"&gt;jira-hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hostname&lt;/span&gt; &lt;span class="c1"&gt;# Your Sync dest Jira hostname&lt;/span&gt;
          &lt;span class="na"&gt;jira-auth-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.JIRA_AUTH_TOKEN }}&lt;/span&gt; &lt;span class="c1"&gt;# Your Jira auth token&lt;/span&gt;
          &lt;span class="na"&gt;jira-auth-email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.JIRA_AUTH_EMAIL }}&lt;/span&gt; &lt;span class="c1"&gt;# email same as jira project creator&lt;/span&gt;
          &lt;span class="na"&gt;jira-project-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;project-key&lt;/span&gt; &lt;span class="c1"&gt;# Your Sync dest Jira project name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/atsushii/github-issue-to-jira" rel="noopener noreferrer"&gt;https://github.com/atsushii/github-issue-to-jira&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/atsushii/github-issue-to-jira/blob/main/LICENSE" rel="noopener noreferrer"&gt;https://github.com/atsushii/github-issue-to-jira/blob/main/LICENSE&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background (What made you decide to build this particular app? What inspired you?)
&lt;/h2&gt;

&lt;p&gt;As a software engineer who frequently uses Github Actions, I was inspired to create and publish my own custom action. Additionally, since I began contributing to open-source projects, I have found it to be a very rewarding experience. As a result, I wanted to alleviate the pain of OSS maintainers by leveraging technology to the fullest extent possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it (How did you utilize GitHub Actions or GitHub Codespaces? Did you learn something new along the way? Pick up a new skill?)
&lt;/h3&gt;

&lt;p&gt;I started by researching how to sync Github issues to Jira and after a few hours of consideration, I realized that Github Actions would be a good way to implement this feature. This was my first time building and releasing a custom action, and I also had no prior experience using Jira, so I had to learn how to create a token to call the Jira API. To do this, I read the Jira REST API documentation and the GitHub documentation on creating and releasing custom actions.&lt;/p&gt;

&lt;p&gt;Throughout the process, I gained new knowledge and skills, which made the experience even more enjoyable. I always find it exciting to learn new things and improve my abilities, and I'm looking forward to continuing to develop and release new versions of my custom action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I'm a Japanese developer, Let's discuss technology while eating sushi 🍣 🍣 &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>githubhack23</category>
      <category>githubactions</category>
      <category>jira</category>
    </item>
    <item>
      <title>Deploy Your Application to ECS via CI/CD with Ecspresso</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Mon, 01 May 2023 00:58:04 +0000</pubDate>
      <link>https://dev.to/atsushii/deploy-your-application-to-ecs-via-cicd-with-ecspresso-34n0</link>
      <guid>https://dev.to/atsushii/deploy-your-application-to-ecs-via-cicd-with-ecspresso-34n0</guid>
      <description>&lt;p&gt;Are you interested in deploy your application to ECS via CI/CD?&lt;br&gt;
if so, ecspresso is tool for you!&lt;/p&gt;
&lt;h2&gt;
  
  
  What is ecspresso?
&lt;/h2&gt;

&lt;p&gt;ecspresso is a tool that helping to deploy your application to ECS,&lt;br&gt;
And easy to integrate it into your CI/CD easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kayac/ecspresso" rel="noopener noreferrer"&gt;ecspresso&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;Why you should consider using ecspresso for the deployment of your application to ECS rather than another deployment tool?&lt;br&gt;
Because ecspresso can manage your ECS resource as code. Why is that useful?&lt;br&gt;
Imagine, your team deploy frequently your application and there is a moment to change ECS configuration relates to the application such as memory or CPU, etc.. If you could manage your ECS resources as code, possible to change the configuration in every deployment easily.&lt;br&gt;
Just remain, this tool is for you who manage infra resources using Terraform or a tool such as CloudFormation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Usage: ecspresso &amp;lt;command&amp;gt;

Flags:
  -h, --help                      Show context-sensitive help.
      --envfile=ENVFILE,...       environment files
      --debug                     enable debug log
      --ext-str=KEY=VALUE;...     external string values for Jsonnet
      --ext-code=KEY=VALUE;...    external code values for Jsonnet
      --config="ecspresso.yml"    config file
      --assume-role-arn=""        the ARN of the role to assume
      --option=OPTION

Commands:

  - deploy
    - deploy service
  - diff
    - show diff between task definition, service definition with current running service and task definition
  - exec
    - execute command on task
  - init --service=SERVICE
    - create configuration files from existing ECS service
  - register
    - register task definition
  - rollback
    - rollback service
  - run
    - run task
  - wait
    - wait until service stable

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  How to Integrate ecspresso into CI/CD?
&lt;/h2&gt;

&lt;p&gt;I will explain to you step by step!&lt;/p&gt;

&lt;p&gt;NOTE:&lt;br&gt;
You need to set your aws credential &lt;code&gt;(~/.aws/credentials)&lt;/code&gt;&lt;br&gt;
Assume your ECS is already running on AWS&lt;/p&gt;
&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// brew
brew install kayac/tap/ecspresso

or

// asdf
asdf plugin add ecspresso
asdf install ecspresso 2.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Init to generate yml file
&lt;/h2&gt;

&lt;p&gt;Import your current ECS service setting to yml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ecspresso init --region ap-northeast-1 --cluster your-cluster-name --service your-service-name --config ecspresso.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the above command, you can see below generated files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- ecspresso.yml
- ecs-service-def.json
- ecs-task-def.json.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Import your tfstate
&lt;/h2&gt;

&lt;p&gt;Possible to write some external resource information such as VPC, security group Id and etc...&lt;br&gt;
However, it will decrease maintainability and readability. ecspresso allows to read tfstate to solve this problem!&lt;/p&gt;

&lt;p&gt;You can set your file path to tfstate in ecspresso.yml and then able to read it inside .json file.&lt;br&gt;
prefer set func_prefix.&lt;/p&gt;

&lt;p&gt;ecspresso.yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;region: ap-northeast-1
cluster: your-cluster-name
service: your-service-name
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: "10m0s"
plugins:
  - name: tfstate
    config:
      url: s3://path-to-terraform.tfstate
    func_prefix: sg
  - name: tfstate
    config:
      url: s3://path-to-terraform.tfstate
    func_prefix: network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ecs-service-def.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "networkConfiguration": {
    "awsvpcConfiguration": {
      "assignPublicIp": "DISABLED",
      "securityGroups": [
        "{{ sg_tfstate `aws_security_group.service.id` }}"
      ],
      "subnets": [
        "{{ network_tfstate `aws_subnet.private['private'].id` }}",
      ]
    }
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup ci/cd
&lt;/h2&gt;

&lt;p&gt;It is simple but one important thing is that most cases, want to set the latest image for ECS task so&lt;br&gt;
need to set the latest image dynamically.&lt;/p&gt;

&lt;p&gt;Look at the &lt;code&gt;export IMAGE_TAG=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG&lt;/code&gt;&lt;br&gt;
I define IMAGE_TAG. It will be key.&lt;br&gt;
In ecs-task-def.json you can use must_env and IMAGE_TAG will dynamically load!&lt;/p&gt;

&lt;p&gt;ecs-task-def.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "image": "{{ must_env `IMAGE_TAG` }}",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHubActions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: checkout
        uses: actions/checkout@v3

      - name: configure aws credentials
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/role
          aws-region: ap-northeast-1

      - name: login to ecr
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - uses: actions/checkout@v3
      - uses: kayac/ecspresso@v2
        with:
          version: v2.0.0 # or latest
          # version-file: .ecspresso-version

      - name: deploy
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: dev
          IMAGE_TAG: api-${{ github.sha }}
        run: |
            export IMAGE_TAG=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
            ecspresso deploy --config ecspresso/ecspresso.yal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;ecspresso is helpful to manage and deploy your application to ECS.&lt;br&gt;
You can manage your ECS resources as code and easy to integrate your deployment flow into CI/CD&lt;/p&gt;

&lt;p&gt;Thank you for reading my article, Happy Coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/kayac/ecspresso" rel="noopener noreferrer"&gt;kayac/ecspresso: ecspresso is a deployment tool for Amazon ECS&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ecs</category>
      <category>deploy</category>
      <category>cicd</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>K9s to managing your k8s cluster</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Fri, 31 Mar 2023 03:20:43 +0000</pubDate>
      <link>https://dev.to/atsushii/k9s-to-managing-your-k8s-cluster-970</link>
      <guid>https://dev.to/atsushii/k9s-to-managing-your-k8s-cluster-970</guid>
      <description>&lt;p&gt;Are you tired of managing and debugging your Kubernetes cluster? If so, K9s is a tool for you!&lt;/p&gt;

&lt;h3&gt;
  
  
  What is K9s?
&lt;/h3&gt;

&lt;p&gt;K9s provides a terminal UI to interact with your Kubernetes clusters. You can manage your cluster easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install derailed/k9s/k9s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic usage
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;exec ctx&lt;/li&gt;
&lt;li&gt;exec pods&lt;/li&gt;
&lt;li&gt;exec node group&lt;/li&gt;
&lt;li&gt;exec svc&lt;/li&gt;
&lt;li&gt;port-forwards&lt;/li&gt;
&lt;li&gt;logs&lt;/li&gt;
&lt;li&gt;delete resource&lt;/li&gt;
&lt;li&gt;describe resource
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command:
  :ctx,                         list contexts
  :pods,                        list pods
  :node,                        list node
  :svc,                         list service
  y,                            show resource manifest
  d,                            kubectl describe
  ctrl-d,                       delete resource
  l,                            show logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  why use?
&lt;/h2&gt;

&lt;p&gt;Based on my experience Managing Kubernetes is hard without UI. Then I found this awesome OSS. is quite helpful, It will save you time in managing and debugging your cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This tool is quite helpful for managing and debugging your k8s!&lt;/p&gt;

&lt;p&gt;Thank you for reading my article, Happy Coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/derailed/k9s" rel="noopener noreferrer"&gt;derailed/k9s: 🐶 Kubernetes CLI To Manage Your Clusters In Style!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>k8s</category>
      <category>devops</category>
      <category>tool</category>
    </item>
    <item>
      <title>Execute ECS task by ecsta</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Thu, 16 Mar 2023 12:53:35 +0000</pubDate>
      <link>https://dev.to/atsushii/execute-ecs-task-by-ecsta-44io</link>
      <guid>https://dev.to/atsushii/execute-ecs-task-by-ecsta-44io</guid>
      <description>&lt;p&gt;Are you tired of debugging when you use an ECS? If so, ecsta is a tool for you!&lt;br&gt;
ecsta is to help you execute the ECS container by cmd.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is ecsta?
&lt;/h2&gt;

&lt;p&gt;ecsta is a tool that you can use to execute your ecs tasks, such as describing, listing, and even port forwarding your ecs task easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/fujiwara/ecsta" rel="noopener noreferrer"&gt;fujiwara/ecsta: ECS Task Assistant tool.&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;list tasks&lt;/li&gt;
&lt;li&gt;describe task&lt;/li&gt;
&lt;li&gt;exec task&lt;/li&gt;
&lt;li&gt;portforward task&lt;/li&gt;
&lt;li&gt;stop task&lt;/li&gt;
&lt;li&gt;trace task&lt;/li&gt;
&lt;li&gt;logs
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Usage: ecsta &amp;lt;command&amp;gt;

Flags:
  -h, --help                        Show context-sensitive help.
  -c, --cluster=STRING              ECS cluster name ($ECS_CLUSTER)
  -r, --region=STRING               AWS region ($AWS_REGION)
  -o, --output="table"              output format (table, tsv, json) ($ECSTA_OUTPUT)
  -q, --task-format-query=STRING    A jq query to format task in selector
                                    ($ECSTA_TASK_FORMAT_QUERY)

Commands:
  configure
    Create a configuration file of ecsta

  describe
    Describe tasks

  exec
    Execute a command on a task

  list
    List tasks

  logs
    Show log messages of a task

  portforward --local-port=INT --remote-port=INT
    Forward a port of a task

  stop
    Stop a task

  trace
    Trace a task

  version
    Show version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  How to use?
&lt;/h2&gt;

&lt;p&gt;I will show you some features&lt;/p&gt;

&lt;p&gt;NOTE: you need to set your aws credential &lt;code&gt;(~/.aws/credentials)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install fujiwara/tap/ecsta
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  List task
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ecsta list -c cluster-name -s service-name

|                ID                | TASKDEFINITION  | INSTANCE | LASTSTATUS | DESIREDSTATUS |         CREATEDAT         |         GROUP         |  TYPE   |
+----------------------------------+-----------------+----------+------------+---------------+
| 12e1e24342a6bddddbf148393ab6e4cf3 | task-definition:1 |          | RUNNING    | RUNNING       | 2023-03-16T00:00:00+09:00 | service:service-name | FARGATE |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Exec task
&lt;/h3&gt;

&lt;p&gt;This command is wrapper of &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/userguide/ecs-exec.html" rel="noopener noreferrer"&gt;ECS Exec&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ecsta exec --service=service-name --container=container-name

Enter cluster name: cluster-name
Enter task ID: 12e1e24342a6bddddbf148393ab6e4cf3

Starting session with SessionId: ecs-execute-command-0dvv124623eaaf0f
/api #

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This tool is quite helpful to exec your ecs task!&lt;/p&gt;

&lt;p&gt;Thank you for reading my article, Happy Coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/userguide/ecs-exec.html" rel="noopener noreferrer"&gt;Using Amazon ECS Exec for debugging - Amazon ECS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/fujiwara/ecsta" rel="noopener noreferrer"&gt;fujiwara/ecsta: ECS Task Assistant tool.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ecs</category>
      <category>tool</category>
      <category>aws</category>
    </item>
    <item>
      <title>Kubernetes CI/CD With GHA and ArgoCD</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Mon, 13 Mar 2023 07:48:11 +0000</pubDate>
      <link>https://dev.to/atsushii/kubernetes-cicd-with-gha-and-argocd-4ob4</link>
      <guid>https://dev.to/atsushii/kubernetes-cicd-with-gha-and-argocd-4ob4</guid>
      <description>&lt;p&gt;Nowadays, most companies try to implement CI/CD pipelines to deploy applications to be easier. But how to implement it?&lt;br&gt;
This article shows how to implement it to deploy your application on Kubernetes with GitHub Actions and ArgoCD.&lt;br&gt;
I hope it can help your deployment process easier.&lt;/p&gt;

&lt;p&gt;Before starting, Let me explain about what is GitOps. Because I will follow this methodology.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is GitOps?
&lt;/h2&gt;

&lt;p&gt;GitOps is an operational framework that takes DevOps best practices used for application development such as version control, collaboration, compliance, and CI/CD tooling, and applies them to infrastructure automation. GitOps was first coined by Weaveworks.&lt;/p&gt;

&lt;p&gt;Based on that I will implement like below CI/CD.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq13f5ycj7s95ru8e1wdq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq13f5ycj7s95ru8e1wdq.png" alt="Gitops" width="659" height="414"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's start building the CI/CD!
&lt;/h2&gt;

&lt;p&gt;There are 5 steps to deploy your application on Kubernetes with GitHub Actions and ArgoCD.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build CI

&lt;ol&gt;
&lt;li&gt;Login to ECR&lt;/li&gt;
&lt;li&gt;Build docker image and push it to ECR&lt;/li&gt;
&lt;li&gt;Update manifest file in manifest file repository&lt;/li&gt;
&lt;li&gt;Create PR&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Prepare Manifest file&lt;/li&gt;
&lt;li&gt;Build CD&lt;/li&gt;
&lt;li&gt;Recap
5.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  1. Build CI
&lt;/h2&gt;

&lt;p&gt;The first step is building the CI by using Github Actions. yaml file should be in application source code repository.&lt;/p&gt;

&lt;p&gt;During CI, we can do testing, building docker, push docker image to repository and update manifest file!&lt;br&gt;
You must create ECR on AWS and IAM role to login and push docker image to ECR. I will omit these part in this time.&lt;/p&gt;

&lt;p&gt;Complete GHA file is below. I will explain each step by step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on:
  push:
    branches: [deploy/stg]

permissions:
  id-token: write
  contents: read

jobs:
  prepare:
    name: code-deploy
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ secrets.IAM_ROLE }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: login to Amazon ECR
        id: ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: docker build and push
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.ecr.outputs.registry }}
          ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -f ./Dockerfile -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG --target release .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

      - name: fetch manifest repository
        uses: actions/checkout@v3
        with:
          repository: github-organization/manifest-repository
          token: ${{ secrets.PAT }}
          path: manifest-repo
          fetch-depth: 1

      - name: update manifest file image tag
        run: |
          wget -q https://github.com/mikefarah/yq/releases/download/v4.27.5/yq_linux_amd64
          sudo mv yq_linux_amd64 /usr/local/bin/yq
          sudo chmod +x /usr/local/bin/yq
          yq e -i '.spec.template.spec.containers[0].image |= "${{ steps.build-image.outputs.image }}"' 'manifest-repo/k8s/sample/dev/deployment.yaml'

      - name: setup Repository
        working-directory: manifest-repo
        run: |
          git fetch origin main
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          git remote set-url --push origin https://github.com/***/manifest-repo.git
          git checkout -b release-${{ github.sha }}

      - name: commit
        working-directory: manifest-repo
        run: |
          git add .
          git commit -m "Release bff-admin"
          git push origin HEAD
      - name: create PR
        working-directory: manifest-repo
        run: |
          gh pr create -B main -H release-${{ github.sha }} -t "deploy-${{ github.sha }}" -b ""
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Login to ECR
The security reason, you must avoid to pass your access key and secret key. Instead pass credential, we can use GitHub's OIDC provider in conjunction with a configured AWS IAM Identity Provider endpoint. You must create Assume role and set it to &lt;code&gt;role-to-assume&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: ${{ secrets.IAM_ROLE }}
        aws-region: ${{ secrets.AWS_REGION }}

    - name: login to Amazon ECR
      id: ecr
      uses: aws-actions/amazon-ecr-login@v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ref: &lt;a href="https://github.com/aws-actions/configure-aws-credentials" rel="noopener noreferrer"&gt;aws-actions/configure-aws-credentials&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build docker image and push it to ECR
The next step, build a docker image and push it to ECR. I prefer to import the registry name and repository name from secret.
After setting these variables, run the docker command to build and push to ECR.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    - name: docker build and push
      id: build-image
      env:
        ECR_REGISTRY: ${{ steps.ecr.outputs.registry }}
        ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }}
        IMAGE_TAG: ${{ github.sha }}
      run: |
        docker build -f ./Dockerfile -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG --target target .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update manifest file in manifest file repository
After pushing the docker image, do update the manifest file to create PR to the manifest repository. Assume the manifest repository manages your k8s manifest files.
At the first, fetch the latest code from the manifest repository, and after that update file using &lt;a href="https://github.com/mikefarah/yq" rel="noopener noreferrer"&gt;yq&lt;/a&gt;.
We just need to update the container image to the newest image which we uploaded to ECR in the previous step.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: fetch manifest repository
        uses: actions/checkout@v3
        with:
          repository: github-organization/manifest-repository
          token: ${{ secrets.PAT }}
          path: manifest-repo
          fetch-depth: 1

      - name: update manifest file image tag
        run: |
          wget -q https://github.com/mikefarah/yq/releases/download/v4.27.5/yq_linux_amd64
          sudo mv yq_linux_amd64 /usr/local/bin/yq
          sudo chmod +x /usr/local/bin/yq
          yq e -i '.spec.template.spec.containers[0].image |= "${{ steps.build-image.outputs.image }}"' 'manifest-repo/k8s/sample/dev/deployment.yaml'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create PR
After updating the manifest file, finally, create PR to trigger CD. Merging PR can be your deploy your latest code to the production environment.
I use gh to create PR.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: commit
      working-directory: manifest-repo
      run: |
        git add .
        git commit -m "Release bff-admin"
        git push origin HEAD
    - name: create PR
      working-directory: manifest-repo
      run: |
        gh pr create -B main -H release-${{ github.sha }} -t "deploy-${{ github.sha }}" -b ""

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Prepare Manifest file
&lt;/h2&gt;

&lt;p&gt;Prepare the manifest file in the manifest repository. It will update by CI.&lt;br&gt;
Below is a sample manifest file.&lt;br&gt;
You must create namespace first. This time I create deploy-test.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;manifest-repository/k8s/deploy-test/deployment.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-test
  namespace: deploy-test
spec:
  selector:
    matchLabels:
      app: deploy-test
  template:
    metadata:
      labels:
        app: deploy-test
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: eks.amazonaws.com/nodegroup
                operator: In
                values:
                  - sample-ng
      containers:
        - name: deploy-test
          image: yourAccountId.dkr.ecr.yourRegion.amazonaws.com/yourRepositoryName:yourImageTag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember, during CI, I use yq to update the image tag. the update part is &lt;code&gt;yourImageTag&lt;/code&gt;.&lt;br&gt;
So your pod will pull the latest image from ECR after PR is merged.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    containers:
        - name: deploy-test
          image: yourAccountId.dkr.ecr.yourRegion.amazonaws.com/yourRepositoryName:yourImageTag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Build CD
&lt;/h2&gt;

&lt;p&gt;Finally, build a CD using ArgoCD!&lt;/p&gt;

&lt;p&gt;*You must create namespace and cluster.&lt;/p&gt;

&lt;p&gt;The first step is to set up a GitHub access token to access the cluster to your repository.&lt;/p&gt;

&lt;p&gt;You can type the below cmd to set your GitHub token to your cluster.&lt;br&gt;
This time namespace that I set is argocd.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export GITHUB_TOKEN=&amp;lt;github-token&amp;gt;
kubectl create secret generic github-cred -n argocd \
  --from-literal url=https://github.com/${GITHUB_USER}/manifest-repository \
  --from-literal username=&amp;lt;github-user&amp;gt; \
  --from-literal password=${GITHUB_TOKEN} \
  --from-literal name=github-cred
kubectl label secret task-tool-cluster-config-cred argocd.argoproj.io/secret-type=repository -n argoc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then write argocd manifest file.&lt;br&gt;
file path is &lt;code&gt;manifest-repository/k8s/deploy-test/argocd/deploy.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: deploy-test
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/${GITHUB_USER}/manifest-repository
    targetRevision: main
    path: k8s/deploy-test
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
  destination:
    server: https://kubernetes.default.svc
    namespace: deploy-test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ArgoCD will sync with the repository that you set on &lt;code&gt;spec.source&lt;/code&gt; part.&lt;/p&gt;

&lt;p&gt;After all setup, finally, apply it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f k8s/deploy-test/argocd/deploy.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!!! you are all done setting CI/CD!&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Recap
&lt;/h2&gt;

&lt;p&gt;You created an application source code repository and manifest repository.&lt;br&gt;
In the source code repo, we added CI to build and push the docker image to ECR, update the manifest file, and create PR.&lt;/p&gt;

&lt;p&gt;You can manage your deployment whether you merge PR. After merging PR, ArgoCD will sync with your newest code.&lt;br&gt;
The pod will replace to newest image from ECR!&lt;/p&gt;

&lt;p&gt;Thank you for reading my article, Happy Coding!&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.weave.works/technologies/gitops/#what-is-gitops" rel="noopener noreferrer"&gt;Guide To GitOps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://about.gitlab.com/topics/gitops/" rel="noopener noreferrer"&gt;What is GitOps? | GitLab&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>cicd</category>
      <category>argocd</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Automate your post to dev.to by using Github Actions</title>
      <dc:creator>Atsushi Miyamoto</dc:creator>
      <pubDate>Thu, 23 Feb 2023 12:22:04 +0000</pubDate>
      <link>https://dev.to/atsushii/automate-your-post-to-devto-by-using-github-actions-2jkm</link>
      <guid>https://dev.to/atsushii/automate-your-post-to-devto-by-using-github-actions-2jkm</guid>
      <description>&lt;p&gt;I've automated dev.to posting by using GitHub Actions and golang. Also, blog content is markdown-based managing. So you can write your blog content using your favourite IDE. Hope this solution is to improve some people's productivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  How many minutes to set up?
&lt;/h2&gt;

&lt;p&gt;It might take only 5 minutes to set up your dev.to post automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's start setting up!
&lt;/h2&gt;

&lt;p&gt;You can copy my template repo from my &lt;a href="https://github.com/atsushii/dev.to."&gt;GitHub&lt;/a&gt; or create your original.&lt;/p&gt;

&lt;p&gt;This time I will describe how you set up your automation posting using my template!&lt;/p&gt;

&lt;p&gt;There are 5 steps to setup.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1. Copy template&lt;/li&gt;
&lt;li&gt;2. Create dev.to API Key&lt;/li&gt;
&lt;li&gt;3. Set dev.to API Key to GitHub actions secret&lt;/li&gt;
&lt;li&gt;4. Set up GitHub actions workflow&lt;/li&gt;
&lt;li&gt;5. Run go program to generate new blog post.&lt;/li&gt;
&lt;li&gt;6. Write your blog post!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Copy template
&lt;/h2&gt;

&lt;p&gt;To copy the template, go to &lt;a href="https://github.com/atsushii/dev.to."&gt;GitHub&lt;/a&gt; and click &lt;code&gt;Use this template&lt;/code&gt; button to copy a template! I recommend you create the private repository. So your blog post can be safe.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1u78sh3zpscuhkkcwdm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1u78sh3zpscuhkkcwdm1.png" alt=" " width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create dev.to API Key
&lt;/h2&gt;

&lt;p&gt;It would be best if you created your API Key to post your blog post to dev.to.&lt;/p&gt;

&lt;p&gt;Don't worry, it is easy.&lt;/p&gt;

&lt;p&gt;First, click your icon to open the dropdown then click settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcwcopd6uc3546hkk92qe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcwcopd6uc3546hkk92qe.png" alt=" " width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, click the &lt;code&gt;⚡️ Extensions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sob20yg5kf5m0l537gu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sob20yg5kf5m0l537gu.png" alt=" " width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then finally, go to bottom and generate your API Key!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02e2q4tf8urzgpggs31x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02e2q4tf8urzgpggs31x.png" alt=" " width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Set dev.to API Key to GitHub actions secret
&lt;/h2&gt;

&lt;p&gt;I use GitHub actions to automate posts to dev.to. So need to set dev.to API Key to GitHub actions secret.&lt;/p&gt;

&lt;p&gt;At the first, go to your dev.to template repo on your GitHub and click Settings.&lt;br&gt;
Then click Secrets and Variables &amp;gt; Actions. It is in the Security section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27tf7kwhpb7vvkfxn888.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27tf7kwhpb7vvkfxn888.png" alt=" " width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that click the &lt;code&gt;New repository secret&lt;/code&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg967q2c2fhv4h8qgcr6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg967q2c2fhv4h8qgcr6a.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set &lt;code&gt;DEV_TO_API_TOKEN&lt;/code&gt; to Name and your dev.to API Key to Secret.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsgxix0vup456xwz6hwm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frsgxix0vup456xwz6hwm.png" alt=" " width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Set up GitHub actions workflow
&lt;/h2&gt;

&lt;p&gt;I use the below package for content proofing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;textlint&lt;/li&gt;
&lt;li&gt;Prettier&lt;/li&gt;
&lt;li&gt;Embedme
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Post
        run: DEV_TO_GIT_TOKEN=${{ secrets.DEV_TO_API_TOKEN }} yarn run dev-to-git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above step is important to post your blog to dev.to automatically.&lt;br&gt;
During this step, set your secret variable to DEV_TO_GIT_TOKEN and then run dev-to-git.&lt;br&gt;
dev-to-git is implemented by &lt;a href="https://github.com/maxime1992/dev-to-git" rel="noopener noreferrer"&gt;maxime1992&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for implementing this awesome OSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Post to dev.to

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  build:
    name: Build
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18]
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: yarn
      - run: yarn

      - name: Install textlint
        run: 'yarn add -D textlint textlint-rule-common-misspellings textlint-rule-spellchecker'

      - name: Run textlint
        run: npx textlint -f checkstyle "posts/**/*.md" &amp;gt;&amp;gt; .textlint.log

      - name: Run Prettier
        run: yarn run prettier:check

      - name: Run Embedme
        run: yarn run embedme:check

  Post:
    name: Post
    if: github.ref == 'refs/heads/main' &amp;amp;&amp;amp; github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: yarn
      - run: yarn

      - name: Post
        run: DEV_TO_GIT_TOKEN=${{ secrets.DEV_TO_API_TOKEN }} yarn run dev-to-git

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Run go program to generate new blog post.
&lt;/h2&gt;

&lt;p&gt;I implemented the go program to create a draft post with just one cmd.&lt;/p&gt;

&lt;p&gt;But wait, before running the cmd, you need to set your dev.to API key to .env file.&lt;br&gt;
I already prepared .env.sample file so you can just type the below cmd to create a .env file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp .env.sample .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the above command you have to create a .env file and finally, you can add your API key to the below part of the code in your .env file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export DEV_TO_GIT_TOKEN=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then now you can create your blog template by running the below cmd!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must have imported golang to your PC.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the prompt shows the below question. You can type the name of the article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Enter the name of the new article:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, the directory is automatically created under the &lt;code&gt;posts/&lt;/code&gt; dir. In this case, I typed the test as a name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivbcmt9tm6bdqq8b92m2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivbcmt9tm6bdqq8b92m2.png" alt=" " width="602" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And also, the &lt;code&gt;dev-to-git.json&lt;/code&gt; was updated, program added &lt;code&gt;{"id":***,"relativePathToArticle": ***}&lt;/code&gt;. It is necessary to manage your post.&lt;/p&gt;

&lt;p&gt;You can manage whether your post will be a draft or public to change the published section on generated .md file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
title: ***
published: false
description: description
tags:
---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Write your blog post!
&lt;/h2&gt;

&lt;p&gt;Finally, write your blog post to generate a .md file!&lt;br&gt;
If need to add an image to your post, you can save image into &lt;code&gt;/assets&lt;/code&gt; folder and then add the relative path to your post!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;e.g.
![alt](https://raw.githubusercontent.com/atsushii/dev.to/master/posts/Automate-your-post-to-dev.-to-by-github-actions/assets/** 'title')

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's it!!&lt;br&gt;
Now push your files to Github and merge them into the main branch. The CI automatically post your content!&lt;/p&gt;

&lt;p&gt;Reference:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/maxime1992/manage-your-dev-to-blog-posts-from-a-git-repo-and-use-continuous-deployment-to-auto-publish-update-them-143j"&gt;Manage your dev.to blog posts from a GIT repo and use continuous deployment to auto publish/update them - DEV Community&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>gha</category>
      <category>ci</category>
    </item>
  </channel>
</rss>
