<?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>Forem: Adebayo Omolumo</title>
    <description>The latest articles on Forem by Adebayo Omolumo (@adebayoomolumo).</description>
    <link>https://forem.com/adebayoomolumo</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%2F555952%2Fa7961f0e-15a8-41c2-86b1-7524165c6730.jpg</url>
      <title>Forem: Adebayo Omolumo</title>
      <link>https://forem.com/adebayoomolumo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/adebayoomolumo"/>
    <language>en</language>
    <item>
      <title>I built a portfolio that can actually answers any questions about me!</title>
      <dc:creator>Adebayo Omolumo</dc:creator>
      <pubDate>Wed, 04 Feb 2026 05:23:39 +0000</pubDate>
      <link>https://forem.com/adebayoomolumo/i-built-a-portfolio-that-can-actually-answers-any-questions-about-me-50li</link>
      <guid>https://forem.com/adebayoomolumo/i-built-a-portfolio-that-can-actually-answers-any-questions-about-me-50li</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/adebayoomolumo/i-built-an-ai-portfolio-that-actually-answers-your-questions-43d5" class="crayons-story__hidden-navigation-link"&gt;I Built an AI Portfolio That Actually Answers Your Questions&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/adebayoomolumo/i-built-an-ai-portfolio-that-actually-answers-your-questions-43d5" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;New Year, New You Portfolio Challenge Submission&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/adebayoomolumo" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F555952%2Fa7961f0e-15a8-41c2-86b1-7524165c6730.jpg" alt="adebayoomolumo profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/adebayoomolumo" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Adebayo Omolumo
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Adebayo Omolumo
                
              
              &lt;div id="story-author-preview-content-3206272" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/adebayoomolumo" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F555952%2Fa7961f0e-15a8-41c2-86b1-7524165c6730.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Adebayo Omolumo&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/adebayoomolumo/i-built-an-ai-portfolio-that-actually-answers-your-questions-43d5" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jan 29&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/adebayoomolumo/i-built-an-ai-portfolio-that-actually-answers-your-questions-43d5" id="article-link-3206272"&gt;
          I Built an AI Portfolio That Actually Answers Your Questions
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/googleaichallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;googleaichallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/portfolio"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;portfolio&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gemini"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gemini&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/adebayoomolumo/i-built-an-ai-portfolio-that-actually-answers-your-questions-43d5" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;20&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/adebayoomolumo/i-built-an-ai-portfolio-that-actually-answers-your-questions-43d5#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;




</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>I Built an AI Portfolio That Actually Answers Your Questions</title>
      <dc:creator>Adebayo Omolumo</dc:creator>
      <pubDate>Thu, 29 Jan 2026 01:27:36 +0000</pubDate>
      <link>https://forem.com/adebayoomolumo/i-built-an-ai-portfolio-that-actually-answers-your-questions-43d5</link>
      <guid>https://forem.com/adebayoomolumo/i-built-an-ai-portfolio-that-actually-answers-your-questions-43d5</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;I'm &lt;strong&gt;Adebayo Omolumo&lt;/strong&gt;—a Senior DevOps &amp;amp; Cloud Engineer who's spent 8+ years in the trenches of software development, with the last 5 dedicated to making infrastructure less... on ground but in the cloud. I co-founded a tech agency, collected certifications like Pokémon cards (AWS, Azure, GCP—gotta catch 'em all), and have participated in 15+ hackathons because apparently I enjoy coding under existential time pressure.&lt;/p&gt;

&lt;p&gt;When I sat down to build this portfolio, I had one thought: &lt;em&gt;"What if my portfolio could actually answer questions the way I would?"&lt;/em&gt; Not just a static page with a photo and some bullet points, but something that feels like a conversation. Something that lets recruiters and collaborators explore who I am, on their terms.&lt;/p&gt;

&lt;p&gt;So I built exactly that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://portfolio-frontend-eoigebmhvq-uc.a.run.app" rel="noopener noreferrer"&gt;View My Portfolio&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%2Fwnz2cj7i1ytyc06ykjxg.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%2Fwnz2cj7i1ytyc06ykjxg.png" alt="Main Landing Page"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Concept: An Interview That Works Both Ways
&lt;/h3&gt;

&lt;p&gt;Traditional portfolios are passive. You scroll down, you skim, you leave. I wanted something interactive—a portfolio that responds to &lt;em&gt;what you want to know&lt;/em&gt;, not what I think you should see first.&lt;/p&gt;

&lt;p&gt;The solution? &lt;strong&gt;A three-tier AI interaction system&lt;/strong&gt; where you can ask anything:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scenario-Based Chips&lt;/strong&gt; — Quick-start suggestions that return curated, rich responses with animated cards (but you're not limited to these)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voice Interface&lt;/strong&gt; — Ask questions out loud and hear me answer (Web Speech API)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG-Powered Chatbot&lt;/strong&gt; — For the curious ones who want to go off-script ("What's your opinion on tabs vs spaces?")&lt;/li&gt;
&lt;/ol&gt;


  





&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Frontend:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 16.1.3&lt;/strong&gt; with App Router &amp;amp; TypeScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS v4&lt;/strong&gt; (yes, the new one)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framer Motion&lt;/strong&gt; for silky-smooth animations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fuse.js&lt;/strong&gt; for fuzzy matching user queries to scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Backend:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI&lt;/strong&gt; (Python) — lean, fast, and async-ready&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LangChain + ChromaDB&lt;/strong&gt; — for the RAG pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Gemini 2.5 Flash&lt;/strong&gt; — powers both the chatbot and generates AI stories for repos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Infrastructure:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud Run&lt;/strong&gt; — serverless, scales to zero, perfect for a portfolio&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud Storage&lt;/strong&gt; — persistent caching for GitHub repo data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel Analytics&lt;/strong&gt; — because I like knowing when someone actually visits&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%2Fu04oz8xpm21h5slzbbgw.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%2Fu04oz8xpm21h5slzbbgw.png" alt="Project Architecture Diagram"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  The Scenario System
&lt;/h3&gt;

&lt;p&gt;Instead of training a model on myself (creepy, and expensive), I wrote &lt;strong&gt;30 scenario files&lt;/strong&gt;—each one a carefully crafted response to a common question.&lt;br&gt;
&lt;/p&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;"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;"03-current-role"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"triggers"&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="s2"&gt;"what do you do"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your current role"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"current job"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"keywords"&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="s2"&gt;"work"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"job"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"doing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"currently"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response"&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;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"I'm a Senior Cloud DevOps Engineer at Infometics..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cards"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stats"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;When you click a suggestion (or speak a question), the system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Exact match&lt;/strong&gt; — Did you click "What's your current role?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyword match&lt;/strong&gt; — Does your question contain "work" or "job"?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fuzzy match&lt;/strong&gt; — Close enough? Fuse.js handles typos and variations&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives the &lt;em&gt;feeling&lt;/em&gt; of AI understanding without the latency or cost.&lt;/p&gt;


  



&lt;h3&gt;
  
  
  The Card System
&lt;/h3&gt;

&lt;p&gt;Every response can render &lt;strong&gt;animated cards&lt;/strong&gt;—reusable components that slide in with staggered animations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Card Type&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BioCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Photo, name, title, bio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ProjectCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Project with tech stack, links, screenshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;StatsCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Animated counters (years experience, hackathon count)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SkillsCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Categorized skill badges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TimelineCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Career milestones&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CertsCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Certification badge grid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ResumeCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Downloadable resume options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ContactCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email, socials, availability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MediaCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;YouTube embeds or images&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each card is a React component wrapped in Framer Motion. The &lt;code&gt;CardRenderer&lt;/code&gt; takes a JSON array and maps it to the right components:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bio&lt;/span&gt;&lt;span class="dl"&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BioCard&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;project&lt;/span&gt;&lt;span class="dl"&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProjectCard&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// ... and so on&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;h3&gt;
  
  
  The RAG Chatbot
&lt;/h3&gt;

&lt;p&gt;For questions that don't match a scenario, there's the ✨ floating chat widget.&lt;/p&gt;

&lt;p&gt;It's powered by &lt;strong&gt;LangChain&lt;/strong&gt; with a &lt;strong&gt;Gemini 2.5 Flash&lt;/strong&gt; model, grounded in a knowledge base I wrote about myself. The RAG pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User sends a message&lt;/li&gt;
&lt;li&gt;Backend embeds it with Gemini&lt;/li&gt;
&lt;li&gt;ChromaDB finds relevant context from my knowledge base&lt;/li&gt;
&lt;li&gt;Gemini generates a response &lt;em&gt;as if I'm answering&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The knowledge base includes everything—my origin story, project deep-dives, cloud platform opinions, even fun facts. It's like having a digital twin (minus the existential crisis).&lt;/p&gt;


  



&lt;h3&gt;
  
  
  Voice Controls
&lt;/h3&gt;

&lt;p&gt;Because typing is so 2025, I added Web Speech API integration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speech-to-Text&lt;/strong&gt; — Click the mic, ask a question&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text-to-Speech&lt;/strong&gt; — Toggle TTS and hear responses read aloud&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works great on Chrome and Edge. Safari... tries its best. I added graceful fallbacks and a polite tooltip for unsupported browsers like Brave 😞.&lt;/p&gt;


  



&lt;h3&gt;
  
  
  Bonus: GitHub Repository Explorer
&lt;/h3&gt;

&lt;p&gt;I went a bit overboard and added a &lt;code&gt;/github&lt;/code&gt; page that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetches my public repos from the GitHub API&lt;/li&gt;
&lt;li&gt;Uses &lt;strong&gt;Gemini 2.5 Flash&lt;/strong&gt; to generate narrative "stories" for each repo&lt;/li&gt;
&lt;li&gt;Stores everything in &lt;strong&gt;ChromaDB&lt;/strong&gt; for semantic search&lt;/li&gt;
&lt;li&gt;Persists to &lt;strong&gt;Google Cloud Storage&lt;/strong&gt; so it survives container restarts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-maintainer System&lt;/strong&gt; — I set up a &lt;strong&gt;Cloud Scheduler&lt;/strong&gt; cron job that hits a protected backend endpoint (&lt;code&gt;/github/sync-trigger&lt;/code&gt;) every 30 days. It wakes up the container, fetches new repos, generates fresh AI stories, and rebuilds the vector index. The portfolio stays current even if I disappear into the woods.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result? A page where my repos aren't just listed—they're &lt;em&gt;explained&lt;/em&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%2Fi2eagwrfb108sncjau2f.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%2Fi2eagwrfb108sncjau2f.png" alt="GitHub Explorer"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  Easter Eggs 🥚
&lt;/h3&gt;

&lt;p&gt;Try typing "matrix" or "confetti" into the chat. You're welcome.&lt;/p&gt;


  



&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. The Scenario System Actually Works
&lt;/h3&gt;

&lt;p&gt;I was worried the fuzzy matching would feel janky, but Fuse.js + keyword fallback makes it feel surprisingly smart. Visitors don't know (or care) that it's not "real" AI—they just get fast, relevant answers.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. The Card Animations
&lt;/h3&gt;

&lt;p&gt;Every card slides in with staggered timing, hovers with subtle transforms, and the stats counters animate from zero. It sounds small, but the micro-interactions make the whole experience feel polished and premium.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Zero-to-Production in 10 Days
&lt;/h3&gt;

&lt;p&gt;From concept to deployed product—including 30 scenarios, voice controls, a RAG chatbot, responsive design, and Cloud Run deployment—in 10 days of focused work. Hackathon muscle memory kicked in hard.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. The GitHub Explorer Bonus
&lt;/h3&gt;

&lt;p&gt;This wasn't in the original plan, but I wanted my repos to tell stories instead of just listing name/description/stars. Gemini writing narratives for each project? &lt;em&gt;Chef's kiss.&lt;/em&gt; 👨‍🍳&lt;/p&gt;


&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Ask it anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Who are you?"&lt;/li&gt;
&lt;li&gt;"What's your Kubernetes experience?"&lt;/li&gt;
&lt;li&gt;"Show me your certifications"&lt;/li&gt;
&lt;li&gt;"What projects have you built?"&lt;/li&gt;
&lt;li&gt;Or just go rogue and use the chatbot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://portfolio-frontend-eoigebmhvq-uc.a.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;








&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Deploy frontend to Vercel with custom domain&lt;/li&gt;
&lt;li&gt;Add more easter eggs (I have ideas)&lt;/li&gt;
&lt;li&gt;Potentially add a "compare resumes" feature based on job description input&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! If you have questions, the chatbot's waiting. 😄&lt;/p&gt;




&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/War533KdqdE"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built with Next.js, FastAPI, Gemini AI, and way too much tea. ☕&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>Credit AI</title>
      <dc:creator>Adebayo Omolumo</dc:creator>
      <pubDate>Mon, 10 Nov 2025 07:41:17 +0000</pubDate>
      <link>https://forem.com/adebayoomolumo/credit-ai-1jgh</link>
      <guid>https://forem.com/adebayoomolumo/credit-ai-1jgh</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/agentic-postgres-2025-10-22"&gt;Agentic Postgres Challenge with Tiger Data&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TigerData Agentic Postgres in Action
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Making PostgreSQL Think, Reason, and Decide About Financial Risk&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Credit AI&lt;/strong&gt; is an intelligent credit decisioning system that showcases TigerData's revolutionary &lt;strong&gt;Agentic Postgres&lt;/strong&gt; capabilities. I wanted to create a product that companies like Buy Now, Pay Later (BNPL) Companies, Credit Card Issuers, Consumer Finance Companies, Credit Unions &amp;amp; Commercial Banks could not ignore.&lt;/p&gt;

&lt;p&gt;The database doesn't just store data—it actively participates in decision-making through &lt;strong&gt;four specialized TigerData agents&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feature Agent&lt;/strong&gt;: TimescaleDB continuous aggregates that maintain 20+ real-time financial metrics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rule Agent&lt;/strong&gt;: PostgreSQL functions that evaluate adaptive credit rules based on customer type
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pattern Agent&lt;/strong&gt;: SQL functions that detect behavioral anomalies and trends&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trend Agent&lt;/strong&gt;: Time-series analysis functions that identify income/spending trajectories&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎯 Problem Solved
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Traditional Credit Systems&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Point-in-time snapshot analysis&lt;/li&gt;
&lt;li&gt;❌ Static rules that miss context&lt;/li&gt;
&lt;li&gt;❌ Unfairly reject freelancers/non-traditional applicants&lt;/li&gt;
&lt;li&gt;❌ Black-box decisions without explanations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Credit AI Innovation with TigerData&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Time-series behavioral understanding&lt;/li&gt;
&lt;li&gt;✅ Dynamic rules that adapt to applicant type&lt;/li&gt;
&lt;li&gt;✅ Multi-agent database collaboration&lt;/li&gt;
&lt;li&gt;✅ Fully explainable decisions with reason codes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/xjaf60V1NXw"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Live Demo&lt;/strong&gt;: &lt;a href="https://credit-ai-tigerdb.netlify.app/" rel="noopener noreferrer"&gt;https://credit-ai-tigerdb.netlify.app/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🚀 &lt;strong&gt;API Endpoint&lt;/strong&gt;: &lt;a href="https://docker-credit-ai-api-dev-855607505295.europe-west4.run.app" rel="noopener noreferrer"&gt;https://docker-credit-ai-api-dev-855607505295.europe-west4.run.app&lt;/a&gt;&lt;br&gt;&lt;br&gt;
📹 &lt;strong&gt;Demo Video&lt;/strong&gt;: [6-minute system walkthrough showcasing agentic capabilities]&lt;br&gt;&lt;br&gt;
📂 &lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/bayurzx/credit_ai" rel="noopener noreferrer"&gt;https://github.com/bayurzx/credit_ai&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Key Demo Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive API Playground&lt;/strong&gt;: Test credit decisions for different customer types&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversational Analytics&lt;/strong&gt;: Ask questions like "Show me freelancers with improving cash flow"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Feature Extraction&lt;/strong&gt;: Watch 28+ financial metrics compute in &amp;lt;1 second&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explainable Decisions&lt;/strong&gt;: See exactly why each decision was made&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How I Used TigerData's Agentic Postgres
&lt;/h2&gt;

&lt;p&gt;I leveraged TigerData's revolutionary capabilities to transform PostgreSQL into a thinking, reasoning financial brain. Here's how I used &lt;strong&gt;TigerData's core features&lt;/strong&gt;:&lt;/p&gt;
&lt;h3&gt;
  
  
  🤖 TigerData Feature #1: TimescaleDB Continuous Aggregates (The Feature Agent)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- This materialized view actively maintains 28+ financial metrics&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;MATERIALIZED&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="n"&gt;financial_features_30d&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timescaledb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;continuous&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- Income Intelligence&lt;/span&gt;
    &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FILTER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;avg_income_30d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;STDDEV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FILTER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;income_volatility&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- Cash Flow Intelligence  &lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;net_cash_flow_30d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balance_after&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;avg_balance_30d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;-- Behavioral Intelligence&lt;/span&gt;
    &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;transaction_count_30d&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1 day'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transaction_date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Auto-refresh every hour - the database maintains itself!&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;add_continuous_aggregate_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'financial_features_30d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;start_offset&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'90 days'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;end_offset&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'1 hour'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;schedule_interval&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'1 hour'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Impact&lt;/strong&gt;: Feature extraction went from &lt;strong&gt;5-10 seconds&lt;/strong&gt; to &lt;strong&gt;&amp;lt;1 second&lt;/strong&gt; - a 10x performance improvement!&lt;/p&gt;
&lt;h3&gt;
  
  
  🧠 TigerData Feature #2: Advanced PostgreSQL Functions (The Rule Agent)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- This function adapts its analysis based on customer type&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;REPLACE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;calculate_income_stability&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;p_customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;p_customer_type&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="s1"&gt;'salaried'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;volatility&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trend&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;DECLARE&lt;/span&gt;
    &lt;span class="n"&gt;lookback_days&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;CASE&lt;/span&gt; 
        &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;p_customer_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'freelancer'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;  &lt;span class="c1"&gt;-- Longer for freelancers&lt;/span&gt;
        &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt; 
    &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;QUERY&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; 
        &lt;span class="n"&gt;STDDEV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;DECIMAL&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;volatility&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;REGR_SLOPE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;EXTRACT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;transaction_date&lt;/span&gt;&lt;span class="p"&gt;))::&lt;/span&gt;&lt;span class="nb"&gt;DECIMAL&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;trend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;CASE&lt;/span&gt; 
            &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&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="mi"&gt;12&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'HIGH'&lt;/span&gt;
            &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&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="mi"&gt;6&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'MEDIUM'&lt;/span&gt;
            &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'LOW'&lt;/span&gt;
        &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p_customer_id&lt;/span&gt;
        &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;transaction_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lookback_days&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;' days'&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="n"&gt;INTERVAL&lt;/span&gt;
        &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt; &lt;span class="k"&gt;STABLE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Innovation&lt;/strong&gt;: The database automatically adjusts its analysis - freelancers get 180-day lookbacks while salaried workers get 90-day analysis!&lt;/p&gt;
&lt;h3&gt;
  
  
  🎯 TigerData Feature #3: TimescaleDB Hyperfunctions (The Pattern Agent)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Detects spending anomalies and behavioral patterns&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;REPLACE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;analyze_spending_patterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p_customer_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;discretionary_ratio&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;spending_trend&lt;/span&gt; &lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;anomaly_count&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;warning_signs&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
    &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;QUERY&lt;/span&gt;
    &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;spending_analysis&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;SELECT&lt;/span&gt; 
            &lt;span class="c1"&gt;-- Discretionary spending ratio&lt;/span&gt;
            &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FILTER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'entertainment'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'dining'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'travel'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; 
            &lt;span class="k"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;disc_ratio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;-- Trend detection using linear regression&lt;/span&gt;
            &lt;span class="n"&gt;REGR_SLOPE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ABS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;EXTRACT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;transaction_date&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;trend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;-- Anomaly detection (2-sigma rule)&lt;/span&gt;
            &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FILTER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;ABS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ABS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;STDDEV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ABS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;anomalies&lt;/span&gt;
        &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;
        &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p_customer_id&lt;/span&gt;
            &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;transaction_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'90 days'&lt;/span&gt;
            &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; 
        &lt;span class="n"&gt;disc_ratio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;trend&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;DECIMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;anomalies&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ARRAY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;disc_ratio&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'High discretionary spending'&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;trend&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Increasing spending trend'&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;anomalies&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'Multiple large expenses detected'&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;
        &lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;spending_analysis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt; &lt;span class="k"&gt;STABLE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  🗣️ TigerData Feature #4: Tiger MCP Integration (The Conversation Agent)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Multi-provider LLM integration with intelligent routing
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NLPtoSQLConverter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_llm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Strategy 1: Template matching (80% success, &amp;lt;100ms)
&lt;/span&gt;        &lt;span class="n"&gt;template_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_try_template_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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;template_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;success&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;template_result&lt;/span&gt;

        &lt;span class="c1"&gt;# Strategy 2: Tiger MCP integration (15% additional, &amp;lt;1s)
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tiger_mcp_available&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;mcp_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_try_tiger_mcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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;mcp_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;success&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;mcp_result&lt;/span&gt;

        &lt;span class="c1"&gt;# Strategy 3: Multi-provider LLM (4% additional, &amp;lt;5s)
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;use_llm&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llm_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_try_llm_conversion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Strategy 4: Intelligent suggestions
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_generate_suggestions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;TigerData Magic&lt;/strong&gt;: Used &lt;code&gt;mcp_tiger_semantic_search_tiger_docs&lt;/code&gt; for development assistance and TimescaleDB setup guidance. Achieved &lt;strong&gt;99%+ query success rate&lt;/strong&gt; by combining Tiger MCP with multi-provider LLM integration!&lt;/p&gt;
&lt;h2&gt;
  
  
  TigerData Agentic Postgres Architecture
&lt;/h2&gt;
&lt;h3&gt;
  
  
  How TigerData Powers the Intelligence
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────┐
│                    FastAPI Application                      │
├─────────────────────────────────────────────────────────────┤
│  Decision Orchestrator  │  Analytics Engine  │  ML Pipeline │
├─────────────────────────────────────────────────────────────┤
│                 🐅 TigerData Agentic Postgres               │
│  ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│
│  │ TimescaleDB     │ │ PostgreSQL      │ │ Tiger MCP       ││
│  │ Continuous      │ │ Functions       │ │ Integration     ││
│  │ Aggregates      │ │ (Adaptive Rules)│ │ (NLP-to-SQL)    ││
│  └─────────────────┘ └─────────────────┘ └─────────────────┘│
│  ┌─────────────────────────────────────────────────────────┐│
│  │         TigerData Cloud (PostgreSQL 17.6 + TS 2.22.1)  ││
│  │    Hypertables: 1000 customers, 4395 accounts, 10K+    ││
│  │              payment records (30-day chunks)            ││
│  └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Performance Achievements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feature Extraction&lt;/strong&gt;: 45.9ms P95 (target: &amp;lt;1s) ✅&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credit Decisions&lt;/strong&gt;: ~800ms P95 (target: &amp;lt;2s) ✅
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics Queries&lt;/strong&gt;: ~2s P95 (target: &amp;lt;5s) ✅&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM Cost&lt;/strong&gt;: $0.003/query (target: &amp;lt;$0.01) ✅&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Success Rate&lt;/strong&gt;: 99%+ (target: 95%) ✅&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  TigerData Innovations Implemented
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. &lt;strong&gt;TimescaleDB Continuous Aggregates - The Game Changer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of expensive on-demand calculations, the database proactively maintains financial intelligence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- The database automatically knows each customer's financial health&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;avg_income_30d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;-- Updated hourly&lt;/span&gt;
    &lt;span class="n"&gt;income_volatility&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;-- Trend-aware&lt;/span&gt;
    &lt;span class="n"&gt;cash_flow_health&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;-- Multi-factor score&lt;/span&gt;
    &lt;span class="n"&gt;debt_to_income_estimate&lt;/span&gt;   &lt;span class="c1"&gt;-- Risk indicator&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;customer_latest_features&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Returns in 2ms instead of 2000ms!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. &lt;strong&gt;TigerData Schema Migration Strategy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I designed a &lt;strong&gt;credit-focused database schema&lt;/strong&gt; that leverages TigerData's full potential:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migration Strategy with TigerData:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;001_create_credit_tables.sql&lt;/code&gt; - All 3 core tables (customers, credit_accounts, payment_history)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;002_create_credit_hypertables.sql&lt;/code&gt; - Convert payment_history to TimescaleDB hypertable (30-day chunks)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;003_create_credit_aggregates.sql&lt;/code&gt; - Implement credit_profile_current with exact ML feature names&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;004_create_credit_functions.sql&lt;/code&gt; - Returns all 10 ML features, portfolio analysis, delinquency patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ 1000 customers with complete credit profiles&lt;/li&gt;
&lt;li&gt;✅ 4395 credit accounts with realistic utilization
&lt;/li&gt;
&lt;li&gt;✅ 10,272 payment records with risk-based patterns&lt;/li&gt;
&lt;li&gt;✅ All 10 ML model features ready for extraction&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Tiger MCP + Multi-Provider LLM Strategy&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I implemented a &lt;strong&gt;4-strategy NLP-to-SQL pipeline&lt;/strong&gt; that showcases TigerData's versatility:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategy 1&lt;/strong&gt;: Template matching (80% success - fast, reliable)&lt;br&gt;
&lt;strong&gt;Strategy 2&lt;/strong&gt;: Tiger MCP integration (15% additional - medium complexity)&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Strategy 3&lt;/strong&gt;: Multi-provider LLM (OpenAI, Gemini, Claude) (4% additional - complex queries)&lt;br&gt;
&lt;strong&gt;Strategy 4&lt;/strong&gt;: Intelligent error suggestions (1% fallback)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tiger MCP Usage:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Used &lt;code&gt;mcp_tiger_semantic_search_tiger_docs&lt;/code&gt; for development assistance&lt;/li&gt;
&lt;li&gt;Got TimescaleDB setup guidance and best practices&lt;/li&gt;
&lt;li&gt;Leveraged Tiger MCP for complex query understanding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;LLM Cost Optimization:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Achieved $0.003/query average cost (target: &amp;lt;$0.01)&lt;/li&gt;
&lt;li&gt;99%+ query success rate through intelligent routing&lt;/li&gt;
&lt;li&gt;Multi-provider fallback ensures reliability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned About TigerData
&lt;/h2&gt;

&lt;h3&gt;
  
  
  TigerData's Revolutionary Capabilities
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;TimescaleDB Continuous Aggregates&lt;/strong&gt;: The killer feature! Moving from on-demand to pre-computed features delivered 10x performance improvement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agentic SQL Functions&lt;/strong&gt;: PostgreSQL functions in TigerData can embody business intelligence and adapt their behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tiger MCP Integration&lt;/strong&gt;: Seamless development assistance through &lt;code&gt;mcp_tiger_semantic_search_tiger_docs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hypertable Performance&lt;/strong&gt;: 30-day chunks with compression policies made 10K+ payment records lightning fast&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  TigerData Performance Achievements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feature Extraction&lt;/strong&gt;: 45.9ms P95 (target: &amp;lt;1s) ✅ - Thanks to continuous aggregates!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credit Decisions&lt;/strong&gt;: ~800ms P95 (target: &amp;lt;2s) ✅ - Powered by hypertables!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics Queries&lt;/strong&gt;: ~2s P95 (target: &amp;lt;5s) ✅ - Tiger MCP + LLM integration!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ML Model&lt;/strong&gt;: AUC = 0.8840 (target: &amp;gt;0.70) ✅ - LightGBM on TigerData!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Success&lt;/strong&gt;: 99%+ (target: 95%) ✅ - Multi-strategy with Tiger MCP!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TigerData's Future Potential
&lt;/h2&gt;

&lt;p&gt;Credit AI demonstrates what's possible when you unleash &lt;strong&gt;TigerData's Agentic Postgres&lt;/strong&gt; capabilities:&lt;/p&gt;

&lt;h3&gt;
  
  
  What TigerData Enables:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Intelligence&lt;/strong&gt;: TimescaleDB continuous aggregates provide insights the moment data arrives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable Analytics&lt;/strong&gt;: Database-native computation scales with data volume&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversational Interfaces&lt;/strong&gt;: Tiger MCP makes complex databases accessible through natural language&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Agent Coordination&lt;/strong&gt;: Different database functions act as specialized reasoning agents&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Next Applications with TigerData:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fraud Detection&lt;/strong&gt;: Real-time behavioral anomaly detection with hyperfunctions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer Churn Prediction&lt;/strong&gt;: Proactive retention using continuous aggregates
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Pricing&lt;/strong&gt;: Risk-based pricing with real-time feature computation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regulatory Reporting&lt;/strong&gt;: Automated compliance through intelligent SQL functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;TigerData doesn't just store data - it thinks about data!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TigerData-Powered Technical Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🐅 TigerData Cloud&lt;/strong&gt;: PostgreSQL 17.6 + TimescaleDB 2.22.1 (The Star!)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🐅 Tiger MCP&lt;/strong&gt;: Development assistance and semantic search integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🐅 TimescaleDB Features&lt;/strong&gt;: Continuous aggregates, hypertables, hyperfunctions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: FastAPI with async/await for high concurrency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ML&lt;/strong&gt;: LightGBM (AUC: 0.884) with SHAP explainability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM&lt;/strong&gt;: Multi-provider (OpenAI, Gemini, Claude) with Tiger MCP integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Vanilla JavaScript showcasing TigerData capabilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt;: Docker containerization optimized for TigerData&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Special Thanks to TigerData
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🐅 TigerData Team&lt;/strong&gt;: For creating the revolutionary Agentic Postgres platform that made this entire vision possible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🐅 TimescaleDB Integration&lt;/strong&gt;: For the seamless time-series capabilities that power our continuous aggregates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🐅 Tiger MCP&lt;/strong&gt;: For the development assistance that accelerated our implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🐅 TigerData Cloud&lt;/strong&gt;: For the robust, scalable infrastructure that handles our complex workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why TigerData Won This Challenge
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;TigerData didn't just provide a database - they provided a thinking partner.&lt;/strong&gt; The continuous aggregates eliminated our performance bottlenecks, the hyperfunctions enabled sophisticated analysis, and Tiger MCP guided our development process. This isn't just PostgreSQL - this is PostgreSQL with superpowers.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;🐅 Credit AI proves that TigerData's Agentic Postgres is the future of intelligent applications. We didn't just build a credit system - we built a financial reasoning engine that thinks, adapts, and explains its decisions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🏆 &lt;strong&gt;Ready to see TigerData's Agentic Postgres in action? Try the live demo!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Demo&lt;/strong&gt;: &lt;a href="https://credit-ai-tigerdb.netlify.app/" rel="noopener noreferrer"&gt;https://credit-ai-tigerdb.netlify.app/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/bayurzx/credit_ai" rel="noopener noreferrer"&gt;https://github.com/bayurzx/credit_ai&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;API&lt;/strong&gt;: &lt;a href="https://docker-credit-ai-api-dev-855607505295.europe-west4.run.app" rel="noopener noreferrer"&gt;https://docker-credit-ai-api-dev-855607505295.europe-west4.run.app&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>agenticpostgreschallenge</category>
      <category>ai</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Kubernetes Storage: Trading a Ferrari for a Reliable Minivan.</title>
      <dc:creator>Adebayo Omolumo</dc:creator>
      <pubDate>Wed, 22 Oct 2025 20:22:20 +0000</pubDate>
      <link>https://forem.com/adebayoomolumo/kubernetes-storage-trading-a-ferrari-for-a-reliable-minivan-4hfg</link>
      <guid>https://forem.com/adebayoomolumo/kubernetes-storage-trading-a-ferrari-for-a-reliable-minivan-4hfg</guid>
      <description>&lt;p&gt;Okay, let’s step back a bit. About two weeks ago, I was performing open-heart surgery on my production-grade Kubernetes cluster — I swapped out the storage backbone from Rook-Ceph to Longhorn.&lt;/p&gt;

&lt;p&gt;And I'm happy to report: the patient is not only alive but running better than ever.&lt;/p&gt;

&lt;p&gt;No theoretical deep-dive here—this is a raw, post-migration debrief from the trenches. If you've ever whispered the words "my storage is a bit... fragile," grab a coffee. This one's for you.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Part 1: The "Why Now?" Moment&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let's be real: I didn't just wake up and decide to rip out a core infrastructure piece for fun. Rook-Ceph is powerful. It’s like owning a Formula 1 car. But my needs? I was basically just doing a school run.&lt;/p&gt;

&lt;p&gt;I needed reliable block storage for my databases, backups and queues. Instead, I got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;"Operational Russian Roulette":&lt;/strong&gt; A single Ceph Monitor having a bad day could trigger a debugging session that felt like defusing a bomb. So many moving parts!&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Resource Hunger Games:&lt;/strong&gt; My Ceph OSDs would constantly brawl with &lt;code&gt;kubelet&lt;/code&gt; for CPU and RAM. The result? Unpredictable node instability that made me a little twitchy.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The "Day-2 Ops" Black Hole:&lt;/strong&gt; I found myself needing to become a Ceph expert, just to keep the lights on. That's not a strategic investment; that's a part-time job I didn't apply for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After one too many 2 AM pages, the message was clear: &lt;strong&gt;My F1 car was too high-maintenance for the daily commute.&lt;/strong&gt; I needed a reliable minivan.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Part 2: The Switch - A Storage Mindset Shift&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Moving from Rook-Ceph to Longhorn isn't a simple "plug and play." It's a fundamental philosophical change.&lt;/p&gt;

&lt;p&gt;I went from managing &lt;strong&gt;dedicated raw block devices&lt;/strong&gt; to using &lt;strong&gt;shared filesystems.&lt;/strong&gt; Think of it like swapping a dedicated warehouse for every tenant (Ceph) for a modern apartment building with secure, individual units (Longhorn).&lt;/p&gt;

&lt;p&gt;Here’s where the real work happened:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change #1: The Great "Raw Disk" Purge&lt;/strong&gt;&lt;br&gt;
Gone are the days of provisioning special &lt;code&gt;/dev/sdb&lt;/code&gt; EBS volumes for Ceph to devour. Longhorn just uses a folder on your existing filesystem. I deleted so much convoluted Terraform and disk-prep code. It was cathartic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;👋 Shout-out to my Talos users!&lt;/strong&gt; This new model is a dream for you. Use the partitioning feature to create a dedicated spot, format it, mount it at &lt;code&gt;/var/lib/longhorn&lt;/code&gt;, and you're golden. All the isolation, none of the raw device voodoo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Change #2: The Prerequisite Scavenger Hunt&lt;/strong&gt;&lt;br&gt;
Longhorn runs on classic Linux tech: iSCSI and NFS. This meant I had to ensure every node had &lt;code&gt;open-iscsi&lt;/code&gt; and &lt;code&gt;nfs-utils&lt;/code&gt; installed and enabled. A quick update to my node bootstrap scripts (or &lt;code&gt;MachineConfig&lt;/code&gt; for the Talos crew) and I was in business.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change #3: Label Liberation&lt;/strong&gt;&lt;br&gt;
Rook-Ceph required me to manually tag nodes with labels like &lt;code&gt;storage-node=true&lt;/code&gt;. Longhorn's &lt;code&gt;manager&lt;/code&gt; DaemonSet just automatically discovers everything. I tore those labels off and celebrated my newfound simplicity.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Part 3: My 2-Week Migration Playbook (That Actually Worked)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;So how did I do it without a multi-day outage? Carefully.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Stage 1: The Controlled Demolition.&lt;/strong&gt; I followed the Rook docs to decommission Ceph &lt;em&gt;safely&lt;/em&gt;. (Let me say this louder for the people in the back: &lt;strong&gt;HAVE VERIFIED BACKUPS&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Stage 2: The Node Makeover.&lt;/strong&gt; I rolled through my nodes, wiping Ceph configs, installing the iSCSI/NFS prereqs, and setting up my dedicated Longhorn partition.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Stage 3: The New Sheriff in Town.&lt;/strong&gt; A simple &lt;code&gt;kubectl apply&lt;/code&gt; brought Longhorn online. It was almost... aNticlImActIC.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Stage 4: The Grand Reopening.&lt;/strong&gt; I created a new Longhorn &lt;code&gt;StorageClass&lt;/code&gt; and began methodically migrating my StatefulSets. One by one, they came online with their new, simpler storage backend.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The Verdict After 2 Weeks?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I traded a feature-laden behemoth for a focused, Kubernetes-native specialist. And I have zero regrets.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;My on-call phone has stopped buzzing.&lt;/strong&gt; The "mystery" storage instability is gone.&lt;br&gt;
✅ &lt;strong&gt;Debugging is now... logical.&lt;/strong&gt; The UI is clear, and the logs make sense.&lt;br&gt;
✅ &lt;strong&gt;It just feels solid.&lt;/strong&gt; Recovery is faster, and the entire system is more predictable.&lt;/p&gt;

&lt;p&gt;Sometimes, the "best" tool isn't the right tool. For me, Longhorn was the &lt;em&gt;right&lt;/em&gt; tool.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Ever been through a major infrastructure swap as a solo operator? Was it a glorious victory or a cautionary tale? I'd love to hear your war stories in the comments!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>longhorn</category>
      <category>sre</category>
    </item>
    <item>
      <title>TF?!: Power of Terraform - A Simple Guide</title>
      <dc:creator>Adebayo Omolumo</dc:creator>
      <pubDate>Mon, 25 Sep 2023 15:02:30 +0000</pubDate>
      <link>https://forem.com/adebayoomolumo/tf-power-of-terraform-a-simple-guide-1n09</link>
      <guid>https://forem.com/adebayoomolumo/tf-power-of-terraform-a-simple-guide-1n09</guid>
      <description>&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%2Fxah4r1k2v93i6nprdalu.jpg" 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%2Fxah4r1k2v93i6nprdalu.jpg" alt="TF?!!!" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this guide, we'll delve into Terraform's capabilities, explore its revamped licensing, and provide you with a step-by-step walkthrough for effective infrastructure automation. &lt;/p&gt;

&lt;p&gt;Terraform is a custodian of infrastructure code, meticulously curated by diligent developers. Its purpose? To automate and manage the provisioning and configuration of infrastructure resources, spanning virtual machines, networks, and storage, across various cloud and on-premises environments. This ingenious tool, conceived by HashiCorp, comprises hundreds of modules written in the HashiCorp Configuration Language (HCL), collectively supported by a vibrant community of developers dedicated to deploying cloud and on-premises infrastructure and services.&lt;/p&gt;

&lt;p&gt;With Terraform, you can say goodbye to the tedium of clicking buttons or typing repetitive command lines for deploying JS or static frontend files. Terraform simplifies infrastructure management by automating the provisioning and configuration of resources across various cloud and on-premises environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Big Changes
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Starting from version 1.6, HashiCorp transitioned to a BSL license from MPL v2, marking significant changes in its journey.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On August 10, 2023, HashiCorp announced a significant shift in licensing for its products, including Terraform. After nearly a decade of being open source under the MPL v2 license, Terraform transitioned to a non-open source BSL v1.1 license, starting with version 1.6.&lt;/p&gt;

&lt;p&gt;While this change primarily impacts the business landscape, it has triggered notable developments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On August 25th, 2023, the OpenTF initiative officially unveiled an open-source fork of Terraform.&lt;/li&gt;
&lt;li&gt;On September 5th, 2023, the OpenTF repository went public, quickly amassing over 32,000 GitHub Stars.&lt;/li&gt;
&lt;li&gt;On September 20th, 2023, OpenTF became a part of the Linux Foundation and underwent a rebranding, emerging as OpenTofu.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Unveiling the Inner Workings
&lt;/h2&gt;

&lt;p&gt;Behind the scenes, Terraform employs a dependency resolution algorithm that &lt;em&gt;automagically&lt;/em&gt; figures out the order in which resources need to be created or updated. The process unfolds as follows:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Configuration Parsing
&lt;/h3&gt;

&lt;p&gt;Terraform meticulously formats and parses your configuration files for syntax correctness, employing &lt;code&gt;tf fmt&lt;/code&gt; and &lt;code&gt;tf validate&lt;/code&gt; commands.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Resource Discovery
&lt;/h3&gt;

&lt;p&gt;Terraform communicates with the configured providers (AWS, Azure, Google Cloud, etc.) to uncover the present state of the infrastructure resources aligned with your configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Dependency Graph Construction
&lt;/h3&gt;

&lt;p&gt;Terraform then constructs a dependency graph based on the relationships defined in your configuration. Each resource becomes a node in this graph, and any resource with dependencies is connected via direct references or pointers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Topological Sorting
&lt;/h3&gt;

&lt;p&gt;Topological sort is a graph traversal algorithm in which each node is visited only after all its dependencies are visited. In other words, resource dependencies are created before the actual resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Error Handling
&lt;/h3&gt;

&lt;p&gt;Terraform's dependency resolution algorithm includes error handling. If a resource encounters issues during creation or updating, Terraform attempts to clean up successfully created resources with dependencies on the problematic resource before proceeding to create resources with no dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Parallelization Planning
&lt;/h3&gt;

&lt;p&gt;While determining the correct order of resource creation or updates, Terraform also identifies opportunities for parallelization. Resources that lack dependencies on each other can be created or updated concurrently.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. State Management
&lt;/h3&gt;

&lt;p&gt;Terraform meticulously tracks the state of each resource. It knows whether a resource has been created, needs an update, or should be obliterated, based on differences between the desired configuration and the current state.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Dry Run
&lt;/h3&gt;

&lt;p&gt;Terraform introduces a dry run, enabling you to preview the intended changes before committing to infrastructure modifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Apply Phase
&lt;/h3&gt;

&lt;p&gt;In the apply phase, Terraform executes the plan generated during the dry run. It creates, updates, or destroys resources as necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. State Management (Again)
&lt;/h3&gt;

&lt;p&gt;After applying changes, Terraform updates its internal state file to reflect the current state of the infrastructure. This state file proves invaluable for tracking changes and ensuring future runs remain idempotent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting Terraform to the Test with a Static Site
&lt;/h2&gt;

&lt;p&gt;Let's dive into Terraform by automating the deployment of a static website on AWS, making it readily accessible to users. Before we delve into the sequential process of hosting a static website, a few things to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is a basic site, and we won't be configuring a custom domain or a signed certificate.&lt;/li&gt;
&lt;li&gt;It's ideal for testing your staging environment.&lt;/li&gt;
&lt;li&gt;This approach is compatible with static ReactJS or Next.js sites.&lt;/li&gt;
&lt;li&gt;Our provider of choice will be AWS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preparing for Liftoff
&lt;/h2&gt;

&lt;p&gt;For those new to Terraform and AWS, we have some preliminary steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up AWS Configuration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you're new to AWS, start by running &lt;code&gt;aws configure&lt;/code&gt; to generate your &lt;code&gt;region&lt;/code&gt;, &lt;code&gt;aws_secret_access_key&lt;/code&gt;, and &lt;code&gt;aws_access_key_id&lt;/code&gt; into your &lt;code&gt;config&lt;/code&gt; file at &lt;code&gt;~/.aws/&lt;/code&gt;. &lt;code&gt;~&lt;/code&gt; or &lt;code&gt;$HOME&lt;/code&gt; represents your home directory on both unix and Windows systems, applicable to both Unix and Windows systems.&lt;/li&gt;
&lt;li&gt;Retrieve your &lt;code&gt;aws_secret_access_key&lt;/code&gt; and &lt;code&gt;aws_access_key_id&lt;/code&gt; from the AWS console by following the &lt;a href="https://docs.aws.amazon.com/sdkref/latest/guide/access-iam-users.html" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;Select the AWS region closest to your location for &lt;code&gt;region&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Terraform Setup
&lt;/h3&gt;

&lt;p&gt;Visit the &lt;a href="https://developer.hashicorp.com/terraform/downloads" rel="noopener noreferrer"&gt;HashiCorp website&lt;/a&gt; to set up Terraform.&lt;br&gt;
Don't forget to &lt;a href="https://www.tecmint.com/create-alias-in-linux/" rel="noopener noreferrer"&gt;alias&lt;/a&gt; &lt;code&gt;terraform&lt;/code&gt; as &lt;code&gt;tf&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Now that you're ready, let's proceed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Infrastructure Components
&lt;/h3&gt;

&lt;p&gt;Our infrastructure will comprise the following core resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Amazon S3 Bucket&lt;/strong&gt;: Amazon S3 (Simple Storage Service) is an object storage service provided by AWS. It allows you to store and retrieve data, such as files, images, videos, and backups, in the cloud. We'll be working with various aspects of it, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS S3 Objects (&lt;code&gt;aws_s3_object&lt;/code&gt;): Representing individual objects stored in an S3 bucket.&lt;/li&gt;
&lt;li&gt;AWS S3 Bucket Website Configuration (&lt;code&gt;aws_s3_bucket_website_configuration&lt;/code&gt;): Configuring static website hosting for an S3 bucket.&lt;/li&gt;
&lt;li&gt;AWS S3 Bucket Public Access Policy (&lt;code&gt;aws_s3_bucket_public_access_block&lt;/code&gt;): Defining policies to control public access to an S3 bucket, enhancing security.&lt;/li&gt;
&lt;li&gt;AWS S3 Bucket Ownership Controls (&lt;code&gt;aws_s3_bucket_ownership_controls&lt;/code&gt;): Enabling ownership controls and management for S3 buckets to enforce data governance.&lt;/li&gt;
&lt;li&gt;AWS S3 Bucket Policy (&lt;code&gt;aws_s3_bucket_policy&lt;/code&gt;): Specifying access policies and permissions for an S3 bucket, governing who can interact with the bucket and how.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CloudFront&lt;/strong&gt;: Amazon CloudFront is a content delivery network (CDN) service provided by AWS. It distributes content like web pages, videos, images, and other assets globally with low latency and high data transfer speeds. Our usage will encompass:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS CloudFront Distribution (&lt;code&gt;aws_cloudfront_distribution&lt;/code&gt;): Facilitating the delivery of content from edge locations for faster and more reliable access.&lt;/li&gt;
&lt;li&gt;AWS CloudFront Origin Access Identity (&lt;code&gt;aws_cloudfront_origin_access_identity&lt;/code&gt;): Establishing an Origin Access Identity (OAI), enhancing security by controlling access to the origin of a CloudFront distribution.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Provider and AWS Credentials Declaration
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/aws"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"4.65.0"&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="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;profile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform"&lt;/span&gt;  &lt;span class="c1"&gt;# AWS Credentials Profile configured on your local machine at $HOME/.aws/credentials&lt;/span&gt;

  &lt;span class="c1"&gt;# Uncomment this lines if not running on your local machine&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# region  = "us-east-1"  &lt;/span&gt;
  &lt;span class="c1"&gt;# access_key = var.aws_access_key_id  &lt;/span&gt;
  &lt;span class="c1"&gt;# secret_key = var.aws_secret_access_key  &lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Remember that &lt;code&gt;aws configure&lt;/code&gt; command? I named my AWS credential as &lt;code&gt;terraform&lt;/code&gt;. You can easily confirm the name of your profile by running &lt;code&gt;cat ~/.aws/credentials&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Creating Bucket Resources
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create bucket resources&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"staticSite"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"staticsite-${var.ID}"&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Static-Site bucket name"&lt;/span&gt;
    &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Staging"&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;blockquote&gt;
&lt;p&gt;The &lt;code&gt;bucket&lt;/code&gt; variable is mandatory.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_object"&lt;/span&gt; &lt;span class="s2"&gt;"out"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../out"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"**/*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticSite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;key&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../out/${each.value}"&lt;/span&gt;
  &lt;span class="nx"&gt;etag&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filemd5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../out/${each.value}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# content_type = "text/html"&lt;/span&gt;
  &lt;span class="nx"&gt;content_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mime_types&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticSite&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;p&gt;This section enables you to upload all your site's files, treating each file and subdirectory as an individual resource. Let's break it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;for_each = fileset("../out", "**/*")&lt;/code&gt;: The &lt;code&gt;for_each&lt;/code&gt; attribute allows you to create multiple instances of a resource based on the elements of a &lt;code&gt;map&lt;/code&gt; or &lt;code&gt;set&lt;/code&gt; variable. In essence, it loops through a set (array) and creates resources accordingly. &lt;code&gt;fileset&lt;/code&gt; is a built-in function generating a list of file paths by matching a specified pattern, helping us create the set needed for looping through and creating these resources. You provide the directory path and the regex pattern as arguments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bucket&lt;/code&gt;, &lt;code&gt;key&lt;/code&gt;, &lt;code&gt;source&lt;/code&gt;, &lt;code&gt;etag&lt;/code&gt;, and &lt;code&gt;content_type&lt;/code&gt; are attributes of the &lt;code&gt;aws_s3_object&lt;/code&gt; resource. Among these, &lt;code&gt;bucket&lt;/code&gt; and &lt;code&gt;key&lt;/code&gt; are mandatory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bucket&lt;/code&gt; represents the bucket name or ARN value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;key&lt;/code&gt; denotes the name to assign to the file in the bucket.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;source&lt;/code&gt; points to the file path.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;etag&lt;/code&gt; triggers updates when the file changes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;content_type&lt;/code&gt; indicates the standard MIME type describing the format of the object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;filemd5&lt;/code&gt; is a cryptographic hash function used to generate a fixed-size string of characters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lookup(var.mime_types, element(split(".", each.key), length(split(".", each.key)) - 1))&lt;/code&gt; extracts the file extension and retrieves the appropriate MIME type from the mapped string. This step is vital; without proper MIME types, files may not display correctly on the website. I created a variable called &lt;code&gt;mime_types&lt;/code&gt; in &lt;code&gt;variable.tf&lt;/code&gt; file to store the mapped MIME values:
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"mime_types"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"html"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"text/html"&lt;/span&gt;
    &lt;span class="s2"&gt;"ico"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"image/x-icon"&lt;/span&gt;
    &lt;span class="s2"&gt;"jpg"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"image/jpeg"&lt;/span&gt;
    &lt;span class="s2"&gt;"py"&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"text/x-python"&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="s2"&gt;"json"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;
    &lt;span class="s2"&gt;"map"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;
    &lt;span class="s2"&gt;"txt"&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"text/plain"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_website_configuration"&lt;/span&gt; &lt;span class="s2"&gt;"staticSite-website"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticSite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;index_document&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;suffix&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.html"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;error_document&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"404.html"&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;blockquote&gt;
&lt;p&gt;The &lt;code&gt;index_document&lt;/code&gt; specifies the file to load as the homepage, and &lt;code&gt;error_document&lt;/code&gt; steps in when a file is not found.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_public_access_block"&lt;/span&gt; &lt;span class="s2"&gt;"staticSite-ACL"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticSite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;block_public_acls&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;block_public_policy&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;ignore_public_acls&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;restrict_public_buckets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This ensures that all public access is permitted for users to view (read) the files. We will define a policy that allows only read operations below.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_ownership_controls"&lt;/span&gt; &lt;span class="s2"&gt;"staticSite-object_ownership"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticSite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;object_ownership&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ObjectWriter"&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;blockquote&gt;
&lt;p&gt;Ownership controls are used to enforce object ownership when uploading objects to the S3 bucket. In this context, the "ObjectWriter" rule means that only the AWS account that uploads an object is considered the object's owner.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_policy"&lt;/span&gt; &lt;span class="s2"&gt;"staticSite-Policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticSite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadForGetBucketObjects",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::${aws_s3_bucket.staticSite.id}/*"
    }
  ]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;staticSite&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;blockquote&gt;
&lt;p&gt;This standard AWS policy allows read actions for all S3 files in the AWS ARN.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  CloudFront
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_cloudfront_origin_access_identity"&lt;/span&gt; &lt;span class="s2"&gt;"CloudFrontOriginAccessIdentity"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;comment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Origin Access Identity for Serverless Static Website"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This section creates an AWS CloudFront Origin Access Identity (OAI).&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_cloudfront_distribution"&lt;/span&gt; &lt;span class="s2"&gt;"WebpageCDN"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;domain_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"onlinesafety-${var.ID}.s3-website-us-east-1.amazonaws.com"&lt;/span&gt;
    &lt;span class="nx"&gt;origin_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"webpage"&lt;/span&gt;
    &lt;span class="nx"&gt;custom_origin_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;http_port&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
      &lt;span class="nx"&gt;https_port&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
      &lt;span class="nx"&gt;origin_protocol_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"match-viewer"&lt;/span&gt;  &lt;span class="c1"&gt;# https-only | http-only | match-viewer&lt;/span&gt;
      &lt;span class="nx"&gt;origin_ssl_protocols&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"SSLv3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"TLSv1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"TLSv1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"TLSv1.2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Ensure compatibility with a wide range of clients and servers.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;enabled&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;default_root_object&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"index.html"&lt;/span&gt;

  &lt;span class="nx"&gt;default_cache_behavior&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;forwarded_values&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;query_string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

      &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;forward&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"none"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;target_origin_id&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"webpage"&lt;/span&gt;
    &lt;span class="nx"&gt;viewer_protocol_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"allow-all"&lt;/span&gt;  &lt;span class="c1"&gt;# Changed back from redirect-to-https&lt;/span&gt;


    &lt;span class="nx"&gt;allowed_methods&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"OPTIONS"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;cached_methods&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"OPTIONS"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;restrictions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;geo_restriction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;restriction_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"none"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;viewer_certificate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cloudfront_default_certificate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnlineSafetyBS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&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;p&gt;This section creates the CloudFront distribution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;origin&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;domain_name&lt;/code&gt;: Specifies the domain name or endpoint of the origin server in your configuration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;origin_id&lt;/code&gt;: Defined by the user, serving as an identifier for the origin.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;enabled&lt;/code&gt;: The enabled attribute is set to true, signifying that the CloudFront distribution is operational.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;default_root_object&lt;/code&gt;: Defines the default object to serve when a viewer requests the root URL of your distribution.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;default_cache_behavior&lt;/code&gt;: Cache behavior settings should adhere to your region's Data Protection Regulations. Here, CloudFront does not forward any cookies to the origin server.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;restrictions&lt;/code&gt;: Typically set to none unless you wish to restrict access to certain regions, like China or North Korea, due to policy considerations.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;viewer_certificate&lt;/code&gt;: As we don't have a custom certificate, we allow AWS CloudFront to provide one for us, enabling HTTPS browsing.&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"CloudFrontURL"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://${aws_cloudfront_distribution.WebpageCDN.domain_name}"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"URL for the CloudFront distribution"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This outputs the CloudFront URL, making it readily accessible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Running Terraform Commands
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initialization
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;init&lt;/code&gt;, short for initialization, is typically the first command you run when working with Terraform. It accomplishes the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initializes the Working Directory: Checks if your Terraform configuration files are present in the current working directory.&lt;/li&gt;
&lt;li&gt;Downloads Provider Plugins: Downloads and installs necessary provider plugins. Providers declared in your configuration files could be AWS, Azure, Google Cloud, or others.&lt;/li&gt;
&lt;li&gt;Sets Up Backend Configuration: Backend configuration specifies where Terraform should store its state files. In this example, they are stored locally, but Terraform Cloud is an example of how they could be stored remotely.&lt;/li&gt;
&lt;li&gt;Creates and Initializes Modules: If modules are included, &lt;code&gt;terraform init&lt;/code&gt; also initializes the modules, downloading any required module sources or dependencies.&lt;/li&gt;
&lt;li&gt;Generates Lock Files: Generates a &lt;code&gt;terraform.lock.hcl&lt;/code&gt; file that records the versions of provider plugins.&lt;/li&gt;
&lt;li&gt;Verifies Configuration Files: Terraform checks the syntax and validity of your configuration files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Planning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Previews Changes: Provides a detailed preview of the infrastructure changes that Terraform will make (Dry Run).&lt;/li&gt;
&lt;li&gt;Dependency Analysis: Terraform evaluates the dependencies between resources and shows you the order in which changes will be applied.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that Terraform expects a Terraform variable file or inline input using &lt;code&gt;terraform plan&lt;/code&gt;. You can add your variables to &lt;code&gt;terraform.tfvars&lt;/code&gt; as key-value pairs or input them inline, e.g., &lt;code&gt;terraform plan -var "key1=value1" -var "key2=value2"&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Applying Changes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Terraform &lt;code&gt;plan&lt;/code&gt; effectively runs again to outline the changes that will be made.&lt;/li&gt;
&lt;li&gt;Request for Approval: Terraform seeks your approval.&lt;/li&gt;
&lt;li&gt;After your approval, Terraform proceeds to make the necessary changes to your infrastructure. It communicates with the cloud provider's APIs or other infrastructure management tools to create or modify resources.&lt;/li&gt;
&lt;li&gt;Terraform is designed to be idempotent, meaning it can be run multiple times without causing harm. If the desired state matches the actual state, Terraform takes no action.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Destroying Resources
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If you want to reverse changes made by a previous &lt;code&gt;terraform apply&lt;/code&gt;, you can use &lt;code&gt;terraform destroy&lt;/code&gt; to remove the created resources.&lt;/li&gt;
&lt;li&gt;Be cautious when using &lt;code&gt;destroy&lt;/code&gt;, as it permanently deletes resources.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Terraform stands as a powerful ally in the realm of infrastructure automation. Its declarative approach, dependency resolution, and seamless integration with major cloud providers empower DevOps professionals to efficiently orchestrate, manage, and scale complex infrastructures.&lt;/p&gt;

&lt;p&gt;By following the steps and best practices outlined here, you'll harness the power of Terraform to efficiently manage your cloud resources. Whether you're a seasoned DevOps engineer or just starting your cloud journey.&lt;/p&gt;




&lt;p&gt;~ &lt;em&gt;By **Adebayo Omolumo&lt;/em&gt;**&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/adebayo-omolumo/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FLinkedIn-Adebayo_Omolumo-brightgreen%3Fstyle%3Dfor-the-badge%26labelColor%3Dblue%26logo%3Dlinkedin" width="241" height="28"&gt;&lt;/a&gt; &lt;br&gt;
&lt;a href="https://visit.adebayoomolumo.website/projects/onepage.html" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FPortfolio-%25F0%259F%259A%2580_-brightgreen%3Fstyle%3Dfor-the-badge%26labelColor%3Dblue%26logo%3Dcloudways" width="146" height="28"&gt;&lt;/a&gt; &lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>aws</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>I Failed My first AZ-400 Exam and Immediately Scored a FREE Retake!</title>
      <dc:creator>Adebayo Omolumo</dc:creator>
      <pubDate>Thu, 24 Aug 2023 07:54:50 +0000</pubDate>
      <link>https://forem.com/adebayoomolumo/i-failed-my-first-az-400-exam-and-immediately-scored-a-free-retake-4cdp</link>
      <guid>https://forem.com/adebayoomolumo/i-failed-my-first-az-400-exam-and-immediately-scored-a-free-retake-4cdp</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
I Failed My first AZ-400 Exam and Immediately Scored a FREE Retake!

&lt;ul&gt;
&lt;li&gt;Table of Contents&lt;/li&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Understanding the AZ-400 Exam&lt;/li&gt;
&lt;li&gt;1. Configure Processes and Communications (10-15%)&lt;/li&gt;
&lt;li&gt;2. Design and Implement Source Control (15-20%)&lt;/li&gt;
&lt;li&gt;3. Design and Implement Build and Release Pipelines (40-45%)&lt;/li&gt;
&lt;li&gt;4. Develop a Security and Compliance Plan (10-15%)&lt;/li&gt;
&lt;li&gt;5. Implement an Instrumentation Strategy (10-15%)&lt;/li&gt;
&lt;li&gt;Securing a Free Voucher&lt;/li&gt;
&lt;li&gt;Preparing for the Exam&lt;/li&gt;
&lt;li&gt;What to Expect in the Exam&lt;/li&gt;
&lt;li&gt;Exam Structure and Retake Policy&lt;/li&gt;
&lt;li&gt;The Retake Opportunity&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Are you considering taking the &lt;a href="https://learn.microsoft.com/en-us/certifications/exams/az-400/" rel="noopener noreferrer"&gt;AZ-400 exam&lt;/a&gt;, "Designing and Implementing Microsoft DevOps Solutions"? If so, you're in for a rewarding journey. &lt;br&gt;
In this article, we'll dive into what you can expect from this certification, how to secure a free voucher, and, most importantly, how to obtain a free retake voucher in case the unexpected happens. &lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the AZ-400 Exam
&lt;/h2&gt;

&lt;p&gt;The AZ-400 exam, offered by Microsoft, is a pivotal certification for those aspiring to excel in DevOps practices using Microsoft technologies. This comprehensive exam focuses on five key objectives:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Configure Processes and Communications (10-15%)
&lt;/h3&gt;

&lt;p&gt;This objective involves setting up and optimizing communication and processes within a DevOps environment. It encompasses methodologies like CMMI, Scrum, and Agile, along with tools such as Azure DevOps Boards and Microsoft Teams channels. The goal is to create efficient workflows and utilize project wikis as knowledge repositories.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Design and Implement Source Control (15-20%)
&lt;/h3&gt;

&lt;p&gt;Managing source code effectively is crucial in DevOps. This objective entails implementing policies for code validation, using Git features, and understanding tools like BFG and Git LFS. Candidates should also excel in branch strategies tailored to project releases.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Design and Implement Build and Release Pipelines (40-45%)
&lt;/h3&gt;

&lt;p&gt;This core aspect of DevOps covers creating and managing build and release pipelines. Topics include optimizing build pipelines with Azure Pipelines Caching, handling code artifacts for various platforms, defining versioning strategies, configuring triggers, using service connections, setting up release gates, and managing hosted agents and retention policies.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Develop a Security and Compliance Plan (10-15%)
&lt;/h3&gt;

&lt;p&gt;Security and compliance are integral to DevOps. This objective entails creating a robust plan to ensure security throughout the application lifecycle. It may involve security validation plans, passive penetration testing, and implementing Azure Policies to enforce security and compliance standards.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Implement an Instrumentation Strategy (10-15%)
&lt;/h3&gt;

&lt;p&gt;This objective focuses on monitoring and instrumentation for applications and services. Candidates should understand how to send data to Log Analytics workspaces, utilize the Kusto Query Language (KQL) for data analysis, leverage Application Insights for monitoring, and define metrics and key performance indicators (KPIs) to track application health and performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Securing a Free Voucher
&lt;/h2&gt;

&lt;p&gt;Now, let's delve into how you can obtain a free voucher for the AZ-400 exam. It's a golden opportunity provided by Microsoft through the annual "&lt;a href="https://www.microsoft.com/en-US/cloudskillschallenge/build/certification-exam-offer-2023?ocid=cloudskillschallenge_build23_email_cnl#eligible-exams" rel="noopener noreferrer"&gt;Microsoft Build Challenge&lt;/a&gt;." This challenge, associated with their developer conference, encourages developers to build innovative solutions using Microsoft technologies and platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's how it works&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Complete the Microsoft Build Challenge before the end date.&lt;/li&gt;
&lt;li&gt;Upon completion, one Microsoft Certification exam will be associated with your Microsoft Learn profile.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please note that you can only earn one free Microsoft Certification exam, regardless of how many Microsoft Learn Cloud Skills Challenges you complete.&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%2Fzc3vdxx9rqj8txe7vhdv.jpg" 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%2Fzc3vdxx9rqj8txe7vhdv.jpg" alt="MSBuild Challenge" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The voucher is automatically linked to your Microsoft Learn user email, and you'll find it when you register for the exam.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing for the Exam
&lt;/h2&gt;

&lt;p&gt;If you've successfully completed the AZ-400 challenge, you're already halfway there. Here are some additional tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;'Microsoft Build: DevOps Challenge' Modules:&lt;/strong&gt; This challenge contains about 51 modules. While it might be tempting to skim through them, it's advisable to keep track of and note down new terminologies you come across. Some modules have Azure DevOps labs, so get hands-on experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Take a Free Practice Assessment:&lt;/strong&gt; You can take a free practice assessment on the &lt;a href="https://learn.microsoft.com/en-us/certifications/exams/az-400/" rel="noopener noreferrer"&gt;Microsoft website&lt;/a&gt;. Surprisingly, it closely resembles the actual exam, making it a valuable resource for preparation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to Expect in the Exam
&lt;/h2&gt;

&lt;p&gt;The AZ-400 exam is structured into three segments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple-Choice Questions:&lt;/strong&gt; The first segment consists of multiple-choice questions covering the five objectives mentioned earlier. Many of these questions can be found in the &lt;a href="https://learn.microsoft.com/certifications/exams/az-400/practice/assessment?assessment-type=practice&amp;amp;assessmentId=56" rel="noopener noreferrer"&gt;free practice assessment&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Yes or No Questions:&lt;/strong&gt; The second segment includes yes-or-no questions that test your understanding of specific problem scenarios and the best solutions to them. You cannot review(go back and change) your answered questions in this segment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-World Scenario Questions:&lt;/strong&gt; The third segment presents real-world scenarios related to infrastructure, including networking, authentication, version control systems, and how to navigate such scenarios effectively.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Exam Structure and Retake Policy
&lt;/h2&gt;

&lt;p&gt;Here's some crucial information about the exam structure and retake policy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Open Book:&lt;/strong&gt; The exam is an open book, meaning you have access to the Microsoft Learn portal &lt;strong&gt;only&lt;/strong&gt; during the exam. This valuable resource can help you solve the questions effectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Breaks:&lt;/strong&gt; You are allowed breaks during the exam for as long as you need, but keep in mind that it counts against your total exam time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Retake Opportunity
&lt;/h2&gt;

&lt;p&gt;In the rare event of encountering technical difficulties during your exam, Microsoft's retake policy can be a lifesaver. Pearson VUE handles Microsoft AZ-400 certification exams, both online with OnVUE and in-person at test centers.&lt;/p&gt;

&lt;p&gt;If you face issues like technical difficulties, Pearson VUE may offer you a free retake voucher, valid for one year. This is what happened to me, and I was able to retake the exam and score 833 (the passing score is 700).&lt;/p&gt;

&lt;p&gt;Before you take the exam, it's advisable to review the &lt;a href="https://learn.microsoft.com/en-us/certifications/exam-retake-policy?wt.mc_id=certnurture_eml8_email_wwl" rel="noopener noreferrer"&gt;Exam retake policy&lt;/a&gt; by Microsoft for a better understanding of your options.&lt;/p&gt;

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

&lt;p&gt;In conclusion, pursuing a Microsoft AZ-400 certification can be a rewarding experience. With access to abundant &lt;a href="https://learn.microsoft.com/" rel="noopener noreferrer"&gt;learning resources&lt;/a&gt; and documentation, Microsoft makes this journey relatively stress-free. Remember, with the right preparation, you can confidently tackle the AZ-400 exam and secure your certification.&lt;/p&gt;

&lt;p&gt;If you have any questions or need further guidance, feel free to reach out. Good luck on your certification journey, and thanks for reading!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;By Adebayo Omolumo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/adebayo-omolumo/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FLinkedIn-Adebayo_Omolumo-brightgreen%3Fstyle%3Dfor-the-badge%26labelColor%3Dblue%26logo%3Dlinkedin" width="241" height="28"&gt;&lt;/a&gt; &lt;br&gt;
&lt;a href="https://home.iglumtech.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FIglumtech-%25F0%259F%259A%2580_-brightgreen%3Fstyle%3Dfor-the-badge%26labelColor%3Dblue%26logo%3Dcloudways" width="148" height="28"&gt;&lt;/a&gt; &lt;/p&gt;

</description>
      <category>azure</category>
      <category>devops</category>
      <category>certification</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Getting Started: Simplify your Full-Stack Environment with Bunnyshell</title>
      <dc:creator>Adebayo Omolumo</dc:creator>
      <pubDate>Wed, 19 Jul 2023 22:14:34 +0000</pubDate>
      <link>https://forem.com/adebayoomolumo/getting-started-simplify-your-full-stack-environment-with-bunnyshell-44nc</link>
      <guid>https://forem.com/adebayoomolumo/getting-started-simplify-your-full-stack-environment-with-bunnyshell-44nc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to Bunnyshell
&lt;/h2&gt;

&lt;p&gt;Bunnyshell is an Environment as a Service (EaaS) platform that simplifies the creation and management of full-stack environments for development, staging, and production. It provides developers with fully managed and pre-configured development environments, enabling them to focus on building great products. Let's explore the core features and benefits of Bunnyshell that set it apart from other similar platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Features and Functionalities of Bunnyshell EaaS Platform
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;EaaS Model&lt;/strong&gt;: Bunnyshell follows the Environment as a Service model, where developers can access fully managed and pre-configured environments. EaaS expands on the conventional IaaS paradigm for application development.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Unified Platform&lt;/strong&gt;: With Bunnyshell, you can perform all stages of your development in one platform. Say goodbye to complex setups and enjoy the convenience of managing your testing, development, and staging environments in minutes.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Collaboration Made Easy&lt;/strong&gt;: Bunnyshell allows multiple participants to clone environments and experiment with ideas and features independently, eliminating the stress of pull requests and breaking changes.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Accelerated Deployment&lt;/strong&gt;: Bunnyshell enables businesses to deploy all-in-one application environments systematically and rapidly, enhancing productivity and time-to-market.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Reproduction and Testing&lt;/strong&gt;: Easily reproduce and test your current solution or explore different use cases in seconds.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cost Management&lt;/strong&gt;: Bunnyshell helps you optimize costs by efficiently managing your environments and resources.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;User-friendly Interface&lt;/strong&gt;: The interface was so easy to use it took me a total of 4 hours to get my app running, 3:45min of it has me updating my code to fix minor bugs and reading the docs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tutorial: Setting Up Full-Stack Environments with Bunnyshell
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we will cover two segments: the first segment will demonstrate using Docker to start a full-stack environment, and the second segment will focus on using Terraform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-tutorial
&lt;/h3&gt;

&lt;p&gt;Before we start, let's talk about variables in Bunnyshell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When working with with environment variables, you can create either a project, environment, or component variable. &lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;Setup Project Variables&lt;br&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%2Ff1j4wygxzotw56m86cxh.jpg" 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%2Ff1j4wygxzotw56m86cxh.jpg" alt="Env_Prj" width="800" height="525"&gt;&lt;/a&gt;&lt;br&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%2Fbfrapcinvtyij5la60hm.jpg" 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%2Fbfrapcinvtyij5la60hm.jpg" alt="Env_Prj" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setup Environment Variables&lt;br&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%2Fcizugeisj1t9xd39xzqn.jpg" 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%2Fcizugeisj1t9xd39xzqn.jpg" alt="Env_Var" width="800" height="390"&gt;&lt;/a&gt;&lt;br&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%2F0po0izp5ha8nqnfxw1vj.jpg" 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%2F0po0izp5ha8nqnfxw1vj.jpg" alt="Env_Var" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setup Component Variables&lt;br&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%2F79uvnqtdpuvbqg8cy8z8.jpg" 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%2F79uvnqtdpuvbqg8cy8z8.jpg" alt="Comp_Var" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;When you define your variables in your YAML file, they will most likely appear in the component variables or environment variables section, depending on the context.&lt;/li&gt;
&lt;li&gt;You should define your secrets from the UI and click on the secret toggle because it's a secret and it shouldn't be exposed in the YAML file.&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%2Fj9bk4z5ytll32cta0qe2.jpg" 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%2Fj9bk4z5ytll32cta0qe2.jpg" alt="secrets" width="528" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The hierarchy that Bunnyshell will follow to select the variable is component first, environment second, and project variable last. In case you have different values with the same key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Segment 1: Using Docker-Compose to Set Up Full-Stack Environment
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Setup your full-stack environment with a Dockerfile and a docker-compose file in your project directory.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To set up a full-stack environment using Docker, you need to have a docker-compose.yaml file in your GitHub directory. Bunnyshell platform will search your repo and automatically use the files it needs to create your desired environment.
Here's an example docker-compose file for a development environment:


&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="c1"&gt;# env_file: ./backend/.env&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1337:1337"&lt;/span&gt;
  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./frontend&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;

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

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Define the services and configurations required for your environment in the docker-compose file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bunnyshell automatically starts your environments as defined in the docker-compose.yaml file&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2F8ppxtyiy8hmxd4oy2puf.jpg" 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%2F8ppxtyiy8hmxd4oy2puf.jpg" alt="running" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Segment 2: Using Terraform to Set Up Full-Stack Environment
&lt;/h3&gt;

&lt;p&gt;To set up a full-stack environment using Terraform, you can utilize Terraform's infrastructure provisioning capabilities. &lt;br&gt;
Here's an example of Terraform configuration created after you have setup your terraform code and bunnyshell environment for provisioning infrastructure resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Environment&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;Staging&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;primary&lt;/span&gt;
&lt;span class="na"&gt;urlHandle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kostzj&lt;/span&gt;
&lt;span class="na"&gt;environmentVariables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;BNS_SECRET&amp;gt;&amp;gt;'&lt;/span&gt;
    &lt;span class="na"&gt;AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
    &lt;span class="na"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;BNS_SECRET&amp;gt;&amp;gt;'&lt;/span&gt;

&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform&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;staging-onlinesafety-s3-cdn&lt;/span&gt;
        &lt;span class="na"&gt;gitRepo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://github.com/Bayurzx/bunnyshell-hackathon.git'&lt;/span&gt;
        &lt;span class="na"&gt;gitBranch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tf&lt;/span&gt;
        &lt;span class="na"&gt;gitApplicationPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/bunnyshell/terraform&lt;/span&gt;
        &lt;span class="na"&gt;runnerImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hashicorp/terraform:1.5.1'&lt;/span&gt;
        &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bunnyshell/terraform'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/bns/helpers/terraform/get_managed_backend&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;zz_backend_override.tf'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;init&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-input=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-no-color'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;apply&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"aws_access_key_id={{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.vars.AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"aws_secret_access_key={{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.vars.AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ID=bunnyshell"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-input=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-auto-approve&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-no-color'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BNS_TF_STATE_LIST=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;show&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-json`'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CLOUD_FRONT_DOMAIN=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CloudFrontDomain`'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CLOUD_FRONT_URL=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CloudFrontURL`'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;TRUNCATED_UNIQUE_ID=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;truncated_unique_id`'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ACCEPTANCE_TEST_STATUS=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;acceptance_test_status`'&lt;/span&gt;
        &lt;span class="na"&gt;destroy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bunnyshell/terraform'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/bns/helpers/terraform/get_managed_backend&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;zz_backend_override.tf'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;init&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-input=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-no-color'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;destroy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"aws_access_key_id={{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.vars.AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"aws_secret_access_key={{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.vars.AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ID=bunnyshell"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-input=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-auto-approve&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-no-color'&lt;/span&gt;

        &lt;span class="na"&gt;exportVariables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CLOUD_FRONT_DOMAIN&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CLOUD_FRONT_URL&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TRUNCATED_UNIQUE_ID&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ACCEPTANCE_TEST_STATUS&lt;/span&gt;
&lt;span class="na"&gt;volumes&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;db-data&lt;/span&gt;
        &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;disk&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;When creating your terraform template, it's important to setup the yaml format in a way that the environment houses the component as shown in the yaml template above. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Kind&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt;,  &lt;code&gt;environmentVariables&lt;/code&gt; are automatically generated

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;environmentVariables&lt;/code&gt; is only generated only if you had created Environment variables beforehand.
&lt;code&gt;urlHandle&lt;/code&gt;: is created after you have created your terraform environment
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Environment&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;Staging&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;primary&lt;/span&gt;
&lt;span class="na"&gt;urlHandle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kostzj&lt;/span&gt;
&lt;span class="na"&gt;environmentVariables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;BNS_SECRET&amp;gt;&amp;gt;'&lt;/span&gt;
    &lt;span class="na"&gt;AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
    &lt;span class="na"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;BNS_SECRET&amp;gt;&amp;gt;'&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;You can now define your components to serve whatever functions you want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Terraform&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;staging-onlinesafety-s3-cdn&lt;/span&gt;
        &lt;span class="na"&gt;gitRepo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://github.com/Bayurzx/bunnyshell-hackathon.git'&lt;/span&gt;
        &lt;span class="na"&gt;gitBranch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tf&lt;/span&gt;
        &lt;span class="na"&gt;gitApplicationPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/bunnyshell/terraform&lt;/span&gt;
        &lt;span class="na"&gt;runnerImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hashicorp/terraform:1.5.1'&lt;/span&gt;
        &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bunnyshell/terraform'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/bns/helpers/terraform/get_managed_backend&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;zz_backend_override.tf'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;init&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-input=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-no-color'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;apply&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"aws_access_key_id={{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.vars.AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"aws_secret_access_key={{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.vars.AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ID=bunnyshell"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-input=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-auto-approve&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-no-color'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BNS_TF_STATE_LIST=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;show&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-json`'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CLOUD_FRONT_DOMAIN=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CloudFrontDomain`'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CLOUD_FRONT_URL=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CloudFrontURL`'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;TRUNCATED_UNIQUE_ID=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;truncated_unique_id`'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ACCEPTANCE_TEST_STATUS=`terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;acceptance_test_status`'&lt;/span&gt;
        &lt;span class="na"&gt;destroy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bunnyshell/terraform'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/bns/helpers/terraform/get_managed_backend&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;zz_backend_override.tf'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;init&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-input=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-no-color'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;destroy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"aws_access_key_id={{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.vars.AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"aws_secret_access_key={{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;env.vars.AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"ID=bunnyshell"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-input=false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-auto-approve&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-no-color'&lt;/span&gt;

        &lt;span class="na"&gt;exportVariables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CLOUD_FRONT_DOMAIN&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CLOUD_FRONT_URL&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TRUNCATED_UNIQUE_ID&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ACCEPTANCE_TEST_STATUS&lt;/span&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  Above, I created a terraform component by simply defining &lt;code&gt;kind: Terraform&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;name: staging-onlinesafety-s3-cdn&lt;/code&gt; defines the name of the component.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;gitRepo&lt;/code&gt;, &lt;code&gt;gitBranch&lt;/code&gt;, &lt;code&gt;gitApplicationPath&lt;/code&gt;, as the names imply, define the GitHub repository URL, git remote or GitHub branch, and the location of the Terraform directory.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;runnerImage: 'hashicorp/terraform:1.5.1'&lt;/code&gt; is a lightweight Alpine based image with Terraform components installed to help with Terraform commands.

&lt;ul&gt;
&lt;li&gt;  Note that when running scripts with Terraform null_providers, only sh scripts may work. Certain Bash syntax may not work as commonly expected with Alpine images. To fix this, you may add another Bunnyshell component with an image that is suitable for your purpose.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  In summary, &lt;code&gt;deploy&lt;/code&gt; and &lt;code&gt;destroy&lt;/code&gt; are basically &lt;code&gt;terraform apply --auto-approve&lt;/code&gt; and &lt;code&gt;terraform destroy --auto-approve&lt;/code&gt;, respectively.

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;aws_secret_access_key&lt;/code&gt; and &lt;code&gt;aws_access_key_id&lt;/code&gt; are defined as outputs in our Terraform code files, allowing us to connect to AWS.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;{{ env.vars.AWS_ACCESS_KEY_ID }}&lt;/code&gt; and &lt;code&gt;{{ env.vars.AWS_SECRET_ACCESS_KEY }}&lt;/code&gt; are how we use our defined environment variables (secrets).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;code&gt;exportVariables&lt;/code&gt; are printed out and saved at your component level&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%2F7tb9lrnu8t8n028im97d.jpg" 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%2F7tb9lrnu8t8n028im97d.jpg" alt="running" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Features and Resources
&lt;/h2&gt;

&lt;p&gt;Bunnyshell provides additional features and resources that can enhance your experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Templates: Bunnyshell offers a collection of templates on GitHub (&lt;a href="https://github.com/bunnyshell/templates/" rel="noopener noreferrer"&gt;https://github.com/bunnyshell/templates/&lt;/a&gt;), which can serve as starting points for setting up common environments or configurations.&lt;/li&gt;
&lt;li&gt;  More detailed understanding on how environment variables work: 

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://documentation.bunnyshell.com/docs/variables" rel="noopener noreferrer"&gt;https://documentation.bunnyshell.com/docs/variables&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://documentation.bunnyshell.com/docs/variables-interpolation" rel="noopener noreferrer"&gt;https://documentation.bunnyshell.com/docs/variables-interpolation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Support with Bunnyshell
&lt;/h2&gt;

&lt;p&gt;If you need any further assistance or support with Bunnyshell, refer to the official documentation (&lt;a href="https://documentation.bunnyshell.com/docs" rel="noopener noreferrer"&gt;https://documentation.bunnyshell.com/docs&lt;/a&gt;) for comprehensive guides and resources. The documentation can help you explore advanced features, troubleshoot issues, and find answers to frequently asked questions.&lt;/p&gt;

&lt;p&gt;By following this tutorial and leveraging Bunnyshell's powerful features, you can simplify the process of creating and managing full-stack environments, enabling your team to deliver software faster and focus on building great products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Round-Up
&lt;/h2&gt;

&lt;p&gt;To get a clearer picture, you can always check out their &lt;a href="https://github.com/bunnyshell/templates" rel="noopener noreferrer"&gt;templates&lt;/a&gt;. You can also visit my GitHub repository, where the code mentioned above was based: &lt;a href="https://github.com/Bayurzx/bunnyshell-hackathon" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reach Out
&lt;/h2&gt;

&lt;p&gt;If you have any questions or simply want to connect, feel free to reach out to me through the following link.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/adebayo-omolumo/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FLinkedIn-0077B5%3Fstyle%3Dfor-the-badge%26logo%3Dlinkedin%26logoColor%3Dwhite" width="91" height="28"&gt;&lt;/a&gt; &lt;br&gt;
&lt;a href="https://www.linkedin.com/in/adebayo-omolumo/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2F%40Adebayoomolumo-1DA1F2%3Fstyle%3Dfor-the-badge%26logo%3Dtwitter%26logoColor%3Dwhite" width="164" height="28"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>eaas</category>
      <category>devops</category>
      <category>containers</category>
      <category>cicd</category>
    </item>
    <item>
      <title># Learn: Solidity’s Smart Contract 🤝🏼 by Creating a Will📜!</title>
      <dc:creator>Adebayo Omolumo</dc:creator>
      <pubDate>Sat, 25 Sep 2021 04:57:14 +0000</pubDate>
      <link>https://forem.com/adebayoomolumo/learn-solidity-s-smart-contract-by-creating-a-will-4599</link>
      <guid>https://forem.com/adebayoomolumo/learn-solidity-s-smart-contract-by-creating-a-will-4599</guid>
      <description>&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%2Fvwtt73t600pl1q5bferr.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%2Fvwtt73t600pl1q5bferr.png" alt="Crypto Will" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hello and welcome👋🏼, I am Adebayo😁. I will be creating a crypto based &lt;code&gt;Will&lt;/code&gt; using a simple smart contract in the Solidity programming language.&lt;br&gt;
This article is largely based on the &lt;a href="https://www.udemy.com/course/complete-dapp-solidity-react-blockchain-development/" rel="noopener noreferrer"&gt;Complete DApp - Solidity &amp;amp; React - Blockchain Development&lt;/a&gt; on Udemy.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Little introduction to writing a smart contract&lt;/li&gt;
&lt;li&gt;Some common feature of solidity&lt;/li&gt;
&lt;li&gt;Create a smart contract and  run it in remix IDE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you know anything about blockchain, then you might have heard about one of its applications, &lt;code&gt;smart contracts&lt;/code&gt;. Smart contracts, just like regular contracts are like agreements🤝🏼 that become valid/active when a condition is met. But with smart contracts, you can automate the execution of a contract after storing it in blockchain. No middleman, no time-delay, tamper proof and efficient making the contract, smart (&lt;em&gt;Sorry, I could not help it😂&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;One of the most common IDE for writing smart contracts is the &lt;a href="https://github.com/ethereum/remix-ide" rel="noopener noreferrer"&gt;remix&lt;/a&gt; IDE hosted on &lt;code&gt;ethereum.org&lt;/code&gt;. This is the fastest way to get started with writing Smart contracts with solidity. It comes with all you need, a web browser-based compiler and about 15 free Ethereum account loaded with 100eth coin. These coins are on the Testnet not the Mainnet so don't even think of spending them🙄. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Hint: You may decide to write you code in VS Code, for easier editing and copy the code to the remix IDE&lt;/em&gt;&lt;br&gt;
&lt;em&gt;You will find the extension, &lt;code&gt;Solidity support for Visual Studio code&lt;/code&gt; by Juan Franco very useful. It supports auto-completion syntax highlighting, Snippets and etc.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;There is also the &lt;code&gt;Ethereum Remix Project extension for Visual Studio Code&lt;/code&gt; extension. It is in beta-release at the moment of this writing.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Let us dive in by creating our solidity file. I will be naming it &lt;code&gt;will.sol&lt;/code&gt;.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Solidity files end with the &lt;code&gt;.sol&lt;/code&gt; extension.&lt;/em&gt;&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;// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.7;

contract Will {
  code...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Before writing your contract, it is mandatory to state the solidity version as this will determine the version of compiler that compiles the code. You should also insert the &lt;code&gt;SPDX-License-Identifier&lt;/code&gt; which should be in a comment as a good practice. Checkout a full list of licenses &lt;a href="https://spdx.org/licenses/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; contract Will {

   ...code

    // define variables
    address owner;
    uint fortune;
    bool deceased;

    constructor() payable {
        // set variables
        owner = msg.sender; // represents address called
        fortune = msg.value; // how much ether is being represents
        deceased = false;
    }

  code...

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

&lt;/div&gt;





&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We define our three state variables (&lt;code&gt;owner&lt;/code&gt;, &lt;code&gt;fortune&lt;/code&gt; and &lt;code&gt;deceased&lt;/code&gt;) which would be stored in this contract storage. It is necessary to always state your variable &lt;code&gt;type&lt;/code&gt; when defining variables in solidity. There are wayyy to many &lt;code&gt;types&lt;/code&gt; used in solidity. This &lt;code&gt;types&lt;/code&gt; affects how a contract interacts with data variables, functions etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;State, Local, Global variable are the three types of variables in solidity&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Local variables&lt;/code&gt; just like in JavaScript are scoped variables, they are often defined in functions and serve out their purpose in the function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;State variables&lt;/code&gt; are defined outside of functions, they are sort of the global variables in JS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Global Variables&lt;/code&gt; are special pre-defined variables that can exist globally across contracts. &lt;code&gt;msg.sender&lt;/code&gt; is an example of global variables&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Constructors are often used to initialize state variables of a contract and are executed only once when the contract was created. Read more &lt;a href="https://www.tutorialspoint.com/solidity/solidity_constructors.htm" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Next, we created two modifiers, an array and then mapped addresses to amount of inheritance
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ...code

    // define modifier functions that only owner can call it
    modifier onlyOwner {
        require(msg.sender == owner);
        _; // function body is inserted where the special symbol "_;" add to functions
    }

    // create modifier functions to only allocate funds if deceased
    modifier mustBeDeceased {
        require(deceased == true);
        _; // function body is inserted where the special symbol "_;" add to functions
    }

    // list of family wallets
    address payable [] familyWallets;

    // map through inheritance
    // this enables us to set the inheritance later on
    mapping(address =&amp;gt; uint) inheritance;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Modifier&lt;/code&gt; Functions are sort of conditions that will allow another function to run if true. It works well with &lt;code&gt;require()&lt;/code&gt; or &lt;code&gt;if statement&lt;/code&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;require&lt;/code&gt; you can add a string as a second argument to be outputted when the condition is not met&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;You create lists in Solidity by indicating the square bracket ahead of its name like this:  &lt;code&gt;[] familyWallets;&lt;/code&gt;. In this example, we indicated the types:  &lt;code&gt;address&lt;/code&gt; and &lt;code&gt;payable&lt;/code&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This ensures that the content are Ethereum addresses and allows for payment respectively&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Mapping helps us to pair &lt;code&gt;_key&lt;/code&gt; and &lt;code&gt;_value&lt;/code&gt; data. This is like &lt;code&gt;objects data type&lt;/code&gt; in JavaScript.&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // set inheritance for each address basically by attributing the amount to address

    function setInheritance(address payable wallet, uint amount) public onlyOwner {
        // add wallet to the family wallets
        familyWallets.push(wallet);
        inheritance[wallet] = amount;
    }

    // pay each family based on their wallet address

    function payout() private mustBeDeceased {
        for (uint256 i = 0; i &amp;lt; familyWallets.length; i++) {
            // familyWallets[i].transfer(inheritance[familyWallets[i]]);
            // or
            (bool success, ) = familyWallets[i].call{value:inheritance[familyWallets[i]]}("");
            require(success, "Transfer failed.");

        }
    }

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The setInhertiance function receives two arguments &lt;code&gt;wallet&lt;/code&gt; and &lt;code&gt;amount&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;As you may have noticed, wallet has two types &lt;code&gt;payable&lt;/code&gt; and &lt;code&gt;address&lt;/code&gt; while &lt;code&gt;amount&lt;/code&gt; has &lt;code&gt;uint&lt;/code&gt;(unsigned integer) type aka &lt;code&gt;uint32&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;We then push each &lt;code&gt;wallet&lt;/code&gt; into the list(familyWallet) created earlier and designate an &lt;code&gt;amount&lt;/code&gt; to be inherited&lt;/li&gt;

&lt;li&gt;The &lt;code&gt;payout&lt;/code&gt; simply loops each &lt;code&gt;wallet&lt;/code&gt; in family wallet and transfers the corresponding amount&lt;code&gt;(mapping)&lt;/code&gt;: &lt;code&gt;&amp;lt;wallet.transfer(amount)&amp;gt;&lt;/code&gt;
&lt;/li&gt;

&lt;li&gt;Notice the two lines of code commented above &lt;code&gt;//or&lt;/code&gt;, it’s an alternative to &lt;code&gt;transfer&lt;/code&gt; method. The &lt;code&gt;transfer&lt;/code&gt; method is avoided sometimes because of the hard dependency on gas costs. Read up on this here and &lt;a href="https://ethereum.stackexchange.com/questions/78124/is-transfer-still-safe-after-the-istanbul-update/78136#78136" rel="noopener noreferrer"&gt;here&lt;/a&gt; 

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;(bool success, )&lt;/code&gt; checks to see if transfer was successful else returns "Transfer failed"&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Note that the visibility is set to private. private is one of the four common visibility type [Public, private, internal, external]. It ensures that the function is not called outside the contract
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      // oracle switch simulation
    function payWill() public onlyOwner {
        deceased = true;
        payout();
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;paywill&lt;/code&gt; function enables us to call the &lt;code&gt;payout&lt;/code&gt; function whose visibility was set to &lt;code&gt;private&lt;/code&gt; after I ensured that the &lt;code&gt;onlyOwner&lt;/code&gt; and &lt;code&gt;mustBeDeceased&lt;/code&gt; conditions are met.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here is where things start to get interesting, Let's run the contract in our &lt;a href="https://remix.ethereum.org/" rel="noopener noreferrer"&gt;remix IDE&lt;/a&gt;
&lt;/h2&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%2Fgjr2m0kzaalj9l6acgqj.jpg" 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%2Fgjr2m0kzaalj9l6acgqj.jpg" alt="compile" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you are done writing the contract, you should go ahead to click the compile button. If you get the green tick ✔, you are good to go &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You might have noticed that the compile version and pragma solidity &lt;code&gt;&amp;lt;version&amp;gt;&lt;/code&gt; are the same. Hence why it is mandatory to indicate it at the beginning of your file&lt;/em&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%2Fa6tncu3q0soay2tekue4.jpg" 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%2Fa6tncu3q0soay2tekue4.jpg" alt="compile" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;A.&lt;/code&gt; =&amp;gt; Take note of the account you will be using, it's where your gas fee and the &lt;code&gt;msg.value&lt;/code&gt; global variable for every contract execution comes from.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;B&lt;/code&gt; =&amp;gt; To make use of Ethereum in the contract, you need to deposit it through the &lt;code&gt;value&lt;/code&gt; input. 1 eth = 10&lt;sup&gt;18&lt;/sup&gt; wei. Make sure to select &lt;code&gt;eth&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;D&lt;/code&gt; =&amp;gt; After clicking deploy, you will notice a ✔ right above the terminal &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%2Fc2cdtz4z8cozzmccs2ij.jpg" 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%2Fc2cdtz4z8cozzmccs2ij.jpg" alt="compile" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After successful deployment, inspect the IDE, at &lt;code&gt;B&lt;/code&gt; you should click the &lt;code&gt;caret-down icon&lt;/code&gt; it reveals the two defined public functions in our contract

&lt;ul&gt;
&lt;li&gt;At &lt;code&gt;C&lt;/code&gt;, there is the setInheritance function with the expected arguments &lt;code&gt;wallet&lt;/code&gt; and &lt;code&gt;amount&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Go back to the list of account and select any other account to copy the eth address, click the copy icon beside it. &lt;strong&gt;Remember to return to the first account when done&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;When selecting an amount. Put in mind that the default is in &lt;code&gt;wei&lt;/code&gt; you will need to add 18 zeros to make it equal to an Ethereum &lt;code&gt;1eth&lt;/code&gt; =&amp;gt; &lt;code&gt;1000000000000000000wei&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Do this repeatedly to add more address to the &lt;code&gt;familyWallet&lt;/code&gt; list. &lt;em&gt;Reminder, make sure to go back to the first account after copying other eth address&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Click transact to run the function. You will see another ✔. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: The limit of Ethereum you can process is the amount added which is 30eth&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;After repeating the setInheritance process, you can finally select the payWill button to complete the contract.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Full Code is &lt;a href="https://github.com/Bayurzx/first_dapp/blob/main/will.sol" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;p&gt;That is all for now on writing a Crypto Will in Solidity. I hope you were at least... whelmed 😁. I will try to document my understanding of a series of useful smart contract here. I will appreciate your input and suggestions so, feel free to follow or reach out to me on my... &lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/adebayo-omolumo-2b1ba078/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FLinkedIn-Adebayo%2520Omolumo-blue" width="172" height="20"&gt;&lt;/a&gt; &lt;a href="https://twitter.com/AdebayoOmolumo/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fbadge%2FTwitter-Adebayo%2520Omolumo-darkblue" width="164" height="20"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
If you appreciate the effort and would like to buy me a Crypto Coffee then ==&amp;gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;eth: 0xeF7dB2944e6BFaF68C1Caf623552A0E9353659Ca&lt;/code&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>solidity</category>
      <category>crypto</category>
      <category>ethereum</category>
    </item>
  </channel>
</rss>
