<script data-pm-proxy="intercept"></script><?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Hands On FullStack Development]]></title><description><![CDATA[Hands On FullStack Development with "Infrastructure Management" Product implementation]]></description><link>https://fullstackinfra.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!Y3IK!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3505e4c-4513-4325-9c7c-20715b7d8910_1079x1079.png</url><title>Hands On FullStack Development</title><link>https://fullstackinfra.substack.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 01 Sep 2026 18:35:14 GMT</lastBuildDate><atom:link href="/__u/fullstackinfra.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[System Design Roadmap]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[fullstackinfra@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[fullstackinfra@substack.com]]></itunes:email><itunes:name><![CDATA[System Design Roadmap]]></itunes:name></itunes:owner><itunes:author><![CDATA[System Design Roadmap]]></itunes:author><googleplay:owner><![CDATA[fullstackinfra@substack.com]]></googleplay:owner><googleplay:email><![CDATA[fullstackinfra@substack.com]]></googleplay:email><googleplay:author><![CDATA[System Design Roadmap]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Day 157: Operations Documentation — Runbooks, Incident Response & Maintenance Guides]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-157-operations-documentation</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-157-operations-documentation</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Tue, 01 Sep 2026 06:30:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!i_4K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>By the end of this lesson you will have:</p><ul><li><p>A <strong>Runbook Engine</strong> &#8212; structured, versioned, step-by-step procedures for every repeatable ops task</p></li><li><p>An <strong>Incident Response System</strong> &#8212; severity classification, escalation tree, on-call paging, and post-mortem generation</p></li><li><p>A <strong>Maintenance Scheduler</strong> &#8212; calendar-driven maintenance windows with approval workflows</p></li><li><p>A <strong>Backup Procedure Manager</strong> &#8212; policy engine defining what backs up, when, how, and how restore is validated</p></li><li><p>A <strong>Monitoring Guide Builder</strong> &#8212; living documentation for every alert and SLO your system owns</p></li></ul><p>All five live in a single React + FastAPI dashboard, backed by PostgreSQL, with a shared search layer.</p><div><hr></div><h2>Where This Fits in Your System</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!i_4K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!i_4K!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!i_4K!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!i_4K!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!i_4K!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!i_4K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png" width="1456" height="990" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:990,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:892447,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/203130205?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!i_4K!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!i_4K!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!i_4K!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!i_4K!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0317440-1ea5-4339-be1f-73be399223d1_4800x3264.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-157-operations-documentation">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 156: User Documentation — Building Help Systems That Actually Help]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-156-user-documentation-building</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-156-user-documentation-building</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Mon, 31 Aug 2026 06:31:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BCpP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p>A structured user documentation portal with searchable manuals</p></li><li><p>Interactive tutorial system with step-by-step guided flows</p></li><li><p>Embedded video tutorial placeholders with transcript support</p></li><li><p>Dynamic FAQ engine with categorization and search</p></li><li><p>Contextual in-app help system with tooltip overlays and help drawer</p></li></ul><p>This is Week 23 of our series. Last lesson we built the technical backbone &#8212; architecture docs, API references, deployment guides. Today we build what the <em>users</em> actually touch: the help experience. Next lesson, Day 157, we cover operational runbooks &#8212; the bridge between user-facing docs and internal ops.</p><div><hr></div><h2>Where This Fits in the Overall System</h2><p>User documentation is the surface layer of your entire platform&#8217;s knowledge graph. When users hit friction &#8212; they either abandon the product, or they find an answer. The difference between those two outcomes is your help system.</p><p>In production infrastructure platforms (think Datadog, Vercel, Render), the help system is not bolted on as an afterthought. It&#8217;s deeply integrated: context-aware tooltips know <em>which page</em> you&#8217;re on; FAQ searches pull from the same content API as the manuals; video tutorials are tagged to specific UI components.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!BCpP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!BCpP!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png 424w, /__u/substackcdn.com/image/fetch/$s_!BCpP!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png 848w, /__u/substackcdn.com/image/fetch/$s_!BCpP!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png 1272w, /__u/substackcdn.com/image/fetch/$s_!BCpP!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!BCpP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png" width="1456" height="946" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:946,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:726221,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/203079749?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!BCpP!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png 424w, /__u/substackcdn.com/image/fetch/$s_!BCpP!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png 848w, /__u/substackcdn.com/image/fetch/$s_!BCpP!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png 1272w, /__u/substackcdn.com/image/fetch/$s_!BCpP!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F648c68ea-a91b-4a7f-9d56-aeca6cd68bc0_4800x3120.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-156-user-documentation-building">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 155: Technical Documentation — Building the Living Blueprint of Your System]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-155-technical-documentation-building</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-155-technical-documentation-building</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Sat, 29 Aug 2026 06:30:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iPQW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>By the end of this lesson, you will have a complete technical documentation system for your Infrastructure Management platform. Here&#8217;s the agenda:</p><ul><li><p><strong>Architecture documentation</strong> &#8212; machine-readable and human-readable system maps</p></li><li><p><strong>API reference</strong> &#8212; auto-generated from code, always in sync</p></li><li><p><strong>Deployment guides</strong> &#8212; reproducible runbook scripts</p></li><li><p><strong>Troubleshooting guides</strong> &#8212; decision-tree format runbooks</p></li><li><p><strong>Maintenance procedures</strong> &#8212; SLA-driven operational playbooks</p></li></ul><p>This week&#8217;s target: wrap production-readiness with documentation that acts as both a knowledge base and an operational contract.</p><div><hr></div><h2>Why Technical Documentation Is an Engineering Artifact, Not a Writing Task</h2><p>Documentation written after the fact is archaeology. The kind that actually gets used is generated <em>from</em> the system &#8212; it derives its accuracy from code, config, and telemetry, not from someone&#8217;s recollection.</p><p>Think about how Stripe, GitHub, and AWS write docs. Their API references are never manually authored. They&#8217;re emitted by annotation processors and schema validators running in CI. When the code changes, the docs change. This lesson builds that exact pipeline for your system.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!iPQW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!iPQW!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!iPQW!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!iPQW!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!iPQW!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!iPQW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png" width="1456" height="990" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:990,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:806687,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/203072960?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!iPQW!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!iPQW!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!iPQW!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!iPQW!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77c5b15e-ad79-40d9-9147-55e3e1284610_4800x3264.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><h2>The Architecture: Documentation as a Pipeline</h2><p>Your documentation system has three layers:</p><p><strong>Layer 1 &#8212; Source Layer:</strong> Python decorators, OpenAPI annotations, and inline docstrings embedded directly in your FastAPI/Flask backend.</p><p><strong>Layer 2 &#8212; Generation Layer:</strong> A docs-build service (MkDocs + mkdocstrings + Redoc) that pulls from source, renders HTML, and packages a versioned artifact.</p><p><strong>Layer 3 &#8212; Serving Layer:</strong> A React dashboard that presents architecture docs, API reference, deployment runbooks, and troubleshooting trees as navigable, searchable content.</p><p>The key insight: documentation is a build artifact. It has a version, a build step, and tests that verify it isn&#8217;t stale.</p><p></p><blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!203w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!203w!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!203w!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!203w!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!203w!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!203w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png" width="1456" height="990" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:990,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1015061,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/203072960?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!203w!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!203w!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!203w!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!203w!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad319694-5bd5-4848-96e0-1907563a08a0_4800x3264.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div></blockquote><div><hr></div><h2>Component 1: Architecture Documentation</h2><p>Architecture docs must answer four questions: What runs where? How do components talk? What are the failure boundaries? What does the data flow look like?</p><p>You generate these from two sources &#8212; your <code>docker-compose.yml</code> (which declares services and networks) and annotated Python modules (which describe business intent). A parser walks both, builds a JSON graph, and renders it as an interactive SVG + Markdown.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;a75c3968-dad2-4888-9052-0c4845a69559&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Pseudo-code: Architecture extractor
def extract_components(compose_path, source_root):
    services = parse_compose(compose_path)       # ports, volumes, depends_on
    annotations = scan_modules(source_root)       # @component, @depends decorators
    return merge(services, annotations)           # unified graph
</code></pre></div><p>The output is a <code>architecture.json</code> that feeds both the dashboard visualization and the exported Markdown page.</p><div><hr></div><h2>Component 2: API Reference Documentation</h2><p>FastAPI emits an OpenAPI 3.1 spec at <code>/openapi.json</code> automatically. The gap is <em>richness</em> &#8212; field descriptions, error codes, example payloads, and authentication notes are only present if engineers annotate their route handlers.</p><p>Your build pipeline:</p><ol><li><p>Hits <code>/openapi.json</code> on the running dev server</p></li><li><p>Validates the spec (no undocumented <code>200</code> responses without schemas)</p></li><li><p>Feeds it to Redoc to render a three-panel reference UI</p></li><li><p>Publishes as a versioned HTML page with each release</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;83f72b7c-7ca7-4885-ad49-88a171fd5845&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Pseudo-code: API doc validator
def validate_openapi(spec):
    for path, methods in spec['paths'].items():
        for method, op in methods.items():
            assert 'description' in op, f"Missing description: {method} {path}"
            assert '200' in op['responses'], f"Missing 200 response: {method} {path}"
</code></pre></div><p>Engineers who skip descriptions fail the build. That&#8217;s how you keep the spec useful.</p><div><hr></div><h2>Component 3: Deployment Guides</h2><p>A deployment guide that isn&#8217;t executable is a fairy tale. Yours is a structured YAML runbook with embedded shell steps, pre-condition checks, and rollback instructions.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;54835ce0-61a2-4b51-a20e-d1e7eab26b33&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># deployment_runbook.yml structure
runbook:
  name: "Production Deploy v2"
  pre_checks:
    - cmd: "kubectl get nodes"
      expect: "Ready"
  steps:
    - name: "Pull images"
      cmd: "docker-compose pull"
    - name: "Run migrations"
      cmd: "python manage.py migrate --check"
  rollback:
    - cmd: "docker-compose down &amp;&amp; git checkout HEAD~1"
</code></pre></div><p>The Python runbook runner executes each step, captures stdout/stderr, logs pass/fail, and presents a live execution trace in the React dashboard.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!QcNR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!QcNR!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png 424w, /__u/substackcdn.com/image/fetch/$s_!QcNR!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png 848w, /__u/substackcdn.com/image/fetch/$s_!QcNR!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png 1272w, /__u/substackcdn.com/image/fetch/$s_!QcNR!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!QcNR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png" width="1456" height="1019" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1019,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:742122,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/203072960?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!QcNR!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png 424w, /__u/substackcdn.com/image/fetch/$s_!QcNR!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png 848w, /__u/substackcdn.com/image/fetch/$s_!QcNR!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png 1272w, /__u/substackcdn.com/image/fetch/$s_!QcNR!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3beb92a4-6b67-4044-a3c0-4781df01b46b_4800x3360.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><h2>Component 4: Troubleshooting Guides</h2><p>Troubleshooting docs written as prose are useless at 3 AM. Yours are decision trees stored as JSON &#8212; each node is a symptom, each edge is an observation, each leaf is an action.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;f5e7024a-8e76-4547-bd1f-f277126bb9fc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  "symptom": "API returns 503",
  "check": "curl /health",
  "branches": {
    "timeout": { "action": "restart backend container" },
    "connection_refused": { "action": "check postgres is up" },
    "200": { "escalate": "check upstream load balancer" }
  }
}
</code></pre></div><p>The React UI renders this as a clickable flowchart. The on-call engineer follows branches interactively &#8212; no reading walls of text. Each leaf records which action was taken, building an incident knowledge base over time.</p><div><hr></div><h2>Component 5: Maintenance Procedures</h2><p>Maintenance procedures encode <em>when</em> and <em>how</em> &#8212; not just what. They&#8217;re SLA-linked: a procedure for database vacuum runs weekly; certificate rotation runs 30 days before expiry.</p><p>Your maintenance scheduler reads <code>maintenance.yml</code>, registers jobs in APScheduler, and logs execution to a PostgreSQL <code>maintenance_log</code> table. The React dashboard shows the next scheduled run, last execution result, and a manual trigger button.</p><p>This closes the loop: documentation isn&#8217;t just reference material. It&#8217;s an active participant in system operations.</p><div><hr></div><h2>How It All Connects in the Infrastructure Management System</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;0c0812eb-cefd-41f8-ad07-1c2362e40f60&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">[Backend API] &#8594; [OpenAPI Spec] &#8594; [Redoc] &#8594; [API Reference Page]
[docker-compose] &#8594; [Architecture Extractor] &#8594; [Arch Diagram Page]
[maintenance.yml] &#8594; [APScheduler] &#8594; [Maintenance Log] &#8594; [Ops Dashboard]
[troubleshoot.json] &#8594; [React Tree] &#8594; [Interactive Runbook]
[deployment.yml] &#8594; [Runbook Runner] &#8594; [Execution Trace Dashboard]
</code></pre></div><p>Every component feeds the React documentation dashboard &#8212; a single pane of glass for all technical knowledge about the system.</p><div><hr></div><h2>Key Insight: Documentation Debt Is Infrastructure Debt</h2><p>When AWS had its famous 2017 S3 outage, one contributing factor was runbooks that didn&#8217;t match the actual system topology. Operators followed documented procedures that no longer reflected reality. Generated, validated documentation eliminates an entire class of operational failure.</p><div><hr></div><h1>Implementation &amp; Build Guide</h1><div><hr></div><h2>Prerequisites</h2><p>Tool Minimum Version Check Command Python 3.11+ <code>python3 --version</code> Node.js 20+ <code>node --version</code> npm 10+ <code>npm --version</code> Docker (optional) 24+ <code>docker --version</code> curl any <code>curl --version</code></p><div><hr></div><h2>Github Link:</h2><p><a href="https://github.com/sysdr/infrawatch-fullstack-p/tree/main/day155/techdocs">https://github.com/sysdr/infrawatch-fullstack-p/tree/main/day155/techdocs</a></p><h2>Architecture Overview</h2><pre><code><code>&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474;              TechDocs Documentation System               &#9474;
&#9474;                                                         &#9474;
&#9474;  React Dashboard (3155)                                 &#9474;
&#9474;  &#9500;&#9472;&#9472; Overview (Health Score Gauge)                      &#9474;
&#9474;  &#9500;&#9472;&#9472; Architecture (Service Map)                         &#9474;
&#9474;  &#9500;&#9472;&#9472; API Reference (OpenAPI Browser)                    &#9474;
&#9474;  &#9500;&#9472;&#9472; Deployment (Runbook Executor)                      &#9474;
&#9474;  &#9500;&#9472;&#9472; Troubleshoot (Decision Tree)                       &#9474;
&#9474;  &#9492;&#9472;&#9472; Maintenance (Procedure Runner)                     &#9474;
&#9474;                           &#9474;                             &#9474;
&#9474;  FastAPI Backend (8155)   &#9474;                             &#9474;
&#9474;  &#9500;&#9472;&#9472; /api/docs/architecture   &#8592; generate_architecture() &#9474;
&#9474;  &#9500;&#9472;&#9472; /api/docs/api-reference  &#8592; validate_openapi()     &#9474;
&#9474;  &#9500;&#9472;&#9472; /api/docs/runbooks       &#8592; execute_runbook()      &#9474;
&#9474;  &#9500;&#9472;&#9472; /api/docs/troubleshoot   &#8592; navigate_tree()        &#9474;
&#9474;  &#9500;&#9472;&#9472; /api/docs/maintenance    &#8592; execute_procedure()    &#9474;
&#9474;  &#9492;&#9472;&#9472; /api/docs/health-score   &#8592; aggregate all          &#9474;
&#9474;                           &#9474;                             &#9474;
&#9474;  SQLite (techdocs.db)     &#9474;                             &#9474;
&#9474;  &#9500;&#9472;&#9472; maintenance_log                                    &#9474;
&#9474;  &#9500;&#9472;&#9472; runbook_execution                                  &#9474;
&#9474;  &#9500;&#9472;&#9472; troubleshoot_session                               &#9474;
&#9474;  &#9492;&#9472;&#9472; architecture_snapshot                             &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
</code></code></pre><div><hr></div><h2>Option A: Run Without Docker (Recommended for Learning)</h2><h3>Step 1 &#8212; Clone / Set Up Project</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;b81b95e2-b201-4c3f-9be1-c6ae43540b2e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Make the build script executable
chmod +x start.sh stop.sh

# Run the full build (creates all files, installs deps, runs tests, starts services)
./start.sh
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;b29c84f3-587e-49b1-a3ff-6dde39a651aa&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">======================================
 Creating Project Structure 
======================================
[OK] &#10003; /path/to/techdocs/backend/app/api
[OK] &#10003; /path/to/techdocs/backend/app/docs_engine
...
======================================
 Running Tests 
======================================
tests/test_docs_system.py::TestArchitectureEngine::test_generate_architecture_doc_has_services PASSED
tests/test_docs_system.py::TestApiDocsEngine::test_validate_spec_returns_coverage PASSED
...
20 passed in 1.23s
</code></pre></div><h3>Step 2 &#8212; Verify Backend is Running</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;0f3af8cb-9899-4fa2-bc1c-9828c149a304&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl http://localhost:8155/health
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;4a48e652-f105-4412-8dbb-06afd5952a7e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  "status": "healthy",
  "service": "techdocs",
  "timestamp": "2025-01-15T14:30:00.000Z",
  "version": "1.0.0"
}
</code></pre></div><h3>Step 3 &#8212; Verify Architecture Endpoint</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;5eaa22dc-8e40-4d51-8dd3-813cfb4d9bb8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl http://localhost:8155/api/docs/architecture | python3 -m json.tool | head -30
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;27b56960-6d8a-44fe-b9d9-faa4f8a9eb9d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  "architecture": {
    "version": "1.0.0",
    "services_count": 6,
    "connections_count": 6,
    "services": [
      {
        "name": "api-gateway",
        "type": "gateway",
        "port": 8155,
        ...
      }
    ]
  }
}
</code></pre></div><h3>Step 4 &#8212; Verify API Reference Endpoint</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;be7123db-b7e7-4644-8f5c-16d94d2d09fb&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">curl http://localhost:8155/api/docs/api-reference | python3 -c "
import json, sys
d = json.load(sys.stdin)
print(f'Endpoints: {d[\"reference\"][\"total_endpoints\"]}')
print(f'Coverage: {d[\"validation\"][\"coverage_percentage\"]}%')
"
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;7d0e46fe-3753-42cb-9768-2a6947a4cac3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Endpoints: 10
Coverage: 100.0%
</code></pre></div><h3>Step 5 &#8212; Test Deployment Runbook Execution</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;31d13327-d249-411d-980d-4f7d7a81b0f1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl -s -X POST http://localhost:8155/api/docs/runbooks/production_deploy/execute | python3 -m json.tool
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;648904de-3912-46da-a18a-68d3e95aed76&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  "success": true,
  "runbook": "production_deploy",
  "steps": [
    {"phase": "pre_check", "name": "health_check", "status": "pass", "output": "Health: All services nominal"},
    {"phase": "pre_check", "name": "db_connectivity", "status": "pass", "output": "..."},
    {"phase": "deploy", "name": "create_backup", "status": "success", "output": "..."},
    ...
  ]
}
</code></pre></div><h3>Step 6 &#8212; Test Troubleshooting Tree Navigation</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;4e5a5ee7-ad03-418e-9ded-4cb8d354a05f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Step 1: List available trees
curl http://localhost:8155/api/docs/troubleshoot

# Step 2: Get a specific tree
curl http://localhost:8155/api/docs/troubleshoot/api_503

# Step 3: Navigate the decision tree
curl -s -X POST http://localhost:8155/api/docs/troubleshoot/api_503/navigate \
  -H "Content-Type: application/json" \
  -d '["timeout", "container_stopped"]'
</code></pre></div><p><strong>Expected final output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;f029d79d-0ce6-4ce4-bcbc-3b463ff350b8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  "type": "resolution",
  "action": "Run: docker-compose restart backend",
  "resolution": "Backend container was stopped &#8212; restarted successfully",
  "path": ["timeout", "container_stopped"]
}
</code></pre></div><h3>Step 7 &#8212; Test Maintenance Procedure Execution</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;380ef714-a42d-46a4-bf9d-6cc4cbbbca98&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># List procedures
curl http://localhost:8155/api/docs/maintenance

# Execute log_rotation
curl -s -X POST http://localhost:8155/api/docs/maintenance/log_rotation/execute | python3 -m json.tool
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;97c67631-9b86-4b5f-a045-bcdb1a2617c6&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  "success": true,
  "procedure": "log_rotation",
  "duration_seconds": 0.05,
  "steps": [
    "[OK] find_old_logs: Found 3 log files for rotation",
    "[OK] compress_logs: Compressed: app.log.1 app.log.2 app.log.3",
    "[OK] verify_retention: Retention policy verified: 30 days"
  ],
  "log_id": 1
}
</code></pre></div><h3>Step 8 &#8212; Check Documentation Health Score</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;fae679ab-7ec0-40af-ac08-8e4095482c2d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">curl http://localhost:8155/api/docs/health-score | python3 -c "
import json, sys
d = json.load(sys.stdin)
print(f'Score: {d[\"total_score\"]}/100  Grade: {d[\"grade\"]}')
for k, v in d['components'].items():
    print(f'  {k}: {v[\"score\"]}/{v[\"max\"]}')
"
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;77577ecb-29e0-4dd6-8773-efd0bced304b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Score: 80/100  Grade: B
  architecture_freshness: 35/60
  api_coverage: 40/40
  maintenance_sla: 5/40
</code></pre></div><div><hr></div><h2>Option B: Run With Docker</h2><h3>Step 1 &#8212; Build and Start</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;7ccbda96-56a7-4fe9-ba8c-cc83bac0a473&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">USE_DOCKER=true ./start.sh
</code></pre></div><p><strong>OR manually:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;506165ea-9604-4dde-92a8-4c9c0110e803&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd techdocs
docker-compose build
docker-compose up -d
</code></pre></div><h3>Step 2 &#8212; Check Container Health</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;92fd1645-b15c-47a6-a6d4-18de3dff0617&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">docker-compose ps
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;7cefb954-bb44-4a38-b6a6-704b57ca8433&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">NAME                STATUS          PORTS
techdocs-backend-1  Up (healthy)    0.0.0.0:8155-&gt;8155/tcp
techdocs-frontend-1 Up              0.0.0.0:3155-&gt;3155/tcp
</code></pre></div><h3>Step 3 &#8212; Follow Logs</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;e0a90f8e-3bd4-40f6-8498-fe13fcf9324f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Backend logs
docker-compose logs -f backend

# All services
docker-compose logs -f
</code></pre></div><h3>Step 4 &#8212; Run Tests Inside Container</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;305f5e7a-e65e-4a77-ab9e-373def2adf04&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">docker-compose exec backend python -m pytest tests/ -v
</code></pre></div><h3>Step 5 &#8212; Stop Docker Services</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;0c9142b5-b586-4dcf-a578-4edf36910171&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">./stop.sh
# OR
cd techdocs &amp;&amp; docker-compose down
</code></pre></div><div><hr></div><h2>Running Tests Manually</h2><h3>Unit Tests Only</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;a4ba61eb-9e8b-4daf-85e3-db31d62c90bf&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd techdocs/backend
source venv/bin/activate
python -m pytest tests/test_docs_system.py::TestArchitectureEngine -v
python -m pytest tests/test_docs_system.py::TestApiDocsEngine -v
python -m pytest tests/test_docs_system.py::TestTroubleshootingEngine -v
python -m pytest tests/test_docs_system.py::TestMaintenanceProcedures -v
</code></pre></div><h3>Integration Tests Only</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;b7f483b8-ce8d-4929-8099-9713dc636530&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd techdocs/backend
source venv/bin/activate
python -m pytest tests/test_docs_system.py::TestAPIEndpoints -v
</code></pre></div><h3>All Tests with Coverage</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;edd63a33-a7c5-40b6-b2e4-df3aa58bb223&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd techdocs/backend
source venv/bin/activate
pip install pytest-cov --quiet
python -m pytest tests/ -v --cov=app --cov-report=term-missing
</code></pre></div><p><strong>Expected test summary:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;9cb651e9-9111-4b20-b7fa-5ded1b700ca5&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">================================ test session starts ==================================
collected 20 items

tests/test_docs_system.py::TestArchitectureEngine::test_generate_architecture_doc_has_services PASSED
tests/test_docs_system.py::TestArchitectureEngine::test_architecture_doc_has_data_flows PASSED
tests/test_docs_system.py::TestArchitectureEngine::test_architecture_doc_has_version PASSED
tests/test_docs_system.py::TestArchitectureEngine::test_health_score_returns_numeric PASSED
tests/test_docs_system.py::TestArchitectureEngine::test_services_have_required_fields PASSED
tests/test_docs_system.py::TestApiDocsEngine::test_validate_spec_returns_coverage PASSED
tests/test_docs_system.py::TestApiDocsEngine::test_undocumented_endpoint_reduces_coverage PASSED
tests/test_docs_system.py::TestApiDocsEngine::test_generate_api_reference_extracts_endpoints PASSED
tests/test_docs_system.py::TestTroubleshootingEngine::test_get_all_trees_returns_list PASSED
tests/test_docs_system.py::TestTroubleshootingEngine::test_each_tree_has_required_fields PASSED
tests/test_docs_system.py::TestTroubleshootingEngine::test_get_tree_by_id PASSED
tests/test_docs_system.py::TestTroubleshootingEngine::test_navigate_to_resolution PASSED
tests/test_docs_system.py::TestTroubleshootingEngine::test_navigate_to_decision_node PASSED
tests/test_docs_system.py::TestMaintenanceProcedures::test_get_all_procedures_returns_list PASSED
tests/test_docs_system.py::TestMaintenanceProcedures::test_procedures_have_required_fields PASSED
tests/test_docs_system.py::TestAPIEndpoints::test_health_endpoint PASSED
tests/test_docs_system.py::TestAPIEndpoints::test_architecture_endpoint PASSED
tests/test_docs_system.py::TestAPIEndpoints::test_api_reference_endpoint PASSED
tests/test_docs_system.py::TestAPIEndpoints::test_list_runbooks_endpoint PASSED
tests/test_docs_system.py::TestAPIEndpoints::test_execute_runbook_endpoint PASSED
...
================================ 20 passed in 2.14s ==================================
</code></pre></div><div><hr></div><h2>UI Dashboard Verification</h2><p>Open your browser and navigate to:</p><p>URL What You Should See </p><p>http://localhost:3155</p><p> TechDocs Dashboard &#8212; Overview with Health Score gauge </p><p>http://localhost:3155</p><p> &#8594; Architecture Service map with 6 services and data flows table </p><p>http://localhost:3155</p><p> &#8594; API Reference All 10 endpoints with method badges, expandable detail </p><p>http://localhost:3155</p><p> &#8594; Deployment Two runbooks with Execute button; live step trace </p><p>http://localhost:3155</p><p> &#8594; Troubleshoot Three symptom cards; interactive decision tree on click </p><p>http://localhost:3155</p><p> &#8594; Maintenance 5 procedure cards with Run Now button and execution log <code>http://localhost:8155/api/docs</code> Swagger UI with all endpoints <code>http://localhost:8155/api/redoc</code> Redoc rendered API reference</p><div><hr></div><h2>Troubleshooting Common Issues</h2><p><strong>Backend fails to start &#8212; port already in use:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;91c47952-37cc-4c08-b895-c44b171f2ada&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">lsof -ti :8155 | xargs kill -9
</code></pre></div><p><strong>Frontend blank page:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;68cd870f-50ba-41ba-a3cb-7b2e2b32200e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Check Vite is running
curl http://localhost:3155
# Check proxy is hitting backend
curl http://localhost:3155/api/docs/architecture
</code></pre></div><p><strong>Tests fail with import errors:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;a8aa0cb0-fabd-4c98-8126-57983f7a1945&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd techdocs/backend
source venv/bin/activate
pip install -r requirements.txt
python -c "from app.main import app; print('Import OK')"
</code></pre></div><p><strong>Docker build fails:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;753d83fc-fed0-48dc-a5ea-ff816c7a6cce&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">docker-compose build --no-cache
docker-compose logs backend
</code></pre></div><div><hr></div><h2>Stopping All Services</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;8c8edff2-f467-4723-a156-c0710edf215e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">./stop.sh
</code></pre></div><p>This kills local processes on ports 8155 and 3155, stops Docker containers if running, and cleans up PID/log files.</p><div><hr></div><h2>File Structure After Build</h2><pre><code><code>techdocs/
&#9500;&#9472;&#9472; backend/
&#9474;   &#9500;&#9472;&#9472; app/
&#9474;   &#9474;   &#9500;&#9472;&#9472; main.py                    &#8592; FastAPI app + all routes
&#9474;   &#9474;   &#9500;&#9472;&#9472; models/database.py         &#8592; SQLAlchemy models
&#9474;   &#9474;   &#9500;&#9472;&#9472; docs_engine/
&#9474;   &#9474;   &#9474;   &#9500;&#9472;&#9472; architecture.py        &#8592; System topology generator
&#9474;   &#9474;   &#9474;   &#9500;&#9472;&#9472; api_docs.py            &#8592; OpenAPI validator + reference builder
&#9474;   &#9474;   &#9474;   &#9492;&#9472;&#9472; deployment.py          &#8592; Runbook executor
&#9474;   &#9474;   &#9500;&#9472;&#9472; troubleshoot/
&#9474;   &#9474;   &#9474;   &#9492;&#9472;&#9472; decision_tree.py       &#8592; Decision tree engine
&#9474;   &#9474;   &#9492;&#9472;&#9472; maintenance/
&#9474;   &#9474;       &#9492;&#9472;&#9472; procedures.py          &#8592; Procedure scheduler + executor
&#9474;   &#9500;&#9472;&#9472; tests/
&#9474;   &#9474;   &#9492;&#9472;&#9472; test_docs_system.py        &#8592; 20 unit + integration tests
&#9474;   &#9500;&#9472;&#9472; requirements.txt
&#9474;   &#9500;&#9472;&#9472; Dockerfile
&#9474;   &#9492;&#9472;&#9472; venv/                          &#8592; Python virtual environment
&#9500;&#9472;&#9472; frontend/
&#9474;   &#9500;&#9472;&#9472; src/
&#9474;   &#9474;   &#9500;&#9472;&#9472; App.jsx                    &#8592; Root component + routing
&#9474;   &#9474;   &#9500;&#9472;&#9472; components/
&#9474;   &#9474;   &#9474;   &#9500;&#9472;&#9472; Sidebar.jsx            &#8592; Navigation
&#9474;   &#9474;   &#9474;   &#9500;&#9472;&#9472; PageHeader.jsx         &#8592; Reusable header
&#9474;   &#9474;   &#9474;   &#9492;&#9472;&#9472; Card.jsx               &#8592; Reusable card
&#9474;   &#9474;   &#9492;&#9472;&#9472; pages/
&#9474;   &#9474;       &#9500;&#9472;&#9472; OverviewPage.jsx       &#8592; Health score gauge
&#9474;   &#9474;       &#9500;&#9472;&#9472; ArchitecturePage.jsx   &#8592; Service map
&#9474;   &#9474;       &#9500;&#9472;&#9472; ApiReferencePage.jsx   &#8592; Endpoint browser
&#9474;   &#9474;       &#9500;&#9472;&#9472; RunbooksPage.jsx       &#8592; Runbook executor
&#9474;   &#9474;       &#9500;&#9472;&#9472; TroubleshootPage.jsx   &#8592; Decision tree UI
&#9474;   &#9474;       &#9492;&#9472;&#9472; MaintenancePage.jsx    &#8592; Procedure runner
&#9474;   &#9500;&#9472;&#9472; package.json
&#9474;   &#9500;&#9472;&#9472; vite.config.js
&#9474;   &#9492;&#9472;&#9472; Dockerfile
&#9500;&#9472;&#9472; docker-compose.yml
&#9500;&#9472;&#9472; start.sh
&#9492;&#9472;&#9472; stop.sh
</code></code></pre><div><hr></div><h2>Assignment Solution Hints</h2><p>The assignment asks you to build a documentation health score gauge. Here&#8217;s the approach:</p><p><strong>Step 1 &#8212; API endpoint already exists:</strong> <code>GET /api/docs/health-score</code> returns all three component scores. The backend is already built.</p><p><strong>Step 2 &#8212; Add a gauge to Overview page:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;a8e4eb30-ee46-4845-b50c-201f0eff632d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">// In OverviewPage.jsx, use recharts RadialBarChart
import { RadialBarChart, RadialBar, ResponsiveContainer } from 'recharts'

const gaugeData = [{ value: healthData.total_score, fill: gradeColor(healthData.grade) }]
// RadialBarChart cx/cy 50%, startAngle=90, endAngle computed from score
</code></pre></div><p><strong>Step 3 &#8212; Grade colour mapping:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:&quot;a46d69a9-602f-4221-abba-576499f46c77&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">const gradeColor = g =&gt; ({ A: '#22c55e', B: '#eab308', C: '#f97316', D: '#ef4444' }[g] || '#8a9bbf')
</code></pre></div><p><strong>Step 4 &#8212; The gauge is already implemented</strong> in <code>OverviewPage.jsx</code> as part of this lesson. Study it and extend it to show a tooltip explaining each component&#8217;s contribution on hover.</p><p></p><p></p><h2>This Week&#8217;s Goal</h2><p>By end of this lesson your system has:</p><ul><li><p>&#9989; Auto-generated API reference that fails CI if undocumented</p></li><li><p>&#9989; Architecture diagram generated from live compose config</p></li><li><p>&#9989; Executable deployment runbooks with rollback steps</p></li><li><p>&#9989; Interactive troubleshooting decision trees</p></li><li><p>&#9989; Scheduled maintenance procedures with execution logs</p></li></ul><div><hr></div><h2>Assignment</h2><p><strong>Task:</strong> Add a documentation health score to the dashboard.</p><p>The score should measure:</p><ol><li><p>Percentage of API endpoints with descriptions (from OpenAPI spec)</p></li><li><p>Percentage of maintenance procedures executed on-schedule in the last 30 days</p></li><li><p>Age of the last architecture doc rebuild (penalise if &gt;7 days)</p></li></ol><p>Combine into a 0&#8211;100 score displayed as a gauge on the dashboard.</p><p><strong>Solution Hints:</strong></p><ol><li><p>Parse <code>/openapi.json</code> &#8212; count total operations, count those with <code>description</code> field. Ratio &#215; 40 = component 1 score.</p></li><li><p>Query <code>maintenance_log</code> for last 30 days, compare against scheduled frequency in <code>maintenance.yml</code>. Ratio &#215; 40 = component 2 score.</p></li><li><p>Read <code>architecture.json</code> mtime, compute age in days. If &lt;7: 20 points; 7&#8211;14: 10 points; &gt;14: 0 points.</p></li><li><p>Sum components, display as a Radial gauge using <code>recharts</code> RadialBarChart.</p></li></ol><div><hr></div><h2>Takeaway</h2><p>Documentation built as a first-class engineering artifact &#8212; generated, validated, versioned, and executed &#8212; is what separates systems that are maintainable at scale from those that collapse under their own operational weight. Stripe doesn&#8217;t write API docs. They write code that emits API docs. That&#8217;s the standard you&#8217;re now building to.</p><h2>Working Code Demo :</h2><div id="youtube2-ygCLLJEqtrM" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;ygCLLJEqtrM&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/ygCLLJEqtrM?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Day 154: Production Integration — Validating Everything Before It Matters]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-154-production-integration-validating</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-154-production-integration-validating</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Thu, 27 Aug 2026 06:30:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!De7C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>What We&#8217;re Building Today</h3><p>By end of this lesson you will have:</p><ul><li><p>A <strong>Production Integration Test Suite</strong> that validates all running services end-to-end</p></li><li><p><strong>Automated security control checks</strong> (JWT, CORS, rate limiting, TLS headers)</p></li><li><p><strong>Alerting pipeline smoke tests</strong> &#8212; confirming Prometheus &#8594; Alertmanager &#8594; notification chain</p></li><li><p><strong>Disaster Recovery drills</strong> &#8212; scripted failover that proves your recovery targets are real</p></li><li><p>A <strong>React Integration Dashboard</strong> displaying live pass/fail status across all validation domains</p></li></ul><div><hr></div><h3>Why This Lesson Exists</h3><p>Every engineering team has a go-live checklist. Most are wrong or incomplete. The gap between &#8220;monitoring is configured&#8221; (Day 153) and &#8220;monitoring actually fires correctly under real failure&#8221; is exactly what kills production systems quietly. Netflix calls this <strong>chaos injection at deploy time</strong> &#8212; they validate failure paths before declaring a deploy stable. We&#8217;re doing the same, at our scale.</p><div><hr></div><h2>Component Architecture</h2><p>The integration test harness wraps around your entire stack. Think of it as a thin validation layer that sits <strong>outside</strong> your application boundary and probes it the same way a real user or adversary would.</p><pre><code><code>&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474;              Integration Test Orchestrator           &#9474;
&#9474;   (pytest + asyncio + httpx)                        &#9474;
&#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
&#9474; Service  &#9474; Security &#9474;  Alerting   &#9474;   DR Validation &#9474;
&#9474; Health   &#9474; Controls &#9474;  Pipeline   &#9474;   &amp; Failover    &#9474;
&#9474; Probes   &#9474; Checks   &#9474;  Smoke Test &#9474;   Drills        &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9524;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474;          &#9474;             &#9474;             &#9474;
     &#9660;          &#9660;             &#9660;             &#9660;
  FastAPI    JWT/CORS     Prometheus    PostgreSQL
  Redis      Rate Limit   Alertmanager  Redis Failover
  Postgres   TLS Headers  Webhook       Backup Restore
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!De7C!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!De7C!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png 424w, /__u/substackcdn.com/image/fetch/$s_!De7C!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png 848w, /__u/substackcdn.com/image/fetch/$s_!De7C!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png 1272w, /__u/substackcdn.com/image/fetch/$s_!De7C!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!De7C!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png" width="1456" height="946" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:946,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:900172,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/203044626?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!De7C!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png 424w, /__u/substackcdn.com/image/fetch/$s_!De7C!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png 848w, /__u/substackcdn.com/image/fetch/$s_!De7C!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png 1272w, /__u/substackcdn.com/image/fetch/$s_!De7C!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe997fbbf-a60f-4622-99bf-7a09f8f31c5e_4800x3120.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>The orchestrator runs sequentially through four validation domains. Each domain emits a structured result object. The React dashboard polls a <code>/api/integration/results</code> endpoint (WebSocket for live updates) and renders the state tree.</p>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-154-production-integration-validating">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 153: Production Monitoring — Observability That Actually Wakes You Up at the Right Time]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-153-production-monitoring-observability</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-153-production-monitoring-observability</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Tue, 25 Aug 2026 06:30:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ERS4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>What We&#8217;re Building Today</h3><ul><li><p>A <strong>Prometheus + Grafana</strong> observability stack collecting real application metrics</p></li><li><p><strong>Alertmanager</strong> with routed alert rules (warning vs. critical severity)</p></li><li><p>A <strong>FastAPI backend</strong> exposing <code>/metrics</code>, <code>/health</code>, and business logic endpoints</p></li><li><p>An <strong>incident response workflow</strong> with on-call rotation logic</p></li><li><p><strong>Runbook automation</strong> &#8212; structured response playbooks tied directly to alerts</p></li><li><p>A <strong>React dashboard</strong> (Datadog/PagerDuty-inspired UI) showing live system health, alert feeds, and on-call status</p></li></ul><div><hr></div><h3>The Architecture at a Glance</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!ERS4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!ERS4!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png 424w, /__u/substackcdn.com/image/fetch/$s_!ERS4!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png 848w, /__u/substackcdn.com/image/fetch/$s_!ERS4!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png 1272w, /__u/substackcdn.com/image/fetch/$s_!ERS4!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!ERS4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png" width="1456" height="860" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:860,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1019670,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202828388?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!ERS4!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png 424w, /__u/substackcdn.com/image/fetch/$s_!ERS4!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png 848w, /__u/substackcdn.com/image/fetch/$s_!ERS4!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png 1272w, /__u/substackcdn.com/image/fetch/$s_!ERS4!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aa6ae08-fd7c-4192-a604-6f6e97873770_5280x3120.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-153-production-monitoring-observability">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 152: Performance Tuning — Making Your System Fast Under Real Load]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-152-performance-tuning-making</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-152-performance-tuning-making</guid><dc:creator><![CDATA[systemdr19]]></dc:creator><pubDate>Sun, 23 Aug 2026 06:30:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!jAi9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>Yesterday you locked the doors with security hardening. Today you optimize the engine. Here&#8217;s the agenda:</p><ul><li><p><strong>Redis caching layer</strong> &#8212; cut database round-trips by 80%</p></li><li><p><strong>Resource monitoring dashboard</strong> &#8212; CPU, memory, disk, and request metrics in real time</p></li><li><p><strong>Auto-scaling logic</strong> &#8212; spin workers up/down based on load signals</p></li><li><p><strong>Capacity planning module</strong> &#8212; forecast when you&#8217;ll need more infrastructure</p></li><li><p><strong>Performance benchmark suite</strong> &#8212; prove the gains with numbers</p></li></ul><p>By end of day you&#8217;ll have a live dashboard that looks and behaves like what the Datadog or New Relic SRE team stares at during a product launch.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!jAi9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!jAi9!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png 424w, /__u/substackcdn.com/image/fetch/$s_!jAi9!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png 848w, /__u/substackcdn.com/image/fetch/$s_!jAi9!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png 1272w, /__u/substackcdn.com/image/fetch/$s_!jAi9!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!jAi9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png" width="1456" height="874" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:874,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2856288,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://autotestman.substack.com/i/202801267?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="/__u/substackcdn.com/image/fetch/$s_!jAi9!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png 424w, /__u/substackcdn.com/image/fetch/$s_!jAi9!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png 848w, /__u/substackcdn.com/image/fetch/$s_!jAi9!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png 1272w, /__u/substackcdn.com/image/fetch/$s_!jAi9!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7603bffc-9576-42cd-b580-7a99a7929d21_4800x2880.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Where This Fits in the System</h2><p>Your stack now has: API Gateway &#8594; App Servers &#8594; PostgreSQL + Redis &#8594; Background Workers. The performance layer wraps all of these &#8212; it doesn&#8217;t replace anything, it sits alongside and observes, caches, and reacts. Think of it as the nervous system.</p>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-152-performance-tuning-making">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 151: Security Hardening — Locking Down Your Production System]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-151-security-hardening-locking</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-151-security-hardening-locking</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Sat, 22 Aug 2026 06:30:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!lOug!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>Yesterday (Day 150), we deployed our production application. Today we harden it. Here&#8217;s the agenda:</p><ul><li><p><strong>Security Control Layer</strong> &#8212; rate limiting, IP allowlisting, request validation</p></li><li><p><strong>Firewall Rules</strong> &#8212; UFW-based network-level access restrictions</p></li><li><p><strong>Intrusion Detection</strong> &#8212; Fail2ban watching live logs and banning attackers</p></li><li><p><strong>Security Monitoring Dashboard</strong> &#8212; real-time React UI showing threat events, ban logs, and system posture</p></li></ul><p>By end of lesson, you&#8217;ll have a live dashboard that detects, blocks, and visualizes attacks happening in real time.</p><div><hr></div><h2>Where This Fits in the 180-Day System</h2><pre><code><code>Week 21: Deploy &#8594; Week 22: Harden &#8594; Week 23: Tune &#8594; Week 24: Scale
          Day 150          Day 151         Day 152
       [Application]   [Security]      [Performance]
       [Deployment ]   [Hardening]     [Tuning     ]
</code></code></pre><p>Security hardening sits between deployment and performance tuning intentionally. You don&#8217;t tune what isn&#8217;t secured &#8212; attackers will exploit any performance shortcuts.</p><div><hr></div><h2>Component Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!lOug!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!lOug!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png 424w, /__u/substackcdn.com/image/fetch/$s_!lOug!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png 848w, /__u/substackcdn.com/image/fetch/$s_!lOug!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png 1272w, /__u/substackcdn.com/image/fetch/$s_!lOug!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!lOug!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png" width="1214" height="809" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:809,&quot;width&quot;:1214,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:159702,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/203379990?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!lOug!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png 424w, /__u/substackcdn.com/image/fetch/$s_!lOug!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png 848w, /__u/substackcdn.com/image/fetch/$s_!lOug!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png 1272w, /__u/substackcdn.com/image/fetch/$s_!lOug!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d472e47-5fed-4a97-acdb-7fd03a63a00e_1214x809.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-151-security-hardening-locking">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 150: Application Deployment — Shipping to Production Like a Senior Engineer]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-150-application-deployment-shipping</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-150-application-deployment-shipping</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Thu, 20 Aug 2026 06:30:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!RYe8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p>Deploy a Python/FastAPI backend and React frontend to production Docker containers</p></li><li><p>Wire environment variables through a secrets-safe <code>.env</code> pipeline</p></li><li><p>Set up Prometheus metrics collection with a custom <code>/metrics</code> endpoint</p></li><li><p>Implement layered health checks: liveness, readiness, and dependency probes</p></li><li><p>Launch a Grafana performance dashboard &#8212; live, real data, zero mocks</p></li></ul><div><hr></div><h2>The Mental Model: Deployment Is Not &#8220;Just Running Code&#8221;</h2><p>Every engineer at some point treats deployment as &#8220;copy code, run it.&#8221; That mental model collapses at scale. Production deployment is an <em>operational contract</em> &#8212; a guarantee that your app starts correctly, fails predictably, exposes its own health, and integrates into the monitoring fabric of your infrastructure.</p><p>Netflix, Shopify, and Stripe all treat deployments as <em>observable events</em>, not silent background tasks. Their systems emit telemetry from the first millisecond of startup.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!RYe8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!RYe8!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png 424w, /__u/substackcdn.com/image/fetch/$s_!RYe8!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png 848w, /__u/substackcdn.com/image/fetch/$s_!RYe8!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png 1272w, /__u/substackcdn.com/image/fetch/$s_!RYe8!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!RYe8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png" width="1456" height="938" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:938,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:878251,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202802138?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!RYe8!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png 424w, /__u/substackcdn.com/image/fetch/$s_!RYe8!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png 848w, /__u/substackcdn.com/image/fetch/$s_!RYe8!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png 1272w, /__u/substackcdn.com/image/fetch/$s_!RYe8!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbbfe44f-c3cc-439c-9726-2778e8b5a7bf_4915x3168.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><h2>Component Architecture</h2><pre><code><code>&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474;                   PRODUCTION STACK                   &#9474;
&#9474;                                                     &#9474;
&#9474;  React Frontend &#9472;&#9472;&#9658; Nginx Proxy &#9472;&#9472;&#9658; FastAPI Backend &#9474;
&#9474;                                          &#9474;           &#9474;
&#9474;                                     PostgreSQL DB    &#9474;
&#9474;                                          &#9474;           &#9474;
&#9474;                              Prometheus &#9668;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472; &#9474;
&#9474;                                   &#9474;                  &#9474;
&#9474;                               Grafana Dashboard      &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
</code></code></pre><p>The backend exposes three categories of endpoints:</p><ol><li><p><strong>Business endpoints</strong> &#8212; actual application logic</p></li><li><p><strong>Health probes</strong> &#8212; <code>/health/live</code>, <code>/health/ready</code>, <code>/health/dependencies</code></p></li><li><p><strong>Metrics endpoint</strong> &#8212; <code>/metrics</code> scraped by Prometheus every 15 seconds</p></li></ol><p>The frontend is a React SPA served via Nginx &#8212; same pattern used by Vercel&#8217;s internal deployments. Nginx also reverse-proxies API calls to the backend container, eliminating CORS complexity.</p><div><hr></div><h2>Environment Variables: The Right Way</h2><p>Most junior engineers hardcode secrets. Mid-level engineers move secrets to <code>.env</code> files. Senior engineers design an <em>environment promotion pipeline</em> where the same app binary runs in dev, staging, and prod &#8212; only the environment context changes.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;e6376487-67bd-470d-928b-cd7e75417462&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">.env.development  &#8594;  dev database, debug logging ON
.env.staging      &#8594;  staging database, debug logging OFF  
.env.production   &#8594;  prod database, structured JSON logging, rate limiting ON
</code></pre></div><p>Your backend reads config using <code>pydantic-settings</code> &#8212; it validates types, provides defaults, and fails loudly at startup if required vars are missing. No silent misconfiguration.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!xLfp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!xLfp!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png 424w, /__u/substackcdn.com/image/fetch/$s_!xLfp!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png 848w, /__u/substackcdn.com/image/fetch/$s_!xLfp!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png 1272w, /__u/substackcdn.com/image/fetch/$s_!xLfp!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!xLfp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png" width="1456" height="1166" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1166,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:870655,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202802138?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!xLfp!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png 424w, /__u/substackcdn.com/image/fetch/$s_!xLfp!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png 848w, /__u/substackcdn.com/image/fetch/$s_!xLfp!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png 1272w, /__u/substackcdn.com/image/fetch/$s_!xLfp!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbea1fd7a-a314-4575-875a-83ce4281a55a_4915x3936.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><h2>Health Checks: Three Levels, Three Purposes</h2><p>Kubernetes and Docker orchestrators need to know: <em>Is this container alive? Is it ready to serve traffic? Are its dependencies healthy?</em></p><p><strong>Liveness probe</strong> &#8212; answers &#8220;Is the process running?&#8221; A 200 means the container shouldn&#8217;t be killed. Returns 503 only on catastrophic internal failure.</p><p><strong>Readiness probe</strong> &#8212; answers &#8220;Can this instance take traffic right now?&#8221; If the DB connection pool is exhausted, return 503 here. The load balancer routes around you.</p><p><strong>Dependency check</strong> &#8212; answers &#8220;Are all my downstream services healthy?&#8221; Checks PostgreSQL connectivity, Redis ping, and external API reachability. Used by deployment automation to gate rollouts.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;5abdbca4-fb75-481f-9c03-bb01e1badb4b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Pseudo-code pattern
@app.get("/health/ready")
async def readiness():
    db_ok = await check_db_connection()
    cache_ok = await check_redis_ping()
    if db_ok and cache_ok:
        return {"status": "ready"}
    raise HTTPException(503, detail="dependencies not ready")
</code></pre></div><p>This pattern is identical to what Google&#8217;s production infrastructure uses internally &#8212; fail fast at startup, fail clear in operation.</p><div><hr></div><h2>Prometheus Metrics: What to Instrument</h2><p>Don&#8217;t instrument everything. Instrument the <em>four golden signals</em> (coined by Google SRE):</p><p>Signal Metric Name What It Tells You Latency <code>http_request_duration_seconds</code> Are requests slow? Traffic <code>http_requests_total</code> How much load? Errors <code>http_errors_total</code> Are things failing? Saturation <code>process_open_fds</code> Am I running out of resources?</p><p>Your FastAPI app will use <code>prometheus-fastapi-instrumentator</code> to auto-instrument all routes with zero boilerplate, plus custom counters for business-specific metrics (e.g., deployments triggered, health check failures).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!GHIu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!GHIu!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png 424w, /__u/substackcdn.com/image/fetch/$s_!GHIu!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png 848w, /__u/substackcdn.com/image/fetch/$s_!GHIu!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png 1272w, /__u/substackcdn.com/image/fetch/$s_!GHIu!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!GHIu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png" width="1456" height="1081" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1081,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:918705,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202802138?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!GHIu!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png 424w, /__u/substackcdn.com/image/fetch/$s_!GHIu!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png 848w, /__u/substackcdn.com/image/fetch/$s_!GHIu!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png 1272w, /__u/substackcdn.com/image/fetch/$s_!GHIu!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabba9e3a-bac6-4f88-a074-a0f63cc2c123_4915x3648.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><h2>Grafana Dashboard: What Good Looks Like</h2><p>A production Grafana dashboard has three rows:</p><ol><li><p><strong>Availability row</strong> &#8212; uptime, health check status, error rate</p></li><li><p><strong>Performance row</strong> &#8212; P50/P95/P99 latency, requests/sec, active connections</p></li><li><p><strong>Resource row</strong> &#8212; CPU, memory, open file descriptors, GC pressure</p></li></ol><p>This is structurally identical to Datadog&#8217;s APM default view. You&#8217;re building the open-source version.</p><div><hr></div><h1>Step-by-Step Implementation Guide</h1><h2>Github Link:</h2><p><a href="https://github.com/sysdr/infrawatch-fullstack-p/tree/main/day150/day150_app">https://github.com/sysdr/infrawatch-fullstack-p/tree/main/day150/day150_app</a></p><h2>Architecture Overview</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;c3978c90-4112-47db-b794-135c2c77c84e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">React SPA (port 3000)
    &#8595; (HTTP)
Nginx Reverse Proxy (port 80)
    &#8595; (/api/*)
FastAPI Backend (port 8000)
    &#9500;&#9472;&#9472; /health/live      &#8594; Liveness probe
    &#9500;&#9472;&#9472; /health/ready     &#8594; Readiness probe
    &#9500;&#9472;&#9472; /health/deps      &#8594; Dependency check
    &#9500;&#9472;&#9472; /api/v1/*         &#8594; Business logic
    &#9492;&#9472;&#9472; /metrics          &#8594; Prometheus scrape target
         &#8593;
    Prometheus (port 9090) &#8594; scrapes every 15s
         &#8595;
    Grafana (port 3001) &#8594; PromQL queries &#8594; dashboards
</code></pre></div><div><hr></div><h2>Prerequisites Check</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ec7627c5-61df-42c5-a00e-d3b9baf98680&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Verify tools
python3 --version        # Expected: Python 3.11+
node --version           # Expected: v20+
docker --version         # Expected: Docker 24+
docker compose version   # Expected: v2.20+
curl --version
</code></pre></div><div><hr></div><h2>Option A: Local Mode (No Docker)</h2><h3>1. Run the Build Script</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ab6cf90c-3db0-49bd-a907-75072ac14e93&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">chmod +x start.sh stop.sh
./start.sh
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;dd8d461a-59cb-4529-abbe-190dd331744f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">&#9552;&#9552; STEP 1: Creating Project Structure &#9552;&#9552;
[BUILD] Directory tree created
[BUILD] All directories verified &#10003;
...
&#9552;&#9552; STEP 7: Setting Up Python Virtual Environment &#9552;&#9552;
[BUILD] Python dependencies installed
&#9552;&#9552; STEP 8: Running Unit Tests (Local) &#9552;&#9552;
PASSED tests/test_health.py::test_liveness_returns_200
PASSED tests/test_health.py::test_readiness_returns_200_when_deps_healthy
PASSED tests/test_health.py::test_readiness_returns_503_when_db_down
PASSED tests/test_health.py::test_dependency_check_endpoint
PASSED tests/test_health.py::test_root_endpoint
PASSED tests/test_health.py::test_metrics_endpoint_returns_prometheus_format
PASSED tests/test_deployments.py::test_trigger_deployment
PASSED tests/test_deployments.py::test_list_deployments
PASSED tests/test_deployments.py::test_feature_flag_evaluation
PASSED tests/test_deployments.py::test_metrics_summary
10 passed in ~2.5s
</code></pre></div><h3>2. Functional Verification</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;00df1032-66fa-4036-841b-91b892d7d442&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Liveness
curl http://localhost:8000/health/live
# Expected: {"status":"alive","uptime_seconds":4.2,"timestamp":...}

# Root info
curl http://localhost:8000/
# Expected: {"name":"Day150App","version":"1.0.0","environment":"development",...}

# Readiness (may be degraded if no DB/Redis &#8212; this is expected behavior)
curl http://localhost:8000/health/ready
# Expected: 200 {"status":"ready",...} or 503 if DB not running

# Prometheus metrics
curl http://localhost:8000/metrics | head -20
# Expected: # HELP http_requests_total ... + metric lines

# Trigger a deployment
curl -X POST http://localhost:8000/api/v1/deployments \
  -H "Content-Type: application/json" \
  -d '{"environment":"staging","version":"v1.2.3","service_name":"api-service"}'
# Expected: {"id":"deploy-...","status":"success",...} (90% of the time)

# Feature flag evaluation
curl http://localhost:8000/api/v1/feature-flags/dark-mode
# Expected: {"flag_name":"dark-mode","result":"enabled",...}

# Metrics summary
curl http://localhost:8000/api/v1/metrics/summary
# Expected: {"total_deployments":1,"successful":1,"failed":0,"success_rate":100.0,...}
</code></pre></div><h3>3. API Interactive Docs</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;e64202e5-ce5a-406c-8964-6544116c1fad&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">http://localhost:8000/docs
</code></pre></div><p>All endpoints are explorable and testable here.</p><div><hr></div><h2>Option B: Docker Compose Mode</h2><h3>1. Run with Docker Flag</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;f2016bc0-d227-4775-b4f7-af38dd9f9ef8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">./start.sh --docker
</code></pre></div><p><strong>Expected output (abridged):</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;d94a01b2-3128-4a69-bc2e-14ccfdbf2dc8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">&#9552;&#9552; STEP 7: Building &amp; Starting Docker Compose Stack &#9552;&#9552;
[+] Building backend ... done
[+] Building frontend ... done
[+] Running 6/6
 &#10004; Container day150_postgres   Healthy
 &#10004; Container day150_redis      Healthy
 &#10004; Container day150_backend    Healthy
 &#10004; Container day150_frontend   Started
 &#10004; Container day150_prometheus Started
 &#10004; Container day150_grafana    Started
</code></pre></div><h3>2. Verify Docker Endpoints</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;8df81153-1f09-4f9c-b86a-9235a89ff730&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Backend health
curl http://localhost:8000/health/live
# Expected: {"status":"alive",...}

curl http://localhost:8000/health/ready
# Expected: {"status":"ready","dependencies":{"postgresql":"healthy","redis":"healthy"}}

# Dependency detail
curl http://localhost:8000/health/dependencies
# Expected: {"overall":"healthy","services":{"postgresql":{"healthy":true,"latency_ms":1.2},...}}

# Prometheus
curl http://localhost:9090/-/healthy
# Expected: Prometheus Server is Healthy.

# Prometheus metrics available
curl "http://localhost:9090/api/v1/query?query=up"
# Expected: JSON with metric values

# Frontend
curl -s http://localhost:3000 | grep -o '&lt;title&gt;.*&lt;/title&gt;'
# Expected: &lt;title&gt;Day 150 &#8212; Deployment Dashboard&lt;/title&gt;
</code></pre></div><h3>3. Grafana Dashboard</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;342ae7e2-fc71-4b65-8f8c-2bf8eab940a3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">URL:      http://localhost:3001
Username: admin
Password: day150admin
</code></pre></div><p>Navigate to: <strong>Dashboards &#8594; Day150 &#8594; Day 150 &#8212; Application Deployment</strong></p><p>You should see:</p><ul><li><p>App Uptime counter (top left)</p></li><li><p>Request Rate stat</p></li><li><p>Error Rate stat</p></li><li><p>Health Status indicator (1 = READY)</p></li><li><p>P95/P50 Latency time series (updates after a few requests)</p></li><li><p>Dependency Health time series</p></li><li><p>HTTP Requests by Status (updates in real-time)</p></li></ul><p><strong>Generate traffic to populate charts:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;cf4bd0ec-26ca-4943-b5bc-e81ca6d23c59&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash"># Stress the API with 50 requests
for i in $(seq 1 50); do
  curl -s http://localhost:8000/api/v1/deployments \
    -X POST -H "Content-Type: application/json" \
    -d "{\"environment\":\"prod\",\"version\":\"v$i.0\",\"service_name\":\"svc\"}" &gt; /dev/null
  curl -s "http://localhost:8000/api/v1/feature-flags/flag-$((i % 4))" &gt; /dev/null
done
echo "Done &#8212; check Grafana in 15s"
</code></pre></div><div><hr></div><h2>Understanding the Code</h2><h3>Why pydantic-settings?</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;0ad619dc-0710-45c1-80e2-0ed5e74b0fb7&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># This fails LOUDLY at startup if DATABASE_URL is missing or wrong type
class Settings(BaseSettings):
    DATABASE_URL: str          # required &#8212; no default
    DEBUG: bool = False        # optional with default
    HEALTH_CHECK_INTERVAL: int = 15
</code></pre></div><p>If you forget <code>DATABASE_URL</code> in your <code>.env</code>, your app exits immediately with a validation error. You catch misconfigurations before the first request, not during.</p><h3>Three-Level Health Checks</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;319ce6d9-3249-4437-8d41-d1059695c987&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">/health/live  &#8594; Docker HEALTHCHECK &#8594; "restart if dead"
/health/ready &#8594; Load balancer &#8594; "route traffic here?"  
/health/deps  &#8594; Deployment gate &#8594; "safe to deploy?"
</code></pre></div><p>These map directly to Kubernetes <code>livenessProbe</code>, <code>readinessProbe</code>, and pre-deployment checks.</p><h3>Prometheus Auto-Instrumentation</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;334b3a45-4c38-4ed5-91e8-cc2a8b2f8083&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Instrumentator().instrument(app).expose(app)
</code></pre></div><p>This one line adds <code>http_requests_total</code>, <code>http_request_duration_seconds</code>, and <code>http_requests_in_progress</code> to every route automatically. You still add custom business metrics on top.</p><div><hr></div><h2>Common Issues &amp; Fixes</h2><p>Symptom Cause Fix <code>/health/ready</code> returns 503 DB not running Start PostgreSQL or use local mode <code>metrics</code> endpoint missing Instrumentator not installed <code>pip install prometheus-fastapi-instrumentator</code> Grafana shows &#8220;No data&#8221; Backend not scraped yet Wait 30s for first scrape; check Prometheus targets Frontend blank CORS origin mismatch Check <code>ALLOWED_ORIGINS</code> in <code>.env</code></p><div><hr></div><h2>Running Tests Independently</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;479e3c0d-b7a3-423a-bbaa-7dacb09fc4da&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd day150_app/backend
source venv/bin/activate

# All tests
pytest tests/ -v

# Single test file
pytest tests/test_health.py -v

# With coverage report
pytest tests/ -v --cov=app --cov-report=term-missing

# Specific test
pytest tests/test_health.py::test_liveness_returns_200 -v
</code></pre></div><div><hr></div><h2>Stopping Everything</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;11d4a822-9b4e-409f-9b7a-e2d7e6492a9a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">./stop.sh
</code></pre></div><p>For Docker specifically:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;7aedf008-2061-4c25-bbe7-0709d0c96f8f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd day150_app
docker compose down -v  # -v removes volumes (DB data)
</code></pre></div><div><hr></div><h2>What You&#8217;ve Built</h2><p>By completing this lesson, you&#8217;ve deployed:</p><ol><li><p>A <strong>FastAPI production backend</strong> with structured JSON logging, Pydantic config validation, and three-tier health checks</p></li><li><p>A <strong>React dashboard</strong> that polls live endpoints and visualizes deployment operations in real-time</p></li><li><p>A <strong>Prometheus + Grafana</strong> observability stack with the four golden signals already wired up</p></li><li><p>A <strong>complete test suite</strong> covering health probes, deployment endpoints, and feature flag logic</p></li></ol><p>This is architecturally identical to how Stripe, Shopify, and Cloudflare deploy and monitor their services &#8212; you have the same operational primitives.</p><div><hr></div><h2>Success Criteria</h2><p>By end of this lesson, you should be able to:</p><ul><li><p>[ ] Hit <code>GET /health/live</code> and get <code>{"status": "alive"}</code> within 100ms</p></li><li><p>[ ] Hit <code>GET /health/ready</code> and see all dependencies marked healthy</p></li><li><p>[ ] See your app&#8217;s request metrics appear in Prometheus at <code>localhost:9090</code></p></li><li><p>[ ] Open Grafana at <code>localhost:3001</code> and see live P95 latency updating every 15 seconds</p></li><li><p>[ ] Trigger a simulated failure, watch the health check turn red, watch it recover</p></li></ul><div><hr></div><h2>Key Insight to Remember</h2><blockquote><p>The app that deploys cleanly, exposes its health, and emits structured telemetry from minute one is worth ten times the app that &#8220;works on my machine.&#8221; Deployment is product quality.</p></blockquote><div><hr></div><h2>Homework Assignment</h2><p><strong>Task:</strong> Extend the monitoring stack with a custom business metric.</p><p>Add a Prometheus counter called <code>feature_flag_evaluations_total</code> with labels <code>{flag_name, result}</code>. Instrument it in a new <code>/api/feature-flags/{flag_name}</code> endpoint that randomly returns <code>enabled</code> or <code>disabled</code> (simulate a feature flag service). Create a Grafana panel showing evaluation rate by flag name.</p><p><strong>Solution Hints:</strong></p><ol><li><p>Use <code>prometheus_client.Counter</code> with <code>labelnames=["flag_name", "result"]</code></p></li><li><p>Call <code>.labels(flag_name=name, result=result).inc()</code> on each request</p></li><li><p>In Grafana: query <code>rate(feature_flag_evaluations_total[1m])</code>, group by <code>result</code> label</p></li><li><p>Add a legend with <code>{{flag_name}} - {{result}}</code> format string</p></li><li><p>Set panel type to &#8220;Time series&#8221; with stacked display</p></li></ol><div><hr></div><h2>Working Code Demo:</h2><div id="youtube2-IKnN4SXG-dA" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;IKnN4SXG-dA&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/IKnN4SXG-dA?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[Day 149: Database Production Setup]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-149-database-production-setup</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-149-database-production-setup</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Tue, 18 Aug 2026 06:31:02 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!AABt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>What We&#8217;re Building Today</h3><p>Today you ship the <strong>production database tier</strong> for the infrastructure stack you&#8217;ve been assembling. This is one of the highest-stakes sessions in the series because every architectural decision here has a direct, measurable cost when something goes wrong at 2 AM.</p><p><strong>Today&#8217;s agenda:</strong></p><ul><li><p>Deploy a primary-replica database cluster with real replication mechanics</p></li><li><p>Build a backup pipeline that actually verifies its own restores</p></li><li><p>Stand up a monitoring layer that measures what it claims to measure</p></li><li><p>Wire in a performance tuning advisor that reads real query plans</p></li><li><p>Connect everything to a production-grade control plane dashboard</p></li></ul><div><hr></div><h3>Where This Fits</h3><p>Last session (Day 148) you configured load balancing, SSL, and CDN at the edge. Today you go one tier deeper &#8212; the database. Tomorrow (Day 150) you deploy the application on top of what you build here.</p><p>Think of this week as building a three-tier sandwich: Day 148 = the crust (edge/CDN), Day 149 = the filling (database), Day 150 = the top layer (application). The crust protects, the filling is what users are actually paying for, and the top layer is what they touch. If today&#8217;s tier goes down, everything above it goes with it.</p><div><hr></div><h3>Component Architecture</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!AABt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!AABt!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png 424w, /__u/substackcdn.com/image/fetch/$s_!AABt!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png 848w, /__u/substackcdn.com/image/fetch/$s_!AABt!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png 1272w, /__u/substackcdn.com/image/fetch/$s_!AABt!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!AABt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png" width="1456" height="938" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:938,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:848097,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202702559?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!AABt!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png 424w, /__u/substackcdn.com/image/fetch/$s_!AABt!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png 848w, /__u/substackcdn.com/image/fetch/$s_!AABt!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png 1272w, /__u/substackcdn.com/image/fetch/$s_!AABt!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bd6d616-fdfd-4fba-8a03-31f13e2bd1cd_4915x3168.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-149-database-production-setup">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 148: Production Environment — Where Code Stops Being a Project and Becomes a Service]]></title><description><![CDATA[What we&#8217;re building today]]></description><link>https://fullstackinfra.substack.com/p/day-148-production-environment-where</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-148-production-environment-where</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Sun, 16 Aug 2026 05:30:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Spjk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What we&#8217;re building today</h2><p>Yesterday you proved your DevOps pipeline could deploy, roll back, and recover. Today we build the thing that pipeline actually deploys <em>to</em> &#8212; a real production environment. By the end of this lesson you&#8217;ll have a load balancer routing live traffic across three application servers, SSL certificates encrypting every request, a CDN simulator caching content at the edge, and a monitoring system watching it all breathe. Four systems, one dashboard, zero mock data.</p><p>Here&#8217;s the high-level shape of what you&#8217;re assembling:</p><ul><li><p>A load balancer that distributes requests using three different algorithms and automatically routes around failures</p></li><li><p>An SSL/TLS certificate authority that issues, inspects, and renews real X.509 certificates</p></li><li><p>A CDN edge cache simulator with independent regional caches, TTL expiry, and hit/miss accounting</p></li><li><p>A production monitoring collector that samples real system metrics and fires threshold-based alerts</p></li></ul><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Spjk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Spjk!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png 424w, /__u/substackcdn.com/image/fetch/$s_!Spjk!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png 848w, /__u/substackcdn.com/image/fetch/$s_!Spjk!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Spjk!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Spjk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png" width="1456" height="824" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:824,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:282664,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202695239?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!Spjk!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png 424w, /__u/substackcdn.com/image/fetch/$s_!Spjk!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png 848w, /__u/substackcdn.com/image/fetch/$s_!Spjk!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Spjk!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3d0803c-128e-4e01-bf3c-a5778dea2754_2392x1353.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-148-production-environment-where">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 147: DevOps Integration — Closing the Loop on Your Pipeline]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-147-devops-integration-closing</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-147-devops-integration-closing</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Fri, 14 Aug 2026 06:30:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!pQpi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>By the end of today, you&#8217;ll have a fully wired DevOps integration suite that proves every stage of your pipeline works together &#8212; not just in isolation. Specifically:</p><ul><li><p><strong>End-to-end pipeline test harness</strong> &#8212; fires a code push and watches it travel from commit &#8594; build &#8594; test &#8594; deploy</p></li><li><p><strong>Deployment procedure validator</strong> &#8212; verifies rollout sequencing, canary health gates, and rollback triggers</p></li><li><p><strong>Disaster recovery (DR) test runner</strong> &#8212; simulates failure scenarios and measures RTO/RPO against targets</p></li><li><p><strong>Monitoring validation layer</strong> &#8212; confirms alerts fire, dashboards refresh, and on-call routing works</p></li><li><p><strong>DevOps runbook generator</strong> &#8212; auto-documents every procedure as machine-readable + human-readable output</p></li></ul><p><strong>Where this fits:</strong> You&#8217;ve spent the last two weeks securing your pipeline (Day 146). Today is &#8220;Integration Day&#8221; &#8212; the day you prove that security gates, deployment logic, monitoring hooks, and disaster recovery mechanisms all cooperate correctly before production goes live (Day 148).</p><div><hr></div><h2>Component Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!pQpi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!pQpi!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png 424w, /__u/substackcdn.com/image/fetch/$s_!pQpi!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png 848w, /__u/substackcdn.com/image/fetch/$s_!pQpi!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png 1272w, /__u/substackcdn.com/image/fetch/$s_!pQpi!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!pQpi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png" width="1456" height="1031" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1031,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:195213,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202680133?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!pQpi!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png 424w, /__u/substackcdn.com/image/fetch/$s_!pQpi!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png 848w, /__u/substackcdn.com/image/fetch/$s_!pQpi!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png 1272w, /__u/substackcdn.com/image/fetch/$s_!pQpi!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabc9de21-e163-4aa8-82cf-236c4cd5eb86_1800x1275.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-147-devops-integration-closing">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 146: DevOps Security — Hardening the Pipeline That Ships Your Code]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-146-devops-security-hardening</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-146-devops-security-hardening</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Wed, 12 Aug 2026 06:30:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!n_Gv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>Yesterday (Day 145) you built a disaster recovery layer that can survive data loss. Today we close the attack surface around everything that pipeline touches. Here&#8217;s the agenda:</p><ul><li><p><strong>Security scanning</strong> baked into the CI/CD pipeline (SAST, dependency audit, container scanning)</p></li><li><p><strong>Secret management</strong> &#8212; Vault-backed dynamic credentials, zero plaintext secrets in code or env files</p></li><li><p><strong>Compliance-as-code</strong> &#8212; automated policy checks that gate deployments</p></li><li><p><strong>Vulnerability management</strong> &#8212; CVE tracking dashboard with severity routing</p></li><li><p><strong>Security monitoring</strong> &#8212; real-time alerting on anomalous events</p></li></ul><p>By end of day you&#8217;ll have a full <code>SecurityOps</code> dashboard &#8212; think Snyk meets Vault meets a SIEM &#8212; running locally and verifiable end-to-end.</p><div><hr></div><h2>Where This Fits &#8212; Week 21 Target</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;db7e2f20-ef87-44f0-ae33-36611805c973&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">Week 21: Production Resilience
  Day 143 &#8212; Performance Optimization  &#10003;
  Day 144 &#8212; Scaling Strategies        &#10003;
  Day 145 &#8212; Disaster Recovery         &#10003;
  Day 146 &#8212; DevOps Security           &#8592; YOU ARE HERE
  Day 147 &#8212; DevOps Integration        (tomorrow)
</code></pre></div><p>Security isn&#8217;t a post-launch concern. At companies like Netflix and Shopify, security gates run <em>inside</em> the deployment pipeline &#8212; a commit that introduces a critical CVE never reaches production, full stop.</p><div><hr></div><h2>Core Concept: Shift-Left Security</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!n_Gv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!n_Gv!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png 424w, /__u/substackcdn.com/image/fetch/$s_!n_Gv!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png 848w, /__u/substackcdn.com/image/fetch/$s_!n_Gv!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png 1272w, /__u/substackcdn.com/image/fetch/$s_!n_Gv!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!n_Gv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png" width="1456" height="1032" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1032,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1141530,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202560279?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!n_Gv!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png 424w, /__u/substackcdn.com/image/fetch/$s_!n_Gv!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png 848w, /__u/substackcdn.com/image/fetch/$s_!n_Gv!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png 1272w, /__u/substackcdn.com/image/fetch/$s_!n_Gv!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aadd8dd-549c-444c-b7c4-a21d377c1e7b_5280x3744.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-146-devops-security-hardening">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 145: Disaster Recovery]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-145-disaster-recovery</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-145-disaster-recovery</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Mon, 10 Aug 2026 06:30:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!w8XY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>Here&#8217;s the agenda for this session:</p><ul><li><p><strong>Backup Engine</strong> &#8212; automated PostgreSQL WAL archiving + snapshot scheduling to MinIO</p></li><li><p><strong>Health Monitor + Failover Controller</strong> &#8212; heartbeat detection with auto-promote of a replica</p></li><li><p><strong>Recovery Tester</strong> &#8212; a chaos runner that validates your RTO and RPO on a schedule</p></li><li><p><strong>Business Continuity Plan (BCP) Module</strong> &#8212; runbooks stored and surfaced through the API</p></li><li><p><strong>DR Dashboard</strong> &#8212; a React UI that looks and feels like PagerDuty&#8217;s incident console</p></li></ul><div><hr></div><h2>Where This Fits in the Week</h2><p>Your infrastructure stack now has observability eyes (Day 144). Disaster recovery is the immune system &#8212; it reacts when those eyes see something bad. The DR components sit between your primary site and your standby site, continuously syncing state and ready to reroute traffic in under 60 seconds.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!w8XY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!w8XY!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png 424w, /__u/substackcdn.com/image/fetch/$s_!w8XY!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png 848w, /__u/substackcdn.com/image/fetch/$s_!w8XY!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png 1272w, /__u/substackcdn.com/image/fetch/$s_!w8XY!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!w8XY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png" width="1456" height="961" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:961,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:875360,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202535848?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!w8XY!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png 424w, /__u/substackcdn.com/image/fetch/$s_!w8XY!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png 848w, /__u/substackcdn.com/image/fetch/$s_!w8XY!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png 1272w, /__u/substackcdn.com/image/fetch/$s_!w8XY!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cb33ed-d373-479e-91d1-da9fc4bd8af6_4800x3168.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Core Concept: RTO vs RPO &#8212; The Two Numbers That Define Your DR Contract</h2><p>Every business conversation about disaster recovery eventually reduces to two numbers:</p><p><strong>RTO (Recovery Time Objective)</strong> &#8212; How long can your service be <em>down</em> before the business bleeds? Netflix targets seconds. A hospital EHR might tolerate 4 hours. Your architecture must be designed to <em>meet</em> this number, not just aspire to it.</p><p><strong>RPO (Recovery Point Objective)</strong> &#8212; How much <em>data loss</em> is acceptable? An e-commerce checkout system might say &#8220;zero seconds&#8221; &#8212; every transaction must survive. A logging pipeline might say &#8220;15 minutes&#8221; is fine.</p><p>These aren&#8217;t soft guidelines. They&#8217;re the engineering spec. If your WAL archiving runs every 5 minutes, your RPO is <em>at least</em> 5 minutes. If your DNS TTL is 300 seconds and your replica takes 40 seconds to promote, your RTO is <em>at least</em> 340 seconds. The math is merciless.</p><div><hr></div><h2>Component Architecture</h2><p>The system has three logical zones:</p><p><strong>Primary Site</strong> runs your FastAPI backend, PostgreSQL primary, and Redis cache. The Backup Engine continuously ships WAL segments to MinIO every 60 seconds and runs full snapshots nightly. The Health Monitor pings a <code>/health</code> endpoint every 10 seconds with a 3-failure threshold before triggering the Failover Controller.</p><p><strong>DR Site</strong> runs a PostgreSQL streaming replica (WAL receiver) and a warm-standby FastAPI instance. It receives WAL in near real-time (~2-5 seconds lag under normal conditions). On failover, the Failover Controller issues <code>pg_promote()</code> to the replica, flushes DNS, and the standby app begins serving traffic.</p><p><strong>Observability Layer</strong> captures RTO measurements (timestamp of failure detected &#8594; timestamp service confirmed healthy at DR site), surfaces them on the dashboard, and archives every test run result.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Q8c1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Q8c1!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png 424w, /__u/substackcdn.com/image/fetch/$s_!Q8c1!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png 848w, /__u/substackcdn.com/image/fetch/$s_!Q8c1!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Q8c1!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Q8c1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png" width="1456" height="1310" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1310,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:786188,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202535848?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!Q8c1!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png 424w, /__u/substackcdn.com/image/fetch/$s_!Q8c1!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png 848w, /__u/substackcdn.com/image/fetch/$s_!Q8c1!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Q8c1!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3896a263-15fb-4b7e-9380-1c88b95f5bea_4800x4320.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><h2>The Five Components &#8212; How They Work</h2><h3>1. Backup Engine (<code>backup_engine.py</code>)</h3><p>This module has two jobs running as background threads:</p><p><strong>WAL Archiving</strong> &#8212; PostgreSQL&#8217;s <code>archive_command</code> is configured to call a Python script that uploads each completed WAL segment to MinIO. Each segment is ~16MB and represents roughly 60 seconds of write activity. You get continuous backup with sub-minute RPO.</p><p><strong>Snapshot Scheduler</strong> &#8212; Every hour (configurable), the engine calls <code>pg_basebackup</code> to take a full base backup, compresses it with <code>pigz</code>, and uploads to MinIO under a dated prefix. These are your recovery anchors.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;b046b46a-ddc2-4127-b828-6dbf966bfe8f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Pseudocode: WAL upload on archive_command trigger
def archive_wal_segment(wal_path: str) -&gt; bool:
    compressed = gzip_compress(wal_path)
    key = f"wal/{datetime.utcnow().isoformat()}/{os.path.basename(wal_path)}.gz"
    return minio_client.put_object(bucket, key, compressed)
</code></pre></div><h3>2. Health Monitor + Failover Controller (<code>health_monitor.py</code>)</h3><p>The monitor runs a tight loop: HTTP GET to the primary&#8217;s health endpoint every 10 seconds. Three consecutive failures flip the internal state machine from <code>OPERATIONAL</code> &#8594; <code>DEGRADED</code> &#8594; <code>FAILOVER_INITIATED</code>.</p><p>The Failover Controller then:</p><ol><li><p>Issues <code>SELECT pg_promote()</code> against the replica</p></li><li><p>Waits for <code>pg_is_in_recovery()</code> to return <code>false</code> (confirms promotion)</p></li><li><p>Updates the service&#8217;s DNS record (or routing config) to point at the DR site</p></li><li><p>Logs the failover timestamp for RTO calculation</p></li><li><p>Fires a notification to the alert channel</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ef37b928-30cc-4925-8320-8c642b9c8d58&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Pseudocode: State transition logic
if consecutive_failures &gt;= THRESHOLD:
    state = "FAILOVER_INITIATED"
    promote_replica(dr_db_conn)
    update_dns(DR_ENDPOINT)
    record_failover_event(triggered_at=now())
</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!3KTq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!3KTq!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png 424w, /__u/substackcdn.com/image/fetch/$s_!3KTq!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png 848w, /__u/substackcdn.com/image/fetch/$s_!3KTq!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png 1272w, /__u/substackcdn.com/image/fetch/$s_!3KTq!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!3KTq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png" width="1456" height="1019" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1019,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:836884,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202535848?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!3KTq!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png 424w, /__u/substackcdn.com/image/fetch/$s_!3KTq!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png 848w, /__u/substackcdn.com/image/fetch/$s_!3KTq!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png 1272w, /__u/substackcdn.com/image/fetch/$s_!3KTq!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc12d892-9c3c-4c6a-9909-783302c27e0c_4800x3360.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>3. Recovery Tester (<code>recovery_tester.py</code>)</h3><p>This is the most underbuilt component in most real systems &#8212; and the most critical. A DR plan you&#8217;ve never tested is a hypothesis, not a guarantee.</p><p>The tester operates in two modes:</p><p><strong>Chaos Mode</strong> &#8212; Deliberately kills the primary process, starts a timer, waits for the Health Monitor to detect failure, and measures the full time to service restoration at the DR site. This is your measured RTO.</p><p><strong>Data Integrity Mode</strong> &#8212; Writes a known set of records to the primary just before simulating failure, then queries the DR site after promotion and verifies every record is present. The gap between &#8220;last write&#8221; and &#8220;earliest recoverable write at DR&#8221; is your measured RPO.</p><p>Both modes log results to a <code>dr_test_results</code> table and surface them on the dashboard.</p><h3>4. Business Continuity Plan Module (<code>bcp_manager.py</code>)</h3><p>Runbooks are only useful if engineers can find them at 3am. The BCP module stores runbooks as structured JSON documents in PostgreSQL, versioned and searchable. The API exposes <code>/api/runbooks</code> and <code>/api/runbooks/{incident_type}</code> so the dashboard can surface the right playbook the moment an alert fires.</p><p>Each runbook has: <code>incident_type</code>, <code>severity</code>, <code>steps[]</code>, <code>estimated_rto_minutes</code>, <code>owner</code>, and <code>last_tested_at</code>. The last field matters &#8212; it&#8217;s how you prove the runbook isn&#8217;t stale.</p><h3>5. DR Dashboard (React)</h3><p>The UI mirrors what you&#8217;d see in a real-time incident tool like PagerDuty or Grafana&#8217;s alerting view:</p><ul><li><p><strong>Status banner</strong> &#8212; green/amber/red based on current system state</p></li><li><p><strong>RTO/RPO gauges</strong> &#8212; dials showing current measurements vs targets</p></li><li><p><strong>Backup timeline</strong> &#8212; shows last N backup events with sizes and durations</p></li><li><p><strong>Test results table</strong> &#8212; history of every recovery drill with pass/fail and measured RTO</p></li><li><p><strong>Runbook panel</strong> &#8212; context-sensitive playbooks that appear when state is not OPERATIONAL</p></li><li><p><strong>Failover trigger button</strong> &#8212; manual override with confirmation dialog</p></li></ul><div><hr></div><h2>Data Flow: Normal Operations &#8594; Disaster &#8594; Recovery</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;33436a1a-9829-45fe-b125-61e4cf1e7796&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">[Primary DB] --WAL--&gt; [MinIO Bucket]
                           |
                    [DR Replica] &lt;-- streaming replication (live)
                    
[Health Monitor] --10s poll--&gt; [Primary /health]
                                     |
                              3x FAIL detected
                                     |
                        [Failover Controller]
                         1. pg_promote(replica)
                         2. DNS update
                         3. Log RTO start&#8594;end
                         4. Alert fired
                                     |
                        [DR Site now PRIMARY]
                        [Dashboard &#8594; RED &#8594; resolving &#8594; GREEN]
</code></pre></div><h1>Implementation, Build, Test &amp; Demo Guide</h1><h2>Github Link:</h2><p><a href="https://github.com/sysdr/infrawatch-fullstack-p/tree/main/day145/day145-dr">https://github.com/sysdr/infrawatch-fullstack-p/tree/main/day145/day145-dr</a></p><div><hr></div><h2>Prerequisites</h2><ul><li><p>Day 144 observability stack running (or standalone PostgreSQL + Docker available)</p></li><li><p>Docker + Docker Compose installed</p></li><li><p>Python 3.11+, Node 20+</p></li></ul><div><hr></div><h2>Project Structure</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;a897b3ab-aea1-4949-bf03-882c2d16139c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">day145-dr/
&#9500;&#9472;&#9472; backend/
&#9474;   &#9500;&#9472;&#9472; app/
&#9474;   &#9474;   &#9500;&#9472;&#9472; main.py               # FastAPI entry point
&#9474;   &#9474;   &#9500;&#9472;&#9472; backup_engine.py      # WAL archiving + snapshot scheduler
&#9474;   &#9474;   &#9500;&#9472;&#9472; health_monitor.py     # Heartbeat + failover controller
&#9474;   &#9474;   &#9500;&#9472;&#9472; recovery_tester.py    # Chaos runner + RTO/RPO validator
&#9474;   &#9474;   &#9500;&#9472;&#9472; bcp_manager.py        # Runbook CRUD API
&#9474;   &#9474;   &#9492;&#9472;&#9472; models.py             # SQLAlchemy models
&#9474;   &#9500;&#9472;&#9472; tests/
&#9474;   &#9474;   &#9500;&#9472;&#9472; test_backup.py
&#9474;   &#9474;   &#9500;&#9472;&#9472; test_failover.py
&#9474;   &#9474;   &#9492;&#9472;&#9472; test_recovery.py
&#9474;   &#9492;&#9472;&#9472; requirements.txt
&#9500;&#9472;&#9472; frontend/
&#9474;   &#9500;&#9472;&#9472; src/
&#9474;   &#9474;   &#9500;&#9472;&#9472; App.jsx
&#9474;   &#9474;   &#9500;&#9472;&#9472; components/
&#9474;   &#9474;   &#9474;   &#9500;&#9472;&#9472; StatusBanner.jsx
&#9474;   &#9474;   &#9474;   &#9500;&#9472;&#9472; RtoRpoGauges.jsx
&#9474;   &#9474;   &#9474;   &#9500;&#9472;&#9472; BackupTimeline.jsx
&#9474;   &#9474;   &#9474;   &#9500;&#9472;&#9472; TestResultsTable.jsx
&#9474;   &#9474;   &#9474;   &#9492;&#9472;&#9472; RunbookPanel.jsx
&#9474;   &#9474;   &#9492;&#9472;&#9472; index.css
&#9474;   &#9492;&#9472;&#9472; package.json
&#9500;&#9472;&#9472; docker-compose.yml
&#9500;&#9472;&#9472; docker-compose.dr.yml          # DR site containers
&#9500;&#9472;&#9472; start.sh
&#9492;&#9472;&#9472; stop.sh
</code></pre></div><div><hr></div><h2>Step 1 &#8212; Project &amp; File Structure Creation</h2><p>The <code>start.sh</code> script handles everything. Here is what it does and what you should see at each step.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;2c3e2d09-a3a9-4e17-aa60-1d7026f982d4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">chmod +x start.sh &amp;&amp; ./start.sh
</code></pre></div><p><strong>Expected output (first 30 seconds):</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;c9b4a04d-2c5b-4413-9aac-81acfd3a7177&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">[DR-BUILD] Creating project structure...
[DR-BUILD] All directories verified &#10003;
[DR-BUILD] Installing Python dependencies in venv...
[DR-BUILD] Installing Node dependencies...
[DR-BUILD] Starting infrastructure (MinIO, PostgreSQL Primary, PostgreSQL Replica)...
[DR-BUILD] Waiting for PostgreSQL primary to be ready...
[DR-BUILD] PostgreSQL primary ready &#10003;
[DR-BUILD] Configuring streaming replication...
[DR-BUILD] Replication slot created: dr_slot &#10003;
[DR-BUILD] Replica connected and streaming &#10003;
</code></pre></div><div><hr></div><h2>Step 2 &#8212; Backend Architecture Details</h2><h3>2a. Backup Engine</h3><p>The engine uses two threads:</p><p><strong>WAL Thread</strong> &#8212; PostgreSQL&#8217;s <code>archive_command</code> is set to <code>python3 /app/wal_archive.py %p %f</code>. Every time Postgres finishes writing a WAL segment, it calls this command. The script uploads the file to MinIO bucket <code>wal-archive</code>.</p><p><strong>Snapshot Thread</strong> &#8212; Every 3600 seconds (configurable via <code>SNAPSHOT_INTERVAL_SECONDS</code> env var), calls <code>pg_basebackup -Ft -z -P</code> and streams the tarball to MinIO bucket <code>snapshots</code>.</p><p>To verify WAL archiving is working:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;26ea96b3-0341-4f40-b0d5-5b0c4cbcde9e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Inside the primary container
psql -U druser drdb -c "SELECT * FROM pg_stat_archiver;"
</code></pre></div><p>Expected output:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;7d1660bd-af91-457f-9dba-7608bc934491&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"> archived_count | last_archived_wal          | last_archived_time
 12             | 000000010000000000000004   | 2025-05-20 14:23:01
</code></pre></div><h3>2b. Health Monitor States</h3><p>The monitor maintains an in-memory state machine with these transitions:</p><ul><li><p><code>OPERATIONAL</code> &#8594; checks pass every 10s</p></li><li><p><code>DEGRADED</code> &#8594; 1&#8211;2 consecutive failures; alert fired but no failover</p></li><li><p><code>FAILOVER_INITIATED</code> &#8594; 3rd consecutive failure; automatic promotion begins</p></li><li><p><code>DR_ACTIVE</code> &#8594; promotion confirmed; metrics logged</p></li><li><p><code>RESTORED</code> &#8594; primary rebuilt and resync complete; failback done</p></li></ul><p>State is persisted to the <code>system_state</code> table so the dashboard survives restarts.</p><h3>2c. Recovery Tester &#8212; What &#8220;Real&#8221; Means</h3><p>The tester does NOT use mocks. It:</p><ol><li><p>Inserts 100 test rows into <code>recovery_test_data</code> table on the primary</p></li><li><p>Records the timestamp of the last insert (<code>write_watermark</code>)</p></li><li><p>Calls <code>docker stop primary_postgres</code> (or sends SIGTERM to the process)</p></li><li><p>Starts a timer</p></li><li><p>Polls the DR endpoint until it returns HTTP 200</p></li><li><p>Queries <code>recovery_test_data</code> at DR site and counts matching rows</p></li><li><p>Calculates: <code>rto = time_to_200 - failure_detected_at</code>, <code>rpo = write_watermark - latest_row_at_dr</code></p></li></ol><div><hr></div><h2>Step 3 &#8212; Build Without Docker</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;9ec816cf-b971-4ad7-8379-3846683ebd75&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># 1. Create virtual environment
python3 -m venv venv &amp;&amp; source venv/bin/activate

# 2. Install dependencies
pip install -r backend/requirements.txt

# 3. Start local Postgres (must have pg installed)
pg_ctl -D /usr/local/var/postgresql start

# 4. Initialize schema
psql -U postgres -f backend/app/schema.sql

# 5. Start backend
uvicorn backend.app.main:app --port 8000 --reload

# 6. Start frontend
cd frontend &amp;&amp; npm install &amp;&amp; npm run dev
</code></pre></div><p><strong>Expected:</strong> Frontend on http://localhost:5173, API on http://localhost:8000</p><div><hr></div><h2>Step 4 &#8212; Build With Docker</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;e8dbaab7-13c7-4a27-9ac1-281190c57abb&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Start full stack (primary + replica + MinIO + backend + frontend)
docker compose -f docker-compose.yml -f docker-compose.dr.yml up -d --build

# Verify all containers running
docker compose ps
</code></pre></div><p><strong>Expected output:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;b906849d-307f-4ee6-92a8-dc792c6683e7&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">NAME                        STATUS          PORTS
day145_postgres_primary     running         5432/tcp
day145_postgres_replica     running         5433/tcp
day145_minio                running         9000-9001/tcp
day145_backend              running         0.0.0.0:8000-&gt;8000/tcp
day145_backend_dr           running         0.0.0.0:8001-&gt;8000/tcp
day145_frontend             running         0.0.0.0:3000-&gt;3000/tcp
</code></pre></div><div><hr></div><h2>Step 5 &#8212; Unit Tests</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;6f674a0e-f5a4-42db-a0da-16cb6bb8c134&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># With venv active
cd backend &amp;&amp; python -m pytest tests/ -v
</code></pre></div><p><strong>Expected:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ff8c4886-148a-4cf1-ab3b-48610a5e4023&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">tests/test_backup.py::test_wal_upload_to_minio          PASSED
tests/test_backup.py::test_snapshot_created             PASSED
tests/test_failover.py::test_health_check_healthy       PASSED
tests/test_failover.py::test_failover_triggered         PASSED
tests/test_recovery.py::test_rto_within_slo             PASSED
tests/test_recovery.py::test_rpo_within_slo             PASSED
tests/test_recovery.py::test_runbook_crud               PASSED

7 passed in 4.31s
</code></pre></div><div><hr></div><h2>Step 6 &#8212; Integration Test (End-to-End Failover)</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;6428ef7a-888d-4cf0-b7f2-c83ad19aca55&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Run the automated chaos test
curl -X POST http://localhost:8000/api/recovery/run-test \
  -H "Content-Type: application/json" \
  -d '{"mode": "chaos", "data_rows": 100}'
</code></pre></div><p><strong>Watch real-time progress:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;46122e73-c213-44d3-ae53-7551633df220&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># In a second terminal
watch -n 2 'curl -s http://localhost:8000/api/system/state | python3 -m json.tool'
</code></pre></div><p><strong>Expected state progression:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;9227cdbe-72cf-446b-a108-1f1aa5bc71db&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{"state": "OPERATIONAL", "since": "2025-05-20T14:00:00Z"}
  &#8595; (test kills primary)
{"state": "FAILOVER_INITIATED", "consecutive_failures": 3}
  &#8595; (~30-45 seconds later)
{"state": "DR_ACTIVE", "rto_seconds": 38, "rpo_seconds": 4}
</code></pre></div><div><hr></div><h2>Step 7 &#8212; Demo Verification</h2><h3>Dashboard Walkthrough</h3><p>Open </p><p>http://localhost:3000</p><p>:</p><ol><li><p><strong>Status Banner</strong> &#8212; Should show green &#8220;OPERATIONAL&#8221; with uptime counter</p></li><li><p><strong>RTO/RPO Gauges</strong> &#8212; Circular dials; RTO target 60s, RPO target 30s. After test run, actual values appear.</p></li><li><p><strong>Backup Timeline</strong> &#8212; Table showing last 10 WAL archives and snapshots with sizes (should see rows within 60 seconds of startup)</p></li><li><p><strong>Run DR Test button</strong> &#8212; Click &#8220;Run Chaos Test&#8221;. Watch the banner turn amber, then red during failover, then green with &#8220;DR ACTIVE&#8221; label.</p></li><li><p><strong>Test Results</strong> &#8212; After test completes, a row appears in the history table with measured RTO, RPO, and pass/fail against your SLOs.</p></li><li><p><strong>Runbook Panel</strong> &#8212; When system is not OPERATIONAL, the relevant runbook auto-loads in the side panel.</p></li></ol><h3>Verify Backup in MinIO</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;9492e999-8643-4e0d-8a26-18906359917c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># MinIO console: http://localhost:9001
# Credentials: minioadmin / minioadmin
# Navigate to: wal-archive bucket &#8594; verify WAL segments present
# Navigate to: snapshots bucket &#8594; verify base backup present
</code></pre></div><h3>Verify Replication Lag</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;40e1289d-b83e-4013-9ae4-9a5d1eeedf3a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl http://localhost:8000/api/replication/status
</code></pre></div><p>Expected:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;44c63043-cc65-4f6c-a6f2-672b0b8e1a02&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  "primary_lsn": "0/4002D88",
  "replica_lsn": "0/4002D88",
  "lag_bytes": 0,
  "lag_seconds": 1.2
}
</code></pre></div><div><hr></div><h2>Step 8 &#8212; Stop Everything</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;90362c3c-6ab5-4765-8d57-a2a2fe377ab4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">./stop.sh
</code></pre></div><div><hr></div><h2>Troubleshooting</h2><p>Symptom Cause Fix Replica not streaming <code>pg_hba.conf</code> missing replication entry <code>start.sh</code> patches this automatically MinIO 403 on upload Bucket policy Script creates buckets with <code>mc mb</code> on startup Failover not triggering Health endpoint returning cached 200 Check <code>HEALTH_CHECK_CACHE_TTL=0</code> env var RTO &gt; 60s DNS TTL too high Script sets TTL to 5 seconds via nginx upstream reload</p><div><hr></div><h2>Key API Endpoints</h2><p>Endpoint Method Description <code>/api/system/state</code> GET Current DR state machine state <code>/api/backups</code> GET List of backup events <code>/api/replication/status</code> GET Real-time replication lag <code>/api/recovery/run-test</code> POST Trigger chaos or integrity test <code>/api/recovery/results</code> GET History of all test runs <code>/api/runbooks</code> GET All BCP runbooks <code>/api/runbooks/{type}</code> GET Runbook for specific incident type <code>/api/failover/trigger</code> POST Manual failover with auth token</p><h2>Working Code Demo:</h2><div id="youtube2-l_uTrKkrTm4" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;l_uTrKkrTm4&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/l_uTrKkrTm4?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[Day 144: Monitoring & Observability — Seeing Inside Your Distributed System]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-144-monitoring-and-observability</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-144-monitoring-and-observability</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Sat, 08 Aug 2026 06:30:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tiZW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Distributed tracing</strong> with OpenTelemetry + Jaeger &#8212; follow a single request across 5 microservices</p></li><li><p><strong>Metrics collection</strong> with Prometheus &#8212; scrape, store, and query time-series data</p></li><li><p><strong>Observability dashboards</strong> with Grafana &#8212; production-grade panels that mirror Datadog/New Relic layouts</p></li><li><p><strong>SLI/SLO monitoring</strong> &#8212; define Service Level Indicators and track error budgets in real time</p></li><li><p><strong>Alerting rules</strong> with Alertmanager &#8212; route incidents to the right people before users notice</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!tiZW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!tiZW!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png 424w, /__u/substackcdn.com/image/fetch/$s_!tiZW!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png 848w, /__u/substackcdn.com/image/fetch/$s_!tiZW!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png 1272w, /__u/substackcdn.com/image/fetch/$s_!tiZW!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!tiZW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png" width="1456" height="1032" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1032,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1660443,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202388099?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!tiZW!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png 424w, /__u/substackcdn.com/image/fetch/$s_!tiZW!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png 848w, /__u/substackcdn.com/image/fetch/$s_!tiZW!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png 1272w, /__u/substackcdn.com/image/fetch/$s_!tiZW!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f0c31c2-b622-4f00-9a5f-10611d36a3e5_5280x3744.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-144-monitoring-and-observability">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 143: Container Orchestration — Kubernetes at Production Scale]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-143-container-orchestration-kubernetes</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-143-container-orchestration-kubernetes</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Thu, 06 Aug 2026 06:30:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!dp0d!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p><strong>Enhanced Kubernetes deployment</strong> with production-grade manifests and rolling update strategies</p></li><li><p><strong>Istio service mesh</strong> integration for traffic management, mTLS, and observability sidecars</p></li><li><p><strong>Horizontal Pod Autoscaler (HPA) + Vertical Pod Autoscaler (VPA)</strong> for intelligent scaling</p></li><li><p><strong>Liveness, readiness, and startup probes</strong> wired to a real health monitoring dashboard</p></li><li><p><strong>Resource quotas, LimitRanges, and PodDisruptionBudgets</strong> for cluster-wide governance</p></li></ul><div><hr></div><h2> Component Architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!dp0d!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!dp0d!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!dp0d!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!dp0d!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!dp0d!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!dp0d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png" width="1456" height="990" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:990,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:843912,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202264467?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!dp0d!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!dp0d!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!dp0d!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!dp0d!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb767da13-0ec1-497e-8eb8-b49c82a467ed_4800x3264.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-143-container-orchestration-kubernetes">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 142: Infrastructure as Code — Terraform, Versioning, and Environment Provisioning]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-142-infrastructure-as-code-terraform</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-142-infrastructure-as-code-terraform</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Tue, 04 Aug 2026 06:31:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Eu1A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><p>Yesterday you automated deployment pipelines. Today you take one level deeper &#8212; you&#8217;re going to <strong>define your entire infrastructure in code</strong>, version it like application code, and provision environments repeatably. Here&#8217;s what we tackle:</p><ul><li><p>Terraform scripts for core infrastructure resources</p></li><li><p>Infrastructure versioning with remote state management</p></li><li><p>Environment provisioning (dev / staging / prod workspaces)</p></li><li><p>Infrastructure testing with <code>pytest</code> + <code>checkov</code></p></li><li><p>Change management via plan/apply workflows with audit trails</p></li></ul><p>By end of day: a working Python + React dashboard that shows your infrastructure state, drift detection results, and change history &#8212; the same way HashiCorp Cloud Platform or Spacelift displays it.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Eu1A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Eu1A!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!Eu1A!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!Eu1A!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Eu1A!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Eu1A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png" width="1456" height="990" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:990,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:771585,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202406164?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!Eu1A!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png 424w, /__u/substackcdn.com/image/fetch/$s_!Eu1A!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png 848w, /__u/substackcdn.com/image/fetch/$s_!Eu1A!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Eu1A!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26c5b653-58f8-4dd2-b671-be5ab6d495ec_4800x3264.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-142-infrastructure-as-code-terraform">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 141: Advanced CI/CD — Pipeline Automation, Multi-Environment Deployments, Canary Releases & Rollbacks]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-141-advanced-cicd-pipeline-automation</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-141-advanced-cicd-pipeline-automation</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Sun, 02 Aug 2026 06:30:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ipTz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>What We&#8217;re Building Today</h3><p>By the end of this lesson, you will have a production-grade CI/CD system that does four things most hobby projects never do:</p><ul><li><p><strong>Multi-environment promotion</strong> &#8212; code flows automatically from dev &#8594; staging &#8594; production, with gates between each</p></li><li><p><strong>Canary deployments</strong> &#8212; ship new code to 5% of users first, watch metrics, then expand or kill it</p></li><li><p><strong>Automated rollback</strong> &#8212; if error rates spike, the system reverts itself without human intervention</p></li><li><p><strong>Deployment monitoring dashboard</strong> &#8212; a React UI that shows live pipeline status, deployment health, and canary traffic splits</p></li></ul><p>This builds directly on Day 140&#8217;s quality pipeline. Those test gates now become the entry condition for every deployment.</p><div><hr></div><h3>Core Concept: The Three Problems Advanced CI/CD Solves</h3><p><strong>Problem 1 &#8212; One environment is a lie.</strong> If you only test in production, every deploy is a gamble. Multi-environment promotion creates a chain of increasingly production-like environments. Dev is fast and forgiving. Staging mirrors production exactly. Production gets only what staging already validated.</p><p><strong>Problem 2 &#8212; Binary deploys are risky.</strong> Old-school deploys are 0% or 100%. Either nobody has the new code or everybody does. Canary deployments give you a dial: route 5% of real traffic to v2 while v1 handles 95%. Watch error rates, latency p99, and business metrics. If anything looks wrong, flip back instantly. Netflix, Facebook, and Google all ship this way &#8212; they call it &#8220;progressive delivery.&#8221;</p><p><strong>Problem 3 &#8212; Humans are slow incident responders.</strong> At 2 AM, nobody wants to be woken up to manually roll back. Automated rollback watches SLOs (Service Level Objectives) continuously. If the canary&#8217;s error rate exceeds your threshold, the system reverts the traffic split within seconds, not minutes.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!ipTz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!ipTz!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png 424w, /__u/substackcdn.com/image/fetch/$s_!ipTz!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png 848w, /__u/substackcdn.com/image/fetch/$s_!ipTz!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png 1272w, /__u/substackcdn.com/image/fetch/$s_!ipTz!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!ipTz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png" width="1456" height="978" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/efcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:978,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1265416,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202241859?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!ipTz!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png 424w, /__u/substackcdn.com/image/fetch/$s_!ipTz!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png 848w, /__u/substackcdn.com/image/fetch/$s_!ipTz!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png 1272w, /__u/substackcdn.com/image/fetch/$s_!ipTz!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefcce265-e5c3-46d9-964f-1ce012dbd860_5529x3715.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-141-advanced-cicd-pipeline-automation">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 140: QA Integration — Wiring the Complete Quality Pipeline]]></title><description><![CDATA[What We&#8217;re Building Today]]></description><link>https://fullstackinfra.substack.com/p/day-140-qa-integration-wiring-the</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-140-qa-integration-wiring-the</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Fri, 31 Jul 2026 06:30:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!yRXt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We&#8217;re Building Today</h2><ul><li><p>A <strong>QA Integration Service</strong> (Python/FastAPI) that orchestrates test execution across unit, integration, and end-to-end layers</p></li><li><p><strong>Quality Gate Engine</strong> &#8212; automated pass/fail decisions based on coverage thresholds, error budgets, and performance baselines</p></li><li><p><strong>Test Reporting Dashboard</strong> (React) with real-time pipeline status, metrics charts, and drill-down failure analysis</p></li><li><p><strong>Procedure documentation generator</strong> &#8212; auto-exports quality runbooks from live pipeline data</p></li></ul><div><hr></div><h2>Where This Fits</h2><p>You&#8217;ve spent the last two weeks writing tests &#8212; unit, integration, UAT. Today is the day those tests graduate from &#8220;files on disk&#8221; to a <strong>living quality system</strong>. Think of it like going from having individual smoke detectors to installing a full building fire-safety network: alarm panels, suppression systems, evacuation logs.</p><p>In production, companies like Spotify, Stripe, and Atlassian don&#8217;t just <em>run</em> tests &#8212; they route test results through quality gates that decide whether a build proceeds. That gate is what you&#8217;re building today.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!yRXt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!yRXt!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png 424w, /__u/substackcdn.com/image/fetch/$s_!yRXt!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png 848w, /__u/substackcdn.com/image/fetch/$s_!yRXt!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png 1272w, /__u/substackcdn.com/image/fetch/$s_!yRXt!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!yRXt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png" width="1456" height="923" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:923,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:890821,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202233220?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="/__u/substackcdn.com/image/fetch/$s_!yRXt!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png 424w, /__u/substackcdn.com/image/fetch/$s_!yRXt!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png 848w, /__u/substackcdn.com/image/fetch/$s_!yRXt!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png 1272w, /__u/substackcdn.com/image/fetch/$s_!yRXt!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1164282e-0534-4864-b3c1-6797b55184a2_4427x2807.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><div><hr></div><h2>Core Concept: Quality Gates Are Decision Engines</h2><p>A quality gate is not a test. It&#8217;s a <strong>policy enforcer</strong>. It consumes test results and makes a binary decision: <em>does this build meet the bar we set?</em></p><p>The bar has three dimensions in real systems:</p><p>Dimension Example Threshold Why It Matters Coverage &#8805; 80% line coverage Prevents untested code reaching prod Failure Rate 0 failing tests One broken test = one production risk Performance p95 &lt; 500ms Regressions caught before merge</p><p>When Netflix deploys 1000x/day, each deploy goes through a gate. If anything drops below threshold, the gate blocks the deploy &#8212; automatically, no human needed.</p><div><hr></div><h2>Architecture: How the Pipeline Flows</h2><h3>Component Breakdown</h3><pre><code><code>&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474;                  QA Integration Service              &#9474;
&#9474;                                                     &#9474;
&#9474;  [Test Runner] &#8594; [Result Aggregator] &#8594; [Gate Engine]&#9474;
&#9474;       &#8595;                &#8595;                    &#8595;       &#9474;
&#9474;  pytest/jest      JSON Reports        Pass/Fail     &#9474;
&#9474;                        &#8595;                    &#8595;       &#9474;
&#9474;               [Report Storage]      [Webhook Notify]&#9474;
&#9474;                        &#8595;                            &#9474;
&#9474;               [React Dashboard]                     &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
</code></code></pre><p><strong>Test Runner</strong> &#8212; executes pytest (backend) and jest (frontend) in isolated subprocesses. Captures stdout, exit codes, and coverage XML.</p><p><strong>Result Aggregator</strong> &#8212; parses JUnit XML + coverage.xml into a unified schema. Every test run becomes a structured event with timestamp, suite name, pass/fail counts, and per-file coverage.</p><p><strong>Gate Engine</strong> &#8212; compares aggregated results against configurable thresholds stored in <code>quality_config.json</code>. Produces a gate verdict with a detailed breakdown.</p><p><strong>Report Storage</strong> &#8212; SQLite (dev) / PostgreSQL (prod) stores every pipeline run. Enables trend analysis: &#8220;has coverage been dropping over the last 10 commits?&#8221;</p><p><strong>React Dashboard</strong> &#8212; polls the QA service every 5 seconds. Shows pipeline status, quality gate verdict, coverage trends, and test failure details.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!Ywl_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!Ywl_!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png 424w, /__u/substackcdn.com/image/fetch/$s_!Ywl_!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png 848w, /__u/substackcdn.com/image/fetch/$s_!Ywl_!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Ywl_!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!Ywl_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png" width="1456" height="910" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:910,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1163581,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202233220?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="/__u/substackcdn.com/image/fetch/$s_!Ywl_!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png 424w, /__u/substackcdn.com/image/fetch/$s_!Ywl_!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png 848w, /__u/substackcdn.com/image/fetch/$s_!Ywl_!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png 1272w, /__u/substackcdn.com/image/fetch/$s_!Ywl_!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbbe533-a9a3-4a7c-bf9e-9f45be08d34e_6047x3779.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Control Flow: A Pipeline Run Step-by-Step</h2><ol><li><p><strong>Trigger</strong> &#8212; POST <code>/api/pipeline/run</code> with suite name (e.g., <code>"backend"</code>, <code>"frontend"</code>, <code>"e2e"</code>)</p></li><li><p><strong>Dispatch</strong> &#8212; Gate Engine spawns subprocess, runs appropriate test command</p></li><li><p><strong>Parse</strong> &#8212; On completion, JUnit XML parsed into structured run object</p></li><li><p><strong>Evaluate</strong> &#8212; Each gate rule checked: coverage &#8805; threshold? failures == 0? duration &lt; max?</p></li><li><p><strong>Persist</strong> &#8212; Run stored with verdict (PASS/FAIL/WARNING) and all metrics</p></li><li><p><strong>Broadcast</strong> &#8212; WebSocket pushes status update to connected dashboard clients</p></li><li><p><strong>Expose</strong> &#8212; GET <code>/api/pipeline/runs</code> serves history; GET <code>/api/pipeline/latest</code> for current verdict</p></li></ol><p>The key architectural insight: <strong>the pipeline is stateless per run but stateful across runs</strong>. Each execution is atomic; trends emerge from the historical record.</p><div><hr></div><h2>Quality Gate Configuration</h2><p>This is where most teams get it wrong &#8212; they hardcode thresholds. Production systems make thresholds <strong>configurable per environment</strong>:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;cf694248-a38a-4a66-be95-4cfe8ddf7ae6&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  &#8220;gates&#8221;: {
    &#8220;coverage&#8221;: { &#8220;warning&#8221;: 75, &#8220;failure&#8221;: 60 },
    &#8220;test_failure_rate&#8221;: { &#8220;failure&#8221;: 0 },
    &#8220;performance_p95_ms&#8221;: { &#8220;warning&#8221;: 800, &#8220;failure&#8221;: 2000 }
  },
  &#8220;environments&#8221;: {
    &#8220;staging&#8221;: { &#8220;coverage&#8221;: { &#8220;failure&#8221;: 50 } },
    &#8220;production&#8221;: { &#8220;coverage&#8221;: { &#8220;failure&#8221;: 80 } }
  }
}
</code></pre></div><p>Staging has looser gates because it&#8217;s an experimentation zone. Production gates are strict because failures there are customer-facing.</p><div><hr></div><h2>Test Automation Validation</h2><p>&#8220;Validate test automation&#8221; doesn&#8217;t mean re-running tests. It means <strong>verifying the test infrastructure itself is healthy</strong>:</p><ul><li><p>Are test suites discoverable? (<code>pytest --collect-only</code> exit code 0)</p></li><li><p>Do test fixtures set up and tear down cleanly? (no leftover temp files, no leaked DB state)</p></li><li><p>Is coverage instrumentation active? (coverage.xml exists after run)</p></li><li><p>Are tests deterministic? (flaky test detector &#8212; run same suite 3x, flag any test that doesn&#8217;t produce consistent results)</p></li></ul><p>This is called <strong>test hygiene validation</strong> &#8212; a practice large eng orgs run as a separate CI step before the actual test run.</p><div><hr></div><h2>Reporting System Architecture</h2><p>Real reporting isn&#8217;t a pretty PDF &#8212; it&#8217;s a queryable data store with a visualization layer on top.</p><p><strong>Data Schema per Run:</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;5096a704-23e2-4309-97f5-0823e5b6fad8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">pipeline_run {
  id, triggered_at, suite, status,
  total_tests, passed, failed, skipped,
  coverage_pct, duration_ms, gate_verdict,
  failures: [{test_name, file, line, error_msg}]
}
</code></pre></div><p>The React dashboard visualizes:</p><ul><li><p><strong>Trend line</strong> &#8212; coverage % over last 20 runs (recharts LineChart)</p></li><li><p><strong>Status board</strong> &#8212; current gate verdict with color coding (green/yellow/red)</p></li><li><p><strong>Failure table</strong> &#8212; expandable rows with error details and file:line references</p></li><li><p><strong>Suite breakdown</strong> &#8212; unit vs integration vs e2e pass rates</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!KyMZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!KyMZ!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png 424w, /__u/substackcdn.com/image/fetch/$s_!KyMZ!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png 848w, /__u/substackcdn.com/image/fetch/$s_!KyMZ!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png 1272w, /__u/substackcdn.com/image/fetch/$s_!KyMZ!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!KyMZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png" width="1456" height="853" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:853,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1056502,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202233220?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="/__u/substackcdn.com/image/fetch/$s_!KyMZ!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png 424w, /__u/substackcdn.com/image/fetch/$s_!KyMZ!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png 848w, /__u/substackcdn.com/image/fetch/$s_!KyMZ!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png 1272w, /__u/substackcdn.com/image/fetch/$s_!KyMZ!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e7f092f-e497-42e5-a607-e0a0c192e70c_5529x3239.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h2>Quality Procedures Documentation</h2><p>The automation generates a living <code>QUALITY_PROCEDURES.md</code> from actual pipeline data &#8212; not hand-written docs that go stale. It captures:</p><ul><li><p>Current gate thresholds (from <code>quality_config.json</code>)</p></li><li><p>Last 5 pipeline verdicts with timestamps</p></li><li><p>Failure patterns (which files fail most often)</p></li><li><p>Coverage hotspots (files below threshold)</p></li></ul><p>This is how mature teams ensure documentation stays current: <strong>generate it from the source of truth</strong>, not from memory.</p><h1>Implementation, Build, Test &amp; Demo Guide</h1><h2>Github Link:</h2><p><a href="https://github.com/sysdr/infrawatch-fullstack-p/tree/main/day140/qa_integration">https://github.com/sysdr/infrawatch-fullstack-p/tree/main/day140/qa_integration</a></p><h2>Prerequisites</h2><ul><li><p>Python 3.11+</p></li><li><p>Node.js 20+</p></li><li><p>Docker + Docker Compose (optional)</p></li><li><p><code>curl</code> and <code>jq</code> installed</p></li></ul><div><hr></div><h2>Architecture Summary</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;07b9e634-d491-49bb-8d4b-6e9091b3bde0&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">qa_integration/
&#9500;&#9472;&#9472; backend/
&#9474;   &#9500;&#9472;&#9472; main.py                          # FastAPI entry point
&#9474;   &#9500;&#9472;&#9472; requirements.txt
&#9474;   &#9500;&#9472;&#9472; pytest.ini
&#9474;   &#9500;&#9472;&#9472; app/
&#9474;   &#9474;   &#9500;&#9472;&#9472; api/pipeline.py              # REST + WebSocket endpoints
&#9474;   &#9474;   &#9500;&#9472;&#9472; core/{config,database}.py    # Settings + SQLAlchemy async
&#9474;   &#9474;   &#9500;&#9472;&#9472; models/pipeline.py           # PipelineRun ORM model
&#9474;   &#9474;   &#9492;&#9472;&#9472; services/
&#9474;   &#9474;       &#9500;&#9472;&#9472; test_runner.py           # Subprocess test executor
&#9474;   &#9474;       &#9500;&#9472;&#9472; result_parser.py         # JUnit XML + coverage parser
&#9474;   &#9474;       &#9500;&#9472;&#9472; gate_engine.py           # Quality gate evaluator
&#9474;   &#9474;       &#9492;&#9472;&#9472; report_generator.py      # Markdown report generator
&#9474;   &#9500;&#9472;&#9472; sample_tests/                    # Real tests for gate demo
&#9474;   &#9492;&#9472;&#9472; tests/unit/ + integration/
&#9500;&#9472;&#9472; frontend/
&#9474;   &#9492;&#9472;&#9472; src/
&#9474;       &#9500;&#9472;&#9472; App.js                       # Dashboard shell
&#9474;       &#9500;&#9472;&#9472; api/pipeline.js              # Axios API client
&#9474;       &#9500;&#9472;&#9472; hooks/usePipeline.js         # Data fetching + WebSocket
&#9474;       &#9492;&#9472;&#9472; components/                  # GateVerdict, Charts, Tables
&#9500;&#9472;&#9472; reports/                             # junit XML, coverage.xml, report.md
&#9500;&#9472;&#9472; quality_config.json                  # Gate thresholds
&#9500;&#9472;&#9472; start.sh
&#9492;&#9472;&#9472; stop.sh
</code></pre></div><div><hr></div><h2>Part A: Without Docker</h2><h3>Step 1 &#8212; Build and Start Everything</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;545605ee-19c9-44c1-9a21-685530c144ec&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">chmod +x start.sh stop.sh
./start.sh
</code></pre></div><p><strong>Expected output (last lines):</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;b8c992a8-4f1c-4f6e-a014-7b6923a57df9&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">[OK] Backend running at http://localhost:8001
[OK] Pipeline run complete &#8594; Verdict: PASS | Coverage: 85.2% | Tests: 10
[OK] Hygiene check &#8594; healthy: True
Day 140 QA Integration &#8212; Build Complete!
  Backend API:  http://localhost:8001
  Frontend:     http://localhost:3001
</code></pre></div><h3>Step 2 &#8212; Verify Backend Health</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;1345fdeb-5050-4d6a-bb28-754980e698d0&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl http://localhost:8001/api/pipeline/health
</code></pre></div><p>Expected:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;61a1375b-eb73-4dcb-9140-eb11662bffc1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{&#8221;status&#8221;: &#8220;ok&#8221;, &#8220;service&#8221;: &#8220;qa-integration&#8221;}
</code></pre></div><h3>Step 3 &#8212; Trigger a Backend Pipeline Run</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;f1a97ded-aee8-4b38-b471-4700b306201e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl -s -X POST http://localhost:8001/api/pipeline/run \
  -H &#8220;Content-Type: application/json&#8221; \
  -d &#8216;{&#8221;suite&#8221;:&#8221;backend&#8221;,&#8221;environment&#8221;:&#8221;development&#8221;}&#8217; | python3 -m json.tool
</code></pre></div><p>Expected (excerpt):</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;a229eb0e-ae0e-499c-bece-a65ff5759668&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  &#8220;id&#8221;: 1,
  &#8220;suite&#8221;: &#8220;backend&#8221;,
  &#8220;status&#8221;: &#8220;PASS&#8221;,
  &#8220;gate_verdict&#8221;: &#8220;PASS&#8221;,
  &#8220;total_tests&#8221;: 10,
  &#8220;passed&#8221;: 10,
  &#8220;failed&#8221;: 0,
  &#8220;coverage_pct&#8221;: 85.2,
  &#8220;gate_details&#8221;: {
    &#8220;coverage&#8221;: {&#8221;actual&#8221;: 85.2, &#8220;status&#8221;: &#8220;PASS&#8221;},
    &#8220;test_failure_rate&#8221;: {&#8221;actual&#8221;: 0, &#8220;status&#8221;: &#8220;PASS&#8221;},
    ...
  }
}
</code></pre></div><h3>Step 4 &#8212; Trigger a Frontend Pipeline Run</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ecc8bb23-2182-4677-a069-23ec9f1dedb1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl -s -X POST http://localhost:8001/api/pipeline/run \
  -H &#8220;Content-Type: application/json&#8221; \
  -d &#8216;{&#8221;suite&#8221;:&#8221;frontend&#8221;,&#8221;environment&#8221;:&#8221;staging&#8221;}&#8217;
</code></pre></div><h3>Step 5 &#8212; View Run History</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;84dff250-b860-4f6e-bf74-1a9a0fa4c657&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl -s http://localhost:8001/api/pipeline/runs | python3 -m json.tool | head -60
</code></pre></div><h3>Step 6 &#8212; Run Hygiene Validation</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ad6a8660-3ae3-4927-abc5-96326c0e4257&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl -s -X POST http://localhost:8001/api/pipeline/validate-hygiene | python3 -m json.tool
</code></pre></div><p>Expected:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;69d6edee-2127-4986-8696-f4d9d939e19a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{
  &#8220;healthy&#8221;: true,
  &#8220;checks&#8221;: [
    {&#8221;name&#8221;: &#8220;Test Discovery&#8221;, &#8220;status&#8221;: &#8220;PASS&#8221;, &#8220;detail&#8221;: &#8220;All tests discoverable&#8221;},
    {&#8221;name&#8221;: &#8220;Reports Directory&#8221;, &#8220;status&#8221;: &#8220;PASS&#8221;, &#8220;detail&#8221;: &#8220;Writable&#8221;},
    {&#8221;name&#8221;: &#8220;Quality Config&#8221;, &#8220;status&#8221;: &#8220;PASS&#8221;, &#8220;detail&#8221;: &#8220;4 gates configured&#8221;}
  ],
  &#8220;issues&#8221;: []
}
</code></pre></div><h3>Step 7 &#8212; Generate Quality Procedures Report</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;07363581-2cf2-4272-b414-0888d2ebf8cd&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl -s http://localhost:8001/api/pipeline/report | python3 -c &#8220;import sys,json; print(json.load(sys.stdin)[&#8217;report&#8217;])&#8221;
</code></pre></div><p>Expected: a markdown document with gate thresholds, run history table, and failure hotspots.</p><h3>Step 8 &#8212; Open Dashboard</h3><p>Navigate to </p><p>http://localhost:3001</p><p> in your browser.</p><p><strong>What you should see:</strong></p><ul><li><p>Green header with QA Integration branding</p></li><li><p>4 stat cards: Total Runs, Pass Rate, Avg Coverage, Last Verdict</p></li><li><p>Trigger panel &#8212; select suite and environment, click &#9654; Run Pipeline</p></li><li><p>After triggering: Gate Evaluation cards (one per gate with PASS/WARNING/FAIL)</p></li><li><p>Coverage Trend line chart with PROD MIN and WARNING reference lines</p></li><li><p>Pipeline Run History table &#8212; click any row to expand failures</p></li><li><p>Hygiene tab &#8212; run infrastructure health checks</p></li><li><p>Report tab &#8212; generate live quality procedures doc</p></li></ul><h3>Step 9 &#8212; Run Tests Manually</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;8d7bf86c-489b-4e28-84f4-b771bdc66af0&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd qa_integration
source .venv/bin/activate
cd backend

# Sample tests (gate engine behavior)
python -m pytest sample_tests/ -v

# Unit tests
python -m pytest tests/unit/ -v

# Integration tests
python -m pytest tests/integration/ -v

# Full run with coverage
python -m pytest sample_tests/ tests/ -v \
  --cov=app --cov-report=term-missing
</code></pre></div><h3>Step 10 &#8212; Stop Services</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;0d0ec4df-393c-44e3-beda-db4970df0258&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">./stop.sh
</code></pre></div><div><hr></div><h2>Part B: With Docker</h2><h3>Step 1 &#8212; Build and Start</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;5bd935c5-effd-4144-9f60-0af6f922f2a9&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd qa_integration/start.sh --docker
</code></pre></div><h3>Step 2 &#8212; Verify</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;889e57ed-dd77-48f4-a902-7d12fd587793&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl http://localhost:8001/api/pipeline/health
curl http://localhost:3001
</code></pre></div><h3>Step 3 &#8212; Trigger Pipeline Run via Docker</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;973395b0-3ea2-4a10-9de3-ce74b13d1e55&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">curl -X POST http://localhost:8001/api/pipeline/run \
  -H &#8220;Content-Type: application/json&#8221; \
  -d &#8216;{&#8221;suite&#8221;:&#8221;backend&#8221;,&#8221;environment&#8221;:&#8221;production&#8221;}&#8217;
</code></pre></div><h3>Step 4 &#8212; Stop Docker Stack</h3><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;f9f599a4-20a5-4334-856e-2eaa1c21da75&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">cd qa_integration/ ./stop.sh
</code></pre></div><div><hr></div><h2>Verification Checklist</h2><p>Check Command Expected Backend health <code>curl :8001/api/pipeline/health</code> <code>{"status":"ok"}</code> Pipeline run POST <code>/api/pipeline/run</code> JSON with <code>gate_verdict</code> Run history GET <code>/api/pipeline/runs</code> Array of runs Hygiene check POST <code>/api/pipeline/validate-hygiene</code> <code>{"healthy":true}</code> Report GET <code>/api/pipeline/report</code> Markdown report Dashboard </p><p>http://localhost:3001</p><p> Green dashboard renders Coverage trend chart Dashboard &#8594; scroll down Line chart visible Failure drill-down Click a run row in history Failure details expand Hygiene tab Dashboard &#8594; Hygiene tab Infrastructure checks Report tab Dashboard &#8594; Report &#8594; Generate Markdown doc rendered</p><div><hr></div><h2>API Reference</h2><p>Method Path Description GET <code>/api/pipeline/health</code> Service health POST <code>/api/pipeline/run</code> Trigger pipeline run GET <code>/api/pipeline/runs</code> All run history GET <code>/api/pipeline/latest</code> Latest run verdict POST <code>/api/pipeline/validate-hygiene</code> Check test infrastructure GET <code>/api/pipeline/report</code> Generate quality procedures WS <code>/api/pipeline/ws</code> Real-time status updates</p><p>Interactive API docs: <code>http://localhost:8001/docs</code></p><div><hr></div><h2>Assignment Steps</h2><p><strong>Task:</strong> Add a &#8220;slow test detection&#8221; alert card to the dashboard.</p><p><strong>Step 1</strong> &#8212; Ensure <code>execution_time_budget_ms</code> is in <code>quality_config.json</code> (it already is, threshold: 5000ms).</p><p><strong>Step 2</strong> &#8212; In <code>gate_engine.py</code>, verify <code>slow_test_warnings</code> is populated when <code>duration_ms &gt; budget_warning</code>.</p><p><strong>Step 3</strong> &#8212; In <code>PipelineRun</code> model, <code>slow_test_warnings</code> column stores the list.</p><p><strong>Step 4</strong> &#8212; In <code>App.js</code>, after <code>GateDetails</code>, add:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;16ef7ea6-d720-4d5d-9b80-b11e47bf3021&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">{latest?.slow_test_warnings?.length &gt; 0 &amp;&amp; (
  &lt;div style={{ background: &#8216;#fffbeb&#8217;, border: &#8216;1.5px solid #d97706&#8217;, borderRadius: 12, padding: 16 }}&gt;
    &lt;b&gt;&#9888; Slow Tests Detected&lt;/b&gt;
    {latest.slow_test_warnings.map((t, i) =&gt; (
      &lt;div key={i}&gt;{t.test_name} &#8212; {t.duration_ms.toFixed(0)}ms&lt;/div&gt;
    ))}
  &lt;/div&gt;
)}
</code></pre></div><p><strong>Step 5</strong> &#8212; In <code>sample_tests/test_gate_engine.py</code>, add a test that creates a slow test entry and verifies the warning card data is in the gate result.</p><p><strong>Hint:</strong> To simulate a slow test without actually waiting, add <code>"slow_tests": [{"test_name": "test_db_load", "duration_ms": 7000}]</code> to your <code>make_result()</code> call in a new test case.</p><div><hr></div><h2>Success Criteria</h2><p>By end of today, you should have:</p><ul><li><p>[ ] QA Integration Service running at <code>localhost:8001</code></p></li><li><p>[ ] Quality gates evaluating coverage, failures, and performance</p></li><li><p>[ ] React dashboard showing real-time pipeline status</p></li><li><p>[ ] At least one pipeline run stored with full metrics</p></li><li><p>[ ] Auto-generated <code>QUALITY_PROCEDURES.md</code> reflecting live data</p></li><li><p>[ ] Docker Compose bringing up the entire stack in one command</p></li></ul><div><hr></div><h2>Assignment</h2><p><strong>Extend the gate engine</strong> to support a fourth gate: <strong>test execution time budget</strong>. If any single test takes longer than 10 seconds, it should trigger a WARNING verdict (not failure, since slowness isn&#8217;t broken &#8212; but it needs investigation).</p><p><strong>Steps:</strong></p><ol><li><p>Add <code>execution_time_budget_ms</code> to <code>quality_config.json</code></p></li><li><p>In the Gate Engine, after parsing results, identify any test with <code>duration_ms &gt; threshold</code></p></li><li><p>Collect slow tests into a <code>slow_test_warnings</code> list on the verdict object</p></li><li><p>Surface them in the dashboard as a yellow warning card, separate from failures</p></li></ol><p><strong>Hint:</strong> JUnit XML has a <code>time</code> attribute on each <code>&lt;testcase&gt;</code> element. Parse it during aggregation and store per-test durations in your run schema.</p><div><hr></div><h2>Key Takeaway</h2><p>A QA pipeline without gates is a report generator. Gates are what transform quality data into <strong>deployment decisions</strong>. The moment you wire a gate verdict to a pipeline stage condition (which you&#8217;ll do tomorrow), quality enforcement becomes automatic &#8212; no human needs to check if coverage dropped. The system decides.</p><p>That&#8217;s the mental model shift: from &#8220;we run tests&#8221; to &#8220;tests govern deployments.&#8221;</p><h2>Working Code Demo:</h2><div id="youtube2-VGBL6kk-TPY" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;VGBL6kk-TPY&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/VGBL6kk-TPY?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p><br><br></p>]]></content:encoded></item><item><title><![CDATA[Day 139: User Acceptance Testing — Building the Last Line of Defense Before Production]]></title><description><![CDATA[What We Build Today]]></description><link>https://fullstackinfra.substack.com/p/day-139-user-acceptance-testing-building</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-139-user-acceptance-testing-building</guid><dc:creator><![CDATA[ctoi]]></dc:creator><pubDate>Wed, 29 Jul 2026 06:30:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7q_X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>What We Build Today</h2><ul><li><p>A full <strong>UAT orchestration backend</strong> (Python/FastAPI) that manages test plans, scenarios, sessions, and feedback</p></li><li><p>A <strong>React UAT Dashboard</strong> that mirrors the look and feel of modern QA platforms like TestRail and Maze</p></li><li><p>Real <strong>usability scoring engine</strong> that computes SUS (System Usability Scale) scores and heatmaps</p></li><li><p>A <strong>feedback collection pipeline</strong> with sentiment tagging</p></li><li><p>End-to-end <strong>user experience validation</strong> workflows with pass/fail gating</p></li></ul><div><hr></div><h2>Why UAT Is Not Just &#8220;Let Users Click Around&#8221;</h2><p>Most teams treat UAT as a rubber stamp &#8212; hand the app to a stakeholder, watch them smile, ship it. That&#8217;s not UAT. That&#8217;s wishful thinking.</p><p>Real UAT is a structured protocol. Think of how NASA runs pre-launch checklists &#8212; UAT is your pre-production checklist written from the <em>user&#8217;s</em> cognitive model, not the engineer&#8217;s. Amazon runs thousands of UAT sessions per quarter through internal beta programs before any significant feature goes live on their retail platform. Netflix calls their equivalent &#8220;dog-fooding cohorts&#8221; &#8212; real employees using real features under real conditions before 200M subscribers see it.</p><p><strong>The goal:</strong> prove the system behaves the way real humans expect it to, not just the way engineers designed it.</p><div><hr></div><h2>Architecture Overview</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!7q_X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!7q_X!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png 424w, /__u/substackcdn.com/image/fetch/$s_!7q_X!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png 848w, /__u/substackcdn.com/image/fetch/$s_!7q_X!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png 1272w, /__u/substackcdn.com/image/fetch/$s_!7q_X!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!7q_X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png" width="1024" height="705" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:705,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:705873,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fullstackinfra.substack.com/i/202101700?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="/__u/substackcdn.com/image/fetch/$s_!7q_X!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png 424w, /__u/substackcdn.com/image/fetch/$s_!7q_X!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png 848w, /__u/substackcdn.com/image/fetch/$s_!7q_X!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png 1272w, /__u/substackcdn.com/image/fetch/$s_!7q_X!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ab7eae-1f4f-4911-a24b-76c97f4a6df8_1024x705.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-139-user-acceptance-testing-building">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Day 138: Performance Testing]]></title><description><![CDATA[Load &#183; Stress &#183; Endurance &#183; Spike &#183; Capacity]]></description><link>https://fullstackinfra.substack.com/p/day-138-performance-testing</link><guid isPermaLink="false">https://fullstackinfra.substack.com/p/day-138-performance-testing</guid><dc:creator><![CDATA[systemdr19]]></dc:creator><pubDate>Mon, 27 Jul 2026 06:30:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!JCbm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Load &#183; Stress &#183; Endurance &#183; Spike &#183; Capacity</h2><div><hr></div><h2>What We&#8217;re Building Today</h2><p>By the end of this lesson you will have a working, production-grade performance testing platform &#8212; not a toy, not a demo with mock numbers. Here is what gets built:</p><ul><li><p>A Locust-powered test suite with five distinct test profiles, each answering a different question about your system</p></li><li><p>A FastAPI backend that orchestrates test runs, polls live metrics every two seconds, computes latency percentiles, evaluates SLO thresholds, and streams everything over WebSocket</p></li><li><p>A React dashboard &#8212; styled after tools like Grafana and k6 Cloud &#8212; that shows live RPS charts, P50/P95/P99 latency curves, error rates, and a real-time SLO pass/fail verdict</p></li><li><p>A SQLite store for run history so you can compare test results across deployments</p></li></ul><p>The full project runs with a single command, with or without Docker.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="/__u/substackcdn.com/image/fetch/$s_!JCbm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="/__u/substackcdn.com/image/fetch/$s_!JCbm!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png 424w, /__u/substackcdn.com/image/fetch/$s_!JCbm!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png 848w, /__u/substackcdn.com/image/fetch/$s_!JCbm!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png 1272w, /__u/substackcdn.com/image/fetch/$s_!JCbm!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_webp, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png 1456w" sizes="100vw"><img src="/__u/substackcdn.com/image/fetch/$s_!JCbm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png" width="1456" height="900" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:900,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="/__u/substackcdn.com/image/fetch/$s_!JCbm!, /__u/fullstackinfra.substack.com/w_424, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png 424w, /__u/substackcdn.com/image/fetch/$s_!JCbm!, /__u/fullstackinfra.substack.com/w_848, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png 848w, /__u/substackcdn.com/image/fetch/$s_!JCbm!, /__u/fullstackinfra.substack.com/w_1272, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png 1272w, /__u/substackcdn.com/image/fetch/$s_!JCbm!, /__u/fullstackinfra.substack.com/w_1456, /__u/fullstackinfra.substack.com/c_limit, /__u/fullstackinfra.substack.com/f_auto, /__u/fullstackinfra.substack.com/q_auto:good, /__u/fullstackinfra.substack.com/fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F57baad34-375a-4502-91bb-5940bee94d09_5939x3671.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>
      <p>
          <a href="/__u/fullstackinfra.substack.com/p/day-138-performance-testing">
              Read more
          </a>
      </p>
   ]]></content:encoded></item></channel></rss>