<?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: Marcus Chan</title>
    <description>The latest articles on DEV Community by Marcus Chan (@marcuscjh).</description>
    <link>https://dev.to/marcuscjh</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%2F2533285%2F3bd43a25-6e32-4af3-ae30-a952de9a5caf.jpeg</url>
      <title>DEV Community: Marcus Chan</title>
      <link>https://dev.to/marcuscjh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marcuscjh"/>
    <language>en</language>
    <item>
      <title>How I Rebuilt My Portfolio with a Little Help from AI</title>
      <dc:creator>Marcus Chan</dc:creator>
      <pubDate>Fri, 23 Jan 2026 13:00:52 +0000</pubDate>
      <link>https://dev.to/marcuscjh/how-i-rebuilt-my-portfolio-with-a-little-help-from-ai-3k12</link>
      <guid>https://dev.to/marcuscjh/how-i-rebuilt-my-portfolio-with-a-little-help-from-ai-3k12</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;What started as a messy side project is now a smarter, easier to maintain site, thanks to a configuration-driven approach and modern dev tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Messy Start
&lt;/h3&gt;

&lt;p&gt;Like many developers, my portfolio started as a quick weekend project. It was built with plain HTML, CSS, and JavaScript, functional but outdated, hard to maintain, and definitely not something I was proud of.&lt;/p&gt;

&lt;p&gt;Every small update meant digging through multiple files, tweaking styles, and hoping nothing broke. So the project sat untouched for months… until I decided to finish it properly.&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%2F2ez7j0mb0gll3kqst6r0.gif" 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%2F2ez7j0mb0gll3kqst6r0.gif" width="720" height="491"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Before&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleaning It Up with AI
&lt;/h3&gt;

&lt;p&gt;The first step was cleaning up the mess. This time, I used &lt;strong&gt;AI as a coding partner&lt;/strong&gt; to help with repetitive work like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactoring messy code&lt;/li&gt;
&lt;li&gt;Organizing files properly&lt;/li&gt;
&lt;li&gt;Making CSS more consistent&lt;/li&gt;
&lt;li&gt;Adding basic JavaScript structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tasks I had procrastinated for weeks were done in days. AI didn’t build the project for me, it simply accelerated the boring parts so I could focus on structure and decisions.&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%2F6nl8k1f5l94je17l4k0i.gif" 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%2F6nl8k1f5l94je17l4k0i.gif" width="480" height="327"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;After&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Making It Configuration-Driven
&lt;/h3&gt;

&lt;p&gt;Next, I tackled the real problem: content was scattered everywhere. Adding a new project or skill meant editing multiple HTML files manually.&lt;/p&gt;

&lt;p&gt;My solution was simple: create a single data.json file to store all the content. This one file now controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bio and personal info&lt;/li&gt;
&lt;li&gt;Project showcases&lt;/li&gt;
&lt;li&gt;Timeline (work, education, certifications)&lt;/li&gt;
&lt;li&gt;Skills and social links
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"_comment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This file controls all content and navigation for the portfolio website."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"real_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"subtitle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"website"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typedMessages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cvDriveId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"social"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"showcase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"backgroundImage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"technologies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"modalContent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"languages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cloud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"web"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"devops"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"databases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ai"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timeline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"order"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"startDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"endDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"modalContent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"navigation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, updating the site means editing one file. Add a new project or certification to data.json, and the site updates automatically, no HTML editing required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrading the Tooling
&lt;/h3&gt;

&lt;p&gt;With the structure in place, I modernized the build process using  &lt;strong&gt;Vite&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The migration was smooth and made development much more enjoyable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automating the Workflow
&lt;/h3&gt;

&lt;p&gt;To finish things off, I added &lt;strong&gt;CI/CD&lt;/strong&gt; with GitHub Actions. Now every change follows this flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update data.json&lt;/li&gt;
&lt;li&gt;Commit and push&lt;/li&gt;
&lt;li&gt;Tests run automatically, the site builds, and it deploys&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No more manual steps, and no more deployment headaches.&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%2Fsah2n085ti9h5a8p849i.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%2Fsah2n085ti9h5a8p849i.png" width="800" height="252"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Github Actions&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Learned
&lt;/h3&gt;

&lt;p&gt;✅ &lt;strong&gt;Centralize your content.&lt;/strong&gt; A single JSON source of truth makes updates simple and scalable.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;AI is a helper, not a replacement.&lt;/strong&gt; It speeds up development and removes friction.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Modern tools matter.&lt;/strong&gt; Vite, TypeScript, and CI/CD make even small projects more maintainable.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Automation saves time.&lt;/strong&gt; Build, test, and deploy steps should run without effort.&lt;/p&gt;

&lt;p&gt;Connect with me on &lt;a href="https://www.linkedin.com/in/marcuschanjh" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;| &lt;a href="https://github.com/MarcusCJH" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;| &lt;a href="http://www.marcuscjh.com" rel="noopener noreferrer"&gt;Portfolio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>automation</category>
      <category>webdev</category>
      <category>portfolio</category>
    </item>
    <item>
      <title>Built a Game in 2 Hours with Amazon Q</title>
      <dc:creator>Marcus Chan</dc:creator>
      <pubDate>Thu, 19 Jun 2025 15:35:21 +0000</pubDate>
      <link>https://dev.to/marcuscjh/built-a-game-in-2-hours-with-amazon-q-2o2d</link>
      <guid>https://dev.to/marcuscjh/built-a-game-in-2-hours-with-amazon-q-2o2d</guid>
      <description>&lt;h3&gt;
  
  
  🧠 The Idea
&lt;/h3&gt;

&lt;p&gt;So I was walking around AWS Summit Singapore and saw this poster:&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%2Fb50c9kvmqzl5x889bftb.jpeg" 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%2Fb50c9kvmqzl5x889bftb.jpeg" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;“Build Games with Amazon Q CLI”&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Score a T-shirt.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I didn’t go there planning to build a game. But I &lt;em&gt;was&lt;/em&gt; curious what Amazon Q CLI could do. And yeah, the swag sounded fun.&lt;/p&gt;

&lt;p&gt;So I gave myself a quick challenge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⏱ Max 2 hours&lt;/li&gt;
&lt;li&gt;🧠 Let Q CLI do most of the work&lt;/li&gt;
&lt;li&gt;🎮 End up with something that runs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧪 My Iteration Journey (with Prompts I gave Q)
&lt;/h3&gt;

&lt;h4&gt;
  
  
  🎮 Getting the First Build Running
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;“Build an endless jumper game in Python using pygame.”&lt;/p&gt;
&lt;/blockquote&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%2Fe1jyrpcxeq3vq59ojrru.gif" 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%2Fe1jyrpcxeq3vq59ojrru.gif" width="799" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Q spun up a basic prototype:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Player block&lt;/li&gt;
&lt;li&gt;Green platforms&lt;/li&gt;
&lt;li&gt;Gravity&lt;/li&gt;
&lt;li&gt;Score counter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It worked! But sometimes… you just drop off the screen instantly. RIP.&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%2Fynl67fa0cb6kssapoglt.gif" 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%2Fynl67fa0cb6kssapoglt.gif" width="799" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  ⛔ Bug #1 — Sudden Death
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;“Fix a bug where the player sometimes falls immediately when the game starts.”&lt;/p&gt;
&lt;/blockquote&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%2F9go90owfv52b1lnut68x.gif" 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%2F9go90owfv52b1lnut68x.gif" width="799" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This worked.&lt;/p&gt;

&lt;p&gt;But there was another issue: once you lost, the game window just closed. No warning, no time to react.&lt;/p&gt;

&lt;h4&gt;
  
  
  💀 Game Over Screen + Reset
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;“When the player loses, show a ‘Game Over’ screen and wait for a key press before closing. Also, add a reset feature, pressing ‘R’ should restart the game.”&lt;/p&gt;
&lt;/blockquote&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%2Fmre65nh1fgfwlhqhk8uo.gif" 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%2Fmre65nh1fgfwlhqhk8uo.gif" width="799" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Q delivered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Game Over screen&lt;/li&gt;
&lt;li&gt;Press ‘R’ to restart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Super helpful for testing. No more relaunching the app every time I mess up.&lt;/p&gt;

&lt;p&gt;But there was something weird, the platforms were too wide. You literally couldn’t lose. You just bounced forever.&lt;/p&gt;

&lt;h4&gt;
  
  
  📏 Fixing the “Can’t Lose” Bug + Adding Difficulty
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;“Fix the bug where when you jump further up, the platform becomes too big — like make some difficulty in the game.”&lt;/p&gt;
&lt;/blockquote&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%2Fvu8qw106r8x6l63eds1r.gif" 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%2Fvu8qw106r8x6l63eds1r.gif" width="799" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this prompt, Q made the game more challenging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Narrower platforms&lt;/strong&gt; : You could finally miss a jump and fall&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaling difficulty&lt;/strong&gt; : Platforms spread apart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we’re talking. It finally felt like a game — one you could actually lose.&lt;/p&gt;

&lt;h4&gt;
  
  
  ⚡ Adding Power-Ups
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;“Add a random power-up — you decide what it is — and spawn it on some platforms. Enhance the game.”&lt;/p&gt;
&lt;/blockquote&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%2Fdm91zf2os2zh9xqq0afw.gif" 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%2Fdm91zf2os2zh9xqq0afw.gif" width="760" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Q gave me power-ups like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Double jump&lt;/li&gt;
&lt;li&gt;Bigger platforms&lt;/li&gt;
&lt;li&gt;Slow motion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cool stuff — but a new bug appeared: timer kept ticking even after you lost.&lt;/p&gt;

&lt;h4&gt;
  
  
  🛥️ Fixing the Timer Bug
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;“Fix the timer — once the game ends or is frozen, the timer should stop.”&lt;/p&gt;
&lt;/blockquote&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%2Fup02qpu9shj68vsa9j1t.gif" 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%2Fup02qpu9shj68vsa9j1t.gif" width="760" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clean fix. Timer now pauses properly during freezes and stops on game over. That wrapped it up nicely.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧹 Final Touches
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;“Create a README.md for the project.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Q generated a clean, well-written README file with usage instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  💡 Final Thoughts
&lt;/h3&gt;

&lt;p&gt;This was a fun, focused experiment. In under 2 hours, I went from nothing to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A playable endless jumper game&lt;/li&gt;
&lt;li&gt;Scaling difficulty and proper fail conditions&lt;/li&gt;
&lt;li&gt;A working power-up system&lt;/li&gt;
&lt;li&gt;Reset and game-over mechanics&lt;/li&gt;
&lt;li&gt;A complete README&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No, I haven’t claimed the T-shirt yet.&lt;br&gt;&lt;br&gt;
But maybe this post will help.&lt;/p&gt;

&lt;p&gt;You can find my repository here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MarcusCJH/amazon-q-pygame" rel="noopener noreferrer"&gt;https://github.com/MarcusCJH/amazon-q-pygame&lt;/a&gt;&lt;/p&gt;

</description>
      <category>amazonwebservices</category>
      <category>amazonq</category>
      <category>python</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>My AWS Cloud Certification Was Expiring — Here’s How I Recertified It Through Gamification</title>
      <dc:creator>Marcus Chan</dc:creator>
      <pubDate>Tue, 11 Mar 2025 08:05:53 +0000</pubDate>
      <link>https://dev.to/marcuscjh/my-aws-cloud-certification-was-expiring-heres-how-i-recertified-it-through-gamification-1j3</link>
      <guid>https://dev.to/marcuscjh/my-aws-cloud-certification-was-expiring-heres-how-i-recertified-it-through-gamification-1j3</guid>
      <description>&lt;h3&gt;
  
  
  My AWS Cloud Certification Was Expiring — Here’s How I Recertified It Through Gamification
&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%2Fzb9y03oj8hacue0w8f68.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%2Fzb9y03oj8hacue0w8f68.png" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📩 &lt;strong&gt;“Important: Your AWS Certification expires on Mar 23, 2025”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fxz76eeat6cx03mjwgdgh.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%2Fxz76eeat6cx03mjwgdgh.png" width="645" height="66"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait, what? My &lt;strong&gt;AWS Certified Cloud Practitioner&lt;/strong&gt; credential was about to expire! And, of course, like any responsible tech professional, I had &lt;em&gt;totally&lt;/em&gt; not forgotten about it &lt;em&gt;(okay, maybe just a little)&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Usual Recertification Route vs. A Gamified Approach&lt;/p&gt;
&lt;/blockquote&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%2Fw7aioob2lsnb2hjaxwag.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%2Fw7aioob2lsnb2hjaxwag.png" width="800" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initially, I was considering the traditional route: &lt;strong&gt;just take an Associate-level exam and be done with it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But then, two things happened at the same time:&lt;/p&gt;

&lt;p&gt;1️⃣ &lt;strong&gt;I saw AWS now offered a gamified recertification process.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
2️⃣ &lt;strong&gt;There was a “Cloud Tournament” happening within my organization.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I thought… &lt;strong&gt;why not align everything and go all in?&lt;/strong&gt; It was the perfect opportunity to &lt;strong&gt;recertify and compete at the same time!&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How AWS Cloud Quest for Recertification Works&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;✔️ &lt;strong&gt;Stages 1–12:&lt;/strong&gt; These were &lt;strong&gt;interactive and scenario-based&lt;/strong&gt; , covering real AWS concepts with plenty of hands-on learning. Sure, there was a &lt;strong&gt;lot of reading&lt;/strong&gt; , but it was a great way to &lt;strong&gt;refresh my cloud knowledge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;✔️ &lt;strong&gt;Stage 13 (Final Boss Battle):&lt;/strong&gt; A &lt;strong&gt;Troubleshooting Challenge&lt;/strong&gt; where you analyze and fix an &lt;strong&gt;AWS Cloud Architecture&lt;/strong&gt;. This one definitely required some &lt;strong&gt;AWS experience&lt;/strong&gt; , but it was a solid &lt;strong&gt;practical application&lt;/strong&gt; of everything learned.&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%2F8k7218bxyjfo2z64r0qm.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%2F8k7218bxyjfo2z64r0qm.png" width="800" height="382"&gt;&lt;/a&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%2Fo1b68efq9og9ufxrsmla.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%2Fo1b68efq9og9ufxrsmla.png" width="788" height="367"&gt;&lt;/a&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%2Fw5wjeyyao1us0i3qwacw.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%2Fw5wjeyyao1us0i3qwacw.png" width="800" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How Long Did It Take?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m suggesting completing one stage per day, meaning you could finish in 13 days.&lt;/p&gt;

&lt;p&gt;Me? I did it in &lt;strong&gt;4 hours.&lt;/strong&gt; &lt;em&gt;(Would have been faster if I didn’t stop for snacks.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Plus, since I was already in &lt;strong&gt;“locked in”&lt;/strong&gt; , I had the extra motivation to &lt;strong&gt;speedrun through it!&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Final Thoughts 💭&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;✅ &lt;strong&gt;Was it fun?&lt;/strong&gt; Yes!&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Did it refresh my AWS knowledge?&lt;/strong&gt; Absolutely.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Would I recommend it?&lt;/strong&gt; If your &lt;strong&gt;AWS Cloud Practitioner cert&lt;/strong&gt; is expiring and you want a &lt;strong&gt;different experience&lt;/strong&gt; from the usual exam, this is a solid option.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Bonus:&lt;/strong&gt; It’s &lt;strong&gt;free until the end of July 2025&lt;/strong&gt; , so why not?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out here:&lt;/strong&gt; &lt;a href="https://explore.skillbuilder.aws/learn/courses/17623/aws-cloud-quest-recertify-cloud-practitioner" rel="noopener noreferrer"&gt;AWS Cloud Quest: Recertify Cloud Practitioner&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can connect with me on linkedin: &lt;a href="https://www.linkedin.com/in/marcuschanjh/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/marcuschanjh/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>amazonwebservices</category>
      <category>aws</category>
      <category>awscertification</category>
      <category>certification</category>
    </item>
    <item>
      <title>Leveraging Amazon Connect for Real-Time Incident Response Calls</title>
      <dc:creator>Marcus Chan</dc:creator>
      <pubDate>Fri, 27 Sep 2024 18:54:13 +0000</pubDate>
      <link>https://dev.to/marcuscjh/leveraging-amazon-connect-for-real-time-incident-response-calls-2a8d</link>
      <guid>https://dev.to/marcuscjh/leveraging-amazon-connect-for-real-time-incident-response-calls-2a8d</guid>
      <description>&lt;p&gt;Amazon Connect is a cloud-based contact center.&lt;/p&gt;

&lt;p&gt;This use case was to automate incident response calls: when an alert is triggered, it sends the alert to SNS, which triggers a Lambda function. This Lambda function calls the first escalation point. If no one answers, it escalates to the second contact.&lt;/p&gt;

&lt;p&gt;Here’s how I built it:&lt;/p&gt;

&lt;p&gt;Ensure that you are in the Correct Region — I’m using ap-southeast-1 as I am located in Singapore.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Setting up AWS Identity and Access Management (IAM)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; In the AWS Console, search for  &lt;strong&gt;IAM&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Fs514fsvkanp60gh7d0k4.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%2Fs514fsvkanp60gh7d0k4.png" width="800" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Under &lt;strong&gt;Access management&lt;/strong&gt; , click on &lt;strong&gt;Roles&lt;/strong&gt; , then select &lt;strong&gt;Create role&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2F35hjouoyqssgol81dgfy.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%2F35hjouoyqssgol81dgfy.png" width="270" height="444"&gt;&lt;/a&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%2Fr7jk4990357pmc67d2ep.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%2Fr7jk4990357pmc67d2ep.png" width="522" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; For the trusted entity type, choose &lt;strong&gt;AWS Service&lt;/strong&gt; , and under &lt;strong&gt;Use Case&lt;/strong&gt; , select  &lt;strong&gt;Lambda&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Frxgocalqrbhznmxaz2dy.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%2Frxgocalqrbhznmxaz2dy.png" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Use the following &lt;strong&gt;AWS Managed Policies&lt;/strong&gt; :&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;AmazonConnect_FullAccess&lt;/li&gt;
&lt;li&gt;AmazonDynamoDBFullAccess&lt;/li&gt;
&lt;li&gt;AmazonSNSFullAccess&lt;/li&gt;
&lt;li&gt;AWSLambdaBasicExecutionRole&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; Finally, create a role name, then click &lt;strong&gt;Create role&lt;/strong&gt;. Make sure to take note of your &lt;strong&gt;Role Name&lt;/strong&gt; for future use.&lt;/p&gt;
&lt;/blockquote&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%2Fubxw7st182abkzves1vv.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%2Fubxw7st182abkzves1vv.png" width="800" height="273"&gt;&lt;/a&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%2F2x71soscmamgdh1suyf0.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%2F2x71soscmamgdh1suyf0.png" width="280" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Setting Up Amazon Simple Notification Service (SNS) (Optional)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; In the AWS Console, search for  &lt;strong&gt;SNS&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Fomunol3xltdkpg8kok3x.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%2Fomunol3xltdkpg8kok3x.png" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Navigate to &lt;strong&gt;Topics&lt;/strong&gt; and click on &lt;strong&gt;Create topic&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2F06pkvcw9llqwsqas8dyx.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%2F06pkvcw9llqwsqas8dyx.png" width="800" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; Choose &lt;strong&gt;Standard&lt;/strong&gt; for the topic type and give it a name (e.g., “AmazonConnectSNS”). After the topic is created, make sure to note down the &lt;strong&gt;ARN&lt;/strong&gt; for later use.&lt;/p&gt;
&lt;/blockquote&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%2Fypzk3ywppxbosp3jws71.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%2Fypzk3ywppxbosp3jws71.png" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Setting Up Amazon Lambda
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; In the AWS Console, search for  &lt;strong&gt;Lambda&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2F0caihhzouamhpowdolp5.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%2F0caihhzouamhpowdolp5.png" width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Click on &lt;strong&gt;Create Function&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Foqg7uhw3auo6osihxmxf.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%2Foqg7uhw3auo6osihxmxf.png" width="622" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; On the Create Function page, provide a &lt;strong&gt;Function Name&lt;/strong&gt; (e.g., “AmazonConnectLambda”), select &lt;strong&gt;Runtime&lt;/strong&gt; as Python 3.xx, and choose the &lt;strong&gt;existing role&lt;/strong&gt; you created in the IAM setup section.&lt;/p&gt;
&lt;/blockquote&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%2Fl4dfehssz3652betxbhy.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%2Fl4dfehssz3652betxbhy.png" width="800" height="795"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Add an &lt;strong&gt;SNS Trigger&lt;/strong&gt; to the Lambda function.&lt;/p&gt;
&lt;/blockquote&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%2Fhrbs6uq5vxm32nkjpv82.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%2Fhrbs6uq5vxm32nkjpv82.png" width="800" height="292"&gt;&lt;/a&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%2Fi3rnpo8dnzundqydr1go.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%2Fi3rnpo8dnzundqydr1go.png" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; Go to &lt;strong&gt;Configuration&lt;/strong&gt; , then navigate to &lt;strong&gt;Generation Configuration&lt;/strong&gt; , and set the &lt;strong&gt;Timeout&lt;/strong&gt; to &lt;strong&gt;1 minute&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Fsi8am544a1lu20xyr3i8.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%2Fsi8am544a1lu20xyr3i8.png" width="800" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6:&lt;/strong&gt; Paste the following code into the lambda_function.py file. I will explain the code in the last section, where we’ll also revisit it to modify variables:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3
import time
from datetime import datetime

# Initialize the DynamoDB resource
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('CallLogs')

# Create a Connect client
connect_client = boto3.client('connect')

#Amazon Connect Instance ID, Contact Flow ID and Claim number
CONNECT_INSTANCE_ID = 'xxxxxxxxx'
CONTACT_FLOW_ID = 'xxxxxxxxx'
SOURCE_PHONE_NUMBER = 'xxxxxxxxx' 

# Phone numbers for the contacts
FIRST_CONTACT_PHONE = "+65xxxxxx"
SECOND_CONTACT_PHONE = "+65xxxxxx"

def log_event_to_dynamodb(contact_id, event, phone_number, escalation_stage):
    """
    Log the event (CONNECTED, DISCONNECTED) into DynamoDB with relevant details.
    """
    try:
        table.put_item(
            Item={
                'ContactId': contact_id,
                'Event': event,
                'Timestamp': datetime.utcnow().isoformat(),
                'PhoneNumber': phone_number,
                'EscalationStage': escalation_stage
            }
        )
        print(f"Logged {event} event for ContactId {contact_id} in DynamoDB")
    except Exception as e:
        print(f"Error logging event to DynamoDB: {e}")

def start_outbound_call(phone_number, escalation_stage):
    """
    Start an outbound call using Amazon Connect and return the ContactId.
    """
    try:
        response = connect_client.start_outbound_voice_contact(
            DestinationPhoneNumber=phone_number,
            ContactFlowId=CONTACT_FLOW_ID,
            InstanceId=CONNECT_INSTANCE_ID,
            SourcePhoneNumber=SOURCE_PHONE_NUMBER,
            Attributes={
                'Escalation': escalation_stage
            }
        )
        contact_id = response['ContactId']
        print(f"Started outbound call to {phone_number} with ContactId: {contact_id}")
        return contact_id
    except Exception as e:
        print(f"Failed to start outbound call: {e}")
        raise e

def check_call_status(contact_id):
    """
    Check the status of the outbound call using the ContactId.
    """
    try:
        response = connect_client.describe_contact(
            InstanceId=CONNECT_INSTANCE_ID,
            ContactId=contact_id
        )

        if 'Contact' in response and 'DisconnectTimestamp' in response['Contact']:
            print(f"Call with ContactId {contact_id} was disconnected at {response['Contact']['DisconnectTimestamp']}")
            return 'DISCONNECTED'

        elif 'Contact' in response and 'ConnectedToSystemTimestamp' in response['Contact']:
            print(f"Call with ContactId {contact_id} was connected at {response['Contact']['ConnectedToSystemTimestamp']}")
            return 'CONNECTED'

    except Exception as e:
        print(f"Failed to check call status: {e}")
        raise e

def lambda_handler(event, context):
    try:
        acknowledgment = event.get('Details', {}).get('Parameters', {}).get('acknowledgment', 'False')
        escalation_stage = event.get('Details', {}).get('Parameters', {}).get('EscalationStage', 'FirstAttempt')
        print(f"Acknowledgment: {acknowledgment}, Escalation Stage: {escalation_stage}")
    except KeyError:
        print("Expected keys not found in event")
        acknowledgment = 'False'

    if acknowledgment == 'False' and escalation_stage == 'FirstAttempt':
        print("Calling the first contact...")
        contact_id = start_outbound_call(FIRST_CONTACT_PHONE, 'FirstAttempt')

        for attempt in range(10):
            time.sleep(5) 
            status = check_call_status(contact_id)

            if status == 'CONNECTED':
                log_event_to_dynamodb(contact_id, 'CONNECTED', FIRST_CONTACT_PHONE, 'FirstAttempt')
                print("First contact answered the call. No need to escalate.")
                return {
                    'statusCode': 200,
                    'body': 'First contact answered the call.'
                }

            elif status == 'DISCONNECTED':
                print(f"First contact did not pick up or disconnected. Escalating to second contact.")
                break

        print("Escalating to second contact...")
        contact_id = start_outbound_call(SECOND_CONTACT_PHONE, 'SecondAttempt')
        log_event_to_dynamodb(contact_id, 'ESCALATION', SECOND_CONTACT_PHONE, 'SecondAttempt')
        return {
            'statusCode': 200,
            'body': 'Second contact attempt made.'
        }

    elif acknowledgment == 'False' and escalation_stage == 'SecondAttempt':
        print("Calling the second contact...")
        contact_id = start_outbound_call(SECOND_CONTACT_PHONE, 'SecondAttempt')
        log_event_to_dynamodb(contact_id, 'ESCALATION', SECOND_CONTACT_PHONE, 'SecondAttempt')
        return {
            'statusCode': 200,
            'body': 'Second contact attempt made.'
        }

    elif acknowledgment == 'True':
        print("First contact acknowledged the call.")
        return {
            'statusCode': 200,
            'body': 'Call acknowledged by the first contact.'
        }

    else:
        print("Unexpected scenario encountered.")
        return {
            'statusCode': 500,
            'body': 'Unexpected scenario.'
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt; : Click on  &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fw04yvnnvo6t7reib5mno.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%2Fw04yvnnvo6t7reib5mno.png" width="767" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Setting up DynamoDB
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; In the AWS Console, search for &lt;strong&gt;DynamoDB&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Fkhga7ppmkfk2tkxhlcjv.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%2Fkhga7ppmkfk2tkxhlcjv.png" width="800" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; In the navigation pane, click on &lt;strong&gt;Tables&lt;/strong&gt; , then select &lt;strong&gt;Create Table&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2F8ab2xiytia961v6lt6fp.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%2F8ab2xiytia961v6lt6fp.png" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; In the &lt;strong&gt;Create Table&lt;/strong&gt; form, follow these steps:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Set the &lt;strong&gt;Table name&lt;/strong&gt; to CallLogs.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Partition key&lt;/strong&gt; , use ContactId.&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Sort key&lt;/strong&gt; , use Timestamp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, click &lt;strong&gt;Create table&lt;/strong&gt; at the bottom.&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%2Fdejlahpcmxq649bjehb4.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%2Fdejlahpcmxq649bjehb4.png" width="800" height="613"&gt;&lt;/a&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%2Fsj6agq9rzjahx94znrod.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%2Fsj6agq9rzjahx94znrod.png" width="800" height="66"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Setting Up Amazon Connect
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt; : In the AWS Console, search for &lt;strong&gt;Amazon Connect&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2Foamfk58hbuy4v1savr52.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%2Foamfk58hbuy4v1savr52.png" width="800" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Create a new instance by following the on-screen instructions. Make sure to enable both &lt;strong&gt;Inbound&lt;/strong&gt; and &lt;strong&gt;Outbound&lt;/strong&gt; calls during setup.&lt;/p&gt;
&lt;/blockquote&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%2Foe51xuu6wqz02ctp5noo.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%2Foe51xuu6wqz02ctp5noo.png" width="800" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; After the instance is created, navigate to &lt;strong&gt;Flows&lt;/strong&gt; in the side menu. In the flow editor, under &lt;strong&gt;AWS Lambda&lt;/strong&gt; , add the Lambda function that was created earlier.&lt;/p&gt;
&lt;/blockquote&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%2Fvt39o62w2bw2gzwungxc.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%2Fvt39o62w2bw2gzwungxc.png" width="279" height="729"&gt;&lt;/a&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%2F2rngelxmbwwqanojp0w1.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%2F2rngelxmbwwqanojp0w1.png" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Log in to your Amazon Connect instance with admin privileges. Once logged in, navigate to the sidebar and select &lt;strong&gt;Phone numbers&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&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%2F1qufkz7qxymyev095i2g.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%2F1qufkz7qxymyev095i2g.png" width="475" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; Click on &lt;strong&gt;Claim a number&lt;/strong&gt; and follow the recommended steps to complete the process.&lt;/p&gt;
&lt;/blockquote&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%2Fnd1d3jjg9nu0wnrucrfs.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%2Fnd1d3jjg9nu0wnrucrfs.png" width="800" height="182"&gt;&lt;/a&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%2Fjn3fxcruc7reooce62vk.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%2Fjn3fxcruc7reooce62vk.png" width="800" height="645"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 6:&lt;/strong&gt; Test both &lt;strong&gt;incoming&lt;/strong&gt; and &lt;strong&gt;outgoing&lt;/strong&gt;  calls:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;To test incoming calls, use a mobile phone to dial the number you claimed.&lt;/li&gt;
&lt;li&gt;For outgoing calls, use the &lt;strong&gt;Contact Control Panel&lt;/strong&gt; in Amazon Connect.&lt;/li&gt;
&lt;/ul&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%2F0ayggq7e2txp93nyh8mk.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%2F0ayggq7e2txp93nyh8mk.png" width="506" height="917"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 7:&lt;/strong&gt; In the Amazon Connect navigation bar, click on &lt;strong&gt;Flows&lt;/strong&gt; and create a new flow.&lt;/p&gt;
&lt;/blockquote&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%2Fci9jvt2jci19eos9rsxc.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%2Fci9jvt2jci19eos9rsxc.png" width="242" height="281"&gt;&lt;/a&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%2Ffni58lz2bi88z70h6wrz.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%2Ffni58lz2bi88z70h6wrz.png" width="429" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Step 8:&lt;/strong&gt; Add a title to your flow, design the flow, and once done, click &lt;strong&gt;Publish&lt;/strong&gt;. You can follow this basic structure for your flow:&lt;/p&gt;
&lt;/blockquote&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%2Fmlt62mhmcev3gczmyjoy.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%2Fmlt62mhmcev3gczmyjoy.png" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entry&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Set Logging Behavior&lt;/strong&gt; block -&amp;gt; &lt;strong&gt;Play Prompt&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Get Customer Input&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the user presses 1, proceed to the &lt;strong&gt;Play Prompt&lt;/strong&gt; block-&amp;gt; &lt;strong&gt;Disconnect&lt;/strong&gt; block&lt;/li&gt;
&lt;li&gt;If not, invoke the &lt;strong&gt;Lambda function&lt;/strong&gt; block -&amp;gt; &lt;strong&gt;Disconnect&lt;/strong&gt; block&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;strong&gt;Invoke AWS Lambda&lt;/strong&gt; block, you’ll need to set up the function input parameters. Follow this structure for the input parameters:&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%2F0axrkfs1h07bd0mbq2g4.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%2F0axrkfs1h07bd0mbq2g4.png" width="401" height="669"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Source Code Explanation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Calling the First Contact&lt;/strong&gt; : Once the Lambda function is triggered, it initiates an outbound call to the FIRST_CONTACT_PHONE. The function then monitors the call status (whether it’s connected or disconnected) and logs the event accordingly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalating to the Second Contact&lt;/strong&gt; : If the first contact doesn’t respond, the function escalates the process by making an outbound call to the SECOND_CONTACT_PHONE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling Call Acknowledgment&lt;/strong&gt; : If an acknowledgment is received (set to ‘True’), the function stops any further escalation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7. Wrapping Things Up
&lt;/h3&gt;

&lt;p&gt;When revisiting the Lambda function, remember to update the following variables:&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%2Fsajf8tst4en317ska22q.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%2Fsajf8tst4en317ska22q.png" width="463" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CONNECT_INSTANCE_ID: This is the unique Amazon Connect instance ARN (UUID) associated with your instance.&lt;/li&gt;
&lt;li&gt;CONTACT_FLOW_ID: This is the UUID of your contact flow. You can find it in the URL of your flow in Amazon Connect, located immediately after /contact-flow/.&lt;/li&gt;
&lt;li&gt;SOURCE_PHONE_NUMBER: This is the phone number you claimed in Amazon Connect.&lt;/li&gt;
&lt;li&gt;FIRST_CONTACT_PHONE: The phone number of the first person to receive the call.&lt;/li&gt;
&lt;li&gt;SECOND_CONTACT_PHONE: The phone number of the second person to receive the call if the first contact doesn’t answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this setup, &lt;strong&gt;SNS&lt;/strong&gt; is used to receive alerts from an &lt;strong&gt;AWS CloudWatch&lt;/strong&gt; alarm, which triggers the SNS topic. You can simulate an alert by going to SNS and publishing a message manually.&lt;/p&gt;

&lt;p&gt;However, for simplicity, we can skip that and go straight to &lt;strong&gt;Lambda&lt;/strong&gt; and trigger the function directly to test the flow.&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%2Fy48hsit7my8ds34ntxr9.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%2Fy48hsit7my8ds34ntxr9.png" width="658" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything works as expected, you should receive a call, and you’ll be able to view the call logs in DynamoDB under the CallLogs table.&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%2F27ct5x1x2xd2vj82y2o0.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%2F27ct5x1x2xd2vj82y2o0.png" width="443" height="951"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While in DynamoDB, you will be able to see the CallLogs.&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%2Fci7wiy4ek6xegefxnkw6.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%2Fci7wiy4ek6xegefxnkw6.png" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you found this use case helpful.&lt;br&gt;&lt;br&gt;
Overall, I found it enjoyable to experiment with Aamzon Connect.&lt;/p&gt;

&lt;p&gt;You can connect with me on linkedin: &lt;a href="https://www.linkedin.com/in/marcuschanjh/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/marcuschanjh/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>amazonconnect</category>
      <category>stepbystepguide</category>
      <category>awslambda</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
