<?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"><channel><title><![CDATA[Martin Mueller's Blog]]></title><description><![CDATA[Latest posts from Martin Mueller's technology blog]]></description><link>https://martinmueller.dev</link><generator>GatsbyJS</generator><lastBuildDate>Thu, 10 Sep 2026 12:11:00 GMT</lastBuildDate><item><title><![CDATA[OpenNext + CDK: Next.js on AWS Without ECS Fargate]]></title><description><![CDATA[I usually ship Next.js as Docker standalone on ECS Fargate — ALB, VPC, always-on tasks. For an MVP like qr-plakat.de I went OpenNext 4.x…]]></description><link>https://martinmueller.dev/opennext-cdk/</link><guid isPermaLink="false">https://martinmueller.dev/opennext-cdk/</guid><category><![CDATA[opennext]]></category><category><![CDATA[cdk]]></category><category><![CDATA[nextjs]]></category><category><![CDATA[aws]]></category><category><![CDATA[lambda]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[openclaw]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/f8626bdc6adb1f2c8dc406b178dc648d/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;I usually ship Next.js as Docker &lt;code&gt;standalone&lt;/code&gt; on &lt;strong&gt;ECS Fargate&lt;/strong&gt; — ALB, VPC, always-on tasks. For an MVP like &lt;a href=&quot;https://qr-plakat.de&quot;&gt;qr-plakat.de&lt;/a&gt; I went &lt;strong&gt;OpenNext 4.x + AWS CDK&lt;/strong&gt; instead. Cheaper to run, faster to iterate. If the product works, I might switch to Fargate.&lt;/p&gt;
&lt;p&gt;Three things made this feel better than the Fargate path. Deploys are &lt;strong&gt;one GitHub Actions job&lt;/strong&gt; from lint to CloudFront invalidation. Infra is &lt;strong&gt;CDK I already know&lt;/strong&gt; — no SST, no extra deploy product. And I can ship from &lt;strong&gt;Telegram → OpenClaw → Cursor&lt;/strong&gt; while watching Netflix or training outside: a PR lands, Actions deploys, I check prod from the phone.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-product-qr-plakatde&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-product-qr-plakatde&quot; aria-label=&quot;the product qr plakatde permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The product: qr-plakat.de&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://qr-plakat.de&quot;&gt;qr-plakat.de&lt;/a&gt; is a DACH SaaS for posters with QR codes. You design in a wizard, overlay one to eight codes, and export 300 dpi PDF or JPG. Each poster gets hosted scan URLs like &lt;code&gt;qr-plakat.de/p/{slug}&lt;/code&gt; that you can change without reprinting. Everything runs in &lt;strong&gt;eu-central-1&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The first real poster is the Brasil shop-window plakat — eight products, eight QR codes, print-ready from the editor.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://qr-plakat.de/#galerie&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 141.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAcABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAEDAgT/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAQID/9oADAMBAAIQAxAAAAHoVt89YOwsg6sYyv/EAB4QAAICAQUBAAAAAAAAAAAAAAECABESAxMiIzFD/9oACAEBAAEFAkrLirjRMDdv0TxLyptwSheIgFT/xAAVEQEBAAAAAAAAAAAAAAAAAAARIP/aAAgBAwEBPwEj/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEREP/aAAgBAgEBPwEhHn//xAAgEAAABAYDAAAAAAAAAAAAAAAAAQIREBITITGBAzJR/9oACAEBAAY/Apah6EtRbjs4Mj49sEsi3rCwU63BHMWMQxH/xAAgEAACAwACAQUAAAAAAAAAAAABEQAhMUFhUXGBkaHB/9oACAEBAAE/IXEAOhX3LanK6lr5MhitiwB/ceMV9P3iN2LiLh4eTjZQ2jotbU3q1sFdZkAyGlmf/9oADAMBAAIAAwAAABDEy87/xAAYEQEBAAMAAAAAAAAAAAAAAAABABARMf/aAAgBAwEBPxDrCi27/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAgEBPxDgWIAsv//EAB8QAQACAgICAwAAAAAAAAAAAAERIQAxQVFhcZGhsf/aAAgBAQABPxCWcZ5hJns+sZ3FCtE6n5wFpFtH44y2iopAd8pxQSU2aj21xmlwdzc3vAClwJRaqj7MZIFKbPKY3ZAhDs8+cs2UmF3JgKxjEFozTKbyOf/Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/5b26db0fd64ae850f78e6bff39cce21b/f1512/brasil-plakat.webp 200w,
/static/5b26db0fd64ae850f78e6bff39cce21b/f59aa/brasil-plakat.webp 400w,
/static/5b26db0fd64ae850f78e6bff39cce21b/47a22/brasil-plakat.webp 800w,
/static/5b26db0fd64ae850f78e6bff39cce21b/5bb53/brasil-plakat.webp 1200w,
/static/5b26db0fd64ae850f78e6bff39cce21b/485a2/brasil-plakat.webp 1600w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/5b26db0fd64ae850f78e6bff39cce21b/16d62/brasil-plakat.jpg 200w,
/static/5b26db0fd64ae850f78e6bff39cce21b/27ec1/brasil-plakat.jpg 400w,
/static/5b26db0fd64ae850f78e6bff39cce21b/5fd6b/brasil-plakat.jpg 800w,
/static/5b26db0fd64ae850f78e6bff39cce21b/5a523/brasil-plakat.jpg 1200w,
/static/5b26db0fd64ae850f78e6bff39cce21b/b46c2/brasil-plakat.jpg 1600w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/jpeg&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/5b26db0fd64ae850f78e6bff39cce21b/5fd6b/brasil-plakat.jpg&quot;
            alt=&quot;Brasil QR-Plakat&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Subscriptions are &lt;strong&gt;mocked&lt;/strong&gt;. I am the only user, so there is no Stripe checkout. If someone wants a higher tier, they request it in the &lt;strong&gt;support chat&lt;/strong&gt; and I set the plan by hand. Real billing comes when I convince the first business to use the product.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-opennext--cdk-for-an-mvp&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-opennext--cdk-for-an-mvp&quot; aria-label=&quot;why opennext  cdk for an mvp permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why OpenNext + CDK for an MVP&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;OpenNext + CDK is the best choice for MVPs&lt;/strong&gt; — low cost, fast iteration. If the product works, I might switch to ECS Fargate.&lt;/p&gt;
&lt;p&gt;Fargate wants a baseline of tasks, a VPC, and an ALB even when almost nobody is hitting the site. OpenNext maps the Next.js app to &lt;strong&gt;pay-per-request Lambda&lt;/strong&gt;, with CloudFront and S3 in front. I still get App Router, RSC, and Server Actions. I do not run &lt;code&gt;next start&lt;/code&gt; in a container.&lt;/p&gt;
&lt;p&gt;I stayed on &lt;strong&gt;CDK&lt;/strong&gt;, not SST. Explicit stacks, same IaC I already use. I tried SST&apos;s OpenNext path years ago in &lt;a href=&quot;/sst-nextjs-s3-picture-uploader&quot;&gt;this post&lt;/a&gt;. DynamoDB, S3, and Cognito mean &lt;strong&gt;no VPC&lt;/strong&gt; for the data plane.&lt;/p&gt;
&lt;p&gt;The ECS Fargate path I used on &lt;a href=&quot;/aws-mcp-listings&quot;&gt;listings-mcp&lt;/a&gt; is the later-stage option: always-on, long jobs, when traffic and product-market fit justify it.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;stack&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#stack&quot; aria-label=&quot;stack permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Stack&lt;/h2&gt;
&lt;ul class=&quot;stack-list&quot;&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img class=&quot;tool-logo-on-dark&quot; src=&quot;/opennext-cdk/icons/nextjs.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://nextjs.org&quot;&gt;Next.js&lt;/a&gt; 16&lt;/span&gt; App Router&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/react.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://react.dev&quot;&gt;React&lt;/a&gt; 19&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img class=&quot;tool-logo-on-dark&quot; src=&quot;/opennext-cdk/icons/shadcnui.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://ui.shadcn.com&quot;&gt;shadcn/ui&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/tailwindcss.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://tailwindcss.com&quot;&gt;Tailwind&lt;/a&gt; 4&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img class=&quot;tool-logo-on-dark&quot; src=&quot;/opennext-cdk/icons/opennext.png&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://github.com/opennextjs/opennextjs-aws&quot;&gt;&lt;code&gt;@opennextjs/aws&lt;/code&gt;&lt;/a&gt;&lt;/span&gt; → Lambda ARM64 (2048 MB, 60s)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/lambda.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://aws.amazon.com/lambda/&quot;&gt;Lambda&lt;/a&gt;&lt;/span&gt; + &lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/cloudfront.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://aws.amazon.com/cloudfront/&quot;&gt;CloudFront&lt;/a&gt;&lt;/span&gt; + &lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/s3.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://aws.amazon.com/s3/&quot;&gt;S3&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/cdk.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://aws.amazon.com/cdk/&quot;&gt;AWS CDK&lt;/a&gt;&lt;/span&gt; stacks: Data → Auth → Web → Observability (+ Cicd OIDC)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/cdk.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://github.com/berenddeboer/cdk-opennext&quot;&gt;cdk-opennext&lt;/a&gt;&lt;/span&gt; &lt;code&gt;NextjsSite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/cognito.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://aws.amazon.com/cognito/&quot;&gt;Cognito&lt;/a&gt;&lt;/span&gt; ×2 (creators / admins)&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/dynamodb.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://electrodb.dev&quot;&gt;ElectroDB&lt;/a&gt;&lt;/span&gt; on DynamoDB single-table&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/opennext-cdk/icons/route53.svg&quot; alt=&quot;&quot; /&gt; &lt;a href=&quot;https://aws.amazon.com/route53/&quot;&gt;Route 53&lt;/a&gt;&lt;/span&gt; &lt;code&gt;qr-plakat.de&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;github-actions--the-part-i-love&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#github-actions--the-part-i-love&quot; aria-label=&quot;github actions  the part i love permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GitHub Actions — the part I love&lt;/h2&gt;
&lt;p&gt;One job. No artifact hop between build and deploy. The runner lints, typechecks, and tests, then runs &lt;code&gt;next build&lt;/code&gt;, &lt;code&gt;open-next build&lt;/code&gt;, and &lt;code&gt;cdk synth&lt;/code&gt;. After that it assumes an IAM role with OIDC, runs &lt;code&gt;cdk deploy --all&lt;/code&gt;, and invalidates CloudFront &lt;code&gt;/*&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;PRs to &lt;code&gt;main&lt;/code&gt; ship prod. That is intentional. Dependabot runs CI only.&lt;/p&gt;
&lt;p&gt;That loop is why Telegram shipping works. The agent opens a PR, Actions deploys, I hit the live site from the phone.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;agentic-loop&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#agentic-loop&quot; aria-label=&quot;agentic loop permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Agentic loop&lt;/h2&gt;
&lt;p&gt;I already wrote about &lt;a href=&quot;/openclaw-eng&quot;&gt;OpenClaw&lt;/a&gt; and &lt;a href=&quot;/openclaw-three-months-later&quot;&gt;what shipped after three months&lt;/a&gt;. On this project the loop is the same, just pointed at qr-plakat.&lt;/p&gt;
&lt;p&gt;I send a voice note or a short text on Telegram while watching Netflix or training outside. OpenClaw on the VPS hands the work to Cursor in the real repo. Cursor does a &lt;code&gt;git pull&lt;/code&gt;, reads &lt;a href=&quot;https://github.com/mmuller88/qr-plakat&quot;&gt;AGENTS.md&lt;/a&gt; and &lt;code&gt;docs/&lt;/code&gt;, implements the change, and opens a PR. Product decisions stay in &lt;code&gt;docs/&lt;/code&gt; and ADRs — not buried in chat.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;mcps-i-actually-used&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#mcps-i-actually-used&quot; aria-label=&quot;mcps i actually used permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;MCPs I actually used&lt;/h2&gt;
&lt;p&gt;Cursor talked to a small set of MCPs on this repo. &lt;strong&gt;shadcn&lt;/strong&gt; for component discovery and install. &lt;strong&gt;aws-knowledge-mcp&lt;/strong&gt; for AWS docs while writing CDK. &lt;strong&gt;playwright&lt;/strong&gt; for browser checks. &lt;strong&gt;firecrawl&lt;/strong&gt; when I needed to scrape or research a page. &lt;strong&gt;sistrix&lt;/strong&gt; for DACH SEO. &lt;strong&gt;pdf-reader&lt;/strong&gt; for print and export PDFs.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;skills-that-helped&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#skills-that-helped&quot; aria-label=&quot;skills that helped permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Skills that helped&lt;/h2&gt;
&lt;p&gt;The useful skills were the ones I already had: &lt;code&gt;aws-cdk-development&lt;/code&gt; and &lt;code&gt;aws-serverless&lt;/code&gt; for infra, &lt;code&gt;vercel-react-best-practices&lt;/code&gt;, &lt;code&gt;shadcn-ui&lt;/code&gt;, and &lt;code&gt;tailwind-patterns&lt;/code&gt; for the app, &lt;code&gt;ci-cd-pipeline-builder&lt;/code&gt; for Actions, &lt;code&gt;seo-audit&lt;/code&gt; and &lt;code&gt;seo-meta&lt;/code&gt; for the landing pages, plus &lt;code&gt;playwright-cli&lt;/code&gt;, &lt;code&gt;diagnosing-bugs&lt;/code&gt;, and &lt;code&gt;code-review&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There is no OpenNext-specific skill. CDK and serverless skills were enough.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;would-i-do-it-again&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#would-i-do-it-again&quot; aria-label=&quot;would i do it again permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Would I do it again&lt;/h2&gt;
&lt;p&gt;For an MVP: &lt;strong&gt;OpenNext + CDK + one Actions job + Telegram agents&lt;/strong&gt;. Cheap to run, fast to ship. If qr-plakat takes off, I might move the Next.js app to ECS Fargate. Until then, stay serverless.&lt;/p&gt;
&lt;p&gt;Live: &lt;a href=&quot;https://qr-plakat.de&quot;&gt;qr-plakat.de&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;mailto:office@martinmueller.dev&quot;&gt;office@martinmueller.dev&lt;/a&gt; · &lt;a href=&quot;https://calendly.com/martinmueller_dev&quot;&gt;calendly.com/martinmueller_dev&lt;/a&gt; · &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;further-reading&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#further-reading&quot; aria-label=&quot;further reading permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/openclaw-eng&quot;&gt;OpenClaw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/openclaw-three-months-later&quot;&gt;OpenClaw, three months later&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/aws-mcp-listings&quot;&gt;Next.js on ECS Fargate + CDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/sst-nextjs-s3-picture-uploader&quot;&gt;SST Next.js + OpenNext&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/opennextjs/opennextjs-aws&quot;&gt;OpenNext AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/berenddeboer/cdk-opennext&quot;&gt;cdk-opennext&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/f8626bdc6adb1f2c8dc406b178dc648d/index.png</featuredImage><media:content url="https://martinmueller.dev/static/f8626bdc6adb1f2c8dc406b178dc648d/index.png" medium="image"/></item><item><title><![CDATA[Sovereign Cloud on AWS: When eu-central-1 Is Enough — and When You Need ESC]]></title><description><![CDATA[The AWS European Sovereign Cloud (ESC) has been generally available since January 2026 — physically isolated EU infrastructure, its own…]]></description><link>https://martinmueller.dev/aws-esc/</link><guid isPermaLink="false">https://martinmueller.dev/aws-esc/</guid><category><![CDATA[aws]]></category><category><![CDATA[esc]]></category><category><![CDATA[sovereign-cloud]]></category><category><![CDATA[data-residency]]></category><category><![CDATA[cdk]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/0f1b31e621e6594bc9a70de398329088/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;The &lt;strong&gt;AWS European Sovereign Cloud (ESC)&lt;/strong&gt; has been &lt;strong&gt;generally available since January 2026&lt;/strong&gt; — physically isolated EU infrastructure, its own partition, EU-resident operations. Across DACH, &lt;strong&gt;digital sovereignty&lt;/strong&gt; is the conversation: data control, operational independence, limiting third-country access.&lt;/p&gt;
&lt;p&gt;The core question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is &lt;strong&gt;eu-central-1&lt;/strong&gt; (EU region) enough, or do you need the &lt;strong&gt;sovereign partition&lt;/strong&gt; &lt;code&gt;aws-eusc&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This post is a &lt;strong&gt;builder&apos;s guide&lt;/strong&gt; — not AWS marketing. I&apos;m &lt;strong&gt;AWS Solutions Architect Professional&lt;/strong&gt; certified, an &lt;strong&gt;AWS Community Builder&lt;/strong&gt;, and help with ESC migrations (CDK/Terraform), sovereignty decisions, and readiness checks. &lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;Resume&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-now&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-now&quot; aria-label=&quot;why now permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why now?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESC GA&lt;/strong&gt; — sovereign AWS workloads are plannable, not &quot;someday&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Region&lt;/strong&gt; &lt;code&gt;eusc-de-east-1&lt;/code&gt; (Brandenburg) — EU infrastructure with its own governance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Public reference customers:&lt;/strong&gt; SCHUFA, ITZBund, SAP, EWE, Swiss Life — organizations treating sovereignty as an architecture decision&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Politics &amp;#x26; procurement:&lt;/strong&gt; &quot;sovereign cloud&quot;, EU-only operations, no third-country access — regardless of which compliance framework applies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is still little &lt;strong&gt;practical builder content&lt;/strong&gt; — most decks sell sovereignty instead of explaining what breaks in migration.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-esc-actually-is--beyond-servers-in-the-eu&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-esc-actually-is--beyond-servers-in-the-eu&quot; aria-label=&quot;what esc actually is  beyond servers in the eu permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What ESC actually is — beyond &quot;servers in the EU&quot;&lt;/h2&gt;
&lt;p&gt;EU region ≠ sovereign partition. Short and factual:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Standard AWS (eu-central-1)&lt;/th&gt;
&lt;th&gt;AWS ESC (aws-eusc)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Partition&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aws-eusc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Physical isolation&lt;/td&gt;
&lt;td&gt;EU region&lt;/td&gt;
&lt;td&gt;Dedicated EU infra, separate partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operations&lt;/td&gt;
&lt;td&gt;Global AWS ops&lt;/td&gt;
&lt;td&gt;EU-resident, European governance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data residency&lt;/td&gt;
&lt;td&gt;Yes (EU)&lt;/td&gt;
&lt;td&gt;Yes (EU) + isolated control and ops layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service scope&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;~90 services at GA — growing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical buyer&lt;/td&gt;
&lt;td&gt;Most workloads&lt;/td&gt;
&lt;td&gt;Sovereignty-critical data &amp;#x26; public sector&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;eu-central-1&lt;/strong&gt; delivers data residency. &lt;strong&gt;ESC&lt;/strong&gt; adds partition isolation and EU-governed operations — that is the sovereignty step, not another certificate.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;decision-framework-three-buckets&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#decision-framework-three-buckets&quot; aria-label=&quot;decision framework three buckets permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decision framework: three buckets&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;First clarify: what sovereignty requirement do you have?&lt;/strong&gt; — not which vendor shouts loudest.&lt;/p&gt;
&lt;h3 id=&quot;bucket-1--eu-central-1-is-enough&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bucket-1--eu-central-1-is-enough&quot; aria-label=&quot;bucket 1  eu central 1 is enough permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bucket 1 — eu-central-1 is enough&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Workloads where &lt;strong&gt;EU data residency&lt;/strong&gt; suffices&lt;/li&gt;
&lt;li&gt;No contractual need for isolated partition or EU-only operations&lt;/li&gt;
&lt;li&gt;You want the full AWS service catalog without a partition split&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Most&lt;/strong&gt; AWS customers land here — and that&apos;s fine&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;bucket-2--esc-for-defined-workloads&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bucket-2--esc-for-defined-workloads&quot; aria-label=&quot;bucket 2  esc for defined workloads permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bucket 2 — ESC for defined workloads&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Contractual or political: &lt;strong&gt;sovereign partition&lt;/strong&gt;, no third-country access&lt;/li&gt;
&lt;li&gt;Highly sensitive data: health, credit, federal IT, critical infrastructure&lt;/li&gt;
&lt;li&gt;Hybrid: core on ESC, rest on eu-central-1 — &lt;strong&gt;phased&lt;/strong&gt;, not big bang&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;bucket-3--full-sovereign-stack&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bucket-3--full-sovereign-stack&quot; aria-label=&quot;bucket 3  full sovereign stack permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bucket 3 — Full sovereign stack&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ESC alone is not enough politically or legally&lt;/li&gt;
&lt;li&gt;Combined with on-prem, BRZ PaaS (AT), Hetzner, or dedicated hosting&lt;/li&gt;
&lt;li&gt;Deliberate architecture decision — not the default&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In practice: &lt;strong&gt;bucket 1 or 2&lt;/strong&gt;. Sovereignty is workload-specific, not org-wide.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-changes-for-builders&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-changes-for-builders&quot; aria-label=&quot;what changes for builders permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What changes for builders&lt;/h2&gt;
&lt;p&gt;Marketing skips &lt;strong&gt;operational&lt;/strong&gt; differences between partitions:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Partition &amp;#x26; identity&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Separate IAM identities — no 1:1 copy from &lt;code&gt;aws&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ARN formats and account layout (new landing zone)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;DNS &amp;#x26; networking&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Route 53 behavior and zones — common pain point&lt;/li&gt;
&lt;li&gt;Plan or avoid cross-partition references&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;IaC / CDK&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Region &lt;code&gt;eusc-de-east-1&lt;/code&gt;, partition &lt;code&gt;aws-eusc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Hardcoded eu-central-1 ARNs break&lt;/li&gt;
&lt;li&gt;CI/CD: separate credentials, possibly separate pipelines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Service availability&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serverless stack at GA — verify before design&lt;/li&gt;
&lt;li&gt;&quot;Available in eu-central-1&quot; ≠ &quot;available in ESC&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Typical path: &lt;strong&gt;readiness → landing zone → pilot → phased migration&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;case-studies-who-is-betting-on-esc&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#case-studies-who-is-betting-on-esc&quot; aria-label=&quot;case studies who is betting on esc permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Case studies: who is betting on ESC?&lt;/h2&gt;
&lt;p&gt;AWS mostly publishes &lt;strong&gt;quotes and direction&lt;/strong&gt; for launch customers — rarely CDK migration paths or account layouts. Still worth studying: &lt;strong&gt;why&lt;/strong&gt; organizations choose ESC and what is &lt;strong&gt;publicly known&lt;/strong&gt; about concrete use.&lt;/p&gt;
&lt;p&gt;Common pattern: not org-wide big bang, but &lt;strong&gt;sovereignty-critical workloads&lt;/strong&gt; — often hybrid alongside eu-central-1.&lt;/p&gt;
&lt;h3 id=&quot;schufa--finance--credit-data&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#schufa--finance--credit-data&quot; aria-label=&quot;schufa  finance  credit data permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SCHUFA — finance &amp;#x26; credit data&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACXklEQVR42i1SaU8TURR921SwYigSoHSbaek6rXSZfsBAGdrplG60ne6VrVOiIhpKjDHW4AdiNH7QH+Cv9b4ZkpubO/fdc8955w1C26+s2EeefeQ9QN5D5C0g3yHyqVa2CxVD9h9hScdiGQq7iZDngIe3gP0qkcoQWNSwv4j5KNRlHCjhAHwWSfQExw0cM3C4DjN8xeNuOINRewhWBHVeQA5W+C5RI9EWSfRwBPBdHG3zAiTYAggcSzZJCUZpuAoK0baKPCoOVUjoGJAk1iE7NQ62I1RH/CYQAY0AiQXmhD4NYJvq6UbZxJEW8pdItIljLY6X+xwZtpi5VAiRY+hOlUXqSKx4dFO+WgROv7i7d/7R5xf6O5Ic0ZcTmhoTecDx/NolZOm0CCVdiDepVEFbh/LV19WT+XL5+qk6cygTd2fOZINGWzTeoXKPRBq2F4j7AXhJE2INEii6mibKd6XejVN/L939Dnz46chPVtVz5D4g0WMqn9he2i5asr1H6/MH12zhrE2DiwfRvN9s3rgHn7avf7in987CdGVvKCjt5f4tU/rAz9/M8pUzu94utv7+ez77xhTjWaK2kTbwTk0c3i4XTJYdrulXJKgJaUNItUm4KuRnLG8+yiYhfX3xa+37n6Xex5X0aCU3wSGdSpojWNqqv3FplyxYhLekoQrlvhZJckAyZ2R3DL8QN4zGG469McsOnqSHS5kxS/ZZagAPaxV9Eu9Rq0MTBo1xz7hs8AzAJDWkqRFNjunua5o5o9kLlrsUlKmQN5kyZbmpoJjQYdDPXtDMOR9LjWlySOT+f2rJhXy1lm2GAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/f48086135c8ac18113239413b9dd010c/f1512/case-finance.webp 200w,
/static/f48086135c8ac18113239413b9dd010c/f59aa/case-finance.webp 400w,
/static/f48086135c8ac18113239413b9dd010c/47a22/case-finance.webp 800w,
/static/f48086135c8ac18113239413b9dd010c/5bb53/case-finance.webp 1200w,
/static/f48086135c8ac18113239413b9dd010c/a8642/case-finance.webp 1536w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/f48086135c8ac18113239413b9dd010c/f8f3a/case-finance.png 200w,
/static/f48086135c8ac18113239413b9dd010c/6a8a8/case-finance.png 400w,
/static/f48086135c8ac18113239413b9dd010c/7842b/case-finance.png 800w,
/static/f48086135c8ac18113239413b9dd010c/5ece7/case-finance.png 1200w,
/static/f48086135c8ac18113239413b9dd010c/437a1/case-finance.png 1536w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/f48086135c8ac18113239413b9dd010c/7842b/case-finance.png&quot;
            alt=&quot;SCHUFA: sovereign credit data platform&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sector:&lt;/strong&gt; Financial data / credit bureau&lt;br&gt;
&lt;strong&gt;Why ESC:&lt;/strong&gt; 69 million consumer records; isolated EU infra, EU-only staff, no access from outside Europe — sovereignty without sacrificing innovation.&lt;br&gt;
&lt;strong&gt;What is known:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migration from &lt;strong&gt;on-premises and other cloud workloads&lt;/strong&gt; to ESC&lt;/li&gt;
&lt;li&gt;New &lt;strong&gt;credit scoring system&lt;/strong&gt; with transparent consumer-facing criteria and weighting&lt;/li&gt;
&lt;li&gt;CTO Klaus Kolitz: innovation and sovereignty together, not either/or&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; &lt;a href=&quot;https://www.aboutamazon.eu/news/aws/sovereignty-without-compromise-whos-choosing-the-aws-european-sovereign-cloud&quot;&gt;About Amazon — Who&apos;s choosing ESC&lt;/a&gt; · &lt;a href=&quot;https://aws.eu/european-sovereign-cloud/customers/&quot;&gt;AWS ESC Customers&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;diehl-metering--smart-metering--critical-infrastructure&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#diehl-metering--smart-metering--critical-infrastructure&quot; aria-label=&quot;diehl metering  smart metering  critical infrastructure permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Diehl Metering — smart metering &amp;#x26; critical infrastructure&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACk0lEQVR42kVSS08aURQ+dx7g+KwNRhsKDAgMMAOIyEO0VEVE5DG8HECQKmCwaaWNkTbVxGqjoU1rF130mbSrrrp10UW7ahdN+qd6Z6pt8uXm3HO/77vnnnMBtDf/4/r8BXTzoI+ANoyB2Kgc6xZAF7kMLiHz/lIxDBiLMtglfKbiJYqXwFUDcxr0OB+9xKK8xVA0ixcpvGKZMY7t+kJ3nHvfHPfPe+c6YJfkPBsDvUL4ZwEGJctGKc8teqoJxmW8HYwccg9/C53vE/s/HA9+qbx1fA9pSfU4cpivsomUJSnrL8SGKOkskxNVZE6BUB6Kn44WPxrW32rLb65VPzPhPTAlGJd0JbhJc+Kwr8YIBUVsXCZtOWTNEI4C5ViF8SRyr4OwRnvWR8rvh8XnpLcBvm3krKiFwqCvRnLpXneRtmflK5E5ycztDaS6w/FjOtRErgI2QoEd9cK+Ruxq0k9Us/cgeBe5qhSfZ9wlla85GD9W+xry44EvEFObzGy7f+mQnG6BU0K2PDX3iJztUKEdOtAiZ9p0eBdca4SvonYXmZl2T3iXmG6AIwtgSYMtB9YsOdW0Vs646hkTewzeJiEUyckNGcFt5G30B+r++rNw+93o/A4eB+IyYEkBsMu4SbS/NRbrZE7Pxe5XXb6r8lR6vTVkyxK8RPCr1OSGJrQZbH9wtj9p00e488gUl+cCxhhm0IHbpD3nrr+a2HpNcmK/v86WXvZNtxh/nRIksIqMsxA9+JJ+8dOQPwE2jsYTiti0IleOJ4QDdgW4DOGpDEQPriZPxrJPRxJHKv8WuEtgyw/5NzQ3tml+FXsBl4PxFQDsgWFKYD3CLlaR4IuEsIbsuOASJZRwO2SqOYkfCHrl/+GaFckf2RuYqU/9tqEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/702484774374fdaebfc7ae816bfc84bc/f1512/case-metering.webp 200w,
/static/702484774374fdaebfc7ae816bfc84bc/f59aa/case-metering.webp 400w,
/static/702484774374fdaebfc7ae816bfc84bc/47a22/case-metering.webp 800w,
/static/702484774374fdaebfc7ae816bfc84bc/5bb53/case-metering.webp 1200w,
/static/702484774374fdaebfc7ae816bfc84bc/a8642/case-metering.webp 1536w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/702484774374fdaebfc7ae816bfc84bc/f8f3a/case-metering.png 200w,
/static/702484774374fdaebfc7ae816bfc84bc/6a8a8/case-metering.png 400w,
/static/702484774374fdaebfc7ae816bfc84bc/7842b/case-metering.png 800w,
/static/702484774374fdaebfc7ae816bfc84bc/5ece7/case-metering.png 1200w,
/static/702484774374fdaebfc7ae816bfc84bc/437a1/case-metering.png 1536w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/702484774374fdaebfc7ae816bfc84bc/7842b/case-metering.png&quot;
            alt=&quot;Diehl Metering: sovereign metering data platform&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sector:&lt;/strong&gt; Smart metering (water/energy), B2B2G&lt;br&gt;
&lt;strong&gt;Why ESC:&lt;/strong&gt; Public-sector customers (utilities, waterworks) require EU data residency and EU operations.&lt;br&gt;
&lt;strong&gt;What is known:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Smart metering data platform&lt;/strong&gt; on ESC&lt;/li&gt;
&lt;li&gt;Modular services: &lt;strong&gt;monitoring, billing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Central system for water/energy data of critical infrastructure operators&lt;/li&gt;
&lt;li&gt;Platform scale without building a fully custom sovereign stack&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; &lt;a href=&quot;https://www.aboutamazon.eu/news/aws/sovereignty-without-compromise-whos-choosing-the-aws-european-sovereign-cloud&quot;&gt;About Amazon — Who&apos;s choosing ESC&lt;/a&gt; · &lt;a href=&quot;https://www.theregister.com/paas-and-iaas/2026/05/21/aws-parades-orgs-that-took-up-its-offer-for-euro-sovereign-cloud/5244197&quot;&gt;The Register (May 2026)&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;university-hospital-essen--sovereign-ai-in-medicine&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#university-hospital-essen--sovereign-ai-in-medicine&quot; aria-label=&quot;university hospital essen  sovereign ai in medicine permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;University Hospital Essen — sovereign AI in medicine&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACn0lEQVR42iWT2U9aURDGZ+4FFcGKVtRu7IsIEaxpjIItiuzLZd+qRUUWF9QYFTfA2NTUNm3TpIltn5r41qQPfenf1zmQTE7uOfl+Z2bOfBdAtYxqL2p8oPWjPgj6EBjCFGiMgiGCtixny7BDCl0QtAEgpdpDFCjdQCRofagNEolGxjDMJBDJ2bPifIv31UEfRlMUaSWNLkCZUO1B4pES6ojsJCRsIsbCHOdnCuJ4oyfR6M1ccM/zYBTQFGMaqq7Ds/z0RSWhMYImAQkzCbwtK5pKo6sqLr7ll2qcd5ejE1sWJ+JIV1BHpO/yqA/QnvWjCRDMWVL8qzJMF8Rzxcf1z482byS5C5zfQHOcyiEB68vQrd8PXVI6XxoNHYI+IppdFfn3RItbo4WmpfnTcvF9tHzbV2jxzhI/nQOqnFpj78eaB9SFeENYX/06//63xLHJmWM4s9IfOpSnL9U7H9W1D4Pxswf5Np+74l0Vys9bkiJrUjQZZ6PhrMmxdNO498327l4ROwNduNdVVmzdShPnw7GTh4mGLNMa2b7tC9TBkpR794eCR/2unYGluogeCBfWZLnWSOh0JHauSLWHk4djm9dDq21wVlSla836FURP5K8vFfnjgeC29GVFtrxriBwo4w205wDNgip1phT2h9y14eWazF2VeChJGqYyvUvVvoUSOjY40tkzTwI7wYNP4rnSyd2flZtfYBYAlB5trrl+/2/x6E4ROR1PtaXOCnOYJQk0HmuKsyQ4awpU/rHF6vGPv9LZonf/y8JaC56SwzTeHmtKPrc24CjJHOVB17bkxRtmKRrbZIK3JnFCgK7tDOFxZ1Fmy4jtOd4UZg4DlQfIoc/coPKCxg9qH5sEk0Y7a6Szhtl1FGpfx1te9juoPP8BW9mhbo8m7ugAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/07e7844565eb6deb132e5f8e060f4345/f1512/case-health.webp 200w,
/static/07e7844565eb6deb132e5f8e060f4345/f59aa/case-health.webp 400w,
/static/07e7844565eb6deb132e5f8e060f4345/47a22/case-health.webp 800w,
/static/07e7844565eb6deb132e5f8e060f4345/5bb53/case-health.webp 1200w,
/static/07e7844565eb6deb132e5f8e060f4345/a8642/case-health.webp 1536w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/07e7844565eb6deb132e5f8e060f4345/f8f3a/case-health.png 200w,
/static/07e7844565eb6deb132e5f8e060f4345/6a8a8/case-health.png 400w,
/static/07e7844565eb6deb132e5f8e060f4345/7842b/case-health.png 800w,
/static/07e7844565eb6deb132e5f8e060f4345/5ece7/case-health.png 1200w,
/static/07e7844565eb6deb132e5f8e060f4345/437a1/case-health.png 1536w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/07e7844565eb6deb132e5f8e060f4345/7842b/case-health.png&quot;
            alt=&quot;Healthcare: sovereign AI research&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sector:&lt;/strong&gt; University medicine / research&lt;br&gt;
&lt;strong&gt;Why ESC:&lt;/strong&gt; Health data at scale under German and European sovereignty expectations.&lt;br&gt;
&lt;strong&gt;What is known:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IKIM&lt;/strong&gt; (Institute for AI in Medicine) uses ESC as foundation for AI research&lt;/li&gt;
&lt;li&gt;Goal: translate medical research into clinical practice with patient data in a sovereign environment&lt;/li&gt;
&lt;li&gt;More &lt;strong&gt;transformation and research path&lt;/strong&gt; than documented full hospital ERP migration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; &lt;a href=&quot;https://www.aboutamazon.eu/news/aws/sovereignty-without-compromise-whos-choosing-the-aws-european-sovereign-cloud&quot;&gt;About Amazon — Who&apos;s choosing ESC&lt;/a&gt; · &lt;a href=&quot;https://aws.amazon.com/blogs/publicsector/how-healthcare-organizations-are-advancing-innovation-while-meeting-digital-sovereignty-requirements-with-aws/&quot;&gt;AWS Public Sector — Healthcare &amp;#x26; Sovereignty&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;medizinische-universität-lausitz--carl-thiem--regional-health-ecosystem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#medizinische-universit%C3%A4t-lausitz--carl-thiem--regional-health-ecosystem&quot; aria-label=&quot;medizinische universität lausitz  carl thiem  regional health ecosystem permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Medizinische Universität Lausitz – Carl Thiem — regional health ecosystem&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Sector:&lt;/strong&gt; Healthcare / research (Brandenburg)&lt;br&gt;
&lt;strong&gt;Why ESC:&lt;/strong&gt; Sovereign digital foundation for the &quot;healthcare model region Lusatia&quot;.&lt;br&gt;
&lt;strong&gt;What is known:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connecting &lt;strong&gt;hospitals, research, regional partners&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Secure sovereign base for care, research, education&lt;/li&gt;
&lt;li&gt;Proximity to ESC region Brandenburg (&lt;code&gt;eusc-de-east-1&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href=&quot;https://aws.eu/european-sovereign-cloud/customers/&quot;&gt;AWS ESC Customers&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;itzbund--federal-it&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#itzbund--federal-it&quot; aria-label=&quot;itzbund  federal it permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ITZBund — federal IT&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Sector:&lt;/strong&gt; Public sector&lt;br&gt;
&lt;strong&gt;Why ESC:&lt;/strong&gt; Central federal IT provider — strictest protection and sovereignty requirements.&lt;br&gt;
&lt;strong&gt;What is known:&lt;/strong&gt; Commitment to ESC with full AWS service catalog; &lt;strong&gt;no&lt;/strong&gt; public workload list (expected for federal IT).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href=&quot;https://aws.eu/european-sovereign-cloud/customers/&quot;&gt;AWS ESC Customers&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;ewe-ag--energy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ewe-ag--energy&quot; aria-label=&quot;ewe ag  energy permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;EWE AG — energy&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Sector:&lt;/strong&gt; Energy / utilities&lt;br&gt;
&lt;strong&gt;Why ESC:&lt;/strong&gt; Sensitive utility data and critical infrastructure; sovereignty as platform strategy.&lt;br&gt;
&lt;strong&gt;What is known:&lt;/strong&gt; ESC as part of &lt;strong&gt;platform strategy&lt;/strong&gt; — no single named product, but clear strategic bet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href=&quot;https://aws.eu/european-sovereign-cloud/customers/&quot;&gt;AWS ESC Customers&lt;/a&gt; · &lt;a href=&quot;https://press.aboutamazon.com/aws/2026/1/aws-launches-aws-european-sovereign-cloud-and-announces-expansion-across-europe&quot;&gt;AWS Launch Press Release&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;eterno-health--health-saas-hybrid-thinking&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#eterno-health--health-saas-hybrid-thinking&quot; aria-label=&quot;eterno health  health saas hybrid thinking permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Eterno Health — health SaaS (hybrid thinking)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Sector:&lt;/strong&gt; Outpatient care / practice software&lt;br&gt;
&lt;strong&gt;Why ESC:&lt;/strong&gt; Digitizing outpatient care across Europe — customers with explicit sovereignty requirements.&lt;br&gt;
&lt;strong&gt;What is known:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full stack on standard AWS today; ESC as &lt;strong&gt;additional option&lt;/strong&gt; for sovereignty-sensitive deployments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leni&lt;/strong&gt; — AI agent (transcription, summaries, patient records) tested in own clinics&lt;/li&gt;
&lt;li&gt;Pattern: SaaS on AWS, ESC partition for customers who need it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; &lt;a href=&quot;https://aws.eu/european-sovereign-cloud/customers/&quot;&gt;AWS ESC Customers&lt;/a&gt; · &lt;a href=&quot;https://aws.amazon.com/solutions/case-studies/aws-pioneers-project/eterno/&quot;&gt;AWS Pioneers: ETERNO&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;platform-partners-not-end-customers-but-relevant&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#platform-partners-not-end-customers-but-relevant&quot; aria-label=&quot;platform partners not end customers but relevant permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Platform partners (not end customers, but relevant)&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vendor&lt;/th&gt;
&lt;th&gt;On ESC&lt;/th&gt;
&lt;th&gt;Sovereignty angle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SAP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SAP Cloud ERP Private GA&lt;/td&gt;
&lt;td&gt;Mission-critical ERP under EU governance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dedalus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hospital software (540M+ patients)&lt;/td&gt;
&lt;td&gt;Clinical workflows with residency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Arvato Systems&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Health Cloud&lt;/td&gt;
&lt;td&gt;Sovereign healthcare digitalization&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt; &lt;a href=&quot;https://www.aboutamazon.eu/news/aws/sovereignty-without-compromise-whos-choosing-the-aws-european-sovereign-cloud&quot;&gt;About Amazon — Who&apos;s choosing ESC&lt;/a&gt; · &lt;a href=&quot;https://aws.amazon.com/blogs/publicsector/how-healthcare-organizations-are-advancing-innovation-while-meeting-digital-sovereignty-requirements-with-aws/&quot;&gt;AWS Healthcare Sovereignty Blog&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;What is publicly missing&lt;/strong&gt; — and where readiness assessments start: IAM/landing zone design, CDK migration paths, timeline, cost. The gap between marketing quote and production migration is large.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;esc-vs-eu-hosting-on-hetzner&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#esc-vs-eu-hosting-on-hetzner&quot; aria-label=&quot;esc vs eu hosting on hetzner permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ESC vs EU hosting on Hetzner&lt;/h2&gt;
&lt;p&gt;I wrote about &lt;a href=&quot;/hetzner-eu-production&quot;&gt;production on Hetzner for EU clients&lt;/a&gt; — &lt;strong&gt;Arc Rider Universe&lt;/strong&gt; with full data control on EU VMs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Hetzner / self-hosted EU&lt;/th&gt;
&lt;th&gt;AWS ESC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sovereignty model&lt;/td&gt;
&lt;td&gt;You operate everything&lt;/td&gt;
&lt;td&gt;AWS-native sovereign partition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audience&lt;/td&gt;
&lt;td&gt;New product, full control&lt;/td&gt;
&lt;td&gt;Existing AWS shop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ops burden&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Lower (managed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical path&lt;/td&gt;
&lt;td&gt;SaaS with EU prod requirement&lt;/td&gt;
&lt;td&gt;Migrating sovereignty-critical AWS workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both can coexist — &lt;strong&gt;hybrid&lt;/strong&gt; is normal. Sovereignty is not either/or.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;cloud-act--third-country-access--honestly&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cloud-act--third-country-access--honestly&quot; aria-label=&quot;cloud act  third country access  honestly permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CLOUD Act &amp;#x26; third-country access — honestly&lt;/h2&gt;
&lt;p&gt;This is the sovereignty elephant in the room. &lt;strong&gt;eu-central-1&lt;/strong&gt; hosts in the EU, but the partition stays &lt;code&gt;aws&lt;/code&gt;. &lt;strong&gt;ESC&lt;/strong&gt; addresses that directly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Physically isolated infrastructure in the EU&lt;/li&gt;
&lt;li&gt;EU-resident operations — no global US ops access path&lt;/li&gt;
&lt;li&gt;European governance structure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What ESC does &lt;strong&gt;not&lt;/strong&gt; replace:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Contract review (subprocessors, support paths)&lt;/li&gt;
&lt;li&gt;Data classification — which workloads need which sovereignty level&lt;/li&gt;
&lt;li&gt;Political expectations vs technical reality&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Honest framing beats marketing. Sovereignty is architecture &lt;strong&gt;and&lt;/strong&gt; contract.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;next-step-esc-readiness-assessment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#next-step-esc-readiness-assessment&quot; aria-label=&quot;next step esc readiness assessment permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Next step: ESC readiness assessment&lt;/h2&gt;
&lt;p&gt;If you use or plan AWS and need to clarify sovereignty:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;45 minutes, no pitch:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Which &lt;strong&gt;bucket&lt;/strong&gt; (1/2/3) fits your workloads&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDK/Terraform pitfalls&lt;/strong&gt; (IAM, Route 53, partition)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Migration path&lt;/strong&gt; — pilot → rollout, hybrid where it makes sense&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Talk at &lt;strong&gt;AWS Community Day DACH 2026&lt;/strong&gt; (Berlin, 15 Sep) — &lt;em&gt;AWS European Sovereign Cloud: A Builder&apos;s Guide&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Contact:&lt;/strong&gt; &lt;a href=&quot;mailto:office@martinmueller.dev&quot;&gt;office@martinmueller.dev&lt;/a&gt; · &lt;a href=&quot;https://calendly.com/martinmueller_dev&quot;&gt;calendly.com/martinmueller_dev&lt;/a&gt; · &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;LinkedIn&lt;/a&gt; · &lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;Resume&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Subject: &lt;em&gt;ESC Readiness&lt;/em&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;further-reading&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#further-reading&quot; aria-label=&quot;further reading permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.eu/en/products/european-sovereign-cloud/&quot;&gt;AWS European Sovereign Cloud&lt;/a&gt; (official)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-eu-production&quot;&gt;Production on Hetzner (EU)&lt;/a&gt; — sovereignty without an AWS partition&lt;/li&gt;
&lt;/ul&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/0f1b31e621e6594bc9a70de398329088/index.png</featuredImage><media:content url="https://martinmueller.dev/static/0f1b31e621e6594bc9a70de398329088/index.png" medium="image"/></item><item><title><![CDATA[OpenClaw, Three Months Later: What Actually Shipped]]></title><description><![CDATA[In April I wrote about OpenClaw — my self-hosted AI agent on a Hostinger VPS, wired to Telegram, email, calendar, and GitHub. That post…]]></description><link>https://martinmueller.dev/openclaw-three-months-later/</link><guid isPermaLink="false">https://martinmueller.dev/openclaw-three-months-later/</guid><category><![CDATA[openclaw]]></category><category><![CDATA[ai]]></category><category><![CDATA[automation]]></category><category><![CDATA[mcp]]></category><category><![CDATA[cursor]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Tue, 07 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/733e00b8638647b8c9505ed1eaf2e1c3/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;In &lt;a href=&quot;https://martinmueller.dev/openclaw-eng&quot;&gt;April I wrote about OpenClaw&lt;/a&gt; — my self-hosted AI agent on a &lt;a href=&quot;https://www.hostinger.com?REFERRALCODE=MARTINMUELLER&quot;&gt;Hostinger&lt;/a&gt; VPS, wired to Telegram, email, calendar, and GitHub. That post ended with a short &quot;What&apos;s Next&quot; list. Three months later, most of it shipped — and the setup feels less like a chatbot and more like a small ops team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&apos;s new since April:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blog posts&lt;/strong&gt; — voice note in, researched draft out, published on my site&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code from GitHub issues&lt;/strong&gt; — agent plans, I approve, PR lands&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invoices&lt;/strong&gt; — bilingual PDFs for US and German clients, email draft ready to send&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO &amp;#x26; compliance work&lt;/strong&gt; — live data pulls and reports without me clicking through five tools&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One Telegram chat, many projects&lt;/strong&gt; — separate topics so context doesn&apos;t mix&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conference proposals&lt;/strong&gt; — talk drafts from memory, not from a blank page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below: what changed, what broke, and what I&apos;d do again.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;quick-recap&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#quick-recap&quot; aria-label=&quot;quick recap permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Quick recap&lt;/h2&gt;
&lt;p&gt;OpenClaw is a persistent assistant with memory. I talk to it on &lt;strong&gt;Telegram&lt;/strong&gt; — often by voice. It can run tasks, read my repos, draft email, and check GitHub. It only sends mail after I say yes.&lt;/p&gt;
&lt;p&gt;Everything below builds on that.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-blog-posts--from-idea-to-publish&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#1-blog-posts--from-idea-to-publish&quot; aria-label=&quot;1 blog posts  from idea to publish permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Blog posts — from idea to publish&lt;/h2&gt;
&lt;p&gt;The April post promised blog drafting. That happened — repeatedly:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Post&lt;/th&gt;
&lt;th&gt;What the agent did&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/hetzner-eu-production&quot;&gt;Hetzner EU production series&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Researched the stack, drafted EN+DE, coordinated images&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/lovable-hetzner-germany&quot;&gt;Lovable → Hetzner DACH&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Same pattern, tied to a real client story&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;/sistrix-mcp-hallocasa-seo&quot;&gt;SISTRIX MCP SEO audit&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Pulled live SEO data, read the client&apos;s site code, exported a strategy PDF&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Typical flow: voice note → agent gathers context from past notes and repos → markdown draft → I edit for tone and accuracy → publish.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Great at first drafts with real data. My job is &quot;would I post this under my name?&quot;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-github-issues--plans--prs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#2-github-issues--plans--prs&quot; aria-label=&quot;2 github issues  plans  prs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. GitHub issues → plans → PRs&lt;/h2&gt;
&lt;p&gt;The biggest upgrade: OpenClaw can hand off coding work to &lt;a href=&quot;https://cursor.com&quot;&gt;Cursor&lt;/a&gt; in the actual repo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;New issue on a client&apos;s product repo&lt;/li&gt;
&lt;li&gt;I get a Telegram ping&lt;/li&gt;
&lt;li&gt;Agent writes an implementation plan from the codebase&lt;/li&gt;
&lt;li&gt;Plan lands as a &lt;strong&gt;GitHub comment&lt;/strong&gt; — visible to the team, not buried in chat&lt;/li&gt;
&lt;li&gt;I approve → code gets written → PR opens&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I stopped burning the expensive model on every small check. Quick triage stays cheap; planning and coding use the heavy models only when it matters.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Keep planning in the repo and in GitHub. Telegram is for pings and decisions, not for hiding the plan.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-invoices--the-boring-work-i-avoided&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-invoices--the-boring-work-i-avoided&quot; aria-label=&quot;3 invoices  the boring work i avoided permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Invoices — the boring work I avoided&lt;/h2&gt;
&lt;p&gt;Invoice day used to mean copy-paste HTML, hunt for rates, second-guess tax wording, export PDF, upload, draft the cover email. Now I open the right Telegram topic and say &lt;em&gt;prepare the next invoice&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The agent already knows each client&apos;s rules — US vs German format, currency, VAT, layout. It pulls the last invoice as a template, bumps the number, fills in the period and line items, and asks me only what&apos;s missing. Output: PDF in Dropbox, email draft waiting — &lt;strong&gt;send only after I approve&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; Highest ROI automation I didn&apos;t mention in April. Repetitive, rule-heavy, easy to get wrong. Perfect for an agent with memory.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-seo-wordpress-compliance--one-prompt-one-artifact&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#4-seo-wordpress-compliance--one-prompt-one-artifact&quot; aria-label=&quot;4 seo wordpress compliance  one prompt one artifact permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;4. SEO, WordPress, compliance — one prompt, one artifact&lt;/h2&gt;
&lt;p&gt;April: basic memory and a few tools. July: the agent can talk to external services I use every week — SEO data, a client&apos;s WordPress blog, security scan reports.&lt;/p&gt;
&lt;p&gt;The pattern is always the same: one Telegram message, agent combines live data + code context, I get a dated deliverable (markdown, PDF, or issue comment). I wrote up the SEO workflow &lt;a href=&quot;/sistrix-mcp-hallocasa-seo&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; One integration per job you do manually more than once a month. Don&apos;t wire everything on day one.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;5-telegram-topics--project-switcher&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-telegram-topics--project-switcher&quot; aria-label=&quot;5 telegram topics  project switcher permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5. Telegram topics = project switcher&lt;/h2&gt;
&lt;p&gt;One group chat, many &lt;strong&gt;topics&lt;/strong&gt; — blog, US client, German client, side projects.&lt;/p&gt;
&lt;p&gt;Each topic loads the right context: which repo, which tone, which rules. I don&apos;t mix invoice talk with blog drafting in one thread.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; If your bot goes quiet in a group, check you&apos;re on a recent OpenClaw build. Forum topics had a reply bug that&apos;s fixed now.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;6-conference-talk-drafts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#6-conference-talk-drafts&quot; aria-label=&quot;6 conference talk drafts permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;6. Conference talk drafts&lt;/h2&gt;
&lt;p&gt;Between client work I still submit to AWS Community Days, AgentCon, CodeMotion, re:Invent. The agent keeps proposal drafts in a folder and knows the submission format.&lt;/p&gt;
&lt;p&gt;Typical flow: &lt;em&gt;draft a talk on security scanning for Poland Community Day&lt;/em&gt; → agent pulls from past project work and prior talks → title, abstract, outline ready to paste into the submission form → calendar reminder for the deadline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; CFP writing is research + structure + your voice. The agent does the first two; I keep the third.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;numbers-rough-three-months-in&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#numbers-rough-three-months-in&quot; aria-label=&quot;numbers rough three months in permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Numbers (rough, three months in)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; dozens of issues triaged; several fixes shipped via agent → Cursor → PR&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blog:&lt;/strong&gt; 4+ substantial posts with agent help (EN+DE pairs)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invoices:&lt;/strong&gt; 5+ US sprint invoices + German client invoices — PDF + email draft each time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CFP:&lt;/strong&gt; 10+ proposal drafts across Poland, DACH, Milan, re:Invent&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost:&lt;/strong&gt; picking the right model for the task matters more than VPS hosting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Failures:&lt;/strong&gt; one email sent too early → hard &quot;ask before send&quot; rule; morning briefing broke once after an update — fixed with a version bump and a cheaper scheduled job&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;whats-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-next&quot; aria-label=&quot;whats next permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Auto-implement after explicit GitHub approval&lt;/li&gt;
&lt;li&gt;Infra changes from chat (Hetzner work in progress)&lt;/li&gt;
&lt;li&gt;Quarterly VAT prep from the invoice folder — agent-assisted, accountant still reviews&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Three months ago OpenClaw was email, calendar, and GitHub pings. Now it&apos;s an &lt;strong&gt;orchestrator&lt;/strong&gt;: topics for context, Cursor for code, live integrations for data, the blog for content, invoices and talk drafts for the business side.&lt;/p&gt;
&lt;p&gt;Still on &lt;strong&gt;€10/mo &lt;a href=&quot;https://www.hostinger.com?REFERRALCODE=MARTINMUELLER&quot;&gt;Hostinger&lt;/a&gt; Docker&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you already run OpenClaw, what helped me most: &lt;strong&gt;hand off coding to Cursor&lt;/strong&gt;, &lt;strong&gt;one Telegram topic per client/project&lt;/strong&gt;, and &lt;strong&gt;one external integration per repetitive manual job&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/openclaw-eng&quot;&gt;Original OpenClaw post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/peachbase-global-brain&quot;&gt;PeachBase — shared memory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/sistrix-mcp-hallocasa-seo&quot;&gt;SISTRIX MCP case study&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openclaw.ai&quot;&gt;OpenClaw&lt;/a&gt; · &lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Questions or want help wiring your agent? &lt;a href=&quot;mailto:office@martinmueller.dev&quot;&gt;office@martinmueller.dev&lt;/a&gt; or &lt;a href=&quot;https://calendly.com/martinmueller_dev&quot;&gt;calendly.com/martinmueller_dev&lt;/a&gt;.&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/733e00b8638647b8c9505ed1eaf2e1c3/index.png</featuredImage><media:content url="https://martinmueller.dev/static/733e00b8638647b8c9505ed1eaf2e1c3/index.png" medium="image"/></item><item><title><![CDATA[Data-Driven SEO with the SISTRIX MCP: A HalloCasa Case Study]]></title><description><![CDATA[I co-founded HalloCasa — a global real estate broker directory with listings, profiles, subscriptions, and courses. Organic search should be…]]></description><link>https://martinmueller.dev/sistrix-mcp-hallocasa-seo/</link><guid isPermaLink="false">https://martinmueller.dev/sistrix-mcp-hallocasa-seo/</guid><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><category><![CDATA[mcp]]></category><category><![CDATA[seo]]></category><category><![CDATA[sistrix]]></category><category><![CDATA[hallocasa]]></category><category><![CDATA[cursor]]></category><category><![CDATA[ai]]></category><pubDate>Tue, 23 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/58a9ec8f7a8d18509cf2683457592bbc/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;I co-founded &lt;a href=&quot;https://hallocasa.com&quot;&gt;HalloCasa&lt;/a&gt; — a global real estate broker directory with listings, profiles, subscriptions, and courses. Organic search should be a major channel for us. But when I sat down to build an SEO strategy, I did not want to spend a day clicking through dashboards, exporting CSVs, and stitching screenshots into a doc.&lt;/p&gt;
&lt;p&gt;Instead I paired my AI &lt;strong&gt;Cursor&lt;/strong&gt; with the &lt;strong&gt;&lt;a href=&quot;https://www.sistrix.com/api/connection-to-chatbot-ai/&quot;&gt;SISTRIX MCP&lt;/a&gt;&lt;/strong&gt; and ran a full audit in one agent session: multi-market visibility baseline, ranking URLs, keyword opportunities, competitor overlap, backlink profile — cross-referenced against our Next.js codebase for canonical tags, hreflang, and sitemaps. The output was a prioritized roadmap, not gut feel.&lt;/p&gt;
&lt;p&gt;The whole thing started with one prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use the SISTRIX MCP to develop a sophisticated SEO strategy for &lt;a href=&quot;https://hallocasa.com/&quot;&gt;https://hallocasa.com/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No keyword spreadsheets, no elaborate system prompt — just the domain and the tool. From there the agent pulled SISTRIX data market by market, read our repo, and turned it into a strategy doc with prioritized tiers.&lt;/p&gt;
&lt;p&gt;This post is about that workflow: what SISTRIX and its MCP are, why MCP matters for SEO, and what the data actually told us about hallocasa.com.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-is-sistrix&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-sistrix&quot; aria-label=&quot;what is sistrix permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is SISTRIX?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.sistrix.com/&quot;&gt;SISTRIX&lt;/a&gt; is a German SEO platform widely used in the DACH market and beyond. Its headline metric is the &lt;strong&gt;Visibility Index (Sichtbarkeitsindex)&lt;/strong&gt; — a score derived from ranking positions and search volume across all keywords a domain ranks for. You also get keyword rankings, backlink data, competitor overlap, search intent, and (newer) AI visibility tooling.&lt;/p&gt;
&lt;p&gt;For a site like HalloCasa — global broker directory, LatAm-heavy country list, German expat content on the blog — SISTRIX is useful because you can slice by &lt;strong&gt;country&lt;/strong&gt; (&lt;code&gt;de&lt;/code&gt;, &lt;code&gt;us&lt;/code&gt;, &lt;code&gt;co&lt;/code&gt;, &lt;code&gt;es&lt;/code&gt;, &lt;code&gt;mx&lt;/code&gt;, …) and compare markets in one session instead of assuming one Google index fits all.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-mcp-for-seo-tools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-mcp-for-seo-tools&quot; aria-label=&quot;why mcp for seo tools permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why MCP for SEO tools?&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://modelcontextprotocol.io/&quot;&gt;Model Context Protocol (MCP)&lt;/a&gt; is an open standard that lets AI assistants call external tools through a unified interface. Without it, chatbots guess or hallucinate metrics. With it, they pull &lt;strong&gt;live data&lt;/strong&gt; from your SEO platform.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Without MCP&lt;/th&gt;
&lt;th&gt;With MCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tab-hopping, manual exports&lt;/td&gt;
&lt;td&gt;Agent queries live data in conversation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stale screenshots in strategy docs&lt;/td&gt;
&lt;td&gt;Reproducible, dated API pulls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEO analyst and developer in separate tools&lt;/td&gt;
&lt;td&gt;Agent cross-references rankings &lt;strong&gt;and&lt;/strong&gt; your repo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In &lt;strong&gt;Cursor → Settings → Tools &amp;#x26; MCP&lt;/strong&gt;, you wire the SISTRIX server once. The agent then calls tools like &lt;code&gt;domain_visindex&lt;/code&gt; or &lt;code&gt;keyword_domain_seo&lt;/code&gt; as part of normal chat — same as reading files or running terminal commands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Workflow (Cursor + SISTRIX MCP + codebase):&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;You&lt;/th&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Ask for SEO audit of your domain&lt;/td&gt;
&lt;td&gt;Calls SISTRIX MCP tools per market&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Point agent at your repo&lt;/td&gt;
&lt;td&gt;Reads &lt;code&gt;seo.ts&lt;/code&gt;, &lt;code&gt;MetaData.tsx&lt;/code&gt;, &lt;code&gt;robots.txt&lt;/code&gt;, sitemaps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Ask for strategy + priorities&lt;/td&gt;
&lt;td&gt;Synthesizes data + code findings into actionable doc&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;setting-up-the-sistrix-mcp&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#setting-up-the-sistrix-mcp&quot; aria-label=&quot;setting up the sistrix mcp permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setting up the SISTRIX MCP&lt;/h2&gt;
&lt;p&gt;SISTRIX ships an official MCP server. Docs and setup guides:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Main hub&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.sistrix.com/api/connection-to-chatbot-ai/&quot;&gt;Connection to AI with MCP&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth for all plans (2025+)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.sistrix.com/changelog/sistrix-mcp-servers/&quot;&gt;SISTRIX MCP Servers changelog&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technical reference&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.sistrix.com/api/connection-to-chatbot-ai/technical-information-mcp/&quot;&gt;Technical Information MCP&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChatGPT setup&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.sistrix.com/api/connection-to-chatbot-ai/setting-up-chatgpt/&quot;&gt;Setting up ChatGPT&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude setup&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.sistrix.com/api/connection-to-chatbot-ai/setting-up-claude/&quot;&gt;Setting up Claude&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Endpoint:&lt;/strong&gt; &lt;code&gt;https://api.sistrix.com/mcp/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Auth:&lt;/strong&gt; OAuth now works on &lt;strong&gt;all SISTRIX plans&lt;/strong&gt; — log in, no API key required. API keys still work on Plus+ if you prefer. Per &lt;a href=&quot;https://www.sistrix.com/api/connection-to-chatbot-ai/technical-information-mcp/&quot;&gt;SISTRIX docs&lt;/a&gt;, MCP requests currently &lt;strong&gt;do not consume API credits&lt;/strong&gt; (unlike direct API calls). For Cursor, configure the MCP server with the same endpoint plus OAuth or an API key in your MCP config.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;sistrix-mcp-tool-surface&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sistrix-mcp-tool-surface&quot; aria-label=&quot;sistrix mcp tool surface permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SISTRIX MCP tool surface&lt;/h2&gt;
&lt;p&gt;The MCP exposes dozens of tools. In the HalloCasa audit we leaned on these groups:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Example tools&lt;/th&gt;
&lt;th&gt;What you learn&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Domain visibility&lt;/td&gt;
&lt;td&gt;&lt;code&gt;domain_visindex&lt;/code&gt;, &lt;code&gt;domain_kwcount_seo&lt;/code&gt;, &lt;code&gt;domain_ranking_distribution&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Footprint per market, page-1 keyword count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keywords&lt;/td&gt;
&lt;td&gt;&lt;code&gt;keyword_domain_seo&lt;/code&gt;, &lt;code&gt;domain_opportunities&lt;/code&gt;, &lt;code&gt;keyword_seo_metrics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What ranks, near-wins, volume and intent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Competition&lt;/td&gt;
&lt;td&gt;&lt;code&gt;domain_competitors_seo&lt;/code&gt;, &lt;code&gt;domain_ideas&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Overlap and content gaps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Links&lt;/td&gt;
&lt;td&gt;&lt;code&gt;links_list&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toxic vs legitimate backlinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI visibility&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ai_entity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;AEO baseline (our HalloCasa entity call returned HTTP 500)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Projects&lt;/td&gt;
&lt;td&gt;&lt;code&gt;project_ranking&lt;/code&gt;, &lt;code&gt;project_visibilityindex&lt;/code&gt;, …&lt;/td&gt;
&lt;td&gt;Ongoing tracking once a project exists&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Pass &lt;strong&gt;&lt;code&gt;country&lt;/code&gt;&lt;/strong&gt; as an ISO code (&lt;code&gt;de&lt;/code&gt;, &lt;code&gt;us&lt;/code&gt;, &lt;code&gt;co&lt;/code&gt;, &lt;code&gt;es&lt;/code&gt;, &lt;code&gt;mx&lt;/code&gt;, …) to audit multiple markets in one session. That is how we discovered Germany has history while Colombia and Mexico have essentially zero visibility today.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hallocasa-case-study-what-the-data-showed&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hallocasa-case-study-what-the-data-showed&quot; aria-label=&quot;hallocasa case study what the data showed permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;HalloCasa case study: what the data showed&lt;/h2&gt;
&lt;p&gt;Domain: &lt;strong&gt;hallocasa.com&lt;/strong&gt;. The agent pulled SISTRIX data across our main markets (DE, US, ES, CO, MX).&lt;/p&gt;
&lt;h3 id=&quot;baseline-snapshot&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#baseline-snapshot&quot; aria-label=&quot;baseline snapshot permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Baseline snapshot&lt;/h3&gt;
&lt;p&gt;Germany is the only market with meaningful organic history — visibility has declined sharply since a peak a few years ago. The US and Spain show traces of activity (mostly blog content). Colombia and Mexico, despite being core business geography, had essentially no organic footprint at all.&lt;/p&gt;
&lt;p&gt;That mismatch between business focus and search visibility was the first big insight — and only visible because we queried per country instead of treating Google as one global index.&lt;/p&gt;
&lt;h3 id=&quot;where-rankings-actually-live&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#where-rankings-actually-live&quot; aria-label=&quot;where rankings actually live permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Where rankings actually live&lt;/h3&gt;
&lt;p&gt;Almost all SEO value sits on &lt;strong&gt;&lt;code&gt;blog.hallocasa.com&lt;/code&gt;&lt;/strong&gt;, mostly German articles about LatAm real estate (Chile, Colombia, Peru, Argentina, Mexico). The &lt;strong&gt;directory&lt;/strong&gt; (&lt;code&gt;www.hallocasa.com&lt;/code&gt;) barely ranks by comparison — a handful of broker-name profile queries and little else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Headline finding:&lt;/strong&gt; authority is stranded on a subdomain, not flowing to broker profiles and &lt;code&gt;/brokers&lt;/code&gt;. That is a structural problem, not a content gap.&lt;/p&gt;
&lt;h3 id=&quot;near-win-keywords-fastest-ranking-upside&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#near-win-keywords-fastest-ranking-upside&quot; aria-label=&quot;near win keywords fastest ranking upside permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Near-win keywords (fastest ranking upside)&lt;/h3&gt;
&lt;p&gt;SISTRIX &lt;code&gt;domain_opportunities&lt;/code&gt; surfaced several German keywords where we already rank on page 2 — cross-border investment and expat real estate topics with relatively low competition. Pushing those over the line to page 1 is lower effort than chasing new head terms.&lt;/p&gt;
&lt;h3 id=&quot;competitors-de-organic-overlap&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#competitors-de-organic-overlap&quot; aria-label=&quot;competitors de organic overlap permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Competitors (DE organic overlap)&lt;/h3&gt;
&lt;p&gt;The overlap set is a mix of large German property portals, international luxury listing sites, and niche expat/investment blogs. We are not competing on generic German portal head terms; our wedge is &lt;strong&gt;cross-border / expat investor&lt;/strong&gt; content.&lt;/p&gt;
&lt;h3 id=&quot;backlinks-mostly-noise&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#backlinks-mostly-noise&quot; aria-label=&quot;backlinks mostly noise permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Backlinks: mostly noise&lt;/h3&gt;
&lt;p&gt;The link profile is dominated by &lt;strong&gt;SEO directory and PBN spam&lt;/strong&gt;. Legitimate links exist but are sparse — partner podcasts, travel sites, conference media. Worth a GSC audit before any disavow; Google often ignores obvious spam automatically.&lt;/p&gt;
&lt;h3 id=&quot;code-cross-check-why-the-directory-does-not-rank&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code-cross-check-why-the-directory-does-not-rank&quot; aria-label=&quot;code cross check why the directory does not rank permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code cross-check: why the directory does not rank&lt;/h3&gt;
&lt;p&gt;The agent read our Next.js repo alongside SISTRIX URLs. Technical issues that explain weak directory visibility:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;i18n via &lt;code&gt;?lang=&lt;/code&gt;&lt;/strong&gt; on the directory, but &lt;strong&gt;canonical URLs strip the query&lt;/strong&gt; — all nine locales collapse to one indexable URL per path.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No &lt;code&gt;hreflang&lt;/code&gt;&lt;/strong&gt; anywhere; blog and home use path locales (&lt;code&gt;/de/&lt;/code&gt;, &lt;code&gt;/es/&lt;/code&gt;), apex uses query locales.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fragmented architecture:&lt;/strong&gt; &lt;code&gt;blog.&lt;/code&gt;, &lt;code&gt;home.&lt;/code&gt;, and apex as separate properties; blog holds the rankings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fixing international SEO and consolidating blog authority onto the main domain are foundation work before scaling content in CO/MX.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;prioritized-roadmap-90-day-lens&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#prioritized-roadmap-90-day-lens&quot; aria-label=&quot;prioritized roadmap 90 day lens permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Prioritized roadmap (90-day lens)&lt;/h2&gt;
&lt;p&gt;From the audit we tiered actions by effort vs impact:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P0 — do first (weeks 1–4)&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GSC domain property + baseline KPIs&lt;/td&gt;
&lt;td&gt;Cannot measure without it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;www&lt;/code&gt; canonical + 301 all host variants&lt;/td&gt;
&lt;td&gt;Stops split link equity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blog → directory CTAs on top DE posts&lt;/td&gt;
&lt;td&gt;Rankings exist; directory gets no traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-link blog ↔ &lt;code&gt;/brokers&lt;/code&gt; ↔ profiles&lt;/td&gt;
&lt;td&gt;Partial authority transfer without migration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;P1 — highest SEO upside (weeks 4–16)&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Optimize near-win DE blog posts&lt;/td&gt;
&lt;td&gt;Fastest ranking wins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blog → &lt;code&gt;/blog/&lt;/code&gt; subfolder consolidation&lt;/td&gt;
&lt;td&gt;Biggest structural lift for directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Path locales + &lt;code&gt;hreflang&lt;/code&gt; on apex&lt;/td&gt;
&lt;td&gt;Required before ES/EN scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DE pillar hub for cross-border investment&lt;/td&gt;
&lt;td&gt;Captures commercial intent cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;P3 — long bets&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Spanish LatAm programmatic pages (CO/MX) only when broker inventory supports it — empty city templates would be thin-content risk.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;how-to-replicate-this-workflow&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-replicate-this-workflow&quot; aria-label=&quot;how to replicate this workflow permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to replicate this workflow&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Wire SISTRIX MCP in Cursor&lt;/strong&gt; — endpoint &lt;code&gt;https://api.sistrix.com/mcp/&lt;/code&gt;, &lt;a href=&quot;https://www.sistrix.com/api/connection-to-chatbot-ai/&quot;&gt;setup docs&lt;/a&gt;, OAuth or API key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open with a clear ask&lt;/strong&gt; — e.g. &lt;em&gt;Use the SISTRIX MCP to develop a sophisticated SEO strategy for &lt;a href=&quot;https://hallocasa.com/&quot;&gt;https://hallocasa.com/&lt;/a&gt;&lt;/em&gt; (that was my entire starting prompt).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ask for multi-market baseline&lt;/strong&gt; — &lt;code&gt;domain_visindex&lt;/code&gt; and &lt;code&gt;domain_kwcount_seo&lt;/code&gt; per country.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pull ranking URLs&lt;/strong&gt; — &lt;code&gt;keyword_domain_seo&lt;/code&gt; to see which subdomain or path actually ranks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pull opportunities, competitors, backlinks&lt;/strong&gt; — &lt;code&gt;domain_opportunities&lt;/code&gt;, &lt;code&gt;domain_competitors_seo&lt;/code&gt;, &lt;code&gt;links_list&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit your codebase&lt;/strong&gt; — canonicals, hreflang, robots, sitemaps, i18n patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synthesize&lt;/strong&gt; — strategy doc with prioritized tiers, not a data dump.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;sample-deliverable-hallocasa-seo-strategy-pdf&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sample-deliverable-hallocasa-seo-strategy-pdf&quot; aria-label=&quot;sample deliverable hallocasa seo strategy pdf permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sample deliverable: HalloCasa SEO strategy (PDF)&lt;/h3&gt;
&lt;p&gt;The agent session produced a full strategy document — baseline by market, competitor overlap, technical findings from our Next.js repo, and a P0–P3 roadmap. We exported it as PDF for stakeholders (&lt;code&gt;pandoc&lt;/code&gt; + headless Chrome from the markdown in &lt;a href=&quot;https://github.com/hallocasacom/hallocasa-next/tree/main/misc/seo&quot;&gt;&lt;code&gt;hallocasa-next/misc/seo&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;hallocasa-seo-strategy.pdf&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 141.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAYAAABh2p9gAAAACXBIWXMAAAsTAAALEwEAmpwYAAACs0lEQVR42u1W2WrcQBD0//9NIDiEPIWQl5ATYhucbLy73tXu6j5Gx4yOSnVLezkkOOBHDxStmdHUdFd3C13gMAYMAyaMz/vRdR3attX1XvdONh+MC6WSF/sBHa3r+gNh4zpYoqobdCR8zFBCL65w+WmNV5/XeHu1wyXtl18xXny4x/sbH++ufbz5tsHrrx5eflwhyJoxpuEvhL2zaKJQYeMQJvDP5k0UwPi+YrNYow4DDFmEPp2QhBhadyQ0poTnbbENM/iJQd1YOMtLaPu+/3eMe+FPPUySDN+vb/FjtsDKoxe7EFs/wnK1hR/ESNIcUZyippaNdYRVWzcN3ANtx5B7Cl9VsHyhpeuOEggsD1ZVrUkpJ1tPGNdrEropicOR0LY9osIhyBtFVFj4FD6rHP53KGHVtFj6OZZBoXYdFljscniRocfdH5AwBW03zqXkhlNCCS2OE2opSBFFMTWLEYQRvG1AhPBU1xF+EGFHjf0wVo2z3JwTFszy7WyJ2XyF+b2nCVl5Oyz4vFhtcLdcq71fb7m2RsQkypm8MEQJU1bnGsrmbH7PrG7oja83r+mZHAzECyJklmPOxTvJuM6Z/TjNNGH78hrrkDcImc8QC97qqIvUourlWkU76Wad07m17rB32jFK2NgWs7slrm6kFueqnRAnvD3NchiGlWTFGGKeEwVS7hUacqF1LB+QkzocsAso/Gan4UhipHuk7nJTqU4ZUZaVEogVMlOWaqUuzzzsSLhi693+vFNSuV28UPBASu8KHs44z+ixaC6k6RSBhH9GKFoJ0YLZFC0lw0VZw0g3UEvpiIZdZCYi6ZJ9x0i/78M9ashFCVVuy8uxQxJjkZaOc0uPzBjiVCryXslWPX6acV6Hh9XD5vCoNtv38PCw9Z5yPBM+E57W3FMSjn8W/aMIfwPoPIuJXKFTuQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/4abf698dc1a265011de19014801af430/f1512/hallocasa-seo-strategy-preview.webp 200w,
/static/4abf698dc1a265011de19014801af430/f59aa/hallocasa-seo-strategy-preview.webp 400w,
/static/4abf698dc1a265011de19014801af430/47a22/hallocasa-seo-strategy-preview.webp 800w,
/static/4abf698dc1a265011de19014801af430/82a5c/hallocasa-seo-strategy-preview.webp 849w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/4abf698dc1a265011de19014801af430/f8f3a/hallocasa-seo-strategy-preview.png 200w,
/static/4abf698dc1a265011de19014801af430/6a8a8/hallocasa-seo-strategy-preview.png 400w,
/static/4abf698dc1a265011de19014801af430/7842b/hallocasa-seo-strategy-preview.png 800w,
/static/4abf698dc1a265011de19014801af430/bd185/hallocasa-seo-strategy-preview.png 849w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/4abf698dc1a265011de19014801af430/7842b/hallocasa-seo-strategy-preview.png&quot;
            alt=&quot;HalloCasa SEO strategy — first page preview&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;hallocasa-seo-strategy.pdf&quot;&gt;Download PDF&lt;/a&gt; · &lt;a href=&quot;https://github.com/hallocasacom/hallocasa-next/blob/main/misc/seo/SEO_STRATEGY.md&quot;&gt;View markdown source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Want something similar for your domain?&lt;/strong&gt; I help teams run the same SISTRIX MCP + codebase audit workflow and turn it into a prioritized strategy doc like this. &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88/&quot;&gt;Reach out on LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;takeaways-for-other-sites&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#takeaways-for-other-sites&quot; aria-label=&quot;takeaways for other sites permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Takeaways for other sites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP turns SEO from dashboard archaeology into agent-native research.&lt;/strong&gt; The agent pulls live SISTRIX data while you stay in the editor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best results when the agent can read your repo too.&lt;/strong&gt; Rankings tell you &lt;em&gt;what&lt;/em&gt; ranks; code tells you &lt;em&gt;why&lt;/em&gt; fixes are hard or easy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-subdomain setups need an explicit architecture decision&lt;/strong&gt; — consolidate (e.g. blog → &lt;code&gt;/blog/&lt;/code&gt;) or cross-link heavily; do not assume authority transfers by default.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prioritize near-win keywords&lt;/strong&gt; before greenfield programmatic SEO or nine-locale translation sprees.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Match market data to business focus.&lt;/strong&gt; We had almost no visibility in CO/MX despite LatAm being core geography — that mismatch only shows up when you query per country.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-is-next-for-hallocasa&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-next-for-hallocasa&quot; aria-label=&quot;what is next for hallocasa permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is next for HalloCasa&lt;/h2&gt;
&lt;p&gt;This post is about the &lt;strong&gt;research method&lt;/strong&gt; — but the audit gave us a clear roadmap, and I am excited to implement it: P0 fixes first, then the DE near-win posts and blog consolidation. SISTRIX will stay in the loop for ongoing tracking, not just this one-off session.&lt;/p&gt;
&lt;p&gt;The same MCP setup opens &lt;strong&gt;GEO&lt;/strong&gt; (Generative Engine Optimization): SISTRIX’s AI visibility tools (&lt;code&gt;ai_entity&lt;/code&gt;, and related project tooling) let us baseline how HalloCasa shows up in AI answers and measure lift as we fix structure and content. Our first &lt;code&gt;ai_entity&lt;/code&gt; call hit a 500 — worth retrying once the foundation work lands.&lt;/p&gt;
&lt;p&gt;I am co-founder of HalloCasa and use MCP heavily elsewhere in my stack (see &lt;a href=&quot;/openclaw-eng&quot;&gt;How I Use OpenClaw&lt;/a&gt; for another angle on agent tooling). If you want help wiring SISTRIX MCP in Cursor or running a similar audit on your domain, reach out on &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88/&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://www.linkedin.com/in/benedikt-rudolf&quot;&gt;Benedikt Rudolf&lt;/a&gt; at SISTRIX for taking the time to walk me through the MCP — that conversation kicked off this workflow.&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/58a9ec8f7a8d18509cf2683457592bbc/index.png</featuredImage><media:content url="https://martinmueller.dev/static/58a9ec8f7a8d18509cf2683457592bbc/index.png" medium="image"/></item><item><title><![CDATA[Built with Lovable? Host Prod in Germany & DACH on Hetzner]]></title><description><![CDATA[You built on Lovable — React app, Supabase auth, Postgres. It works. Then your first DACH customer or pilot asks: Where is prod hosted…]]></description><link>https://martinmueller.dev/lovable-hetzner-germany/</link><guid isPermaLink="false">https://martinmueller.dev/lovable-hetzner-germany/</guid><category><![CDATA[lovable]]></category><category><![CDATA[hetzner]]></category><category><![CDATA[supabase]]></category><category><![CDATA[netlify]]></category><category><![CDATA[dach]]></category><category><![CDATA[germany]]></category><category><![CDATA[austria]]></category><category><![CDATA[switzerland]]></category><category><![CDATA[eu-hosting]]></category><category><![CDATA[gdpr]]></category><category><![CDATA[opensource]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/dc3b5ab126bd0a1ae278341c4686f940/index.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;You built on &lt;strong&gt;Lovable&lt;/strong&gt; — React app, Supabase auth, Postgres. It works. Then your first &lt;strong&gt;DACH&lt;/strong&gt; customer or pilot asks: &lt;em&gt;Where is prod hosted? Where do login and data live?&lt;/em&gt; That question shows up fast in &lt;strong&gt;Germany&lt;/strong&gt;, &lt;strong&gt;Austria&lt;/strong&gt;, and &lt;strong&gt;Switzerland&lt;/strong&gt; B2B — especially HR, health, finance, and anything that touches procurement or a security questionnaire.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-eu-is-fine-is-not-enough-in-dach&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-eu-is-fine-is-not-enough-in-dach&quot; aria-label=&quot;why eu is fine is not enough in dach permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why “EU is fine” is not enough in DACH&lt;/h2&gt;
&lt;p&gt;Lovable’s default path — &lt;strong&gt;Netlify&lt;/strong&gt; (or similar) plus &lt;strong&gt;managed Supabase&lt;/strong&gt; — is great for building. It is not always enough for &lt;strong&gt;prod you can point to&lt;/strong&gt; in a buyer review.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Germany&lt;/strong&gt; — GDPR, vendor questionnaires, and “EU hosting” often means &lt;em&gt;nameable EU infrastructure&lt;/em&gt;, not “we use a US cloud somewhere in eu-west-1.”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Austria&lt;/strong&gt; — Same GDPR frame; many buyers mirror German expectations on data location and subprocessors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Switzerland&lt;/strong&gt; — Not in the EU/GDPR, but strong privacy expectations (revDSG). &lt;strong&gt;Hetzner&lt;/strong&gt; — German company, EU datacenters — is a credible answer for many Swiss buyers without overclaiming compliance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is not legal advice. It is the practical friction you hit when DACH customers want a clear answer on &lt;strong&gt;where prod runs&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;phased-prod-on-hetzner--dev-stays-on-lovable&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#phased-prod-on-hetzner--dev-stays-on-lovable&quot; aria-label=&quot;phased prod on hetzner  dev stays on lovable permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Phased prod on Hetzner — dev stays on Lovable&lt;/h2&gt;
&lt;p&gt;You do &lt;strong&gt;not&lt;/strong&gt; need a big-bang migration. In a recent &lt;a href=&quot;/hetzner-eu-production&quot;&gt;German-client case study&lt;/a&gt;, &lt;strong&gt;dev&lt;/strong&gt; stayed on Netlify + managed Supabase while &lt;strong&gt;prod&lt;/strong&gt; — app, login, Postgres — went live on &lt;strong&gt;Hetzner&lt;/strong&gt; in the EU. Same pattern fits Lovable stacks: keep building in Lovable; add a &lt;strong&gt;DACH-facing prod environment&lt;/strong&gt; on EU VMs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-eu-production&quot;&gt;Production on Hetzner (Part 1)&lt;/a&gt; — phased EU prod, OpenTofu, CI deploys, self-hosted Supabase&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-self-hosted-insights&quot;&gt;Self-hosted insights (Part 2)&lt;/a&gt; — observability, cost guardrails, EU telemetry&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prod users hit the React app on Hetzner. Sign-in and Postgres for prod stay on Hetzner too. Dev keeps using Lovable’s stack unchanged.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 27%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAx0lEQVR42kVP0U7EQAjs/3+d78YHjaetZ/e62wUG2G1lq4kTQggDwzD13o/jQHVDO1rv7Q99RG/e3N3M2j+CcU5PRrfpdzl/KRWdZU2cXZ0VGXWTPToUqAyARRRqUAi0vDtv0z3JTvJIiZie5TZLMtgnr3c8xLSEplAGfSO/ylJAq+YKspmsYNIaUppSqjwmCqqpkXJccQvHvtm+GxWjHBn0Ih+rbL4UU53O8wzb8ZV7a9f0qK9CLXQuxsYjIS0ib7xk7AeP5g9cZyDrGx/EfwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/c33ad5e2b37017b1c9f7f2c998f10fa7/f1512/architecture.webp 200w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/f59aa/architecture.webp 400w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/47a22/architecture.webp 800w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/5bb53/architecture.webp 1200w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/485a2/architecture.webp 1600w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/d0fcf/architecture.webp 7734w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/c33ad5e2b37017b1c9f7f2c998f10fa7/f8f3a/architecture.png 200w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/6a8a8/architecture.png 400w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/7842b/architecture.png 800w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/5ece7/architecture.png 1200w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/0d4f8/architecture.png 1600w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/5cc8a/architecture.png 7734w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/c33ad5e2b37017b1c9f7f2c998f10fa7/7842b/architecture.png&quot;
            alt=&quot;Lovable prod architecture on Hetzner in the EU&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;open-source-stack--no-black-box-prod&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#open-source-stack--no-black-box-prod&quot; aria-label=&quot;open source stack  no black box prod permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Open source stack — no black box prod&lt;/h2&gt;
&lt;p&gt;DACH buyers often ask not only &lt;em&gt;where&lt;/em&gt; data lives but &lt;em&gt;what software runs there&lt;/em&gt;. The prod path we use is built on &lt;strong&gt;open source&lt;/strong&gt; you can name, audit, and run yourself — not a proprietary PaaS you cannot inspect.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Open source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Infra as code&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/opentofu.svg&quot; alt=&quot;&quot;&gt; &lt;a href=&quot;https://opentofu.org/&quot;&gt;OpenTofu (an open-source fork of Terraform)&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App runtime&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/react.svg&quot; alt=&quot;&quot;&gt; React (from Lovable)&lt;/span&gt;, &lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/nginx.svg&quot; alt=&quot;&quot;&gt; nginx&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth + API + DB&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/supabase.svg&quot; alt=&quot;&quot;&gt; &lt;a href=&quot;https://github.com/supabase/supabase&quot;&gt;Supabase&lt;/a&gt; (self-hosted)&lt;/span&gt;, &lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/postgresql.svg&quot; alt=&quot;&quot;&gt; Postgres&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/grafana.svg&quot; alt=&quot;&quot;&gt; &lt;a href=&quot;https://grafana.com/oss/&quot;&gt;Grafana&lt;/a&gt;&lt;/span&gt;, &lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/prometheus.svg&quot; alt=&quot;&quot;&gt; Prometheus&lt;/span&gt;, &lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/loki.svg&quot; alt=&quot;&quot;&gt; Loki&lt;/span&gt;, &lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/tempo.svg&quot; alt=&quot;&quot;&gt; Tempo&lt;/span&gt;, &lt;span class=&quot;tool-item&quot;&gt;&lt;img src=&quot;/lovable-hetzner-germany/icons/opentelemetry.svg&quot; alt=&quot;&quot;&gt; &lt;a href=&quot;https://opentelemetry.io/&quot;&gt;OpenTelemetry&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That matters in security reviews: subprocessors and components are identifiable. You are not locked into a single vendor’s managed layer for prod. Hetzner gives you VMs; the stack on top stays portable and forkable.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-i-handle-vs-what-you-keep-doing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-i-handle-vs-what-you-keep-doing&quot; aria-label=&quot;what i handle vs what you keep doing permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What I handle vs what you keep doing&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; keep shipping features in Lovable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; OpenTofu (servers, firewall, DNS), GitHub Actions deploys, &lt;strong&gt;self-hosted open-source Supabase&lt;/strong&gt; on prod VMs, and &lt;strong&gt;self-hosted observability&lt;/strong&gt; (Grafana LGTM, cost alerts) — the documentation DACH buyers often ask for: where data lives, what runs there, who operates prod, what it costs.&lt;/p&gt;
&lt;p&gt;I work with &lt;strong&gt;DACH clients&lt;/strong&gt; on exactly this path. If that sounds like your next step, reach out.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;mailto:office@martinmueller.dev&quot;&gt;office@martinmueller.dev&lt;/a&gt; · &lt;a href=&quot;https://calendly.com/martinmueller_dev&quot;&gt;calendly.com/martinmueller_dev&lt;/a&gt; · &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;further-reading&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#further-reading&quot; aria-label=&quot;further reading permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-eu-production&quot;&gt;Production on Hetzner for a German client (Part 1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/hetzner-self-hosted-insights&quot;&gt;Self-hosted insights on Hetzner (Part 2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/dc3b5ab126bd0a1ae278341c4686f940/index.jpg</featuredImage><media:content url="https://martinmueller.dev/static/dc3b5ab126bd0a1ae278341c4686f940/index.jpg" medium="image"/></item><item><title><![CDATA[Production on Hetzner for a German Client — EU Hosting (Part 1)]]></title><description><![CDATA[Part 2: Self-hosted insights on Hetzner A German client needed production in the EU on Hetzner — clear control over where customer data and…]]></description><link>https://martinmueller.dev/hetzner-eu-production/</link><guid isPermaLink="false">https://martinmueller.dev/hetzner-eu-production/</guid><category><![CDATA[hetzner]]></category><category><![CDATA[supabase]]></category><category><![CDATA[netlify]]></category><category><![CDATA[opentofu]]></category><category><![CDATA[devops]]></category><category><![CDATA[case-study]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Fri, 05 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/b4a74d54422b38ecaa76ee1226f66427/index.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;&lt;strong&gt;Part 2:&lt;/strong&gt; &lt;a href=&quot;/hetzner-self-hosted-insights&quot;&gt;Self-hosted insights on Hetzner&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;German client&lt;/strong&gt; needed &lt;strong&gt;production in the EU on Hetzner&lt;/strong&gt; — clear control over where customer data and login live. The product is &lt;strong&gt;Arc Rider Universe&lt;/strong&gt;: the SaaS behind &lt;a href=&quot;https://universe.arc-rider.com/&quot;&gt;universe.arc-rider.com&lt;/a&gt; — &lt;em&gt;Mission: Interface&lt;/em&gt;, a UI toolkit for builders (tables, Kanban, Gantt, layouts, and more via JSON instead of hand-rolled UI code). &lt;strong&gt;Dev&lt;/strong&gt; already ran happily on &lt;strong&gt;Netlify&lt;/strong&gt; and &lt;strong&gt;managed Supabase&lt;/strong&gt; — and still does. The goal was a &lt;strong&gt;dedicated prod environment on Hetzner&lt;/strong&gt;, not a big-bang migration that would slow down the team.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;why-hetzner-and-why-not-move-everything-at-once&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-hetzner-and-why-not-move-everything-at-once&quot; aria-label=&quot;why hetzner and why not move everything at once permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why Hetzner, and why not “move everything at once”&lt;/h2&gt;
&lt;p&gt;The client is in Germany. &lt;strong&gt;Prod&lt;/strong&gt; had to sit on &lt;strong&gt;EU infrastructure they can point to&lt;/strong&gt; — Hetzner VMs for the app and the database.&lt;/p&gt;
&lt;p&gt;That did &lt;strong&gt;not&lt;/strong&gt; mean touching dev:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://dev.universe.arc-rider.com/&quot;&gt;dev.universe.arc-rider.com&lt;/a&gt;&lt;/strong&gt; (dev) stays on &lt;strong&gt;Netlify&lt;/strong&gt; + &lt;strong&gt;managed Supabase&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prod&lt;/strong&gt; — app, login, Postgres — runs on &lt;strong&gt;Hetzner&lt;/strong&gt; at &lt;a href=&quot;https://universe.arc-rider.com&quot;&gt;universe.arc-rider.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are planning something similar: you can add EU prod on Hetzner &lt;strong&gt;in one weekend&lt;/strong&gt; — &lt;strong&gt;without&lt;/strong&gt; replatforming dev.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-prod-looks-like-in-plain-terms&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-prod-looks-like-in-plain-terms&quot; aria-label=&quot;what prod looks like in plain terms permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What prod looks like (in plain terms)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Prod users&lt;/strong&gt; open the React app on Hetzner. Sign-in and data for prod live on Hetzner too. Dev keeps using Netlify and managed Supabase unchanged.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 27%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAx0lEQVR42kVP0U7EQAjs/3+d78YHjaetZ/e62wUG2G1lq4kTQggDwzD13o/jQHVDO1rv7Q99RG/e3N3M2j+CcU5PRrfpdzl/KRWdZU2cXZ0VGXWTPToUqAyARRRqUAi0vDtv0z3JTvJIiZie5TZLMtgnr3c8xLSEplAGfSO/ylJAq+YKspmsYNIaUppSqjwmCqqpkXJccQvHvtm+GxWjHBn0Ih+rbL4UU53O8wzb8ZV7a9f0qK9CLXQuxsYjIS0ib7xk7AeP5g9cZyDrGx/EfwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/c33ad5e2b37017b1c9f7f2c998f10fa7/f1512/architecture.webp 200w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/f59aa/architecture.webp 400w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/47a22/architecture.webp 800w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/5bb53/architecture.webp 1200w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/485a2/architecture.webp 1600w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/d0fcf/architecture.webp 7734w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/c33ad5e2b37017b1c9f7f2c998f10fa7/f8f3a/architecture.png 200w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/6a8a8/architecture.png 400w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/7842b/architecture.png 800w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/5ece7/architecture.png 1200w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/0d4f8/architecture.png 1600w,
/static/c33ad5e2b37017b1c9f7f2c998f10fa7/5cc8a/architecture.png 7734w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/c33ad5e2b37017b1c9f7f2c998f10fa7/7842b/architecture.png&quot;
            alt=&quot;Arc Rider prod architecture on Hetzner&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Infra and deploys are automated with &lt;strong&gt;OpenTofu&lt;/strong&gt; (servers, firewall, DNS) and &lt;strong&gt;GitHub Actions&lt;/strong&gt; (build, deploy, quick smoke checks after a release).&lt;/p&gt;
&lt;p&gt;Once prod was stable, we added &lt;strong&gt;self-hosted observability&lt;/strong&gt; on a dedicated VM — metrics, logs, traces, cost guardrails, and agent-friendly ops. See &lt;a href=&quot;/hetzner-self-hosted-insights&quot;&gt;Part 2&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-we-learned-short-version&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-we-learned-short-version&quot; aria-label=&quot;what we learned short version permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What we learned (short version)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phased beats big bang&lt;/strong&gt; — dev stayed on Netlify + managed Supabase while Hetzner prod came online.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted login is not a copy-paste from cloud Supabase&lt;/strong&gt; — prod OAuth and magic links need prod-specific URLs and config; dev config stays separate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Predictable cost and EU hosting&lt;/strong&gt; — VMs on Hetzner for app, login, and data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prod is live at &lt;a href=&quot;https://universe.arc-rider.com&quot;&gt;universe.arc-rider.com&lt;/a&gt;. For this product stage, the tradeoff worked: &lt;strong&gt;control where it mattered&lt;/strong&gt; on EU infrastructure the client can point to.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hetzner-migrations--how-i-can-help&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hetzner-migrations--how-i-can-help&quot; aria-label=&quot;hetzner migrations  how i can help permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hetzner migrations — how I can help&lt;/h2&gt;
&lt;p&gt;On &lt;strong&gt;Netlify&lt;/strong&gt;, &lt;strong&gt;managed Supabase&lt;/strong&gt;, or &lt;strong&gt;AWS&lt;/strong&gt; for dev and need &lt;strong&gt;prod in the EU on Hetzner&lt;/strong&gt;? I help with planning, OpenTofu, CI deploys, self-hosted Supabase on prod VMs, and &lt;strong&gt;self-hosted observability&lt;/strong&gt; (Grafana LGTM, Alloy, cost guardrails, Grafana MCP for agent-friendly ops).&lt;/p&gt;
&lt;p&gt;Built with &lt;a href=&quot;/lovable-hetzner-germany&quot;&gt;Lovable&lt;/a&gt; for Germany/DACH? Same phased EU-prod path.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;mailto:office@martinmueller.dev&quot;&gt;office@martinmueller.dev&lt;/a&gt; · &lt;a href=&quot;https://calendly.com/martinmueller_dev&quot;&gt;calendly.com/martinmueller_dev&lt;/a&gt; · &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;further-reading&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#further-reading&quot; aria-label=&quot;further reading permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://community.hetzner.com/tutorials/howto-hcloud-s3-terraform-backend/&quot;&gt;Hetzner: Object Storage as OpenTofu backend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://supabase.com/docs/guides/self-hosting/docker&quot;&gt;Supabase self-hosting (Docker)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/b4a74d54422b38ecaa76ee1226f66427/index.jpg</featuredImage><media:content url="https://martinmueller.dev/static/b4a74d54422b38ecaa76ee1226f66427/index.jpg" medium="image"/></item><item><title><![CDATA[Self-Hosted Insights on Hetzner — Observability, Cost, AI Agents (Part 2)]]></title><description><![CDATA[Part 1: EU production on Hetzner After prod went live on Hetzner — React app, self-hosted Supabase login, Postgres on EU VMs; dev still on…]]></description><link>https://martinmueller.dev/hetzner-self-hosted-insights/</link><guid isPermaLink="false">https://martinmueller.dev/hetzner-self-hosted-insights/</guid><category><![CDATA[hetzner]]></category><category><![CDATA[grafana]]></category><category><![CDATA[observability]]></category><category><![CDATA[opentelemetry]]></category><category><![CDATA[mcp]]></category><category><![CDATA[ai-agents]]></category><category><![CDATA[devops]]></category><category><![CDATA[case-study]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Fri, 05 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/aed42448c77e6298ddc3f02be5fcc85c/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;&lt;strong&gt;Part 1:&lt;/strong&gt; &lt;a href=&quot;/hetzner-eu-production&quot;&gt;EU production on Hetzner&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After &lt;a href=&quot;/hetzner-eu-production&quot;&gt;prod went live on Hetzner&lt;/a&gt; — React app, self-hosted Supabase login, Postgres on EU VMs; dev still on Netlify + managed Supabase — we added &lt;strong&gt;self-hosted observability&lt;/strong&gt; on a dedicated prod VM. Metrics, logs, traces, and cost data stay in the EU. No third-party APM SaaS. Then we wired &lt;strong&gt;AI agents&lt;/strong&gt; to query prod through Grafana MCP instead of SSH guesswork.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;insights-without-leaving-the-eu&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#insights-without-leaving-the-eu&quot; aria-label=&quot;insights without leaving the eu permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Insights without leaving the EU&lt;/h2&gt;
&lt;p&gt;We added &lt;strong&gt;self-hosted observability&lt;/strong&gt; on Hetzner: OpenTelemetry ingest, &lt;strong&gt;Grafana LGTM&lt;/strong&gt; (Prometheus, Loki, Tempo), and &lt;strong&gt;Grafana Alloy&lt;/strong&gt; agents on the static and Supabase VMs. Browser &lt;strong&gt;RUM&lt;/strong&gt; and &lt;strong&gt;edge-function&lt;/strong&gt; traces and logs export to the same stack — nothing leaves the EU for “how is prod doing?”&lt;/p&gt;
&lt;p&gt;Provisioned dashboards (git → redeploy):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dashboard&lt;/th&gt;
&lt;th&gt;What it shows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data health&lt;/td&gt;
&lt;td&gt;Are metrics, logs, and traces flowing?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prod Overview&lt;/td&gt;
&lt;td&gt;High-level prod health&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure USE&lt;/td&gt;
&lt;td&gt;CPU, memory, disk on VMs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nginx RED&lt;/td&gt;
&lt;td&gt;Request rate, errors, duration from JSON access logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supabase Docker&lt;/td&gt;
&lt;td&gt;Container health on the API VM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Postgres&lt;/td&gt;
&lt;td&gt;Connections, query stats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend RUM&lt;/td&gt;
&lt;td&gt;Browser traces (Tempo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edge Functions&lt;/td&gt;
&lt;td&gt;Edge traces + app logs in Loki&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Why this matters for clients:&lt;/strong&gt; you get Datadog-class visibility without shipping telemetry to US SaaS or guessing from SSH. Dashboards and alert rules live in git; Google OAuth gates the Grafana UI.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;predictable-cost-watched-automatically&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#predictable-cost-watched-automatically&quot; aria-label=&quot;predictable cost watched automatically permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Predictable cost, watched automatically&lt;/h2&gt;
&lt;p&gt;Hetzner pricing is transparent — but three VMs, backups, primary IPs, and volumes still add up. We wired a &lt;strong&gt;Production Costs&lt;/strong&gt; dashboard that pulls &lt;strong&gt;live Hetzner API pricing&lt;/strong&gt; into Prometheus (&lt;code&gt;arc_infra_cost_eur_monthly&lt;/code&gt;): per-server, backup, volume, and primary IP breakdown, plus total monthly and annual projection.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 58.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAACYUlEQVR42pVT227TQBD1K5eSxE5824t315c4TuOkSVvaSqUgJC4PFS8VohJqEapE81IqPoEfP8xsVSHxxsN4x+OZ45kzZ4NMGIRR+mDjFEmmIJTDJBYUSxBNMsSpRJoXCMMUkyT3uRybtj0KW0NIC+umvi5QrkLR1tB1RUUauTSQRQk3b1E0JVJRgH/Kefvnh2jWHTJZUNzQaaFMBUNgnBdnkgBtSYUOqrTIVAFROIhcQjiL1NTIdYGEujOzCvOzHqakfGsxSRWZgCbApl1A6hK2bBEYekjbIZUPHQptkHfHWJ2tsFkmVMQdW4pX0LZFM1tg0R+gnu56oNl8z4NlyvjOA27d9a+hmzVi8k0m8OboFt3bD7j58gwnBwKuWWFKQO18BVd3BNp7a7sedTuHq5gemsYYBEx6GE0QRTFeTHIsMovfsUbwVOJwI3D5aYxx1qAgDiXRYU2Hyq1g7QrG7mEcNxiEFURFgJYAB8MxhqMYozDGkPyQeLkfl7hdSny/HmG5KxEmvARFm1U4vTjFxd17XG7P8OP+FX7+OsbdtsX+AXGvFQKhiOBE0J9yb7GgTQuHk1YSTxJRYvzmhXYkKY3Nxw3eXR3h/Osan6+XuPrWYXtTY7220AV1WJRTlA3xUM/AviCCWTZhZkgGtHkCy0lfmvTG/jiSGA0EBkOJnYHC84HGkx1NE/D2GwScyGQv1y9R1p0v4m5yD2T+vtMkGWmNT6Etbdb5k1UhSVrchKXlBCzMKW1s3m98F1ysSH9e0ATGJ+fwt8fYv8ZxnoxvS8BitK71YzOffPVYj/9rjzfsD9/XUDb+uQX9AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/f1512/grafana-dashboard.webp 200w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/f59aa/grafana-dashboard.webp 400w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/47a22/grafana-dashboard.webp 800w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/5bb53/grafana-dashboard.webp 1200w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/485a2/grafana-dashboard.webp 1600w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/cb46b/grafana-dashboard.webp 3484w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/f8f3a/grafana-dashboard.png 200w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/6a8a8/grafana-dashboard.png 400w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/7842b/grafana-dashboard.png 800w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/5ece7/grafana-dashboard.png 1200w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/0d4f8/grafana-dashboard.png 1600w,
/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/75869/grafana-dashboard.png 3484w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/dd7ecf1d6cd2b0cec13e24cd4ed5925b/7842b/grafana-dashboard.png&quot;
            alt=&quot;Grafana Production Costs dashboard on Hetzner&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;Grafana alert&lt;/strong&gt; fires when estimated infra cost hits &lt;strong&gt;EUR 50/month&lt;/strong&gt; — email to the ops list before the invoice surprises anyone. That is the opposite of opaque cloud bills where you discover the spike in the console.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ai-agents-with-real-tools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ai-agents-with-real-tools&quot; aria-label=&quot;ai agents with real tools permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AI agents with real tools&lt;/h2&gt;
&lt;p&gt;A lot of this was designed, debugged, and &lt;strong&gt;operated&lt;/strong&gt; with &lt;strong&gt;AI assistants in the loop&lt;/strong&gt; (Cursor, Claude Code). The standout learning: once Grafana is self-hosted on Hetzner, you can point agents at &lt;strong&gt;prod itself&lt;/strong&gt; — not just docs and IaC.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;&lt;a href=&quot;https://github.com/grafana/mcp-grafana&quot;&gt;Grafana MCP&lt;/a&gt;&lt;/strong&gt; (&lt;code&gt;mcp-grafana&lt;/code&gt; via &lt;code&gt;uvx&lt;/code&gt;) and a &lt;strong&gt;read-only Viewer&lt;/strong&gt; service-account token, an agent can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;strong&gt;PromQL&lt;/strong&gt; (host CPU, Postgres connections, cost metrics)&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;LogQL&lt;/strong&gt; (nginx access logs, edge-function output)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Search dashboards&lt;/strong&gt; and summarize panels&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;List alert rules&lt;/strong&gt; and check firing state&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That turned “something is slow in prod” into a loop: agent queries Grafana → finds the panel or log stream → suggests or applies a fix in git/CI — without SSH guesswork. &lt;strong&gt;Tool approval stays on&lt;/strong&gt; in Cursor; the token is read-only; infra and schema changes still go through OpenTofu and CI.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;Cursor → Settings → Tools &amp;#x26; MCP&lt;/strong&gt;, the project wires MCP servers plus the usual CLIs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What we used it for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/hetznercloud/cli&quot;&gt;hcloud CLI&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Check servers, IPs, firewalls from the terminal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenTofu CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Plan and apply infra (VMs, firewall, DNS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenTofu MCP&lt;/strong&gt; (&lt;code&gt;@opentofu/opentofu-mcp-server&lt;/code&gt; via &lt;code&gt;npx&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Look up provider docs in chat (read-only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supabase CLI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Migrations and schema work in git&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supabase MCP&lt;/strong&gt; (&lt;a href=&quot;https://supabase.com/docs/guides/ai-tools/mcp&quot;&gt;official hosted MCP&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;Inspect tables, run read-only SQL, check logs and docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Grafana MCP&lt;/strong&gt; (&lt;a href=&quot;https://github.com/grafana/mcp-grafana&quot;&gt;mcp-grafana&lt;/a&gt; via &lt;code&gt;uvx&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;PromQL, LogQL, dashboards, alerts on self-hosted Grafana&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;&quot;mcpServers&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;supabase&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://mcp.supabase.com/mcp?project_ref=YOUR_REF&amp;amp;read_only=true&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;opentofu&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-y&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@opentofu/opentofu-mcp-server&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;grafana&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;uvx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;mcp-grafana&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;--disable-admin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;--disable-oncall&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;--disable-incident&quot;&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;env&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;GRAFANA_URL&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://grafana.prod.universe.arc-rider.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;GRAFANA_SERVICE_ACCOUNT_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;YOUR_GRAFANA_SERVICE_ACCOUNT_TOKEN&quot;&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Together with runbooks, that felt closer to &lt;strong&gt;IaC plus observability plus CLIs&lt;/strong&gt; than to “SSH into a pet server and hope.” Applies still go through OpenTofu/CI; MCP is for lookup, schema, logs, and prod queries — not silent infra or schema writes.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;what-we-learned-short-version&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-we-learned-short-version&quot; aria-label=&quot;what we learned short version permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What we learned (short version)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Observability on Hetzner is a product asset&lt;/strong&gt; — metrics, logs, and traces in the EU, provisioned from git, no APM SaaS lock-in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Predictable cost and EU hosting&lt;/strong&gt; — cost dashboard + budget alert so spend stays visible before the invoice surprises anyone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI agents shine on self-hosted Grafana&lt;/strong&gt; — Grafana MCP + read-only token lets agents investigate prod (PromQL, LogQL, dashboards) instead of guessing from SSH.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prod is live at &lt;a href=&quot;https://prod.universe.arc-rider.com&quot;&gt;prod.universe.arc-rider.com&lt;/a&gt;. For this product stage, the tradeoff worked: &lt;strong&gt;control where it mattered&lt;/strong&gt; on EU infrastructure the client can point to — including how prod is watched and what it costs.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;hetzner-migrations--how-i-can-help&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hetzner-migrations--how-i-can-help&quot; aria-label=&quot;hetzner migrations  how i can help permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hetzner migrations — how I can help&lt;/h2&gt;
&lt;p&gt;On &lt;strong&gt;Netlify&lt;/strong&gt;, &lt;strong&gt;managed Supabase&lt;/strong&gt;, or &lt;strong&gt;AWS&lt;/strong&gt; for dev and need &lt;strong&gt;prod in the EU on Hetzner&lt;/strong&gt;? I help with planning, OpenTofu, CI deploys, self-hosted Supabase on prod VMs, and &lt;strong&gt;self-hosted observability&lt;/strong&gt; (Grafana LGTM, Alloy, cost guardrails, Grafana MCP for agent-friendly ops).&lt;/p&gt;
&lt;p&gt;Built with &lt;a href=&quot;/lovable-hetzner-germany&quot;&gt;Lovable&lt;/a&gt; for Germany/DACH? Same phased EU-prod path.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;mailto:office@martinmueller.dev&quot;&gt;office@martinmueller.dev&lt;/a&gt; · &lt;a href=&quot;https://calendly.com/martinmueller_dev&quot;&gt;calendly.com/martinmueller_dev&lt;/a&gt; · &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;further-reading&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#further-reading&quot; aria-label=&quot;further reading permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/grafana/docker-otel-lgtm&quot;&gt;grafana/docker-otel-lgtm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/grafana/mcp-grafana&quot;&gt;grafana/mcp-grafana&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/aed42448c77e6298ddc3f02be5fcc85c/index.png</featuredImage><media:content url="https://martinmueller.dev/static/aed42448c77e6298ddc3f02be5fcc85c/index.png" medium="image"/></item><item><title><![CDATA[How I Use OpenClaw as My AI-Powered Personal Operating System]]></title><description><![CDATA[I've been running OpenClaw on a Hostinger VPS for about a month now, and it has fundamentally changed how I work. What started as "let me…]]></description><link>https://martinmueller.dev/openclaw-eng/</link><guid isPermaLink="false">https://martinmueller.dev/openclaw-eng/</guid><category><![CDATA[openclaw]]></category><category><![CDATA[ai]]></category><category><![CDATA[automation]]></category><category><![CDATA[devops]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/733e00b8638647b8c9505ed1eaf2e1c3/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;I&apos;ve been running &lt;a href=&quot;https://openclaw.ai&quot;&gt;OpenClaw&lt;/a&gt; on a &lt;a href=&quot;https://www.hostinger.com?REFERRALCODE=MARTINMUELLER&quot;&gt;Hostinger&lt;/a&gt; VPS for about a month now, and it has fundamentally changed how I work. What started as &quot;let me try this AI agent thing&quot; turned into a powerful assistant that saves me hours every week by automating routine tasks — from GitHub issue triage to email management.&lt;/p&gt;
&lt;p&gt;OpenClaw doesn&apos;t do everything for me (yet), but it handles a lot of the repetitive work that used to eat up my day. Here&apos;s a deep dive into every use case I&apos;ve discovered so far.&lt;/p&gt;
&lt;h2 id=&quot;what-is-openclaw&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-openclaw&quot; aria-label=&quot;what is openclaw permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is OpenClaw?&lt;/h2&gt;
&lt;p&gt;OpenClaw is an open-source AI agent platform that runs on your own infrastructure. You connect it to your chat channels (Telegram, WhatsApp, Discord), give it access to your tools, and it becomes a persistent assistant that remembers context across sessions. Think of it as your own self-hosted AI employee that&apos;s always on.&lt;/p&gt;
&lt;p&gt;My setup: Docker container on a &lt;a href=&quot;https://www.hostinger.com?REFERRALCODE=MARTINMUELLER&quot;&gt;Hostinger&lt;/a&gt; VPS, with &lt;strong&gt;Telegram as my primary interface&lt;/strong&gt;. Most of my interactions — voice messages, text, files — go through Telegram. It feels like texting a colleague who never sleeps.&lt;/p&gt;
&lt;h2 id=&quot;use-case-1-autonomous-github-issue-management&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-1-autonomous-github-issue-management&quot; aria-label=&quot;use case 1 autonomous github issue management permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 1: Autonomous GitHub Issue Management&lt;/h2&gt;
&lt;p&gt;This is the killer feature for me. OpenClaw monitors my &lt;a href=&quot;https://hallocasa.com&quot;&gt;HalloCasa&lt;/a&gt; repositories every 2 hours via a heartbeat. When a new issue appears, it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Notifies me&lt;/strong&gt; on Telegram&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generates a detailed implementation plan&lt;/strong&gt; using Cursor CLI with Claude Opus for planning&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Posts the plan as a comment&lt;/strong&gt; on the GitHub issue&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Waits for my approval&lt;/strong&gt; before implementing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implements the fix&lt;/strong&gt; using Cursor CLI with Composer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Creates a branch, commits, pushes, and opens a PR&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the first week alone, it planned and implemented fixes for currency display bugs, locale changes, phone validation, and filter cleanup — all with minimal intervention from me.&lt;/p&gt;
&lt;p&gt;The workflow follows the &quot;Factory&quot; pattern I heard about at Agentic Conf Hamburg: don&apos;t just use AI to build features — build a production line that builds features for you.&lt;/p&gt;
&lt;h2 id=&quot;use-case-2-email-management&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-2-email-management&quot; aria-label=&quot;use case 2 email management permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 2: Email Management&lt;/h2&gt;
&lt;p&gt;OpenClaw reads and sends emails via Himalaya CLI (IMAP/SMTP). I just tell it what to do on Telegram:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&quot;Tell the sports group leader we can&apos;t come today&quot;&lt;/strong&gt; → Searched my contacts, found the match, sent a polite cancellation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&quot;Email my tax advisor that I need to reschedule&quot;&lt;/strong&gt; → Found the firm in contacts, sent a professional German email.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&quot;Reply to the kindergarten about scheduling a visit&quot;&lt;/strong&gt; → Continued an existing email thread with context-aware reply.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It sends HTML emails with a professional signature and handles German and English.&lt;/p&gt;
&lt;h2 id=&quot;use-case-3-morning-briefing-cron-job&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-3-morning-briefing-cron-job&quot; aria-label=&quot;use case 3 morning briefing cron job permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 3: Morning Briefing (Cron Job)&lt;/h2&gt;
&lt;p&gt;Every morning at 7:00 AM (my timezone, Europe/Berlin), OpenClaw runs an automated check:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scans unread emails from the last 24 hours&lt;/li&gt;
&lt;li&gt;Checks yesterday&apos;s emails for pending follow-ups&lt;/li&gt;
&lt;li&gt;Cross-references with my Google Calendar for today and tomorrow&lt;/li&gt;
&lt;li&gt;Sends me a concise summary on Telegram&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This runs on Claude Haiku (cheap) and costs almost nothing. I wake up to a briefing instead of manually checking three different apps.&lt;/p&gt;
&lt;h2 id=&quot;use-case-4-calendar-management&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-4-calendar-management&quot; aria-label=&quot;use case 4 calendar management permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 4: Calendar Management&lt;/h2&gt;
&lt;p&gt;OpenClaw has full access to my Google Calendar via OAuth. Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Conference schedule&lt;/strong&gt;: I sent a PDF of the Agentic Conf Hamburg schedule with sessions I&apos;d marked with red boxes. It extracted the image, identified the marked sessions using vision AI, fetched details from the conference website, and created 9 calendar events with full descriptions, speaker info, and links.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Creating meetings&lt;/strong&gt;: &quot;Create a meeting with Phillip P. for today at 18:00 CET&quot; → Done.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-case-5-contact-lookup&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-5-contact-lookup&quot; aria-label=&quot;use case 5 contact lookup permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 5: Contact Lookup&lt;/h2&gt;
&lt;p&gt;Connected to my iCloud contacts via CardDAV, OpenClaw searches by name, organization, or context. When I say &quot;email the sports group leader,&quot; it finds the match and uses the right email. No manual lookup needed.&lt;/p&gt;
&lt;h2 id=&quot;use-case-6-linkedin-post-drafting&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-6-linkedin-post-drafting&quot; aria-label=&quot;use case 6 linkedin post drafting permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 6: LinkedIn Post Drafting&lt;/h2&gt;
&lt;p&gt;I&apos;ve used it to draft LinkedIn posts for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWS Community Day Athens 2026&lt;/strong&gt;: Looked up all speakers from the conference website, compiled them alphabetically, created a professional announcement post.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agentic Conf Hamburg recap&lt;/strong&gt;: Searched for organizers&apos; backgrounds, found LinkedIn profiles, referenced specific talks, and wove in my personal highlights about the &quot;Factory&quot; concept.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It does the research, I do the personal touch.&lt;/p&gt;
&lt;h2 id=&quot;use-case-7-research--due-diligence&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-7-research--due-diligence&quot; aria-label=&quot;use case 7 research  due diligence permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 7: Research &amp;#x26; Due Diligence&lt;/h2&gt;
&lt;p&gt;Questions that would normally cost 15 minutes of Googling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&quot;Is there an app for biometric passport photos with QR codes?&quot;&lt;/strong&gt; → Comparison of available apps, including recent regulation changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&quot;There&apos;s a conference in my area tomorrow, what is it?&quot;&lt;/strong&gt; → Found the event, full program, speakers, venue, and registration link.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-case-8-document-generation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-8-document-generation&quot; aria-label=&quot;use case 8 document generation permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 8: Document Generation&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Birthday invitation&lt;/strong&gt;: Generated a themed HTML invitation card with embedded images and QR code, published as a shareable link.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application form&lt;/strong&gt;: Built a bilingual job application form, deployed to GitHub Pages so it works when shared via WhatsApp.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kindergarten applications&lt;/strong&gt;: Generated PDF application forms from templates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email signatures&lt;/strong&gt;: Set up HTML signatures in Gmail (via API) and Apple Mail.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-case-9-workspace--config-management&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-9-workspace--config-management&quot; aria-label=&quot;use case 9 workspace  config management permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 9: Workspace &amp;#x26; Config Management&lt;/h2&gt;
&lt;p&gt;OpenClaw manages its own configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Version-controls its workspace files in a Git repo&lt;/li&gt;
&lt;li&gt;Adjusts its own heartbeat intervals and model settings when I ask&lt;/li&gt;
&lt;li&gt;Maintains daily memory notes and long-term memory files for context continuity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-case-10-global-brain-via-peachbase&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-10-global-brain-via-peachbase&quot; aria-label=&quot;use case 10 global brain via peachbase permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 10: Global Brain via PeachBase&lt;/h2&gt;
&lt;p&gt;OpenClaw is connected to &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-mmaafgzgntjhk&quot;&gt;PeachBase&lt;/a&gt; — a serverless vector database that acts as my persistent memory across all AI agents. Via MCP, OpenClaw can store and retrieve knowledge: personal info, project decisions, contacts, learnings.&lt;/p&gt;
&lt;p&gt;When I tell OpenClaw something worth remembering, it stores it in PeachBase. When I ask a question weeks later — even from a different agent like Cursor — the knowledge is there. It&apos;s the shared brain that ties everything together.&lt;/p&gt;
&lt;p&gt;I wrote a dedicated post about this: &lt;a href=&quot;/peachbase-global-brain&quot;&gt;My Global Brain with PeachBase&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;use-case-11-multi-channel-communication&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-11-multi-channel-communication&quot; aria-label=&quot;use case 11 multi channel communication permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 11: Multi-Channel Communication&lt;/h2&gt;
&lt;p&gt;I talk to OpenClaw primarily via Telegram, but it also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sends emails on my behalf (Himalaya/SMTP)&lt;/li&gt;
&lt;li&gt;Is connected to WhatsApp&lt;/li&gt;
&lt;li&gt;Can deliver cron job results to specific Telegram chats&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-case-12-writing-this-blog-post&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#use-case-12-writing-this-blog-post&quot; aria-label=&quot;use case 12 writing this blog post permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Use Case 12: Writing This Blog Post&lt;/h2&gt;
&lt;p&gt;Meta moment: this very blog post was drafted by OpenClaw. I sent a voice message on Telegram (in German): &quot;I want to write about OpenClaw and how I&apos;ve been using it — go through all your history and find the use cases, in English please.&quot;&lt;/p&gt;
&lt;p&gt;It scanned 23 days of daily memory notes, extracted every use case, researched the blog repo format, and produced a full draft in the right Gatsby frontmatter format — all in one turn. I just reviewed and tweaked.&lt;/p&gt;
&lt;p&gt;This is the &quot;Factory&quot; idea in action: I didn&apos;t write a blog post. I told my agent to write one, and it had all the context it needed because it &lt;em&gt;was there&lt;/em&gt; for every use case.&lt;/p&gt;
&lt;h2 id=&quot;security-its-a-spectrum&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#security-its-a-spectrum&quot; aria-label=&quot;security its a spectrum permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Security: It&apos;s a Spectrum&lt;/h2&gt;
&lt;p&gt;Giving an AI agent access to your email, contacts, calendar, and GitHub is powerful — but it&apos;s also a security conversation you need to have with yourself.&lt;/p&gt;
&lt;p&gt;OpenClaw treats security as a spectrum, not a binary. You can start wide-open for convenience and tighten as you go. Here&apos;s what&apos;s available and what I use:&lt;/p&gt;
&lt;h3 id=&quot;sandboxing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sandboxing&quot; aria-label=&quot;sandboxing permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sandboxing&lt;/h3&gt;
&lt;p&gt;OpenClaw supports &lt;strong&gt;Docker-based sandboxing&lt;/strong&gt; where tool execution (shell commands, file reads/writes) runs inside an isolated container instead of directly on the host. You can choose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;off&quot;&lt;/code&gt; — everything runs on the host (my current setup, maximum convenience)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;non-main&quot;&lt;/code&gt; — only non-main sessions (group chats, webhooks) are sandboxed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;all&quot;&lt;/code&gt; — every session runs sandboxed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&apos;m still on &lt;code&gt;&quot;off&quot;&lt;/code&gt; because I&apos;m the only user and I trust the agent boundary. But if you&apos;re running OpenClaw on a shared machine or exposing it to group chats, sandboxing is a must.&lt;/p&gt;
&lt;h3 id=&quot;tool-policy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#tool-policy&quot; aria-label=&quot;tool policy permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tool Policy&lt;/h3&gt;
&lt;p&gt;You can allowlist or denylist specific tools per agent. For example, you could disable &lt;code&gt;exec&lt;/code&gt; (shell access) entirely and only allow &lt;code&gt;read&lt;/code&gt;/&lt;code&gt;write&lt;/code&gt; — or restrict which commands can run. OpenClaw also has an &lt;strong&gt;elevated exec&lt;/strong&gt; model (think &lt;code&gt;sudo&lt;/code&gt;) where dangerous commands require explicit approval.&lt;/p&gt;
&lt;h3 id=&quot;secrets&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#secrets&quot; aria-label=&quot;secrets permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Secrets&lt;/h3&gt;
&lt;p&gt;One thing I&apos;d do differently: my early setup had API keys in config files. OpenClaw supports environment variables and secret refs instead. Move your credentials out of plaintext config.&lt;/p&gt;
&lt;h3 id=&quot;the-human-in-the-loop-rule&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-human-in-the-loop-rule&quot; aria-label=&quot;the human in the loop rule permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Human-in-the-Loop Rule&lt;/h3&gt;
&lt;p&gt;My most important security measure isn&apos;t technical — it&apos;s a rule in my agent&apos;s config: &lt;strong&gt;always ask before sending emails.&lt;/strong&gt; After one incident where the agent sent an email I hadn&apos;t approved, I added a hard rule. The agent now shows me a draft and waits for &quot;OK&quot; before any outbound communication. This applies to anything that &quot;leaves the machine&quot; — emails, social posts, webhooks.&lt;/p&gt;
&lt;h3 id=&quot;network&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#network&quot; aria-label=&quot;network permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Network&lt;/h3&gt;
&lt;p&gt;The Gateway port (18789) should never be public. Mine is localhost-only inside Docker. If you need remote access, use Tailscale or an authenticated reverse proxy with TLS.&lt;/p&gt;
&lt;h3 id=&quot;my-take&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-take&quot; aria-label=&quot;my take permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My Take&lt;/h3&gt;
&lt;p&gt;Security with AI agents is genuinely new territory. The threat model is different from traditional apps because the agent can be influenced by external content (prompt injection via emails, web pages). OpenClaw has tools to limit blast radius — sandboxing, tool policies, approval gates — but the most important thing is being deliberate about what you give access to and expanding gradually.&lt;/p&gt;
&lt;h2 id=&quot;the-numbers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-numbers&quot; aria-label=&quot;the numbers permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Numbers&lt;/h2&gt;
&lt;p&gt;After a month of use, here&apos;s what surprised me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cost optimization matters&lt;/strong&gt;: Running on Claude Opus 4.6 burns through API credits fast. Switching heartbeats to Haiku and reducing intervals from 30min to 2h made a huge difference.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory is everything&lt;/strong&gt;: The daily notes + MEMORY.md system means I never have to re-explain context. It knows my projects, my contacts, my preferences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTML email was harder than expected&lt;/strong&gt;: Getting Himalaya to send proper HTML emails with MML syntax took some trial and error. Plain text signatures don&apos;t have clickable links.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;whats-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-next&quot; aria-label=&quot;whats next permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blog post automation&lt;/strong&gt;: Using OpenClaw to help draft and publish posts (like this one!)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deeper GitHub integration&lt;/strong&gt;: Auto-implementing approved plans without manual trigger&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More cron jobs&lt;/strong&gt;: Weather briefings, social media monitoring, calendar reminders&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;OpenClaw isn&apos;t just a chatbot. It&apos;s a personal operating system that happens to be powered by AI. The combination of persistent memory, tool access (email, calendar, contacts, GitHub, file system), and multi-channel communication makes it genuinely useful — not in a &quot;cool demo&quot; way, but in a &quot;I saved 2 hours today&quot; way.&lt;/p&gt;
&lt;p&gt;If you&apos;re a developer comfortable with Docker and CLI tools, I highly recommend giving it a try. The learning curve is worth it.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://openclaw.ai&quot;&gt;OpenClaw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;OpenClaw GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discord.com/invite/clawd&quot;&gt;OpenClaw Discord&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev/peachbase-global-brain/&quot;&gt;PeachBase — My Global Brain (Blog Post)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;🚀 &lt;strong&gt;I&apos;m also looking for beta testers for &lt;a href=&quot;https://forms.gle/a7SErMaLMYHMnmAn7&quot;&gt;PeachBase&lt;/a&gt;&lt;/strong&gt; — the serverless vector DB I use as shared memory across all my AI agents. If you want to try it, sign up!&lt;/p&gt;
&lt;p&gt;Thanks for reading! If you have questions about my setup, feel free to reach out. And if you&apos;d like help setting up your own OpenClaw AI agent — whether it&apos;s configuration, tool integration, or building custom workflows — I&apos;m available for consulting. Just drop me a message at &lt;a href=&quot;mailto:office@martinmueller.dev&quot;&gt;office@martinmueller.dev&lt;/a&gt; or book a call at &lt;a href=&quot;https://calendly.com/martinmueller_dev&quot;&gt;calendly.com/martinmueller_dev&lt;/a&gt;.&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/733e00b8638647b8c9505ed1eaf2e1c3/index.png</featuredImage><media:content url="https://martinmueller.dev/static/733e00b8638647b8c9505ed1eaf2e1c3/index.png" medium="image"/></item><item><title><![CDATA[Strands TypeScript SDK - Building Production AI Agents]]></title><description><![CDATA[Introduction Building AI agents that work in production requires more than wrapping an LLM API. You need tool execution, streaming responses…]]></description><link>https://martinmueller.dev/strands-sdk/</link><guid isPermaLink="false">https://martinmueller.dev/strands-sdk/</guid><category><![CDATA[aws]]></category><category><![CDATA[ai-agent]]></category><category><![CDATA[strands]]></category><category><![CDATA[typescript]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Fri, 30 Jan 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/afa17c049692b2920e74b458b0cdf1e0/strands-ts-robot.png" length="0" type="image/png"/><content:encoded>&lt;h2 id=&quot;introduction&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introduction&quot; aria-label=&quot;introduction permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Building AI agents that work in production requires more than wrapping an LLM API. You need tool execution, streaming responses, cost management, and integration with existing systems. After evaluating several frameworks for &lt;a href=&quot;https://ai-secure.dev&quot;&gt;ai-secure.dev&lt;/a&gt;, I chose the &lt;a href=&quot;https://github.com/strands-agents/sdk-typescript&quot;&gt;Strands TypeScript SDK&lt;/a&gt; from AWS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Strands over alternatives?&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LangChain&lt;/td&gt;
&lt;td&gt;Feature-rich, large ecosystem&lt;/td&gt;
&lt;td&gt;Heavy, complex abstractions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;crewAI&lt;/td&gt;
&lt;td&gt;Multi-agent orchestration, role-based agents&lt;/td&gt;
&lt;td&gt;Python-focused, heavier runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raw Anthropic/OpenAI API&lt;/td&gt;
&lt;td&gt;Full control&lt;/td&gt;
&lt;td&gt;Too low-level, no tool orchestration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Strands SDK&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lightweight, AWS-native, streaming-first&lt;/td&gt;
&lt;td&gt;Newer, smaller community&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Strands hits the sweet spot: enough abstraction to be productive, low enough to maintain control. It&apos;s what I used to build the security audit agent behind &lt;a href=&quot;https://ai-secure.dev&quot;&gt;ai-secure.dev&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;agent-creation-basics&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#agent-creation-basics&quot; aria-label=&quot;agent creation basics permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Agent Creation Basics&lt;/h2&gt;
&lt;p&gt;Creating an agent requires three things: a model, a system prompt, and tools.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Agent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tool &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@strands-agents/sdk&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; z &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;zod&apos;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; agent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Agent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;                    &lt;span class=&quot;token comment&quot;&gt;// BedrockModel or custom provider&lt;/span&gt;
  systemPrompt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;You are a security auditor...&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  tools&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;httpSecurityCheck&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dnsLookup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; browserNavigate&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Invoke the agent&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; agent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Audit https://example.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Or stream for real-time updates&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; event &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; agent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Handle events: text deltas, tool calls, metadata&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The SDK handles the agentic loop: model generates response → tool calls extracted → tools executed → results fed back → repeat until done.&lt;/p&gt;
&lt;h2 id=&quot;defining-tools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#defining-tools&quot; aria-label=&quot;defining tools permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Defining Tools&lt;/h2&gt;
&lt;p&gt;Tools are functions the agent can call. The &lt;code&gt;tool()&lt;/code&gt; helper wraps them with Zod schema validation:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; calculatorTool &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;calculator&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Performs arithmetic. Params: operation, a, b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  inputSchema&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    operation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;add&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;subtract&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;multiply&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;divide&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    a&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    b&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; result&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;operation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;add&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;subtract&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Result: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;result&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For domain-specific agents, design tools around your use case. My security agent has tools like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http_security_check&lt;/code&gt; - Headers, TLS inspection, redirect chain&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dns_lookup&lt;/code&gt; - SPF/DMARC/CAA records&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_navigate&lt;/code&gt; - Navigate and interact with pages&lt;/li&gt;
&lt;li&gt;&lt;code&gt;totp&lt;/code&gt; - Generate 2FA codes for authenticated scans&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Complex tool example&lt;/strong&gt; (abbreviated):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; httpSecurityCheckTool &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http_security_check&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;HTTP security analysis: headers, TLS cert, redirects&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  inputSchema&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;URL to check&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;HEAD&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;OPTIONS&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    includeTls&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Make request, inspect TLS socket, check headers&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; securityHeaders &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;strict-transport-security&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;content-security-policy&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ... implementation&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; statusCode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; securityHeaders&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tls &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Tools are the agent&apos;s &quot;hands&quot; - design them for your domain, not as generic utilities.&lt;/p&gt;
&lt;h2 id=&quot;custom-model-provider&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#custom-model-provider&quot; aria-label=&quot;custom model provider permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Custom Model Provider&lt;/h2&gt;
&lt;p&gt;The SDK includes &lt;code&gt;BedrockModel&lt;/code&gt; for AWS Bedrock, but you can create custom providers. I built &lt;code&gt;AnthropicModel&lt;/code&gt; for direct Anthropic API access with features like message caching:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnthropicModel&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AnthropicModelConfig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Anthropic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; apiKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;apiKey &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      modelId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelId &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;claude-sonnet-4-5-20250929&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      maxTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxTokens &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      enableMessageCaching&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enableMessageCaching &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  async &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;messages&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Convert messages to Anthropic format&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Add cache_control blocks for cost reduction&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Yield SDK-compatible events&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Message caching&lt;/strong&gt; reduces costs by 90% on repeated context. Add &lt;code&gt;cache_control&lt;/code&gt; to strategic messages:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Cache system prompt (reused every call)&lt;/span&gt;
request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;system &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; systemPrompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  cache_control&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ephemeral&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ttl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1h&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Cache last tool definition&lt;/span&gt;
tools&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tools&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache_control &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ephemeral&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ttl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1h&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Cost tracking&lt;/strong&gt; built into the model:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MODEL_PRICING&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;claude-sonnet-4-5-20250929&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; output&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15.00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cacheRead&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.30&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&apos;claude-haiku-4-5-20251001&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; input&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; output&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5.00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cacheRead&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.10&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;calculateCost&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;modelId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; inputTokens&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputTokens&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cacheReadTokens&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pricing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MODEL_PRICING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;modelId&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputTokens &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; pricing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; outputTokens &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; pricing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;output 
          &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; cacheReadTokens &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; pricing&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cacheRead&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1_000_000&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;model-routing-for-cost-optimization&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#model-routing-for-cost-optimization&quot; aria-label=&quot;model routing for cost optimization permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Model Routing for Cost Optimization&lt;/h2&gt;
&lt;p&gt;Not every request needs your most powerful model. Route simple tasks to cheaper models:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;classifyTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lower &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; prompt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// Complex patterns → Sonnet&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; complexPatterns &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;security|vulnerabil|audit&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;iso\s*27001|compliance&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;investigate|analyze|assess&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// Simple patterns → Haiku (10x cheaper)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; simplePatterns &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^(hi|hello|hey)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^(thanks|thank\s*you)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;^(yes|no|ok)&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pattern &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; complexPatterns&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pattern&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; complexity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;complex&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;claude-sonnet-4-5&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pattern &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; simplePatterns&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pattern&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lower&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; complexity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;simple&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;claude-haiku-4-5&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// URLs always complex (security audits need full power)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;http://&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; prompt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;https://&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; complexity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;complex&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;claude-sonnet-4-5&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; complexity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;complex&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;claude-sonnet-4-5&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Default safe&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Log cost comparisons in production to validate routing:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;📊 Tokens: 15420 in, 2341 out | $0.0812 (sonnet-4-5)
   Alternative: $0.4102 (opus-4-5) → +$0.329 (+405%)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;streaming-architecture&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#streaming-architecture&quot; aria-label=&quot;streaming architecture permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Streaming Architecture&lt;/h2&gt;
&lt;p&gt;For real-time UX, stream agent events via Server-Sent Events (SSE):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/invocations&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setHeader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text/event-stream&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setHeader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Cache-Control&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;no-cache&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;sendEvent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;data: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;data &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; event &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; agent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Text streaming&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;modelContentBlockDeltaEvent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; delta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;delta
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delta&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;textDelta&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;sendEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; delta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Tool execution tracking&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;modelContentBlockStartEvent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;start
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;start&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;toolUseStart&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;sendEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tool_start&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; tool&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;afterToolsEvent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;sendEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tool_end&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; tool&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; currentTool &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Token usage&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;modelMetadataEvent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      totalTokens &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;usage&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;totalTokens &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;token function&quot;&gt;sendEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;done&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; usage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; totalTokens &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Key event types:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;modelContentBlockDeltaEvent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text/tool input streaming&lt;/td&gt;
&lt;td&gt;Real-time display&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;modelContentBlockStartEvent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tool call begins&lt;/td&gt;
&lt;td&gt;Show &quot;Analyzing...&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;afterToolsEvent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tool finished&lt;/td&gt;
&lt;td&gt;Show result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;modelMetadataEvent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tokens counted&lt;/td&gt;
&lt;td&gt;Cost tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;openai-compatible-adapter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#openai-compatible-adapter&quot; aria-label=&quot;openai compatible adapter permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;OpenAI-Compatible Adapter&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Why build this?&lt;/strong&gt; During development, I needed to chat with my agent without building a UI first. By exposing an OpenAI-compatible endpoint, I could use &lt;a href=&quot;https://github.com/cline/cline&quot;&gt;Cline&lt;/a&gt; (VS Code extension) as my interface - instant chat UI for free.&lt;/p&gt;
&lt;p&gt;This let me iterate on tools and prompts rapidly before touching frontend code.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createOpenAIAdapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; router &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  
  router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/v1/models&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;modelName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; owned_by&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;strands-agents&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  
  router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/v1/chat/completions&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; messages&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stream &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prompt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;extractPromptFromMessages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;messages&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; agent &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createAgent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Stream SSE chunks in OpenAI format&lt;/span&gt;
      res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setHeader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text/event-stream&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; event &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; agent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Convert to OpenAI chunk format&lt;/span&gt;
        res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;data: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chunk&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;data: [DONE]\n\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Collect and return&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; agent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;invoke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; choices&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; response &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; router
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Mount the adapter&lt;/span&gt;
app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createOpenAIAdapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; modelName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;security-agent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; createAgent &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now point Cline at &lt;code&gt;http://localhost:8080/v1&lt;/code&gt; and it works.&lt;/p&gt;
&lt;h2 id=&quot;production-tips&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#production-tips&quot; aria-label=&quot;production tips permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Production Tips&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Session management with TTL:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sessions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Session&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SESSION_TTL_MS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 30 min&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; session&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; sessions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;now &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; session&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastAccessedAt &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SESSION_TTL_MS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      sessions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Issue tracking during scans:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; issueTrackerTool &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;issue_tracker&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Track problems during audit: auth failures, timeouts, etc.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  inputSchema&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;auth_failed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;access_denied&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;timeout&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;credentials_required&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    title&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    session&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;issues&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Issue tracked: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Include issues in the final report so users know what couldn&apos;t be tested.&lt;/p&gt;
&lt;h2 id=&quot;architecture-overview&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#architecture-overview&quot; aria-label=&quot;architecture overview permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Architecture Overview&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;┌─────────────┐     ┌──────────────────┐     ┌─────────────┐
│   Frontend  │────▶│  Agent Server    │────▶│   Tools     │
│   (Next.js) │     │  (Strands SDK)   │     │ (http, dns, │
└─────────────┘     │                  │     │  browser)   │
      ▲             └────────┬─────────┘     └─────────────┘
      │                      │
   SSE Events           ┌────▼────┐
                        │  Model  │
                        │ Provider│
                        └─────────┘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Cost comparison (per 1M tokens):&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Cache Read&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Haiku 4.5&lt;/td&gt;
&lt;td&gt;$1.00&lt;/td&gt;
&lt;td&gt;$5.00&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;td&gt;Simple queries, greetings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sonnet 4.5&lt;/td&gt;
&lt;td&gt;$3.00&lt;/td&gt;
&lt;td&gt;$15.00&lt;/td&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;td&gt;Security audits, analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opus 4.5&lt;/td&gt;
&lt;td&gt;$5.00&lt;/td&gt;
&lt;td&gt;$25.00&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;Complex reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;With routing + caching, typical security audit costs ~$0.08-0.15 vs $0.40+ without.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The Strands TypeScript SDK provides a solid foundation for building production AI agents. Key takeaways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Tools are everything&lt;/strong&gt; - Design domain-specific tools, not generic utilities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache aggressively&lt;/strong&gt; - Message caching saves 90% on repeated context&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Route by complexity&lt;/strong&gt; - Not every request needs your best model&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stream for UX&lt;/strong&gt; - Users need to see progress during long operations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Track costs&lt;/strong&gt; - Log token usage and compare models in production&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The SDK handles the agentic loop so you can focus on domain logic. For &lt;a href=&quot;https://ai-secure.dev&quot;&gt;ai-secure.dev&lt;/a&gt;, that meant security analysis - not prompt engineering infrastructure.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Questions or building your own agent? Connect on &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88/&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/afa17c049692b2920e74b458b0cdf1e0/strands-ts-robot.png</featuredImage><media:content url="https://martinmueller.dev/static/afa17c049692b2920e74b458b0cdf1e0/strands-ts-robot.png" medium="image"/></item><item><title><![CDATA[AWS Bedrock AgentCore - AI Agent Development from Local to Cloud]]></title><description><![CDATA[Introduction Building production-ready AI agents requires more than just a prompt and an LLM. You need infrastructure for state management…]]></description><link>https://martinmueller.dev/aws-agentcore/</link><guid isPermaLink="false">https://martinmueller.dev/aws-agentcore/</guid><category><![CDATA[aws]]></category><category><![CDATA[ai-agent]]></category><category><![CDATA[agentcore]]></category><category><![CDATA[bedrock]]></category><category><![CDATA[eng]]></category><category><![CDATA[2026]]></category><pubDate>Fri, 09 Jan 2026 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/8473e851cda223e6f111416de4b98df7/robot-climbing.png" length="0" type="image/png"/><content:encoded>&lt;h2 id=&quot;introduction&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introduction&quot; aria-label=&quot;introduction permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Building production-ready AI agents requires more than just a prompt and an LLM. You need infrastructure for state management, tool execution, and secure deployment. I recently built &lt;strong&gt;&lt;a href=&quot;https://ai-secure.dev&quot;&gt;https://ai-secure.dev&lt;/a&gt;&lt;/strong&gt;, a SaaS for automated security compliance audits, using &lt;strong&gt;AWS Bedrock AgentCore&lt;/strong&gt;. This post explores how AgentCore simplifies the transition from a local prototype to a scalable cloud agent.&lt;/p&gt;
&lt;h2 id=&quot;what-is-aws-bedrock-agentcore&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-aws-bedrock-agentcore&quot; aria-label=&quot;what is aws bedrock agentcore permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is AWS Bedrock AgentCore?&lt;/h2&gt;
&lt;p&gt;AgentCore is AWS&apos;s managed runtime for AI agents. Think of it as &quot;Fargate for AI agents&quot; - you bring your container, AWS handles scaling, networking, and infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Container-based&lt;/strong&gt;: Package agent as Docker image, push to ECR, deploy via CDK&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VPC networking&lt;/strong&gt;: Agents run in private subnets with NAT for outbound (Anthropic API, target websites)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AgentCore Browser&lt;/strong&gt;: Managed Chromium browser for web automation - no Playwright/Puppeteer infra needed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory&lt;/strong&gt;: Built-in conversation memory across sessions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Streaming&lt;/strong&gt;: SSE responses for real-time progress updates&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;httpsai-securedev&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#httpsai-securedev&quot; aria-label=&quot;httpsai securedev permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;https://ai-secure.dev&quot;&gt;https://ai-secure.dev&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A security compliance scanner that uses an AI agent to audit websites.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;User submits URL + selects security compliance framework (ISO 27001, NIST, SOC2, COBIT)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 97.50000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAABYlAAAWJQFJUiTwAAACpUlEQVR42o2Uy08TURTGu6BQwM6jZdppO9OZ0sf0MdNW2k4RRAyogAuXxmhiDAEhMUZCiBoXJMSNGyOgkLAxLv0vP8+5MzTR1DCLX8+9vXe+Od89506s1XuAznADXv8hWr11uP1gblaHmJ1zcEurC6RsMxIxp7uG9nATncXHFLfg+ZtiPu/egz4/gFG9I2JkwWSmiZm0I5hO1zDLGWUakPUW1LwHtdCGQjGyYNpoC5suWe74GyhUfLHAgv8SSVDJuSQyRJ4wa2Sv1Ec2RC8NkLXDud1DirJNUvaRBI3qosBu3IVm3YakU5a0Ni7T/yEEeVB2V6kYWyg6y5TJABlCs/ojMjfAz7AT1hKCbC1fHlI1/b/GhcoichSVnBeJkeV82acz9EPbQ6quS4uN0EozcoVHgmZtmc5uBXZzFQaNtWJvRMaKhlZcCCwruhtWcoAcZxrazVFky3NmF/xS0ZM3IAlB2qyXeiQ0EG/ga8atcd0e1+MoCMusWvHuw+muw66voNQMMGtLlN2CsHJNJMv8w/YMauqisyTEOLIgHwGvcaWZtNEVzT0ONd+mDENBvq+pfEecA5efF4Nzof+NTjCnPbLuiofGE1xX8XEo1pfg0ier5T+Cs7AGl+607a5ALnhI5lojJDrvcciciHghZ0iCaaWBjNJEVg3Q5DrFBsUapGmbsATyjAVFUAwxR6hJKxCUTA+JF08wtfcUUzvPMLX7nHiJyZ1XxDaUvX2k9t9A3X8Lae8dErsHxCESO0cUP1D8iMTrY9I4Enc/JpU6mPy8jfjFAeJnh4ifvyc+EceYOD+BevEF2uVXzF2cQvlxjomz77TvEvHTK+In4t9+0d7fmDy5gkS2YxJZVqQalGQ1pEJzpiyQkiUkCSlEkRg7xAoh+7Il+vAPXlk33OIK3ZwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/322dda3402f2b2de2471e9fac2c829ae/f1512/1_new_scan.webp 200w,
/static/322dda3402f2b2de2471e9fac2c829ae/f59aa/1_new_scan.webp 400w,
/static/322dda3402f2b2de2471e9fac2c829ae/47a22/1_new_scan.webp 800w,
/static/322dda3402f2b2de2471e9fac2c829ae/5bb53/1_new_scan.webp 1200w,
/static/322dda3402f2b2de2471e9fac2c829ae/4b260/1_new_scan.webp 1422w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/322dda3402f2b2de2471e9fac2c829ae/f8f3a/1_new_scan.png 200w,
/static/322dda3402f2b2de2471e9fac2c829ae/6a8a8/1_new_scan.png 400w,
/static/322dda3402f2b2de2471e9fac2c829ae/7842b/1_new_scan.png 800w,
/static/322dda3402f2b2de2471e9fac2c829ae/5ece7/1_new_scan.png 1200w,
/static/322dda3402f2b2de2471e9fac2c829ae/0e08c/1_new_scan.png 1422w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/322dda3402f2b2de2471e9fac2c829ae/7842b/1_new_scan.png&quot;
            alt=&quot;New Scan&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Agent navigates site using AgentCore Browser, shows real-time progress&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 99%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAABYlAAAWJQFJUiTwAAACvElEQVR42qWUS2/TQBSFHdpSIfK2kzixkzZN/B4/kthpmqpQgQSqEH+gWcCKn4BQERuEBBQW/OPDGbvlUVUkFYvPMx5fnzkzc+cq9W4I0zrEbPkCU5KdvERrkKDS9lDt+JuhBwXsK41eCK2fwBgf5gycJVp7U9SuAtaLEdVFpemg0vGgVDhQNyhqRlCNCPVuQHcuBf31dEmLseEcakIjRgKlSrFBcIJg9gxO8gRWdMrAMF9ype1f8Wf/+p3QYaXhoDo/Ruv4CdrmDEqdS1O70r6Lsmahwb5mhmj2ghzVDIt3Q/C9QDWKMVWOGYzTXDTptN7lkqvqAcq7u9ja3oaiKNB1HVEUwfd9BEGAMAohQoE0S7FcLrE4WiCZJBwLERIZ4/kev2ewLAtKmYJSqFQq3SLoUzAhM46liJMMUZxCiAn8IOF3UQh6FExTjEajfwnSnXBwEKzQ9T7Aml7Aml3Azt6j572F7ryDI55CBA4F/c0Eo9BG332NyvAz9hIy+ZLTtD6iYX2i4HMK2psKCjq0MRRvoHk/YEaX6MffYUTf0PG/omlfwgrONhOM46g4EOFCTM6YUq/IOYJ0BX+6Yn8FOz6HJ44Y43FyD/N5BtuWh6KNsLWzi+37D1C6t4OObsD1Q1iOD9sN4DgOGcN2LLbELVpXtq6Xx4xtD8k0g+MJKPKKySQtM48etpw8WeVtuabWFXmi129Q09nq4q9YiVLhQx9n6LNADL1jtPcmdysMN1BqLA4DCo14/ez4FHvsa4MJOvspOsM0LxR3EpS2m7Io9KLibv6Hu1/lq0VHWn9C0fD3xb8Fud/rUKS7sXgEK3yc7197f5pPIGlzuTqXLensz7jpYr3DKg9Fu/q5N55j4C7zQmtai1xITqiaMYk2KrqKTIumEaPBH3ujOfr2AgZP3JQtha+dSodSfN0e/wRreSrZcK6gcQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/5ab36145c38d8407f0a6ec6843c2698b/f1512/2_scan_progress.webp 200w,
/static/5ab36145c38d8407f0a6ec6843c2698b/f59aa/2_scan_progress.webp 400w,
/static/5ab36145c38d8407f0a6ec6843c2698b/47a22/2_scan_progress.webp 800w,
/static/5ab36145c38d8407f0a6ec6843c2698b/5bb53/2_scan_progress.webp 1200w,
/static/5ab36145c38d8407f0a6ec6843c2698b/485a2/2_scan_progress.webp 1600w,
/static/5ab36145c38d8407f0a6ec6843c2698b/25be7/2_scan_progress.webp 1732w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/5ab36145c38d8407f0a6ec6843c2698b/f8f3a/2_scan_progress.png 200w,
/static/5ab36145c38d8407f0a6ec6843c2698b/6a8a8/2_scan_progress.png 400w,
/static/5ab36145c38d8407f0a6ec6843c2698b/7842b/2_scan_progress.png 800w,
/static/5ab36145c38d8407f0a6ec6843c2698b/5ece7/2_scan_progress.png 1200w,
/static/5ab36145c38d8407f0a6ec6843c2698b/0d4f8/2_scan_progress.png 1600w,
/static/5ab36145c38d8407f0a6ec6843c2698b/c3f2e/2_scan_progress.png 1732w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/5ab36145c38d8407f0a6ec6843c2698b/7842b/2_scan_progress.png&quot;
            alt=&quot;Scan Progress&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Scan completes with summary&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 101.49999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAABYlAAAWJQFJUiTwAAAC/UlEQVR42qVUyW7TUBT1ohKUxBkc240zp4kT22lsZ2qTNm1TQhqVgigIIVQkVgixaysBEmKF2LBG7KBs4AP4w8O9zxlaoJRhcfyenu87991zB0lJu1AyPpzmEHt3HqM3OMDo1iHuPXyKZaePRcVENFlDZMm5ELLThtzuQa40ITGhlm9CyzVQsDaQKq0iW11H3u7DoP1SoT27GE06gvwsBKHZhOx3IZd9SOJAtRAihLVgDWk2GdIFYwUxgtjT5TCdX5vYBnaWOItq5CjBq02E7MVqo+oPUKlvodYaCkwJZN0We14tsuls3oa3Nka9M0Jz/aaQhR8SMYiHIpDYeMnuoewOYLo7sBpDAQ5dL7QEpiEr6Tr0fAOpYhNq1kci49HqCWcMthEh6/QznqrPRWa9JuHyKl6rO8jnPGQJRs5GybbgNSlhpR3o5TWkSXcmlZhoa3QfRWeDMloJCCfeBDhk0pCdGHodyZgDLW7BIA1TWgWJqIlEpAhd5bt2EHLa7CJHGU6bPVr7UCnj50g5o0Rw5cE+wi+eIHb8DPLREaLHLxE7eoXFk7e4engi7CTOIG/4pTGDQOtPdcdhKxYWnj+C/OUN1I/voJ++R/L0E9KnXxH6/A0Lrz8IO+lXRftjrc2gkvhKFWGShhESMBFJVOhfVdSpdOHlc8V7uc0UEgs+TcS0uM/p95cIyoZqLUWp58TkKP0JKqN/I60FhJwIJeOKfuYMB+32Hy/k13CbBbAmlT/3+qf6BRrSR8vxtPEJnmgtnV7JK5dS3OAyWrl0hM1eyIasX72zKxq+0duDuzpGa31fNL6abSBZ7JAk3m91jafcOWGSBoFR7hJxD1lnCxlnE2p5FXlnG8veEPnaNnL1AQx7A6Y/QrF1A3qliwrtl1sjKAWahzxxOGT2WqJLbv8AZmeMUmsXef86rPaeOHP7d1Gm84I/RIGI2YlwWGyjwM5rm4jRxOGen7SeQ2PIh04GURpPHKLC+tEk53JSaZrrNLXjpHFYs2aI6PZ8f0bD75BwL5UuD4o6AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/162ddb0129ce9f93347ab5688f17aa7c/f1512/3_scan_finished.webp 200w,
/static/162ddb0129ce9f93347ab5688f17aa7c/f59aa/3_scan_finished.webp 400w,
/static/162ddb0129ce9f93347ab5688f17aa7c/47a22/3_scan_finished.webp 800w,
/static/162ddb0129ce9f93347ab5688f17aa7c/af1f5/3_scan_finished.webp 1180w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/162ddb0129ce9f93347ab5688f17aa7c/f8f3a/3_scan_finished.png 200w,
/static/162ddb0129ce9f93347ab5688f17aa7c/6a8a8/3_scan_finished.png 400w,
/static/162ddb0129ce9f93347ab5688f17aa7c/7842b/3_scan_finished.png 800w,
/static/162ddb0129ce9f93347ab5688f17aa7c/27179/3_scan_finished.png 1180w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/162ddb0129ce9f93347ab5688f17aa7c/7842b/3_scan_finished.png&quot;
            alt=&quot;Scan Finished&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;User views detailed report with findings + recommendations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 101.49999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAABYlAAAWJQFJUiTwAAACmklEQVR42pVU2XbaUAz0a08CmMXGBrxA2AzGgCGEUpqtSU6WvvTL2j+eamScpCQlJw9j2dfSXGmke42SG6PqzUDbHn1DcnonuMXs7B7x4gbeYINgfI5qa4qCHaFYH/0DU+JqEm8HKcqNCQwuWP4c5WaCRneF/vQKJ/GF2l5yiXq4gCXO9CPhPqkpJPRpnKxQEQ6DiyRjlkUnxpE1FEQ4kkDagvw/lveSM1afvJqifOfIfcilhCWHWaa6Q2EX/DqL0i6wzNL8LNv90nNoycnqTnSY4liye8+JGdSltE5rgi+1wX/JlJC7D6aXInqihMS+TiS0GjECbsqMDxGa4liRDrIxNbEU2A7T57JLTgaSHtmHyZSwKvr53hyedMkKlzomzf5GG1RUsTOyLCA6SKaEhcd7mH9+o7x6wsKNUGtO0faH6HfGknmMZdpF0I1hNmV8+jc6Ee9pnG9qlOM1Kne/YA+38EQjDqnjJQoOc6szhRPMVBI7lCrkP6V5DVvW6hwpzqHVSNDrnmGYXKArGMyuEEZbnTeSFOvxm5JzHU3RmU1qNyeYSTJMwKjKiyVNYGacQ3bbDub6zVFix/PuHwL9mK3BR2e0RW9yoSQkfMFL1+tEsLMCnl2nvcggPjzHjFHCiVwIy+1PtbP1A9LNE+ZfH9VyrbeTIkqvMV7eYpT+QDS/xlDWYvkfRhs9PUrIR0suBd40bcnUH6y15CyL+edLJqF2VlJ3O6fP11SB82dn53gf5v63mx2CZ0KScL6OrejNec6vrA8hcdpldpKi1llmkAnvhJ9DJo8Mvj+TOZTHyfi7dpq2G5/LFSUXrohckc59hLI7gevJjdWLdOgNpun31wiHG7jtJRqdJZrSJFcsQY0+KrckA2+7Ay35L+ARJfO4V0SJAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/66888423b1aa5237e54a4bbbe037e3cd/f1512/4_scan_report.webp 200w,
/static/66888423b1aa5237e54a4bbbe037e3cd/f59aa/4_scan_report.webp 400w,
/static/66888423b1aa5237e54a4bbbe037e3cd/47a22/4_scan_report.webp 800w,
/static/66888423b1aa5237e54a4bbbe037e3cd/5bb53/4_scan_report.webp 1200w,
/static/66888423b1aa5237e54a4bbbe037e3cd/451c4/4_scan_report.webp 1568w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/66888423b1aa5237e54a4bbbe037e3cd/f8f3a/4_scan_report.png 200w,
/static/66888423b1aa5237e54a4bbbe037e3cd/6a8a8/4_scan_report.png 400w,
/static/66888423b1aa5237e54a4bbbe037e3cd/7842b/4_scan_report.png 800w,
/static/66888423b1aa5237e54a4bbbe037e3cd/5ece7/4_scan_report.png 1200w,
/static/66888423b1aa5237e54a4bbbe037e3cd/acc8b/4_scan_report.png 1568w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/66888423b1aa5237e54a4bbbe037e3cd/7842b/4_scan_report.png&quot;
            alt=&quot;Scan Report&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Architecture:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;┌─────────────┐     ┌──────────────────┐     ┌─────────────┐
│   Frontend  │────▶│  AgentCore       │────▶│  AgentCore  │
│  (Next.js)  │     │  Runtime         │     │   Browser   │
└─────────────┘     │  (your container)│     │  (Chromium) │
                    └──────────────────┘     └─────────────┘
                           │
                     ┌─────▼─────┐
                     │  Claude   │
                     │ (Anthropic)│
                     └───────────┘&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Tech stack:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/strands-agents/sdk-typescript&quot;&gt;Strands TypeScript SDK&lt;/a&gt; + Claude (Anthropic)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;td&gt;AgentCore Browser (cloud) / Playwright MCP (local)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Next.js 16 + React 19 + Tailwind (Hosted on AWS ECS Fargate)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;AWS Cognito&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;DynamoDB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infra&lt;/td&gt;
&lt;td&gt;AWS CDK → AWS ECS Fargate + AWS Bedrock AgentCore Runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Agent tools:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;browser_navigate&lt;/code&gt;, &lt;code&gt;browser_snapshot&lt;/code&gt;, &lt;code&gt;browser_click&lt;/code&gt;, &lt;code&gt;browser_type&lt;/code&gt; - web automation&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http_security_check&lt;/code&gt; - headers, TLS, redirects&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dns_lookup&lt;/code&gt; - SPF/DMARC/CAA records&lt;/li&gt;
&lt;li&gt;&lt;code&gt;totp&lt;/code&gt; - 2FA code generation for authenticated scans&lt;/li&gt;
&lt;li&gt;&lt;code&gt;issue_tracker&lt;/code&gt; - tracks problems during scan&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Model routing for cost optimization:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Simple tasks → Haiku (~10x cheaper)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Complex tasks → Sonnet&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; classification &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;classifyTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; classification&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;complexity &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;simple&apos;&lt;/span&gt; 
  &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;claude-haiku-4-5&apos;&lt;/span&gt; 
  &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;claude-sonnet-4-5&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;learnings&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#learnings&quot; aria-label=&quot;learnings permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Learnings&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Agent development:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don&apos;t build an agent from scratch initially. Validate your use case works with existing agents (Cursor, Claude Code, Kiro). If they can&apos;t solve it, your custom agent probably won&apos;t either. Your goal: beat them on speed, accuracy, cost for your specific domain.&lt;/li&gt;
&lt;li&gt;Develop locally first using Docker. Same container runs locally and in AgentCore.&lt;/li&gt;
&lt;li&gt;Use Server-Sent Events (SSE) streaming for real-time progress - users need to see what the agent is doing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Browser automation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AgentCore Browser is game-changer. No more managing Playwright/Puppeteer infrastructure.&lt;/li&gt;
&lt;li&gt;For local dev, use existing MCP Docker images (playwright-mcp). Your custom implementation won&apos;t be better.&lt;/li&gt;
&lt;li&gt;Browser tools need good error handling - pages don&apos;t always load, elements move, auth flows vary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cost optimization:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Model routing: Haiku for greetings/simple queries, Sonnet for audits&lt;/li&gt;
&lt;li&gt;Message caching: 90% cost reduction on repeated context&lt;/li&gt;
&lt;li&gt;Disable extended thinking unless needed (~$0.15/call)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Production gotchas:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AgentCore logs are separate from your app logs. Use CloudWatch SDK directly for application logging.&lt;/li&gt;
&lt;li&gt;Use Infrastructure as Code (IaC) to deploy your agent to AgentCore.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AWS Bedrock AgentCore provides a robust foundation for building complex, stateful AI agents. By offloading the heavy lifting of runtime management and browser infrastructure to AWS, I was able to focus on the core logic of &lt;a href=&quot;https://ai-secure.dev&quot;&gt;https://ai-secure.dev&lt;/a&gt; - creating high-quality security audits - rather than debugging infrastructure. If you&apos;re building agents that need to browse the web or maintain long-term state, AgentCore is a powerful accelerator.&lt;/p&gt;
&lt;p&gt;Please give me feedback on &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88/&quot;&gt;LinkedIn&lt;/a&gt;. Either if you find the &lt;a href=&quot;https://ai-secure.dev&quot;&gt;https://ai-secure.dev&lt;/a&gt; useful and how I can make it better or if you need help with your own AI agent project. More and more builders are curious about how I build and deploy AI Agents in more specifics. So let me know if you would interested in more blog posts around this or perhaps a workshop/course around how I build my AI Agents?!&lt;/p&gt;
&lt;p&gt;As well I think my next post will be about &lt;a href=&quot;https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview&quot;&gt;Agent Skills&lt;/a&gt; as I&apos;m exploring those to start another AI Agent idea where I want the agent helping me with marketing for &lt;a href=&quot;https://ai-secure.dev&quot;&gt;https://ai-secure.dev&lt;/a&gt;. So make sure to subscribe to my blog posts &lt;a href=&quot;https://martinmueller.dev/rss.xml&quot;&gt;RSS feed&lt;/a&gt;.&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/8473e851cda223e6f111416de4b98df7/robot-climbing.png</featuredImage><media:content url="https://martinmueller.dev/static/8473e851cda223e6f111416de4b98df7/robot-climbing.png" medium="image"/></item><item><title><![CDATA[A MCP Server with AWS Bedrock AgentCore Gateway]]></title><description><![CDATA[Hi there, I recently developed an MCP Server with using our HalloCasa Zapier Integration. Zapier MCP is nice but I wanted to try AWS Bedrock…]]></description><link>https://martinmueller.dev/aws-mcp-bedrock/</link><guid isPermaLink="false">https://martinmueller.dev/aws-mcp-bedrock/</guid><category><![CDATA[eng]]></category><category><![CDATA[2025]]></category><category><![CDATA[aws]]></category><category><![CDATA[ai]]></category><category><![CDATA[mcp]]></category><pubDate>Sat, 20 Sep 2025 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/1ddc9578da8b3d93e8ef612a1b2a7014/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi there,&lt;/p&gt;
&lt;p&gt;I recently developed an MCP Server with using our &lt;a href=&quot;https://zapier.com/apps/hallocasa/integrations&quot;&gt;HalloCasa Zapier Integration&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zapier MCP is nice but I wanted to try AWS Bedrock AgentCore Gateway to develop an MCP Server&lt;/li&gt;
&lt;li&gt;Because it allows you to leverage an OpenAPI Spec as target which we already have&lt;/li&gt;
&lt;li&gt;I was curious to see how it would perform&lt;/li&gt;
&lt;li&gt;Additionally adjusting our openapi spec to serve better as an MCP Server improves the the spec&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;If you want more details, like how I build the MCP integration or how I deploy the NextJS app via AWS CDK, reach out to me on &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88/&quot;&gt;LinkedIn&lt;/a&gt;. I&apos;m super eager to share my knowledge with you.&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/1ddc9578da8b3d93e8ef612a1b2a7014/index.png</featuredImage><media:content url="https://martinmueller.dev/static/1ddc9578da8b3d93e8ef612a1b2a7014/index.png" medium="image"/></item><item><title><![CDATA[A property listings AI chat with MCP integrations running in AWS]]></title><description><![CDATA[Hi there, My Co-Founder Michael Franz and I founded https://hallocasa.com a while back. It is a property listing and agency platform to list…]]></description><link>https://martinmueller.dev/aws-mcp-listings/</link><guid isPermaLink="false">https://martinmueller.dev/aws-mcp-listings/</guid><category><![CDATA[eng]]></category><category><![CDATA[2025]]></category><category><![CDATA[aws]]></category><category><![CDATA[ai]]></category><category><![CDATA[mcp]]></category><category><![CDATA[cdk]]></category><pubDate>Wed, 09 Jul 2025 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/1ddc9578da8b3d93e8ef612a1b2a7014/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi there,&lt;/p&gt;
&lt;p&gt;My Co-Founder &lt;a href=&quot;https://www.linkedin.com/in/michael-franz-308943b8/&quot;&gt;Michael Franz&lt;/a&gt; and I founded &lt;a href=&quot;https://hallocasa.com&quot;&gt;https://hallocasa.com&lt;/a&gt; a while back. It is a property listing and agency platform to list and search for properties &lt;a href=&quot;https://hallocasa.com/properties&quot;&gt;https://hallocasa.com/properties&lt;/a&gt; or to find a property broker &lt;a href=&quot;https://hallocasa.com/brokers&quot;&gt;https://hallocasa.com/brokers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As I&apos;m a big fan of AWS, AI and MCP (Model Context Protocol &lt;a href=&quot;https://modelcontextprotocol.io/&quot;&gt;https://modelcontextprotocol.io/&lt;/a&gt;), I wanted to build an AI chat with MCP integrations running in AWS to improve the property search experience. I also believe the future of property search will be AI-driven and you basically write or speak to an AI to find a property.&lt;/p&gt;
&lt;h2 id=&quot;listings-mcpcom&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#listings-mcpcom&quot; aria-label=&quot;listings mcpcom permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;listings-mcp.com&lt;/h2&gt;
&lt;p&gt;I&apos;m hosting the app on &lt;a href=&quot;https://listings-mcp.com&quot;&gt;https://listings-mcp.com&lt;/a&gt; and you can try it out there. It is comparable with &lt;a href=&quot;https://www.perplexity.ai/&quot;&gt;https://www.perplexity.ai/&lt;/a&gt; when you use it for property search. But perplexity isn&apos;t working as good as I expected. It pretends to show properties but if you click on the source it only forwards you to the properties search. But what I really want is to see the property details and images like you get with &lt;a href=&quot;https://listings-mcp.com&quot;&gt;https://listings-mcp.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;mcp-integration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#mcp-integration&quot; aria-label=&quot;mcp integration permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;MCP Integration&lt;/h2&gt;
&lt;p&gt;We do have a &lt;a href=&quot;https://zapier.com/apps/hallocasa/integrations&quot;&gt;HalloCasa Zapier Integration&lt;/a&gt;. That is quite convenient because Zapier allows you to use your integration as MCP server &lt;a href=&quot;https://zapier.com/mcp&quot;&gt;https://zapier.com/mcp&lt;/a&gt;. So very conveniently with Zapier MCP you choose the Zapier integration like HalloCasa, choose which tools you want to use and configure the parameters (if you need at all). After that Zapier provides you with an MCP server url which you can use in your AI chat.&lt;/p&gt;
&lt;p&gt;This approach is incredible easy and powerful as it allows me to enhance the MCP quickly.&lt;/p&gt;
&lt;p&gt;For putting together the AI Chat capabilities and the MCP integration, I&apos;m using the AI libraries from Vercel &lt;a href=&quot;https://ai-sdk.dev/&quot;&gt;ai-sdk&lt;/a&gt;. The &lt;a href=&quot;https://ai-sdk.dev/cookbook/node/mcp-tools&quot;&gt;mcp-tools&lt;/a&gt; make it incredible easy to build an AI chat with MCP integrations. I wrote everything down in a few hours. Of course cursor AI made most of the work.&lt;/p&gt;
&lt;p&gt;Here is the code for the nextJS page route &lt;code&gt;/api/chat&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; openai &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@ai-sdk/openai&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; createAmazonBedrock &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@ai-sdk/amazon-bedrock&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; fromNodeProviderChain &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@aws-sdk/credential-providers&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; streamText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; experimental_createMCPClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ai&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Experimental_StdioMCPTransport &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ai/mcp-stdio&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; StreamableHTTPClientTransport &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@modelcontextprotocol/sdk/client/streamableHttp.js&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getEnabledMCPServers&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; validateMCPConfig&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MCPServerConfig&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@/lib/mcp-config&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; DynamoDBClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@aws-sdk/client-dynamodb&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; DynamoDBDocumentClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PutCommand &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@aws-sdk/lib-dynamodb&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; randomUUID &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;crypto&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maxDuration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Model configuration - you can switch between providers here&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MODEL_PROVIDER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MODEL_PROVIDER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bedrock&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;openai&quot; or &quot;bedrock&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// DynamoDB configuration&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dynamoDBClient &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DynamoDBClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_REGION&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;us-east-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    credentials&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      accessKeyId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      secretAccessKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_SESSION_TOKEN&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; sessionToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_SESSION_TOKEN&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    credentialProvider&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fromNodeProviderChain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; docClient &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; DynamoDBDocumentClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dynamoDBClient&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CHAT_SESSIONS_TABLE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DYNAMODB_CHAT_SESSIONS_TABLE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;listings-mcp-chat-sessions&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Helper functions for session management&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ChatMessage&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  sessionId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  messageId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;user&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;assistant&apos;&lt;/span&gt;
  content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  timestamp&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;
  userId&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
  includePropertyPictures&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;
  toolCalls&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  toolResults&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  metadata&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;
  ttl&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// TTL for automatic cleanup (30 days from now)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateSessionId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;randomUUID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateMessageId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;randomUUID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUserId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Try to extract user ID from headers, auth token, or IP address&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userAgent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;user-agent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;unknown&apos;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; forwarded &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-forwarded-for&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-real-ip&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;unknown&apos;&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// For now, create a simple hash-based user ID&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// In production, this should come from authentication&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userIdentifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;userAgent&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;forwarded&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[^a-zA-Z0-9-]&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;_&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; userIdentifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Limit length&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;saveMessageToDynamoDB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ChatMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ttl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 30 days from now&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; docClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PutCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      TableName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CHAT_SESSIONS_TABLE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      Item&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        ttl
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[DynamoDB] Saved message &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;messageId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; to session &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sessionId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[DynamoDB] Error saving message:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Don&apos;t throw - we don&apos;t want to break the chat if DB fails&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Create Bedrock provider with region configuration&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// In ECS, credentials are automatically provided via the task role&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Only set explicit credentials if they exist (for local development)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bedrockConfig&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_REGION&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;us-east-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Default to us-east-1 if not set&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Check if explicit credentials are provided (for local development)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  bedrockConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accessKeyId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;
  bedrockConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;secretAccessKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_SESSION_TOKEN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    bedrockConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sessionToken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_SESSION_TOKEN&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Use AWS credential provider chain for automatic credential resolution&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// This will work with ECS task roles, EC2 instance profiles, etc.&lt;/span&gt;
  bedrockConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;credentialProvider &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fromNodeProviderChain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bedrock &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createAmazonBedrock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bedrockConfig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MODEL_PROVIDER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;openai&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;openai&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gpt-4o&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bedrock&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Use inference profile ID for cross-region access to Claude Sonnet 4&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bedrock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;us.anthropic.claude-sonnet-4-20250514-v1:0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connectToMCPServers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;enabledServers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MCPServerConfig&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; clients&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; allTools&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; clients&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; allTools &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Attempting to connect to &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;enabledServers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; MCP servers...&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; serverConfig &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; enabledServers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Processing server: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Validate configuration before attempting connection&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;validateMCPConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Invalid MCP server configuration for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Creating client for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; client

      &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sse&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
          client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;experimental_createMCPClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            transport&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sse&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; transport &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StreamableHTTPClientTransport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;URL&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;experimental_createMCPClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            transport
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;
          
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;stdio&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Creating stdio transport for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; with command: node &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;command&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stdioTransport &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Experimental_StdioMCPTransport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            command&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;command&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Creating MCP client for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;experimental_createMCPClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            transport&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; stdioTransport
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Client created for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, waiting for initialization...&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// Give stdio process more time to fully initialize&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Initialization wait complete for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        clients&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; config&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; serverConfig &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;token comment&quot;&gt;// Get tools from this MCP server with retry logic&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; serverTools&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; attempts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maxAttempts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attempts &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; maxAttempts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Attempt &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;attempts &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; to get tools from &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            serverTools &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Successfully retrieved &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serverTools&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; tools from &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Success, exit retry loop&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toolError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            attempts&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Attempt &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;attempts&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; failed to get tools from &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toolError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attempts &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; maxAttempts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token comment&quot;&gt;// Wait before retrying (exponential backoff)&lt;/span&gt;
              &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; attempts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Failed to get tools from &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; after &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;maxAttempts&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; attempts&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; toolError
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;token comment&quot;&gt;// Prefix tool names with server name to avoid conflicts&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prefixedTools &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serverTools&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toolName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prefixedName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;toolName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; originalTool &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; serverTools&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;toolName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
          
          &lt;span class=&quot;token comment&quot;&gt;// Use the original tool directly from MCP client&lt;/span&gt;
          &lt;span class=&quot;token comment&quot;&gt;// The AI SDK should handle MCP tools correctly without modification&lt;/span&gt;
          acc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prefixedName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; originalTool
          &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Added tool &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;prefixedName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; with original MCP interface&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; acc
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        
        allTools &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;allTools&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;prefixedTools &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Successfully connected to MCP server: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; with &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;serverTools&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; tools&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Failed to connect to MCP server &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;serverConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// Continue with other servers even if one fails&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[MCP] Connection process complete. Connected to &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;clients&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; servers with &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;allTools&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; total tools&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; clients&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; allTools &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; messages&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; includePropertyPictures&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sessionId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; existingSessionId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[API] Received chat request with &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;messages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; messages&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[API] Include property pictures: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;includePropertyPictures&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[API] Existing session ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;existingSessionId &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;none&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Generate or use existing session ID&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sessionId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; existingSessionId &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateSessionId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getUserId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; timestamp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Track tool usage for this session&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; toolUsageTracker &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    totalSteps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    toolCalls&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    toolResults&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[API] Session ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sessionId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, User ID: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;userId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Save user messages to DynamoDB (only new messages)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;messages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lastMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; messages&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;messages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lastMessage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;role &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;user&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userMessage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ChatMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        sessionId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        messageId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateMessageId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;user&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lastMessage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        timestamp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        includePropertyPictures&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        metadata&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          userAgent&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;user-agent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          ip&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-forwarded-for&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x-real-ip&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      
      &lt;span class=&quot;token comment&quot;&gt;// Save user message (don&apos;t await to avoid blocking)&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;saveMessageToDynamoDB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Get enabled MCP servers&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; enabledServers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getEnabledMCPServers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[API] Found &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;enabledServers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; enabled MCP servers&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Connect to MCP servers and get tools&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; startTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; clients&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; allTools &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connectToMCPServers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;enabledServers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; connectionTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; startTime
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[API] MCP connection process took &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;connectionTime&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[API] Available tools:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;allTools&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[API] Starting streamText...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[API] Tool count:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;allTools&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[API] Tool names:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;allTools&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Build system prompt with conditional instructions&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pictureInstruction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; includePropertyPictures 
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;- When returning property data, make sure to include the first picture\n&quot;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;streamText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      system&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;You are a knowledgeable international real estate assistant helping clients find properties worldwide. You have access to various property platforms and tools through MCP (Model Context Protocol) integrations.

You should:
- Help clients explore property options in different countries
- Use MCP tools to fetch real-time property data when available
- Provide insights about local real estate markets, prices, and trends
- Discuss legal requirements for foreign property buyers
- Suggest popular areas and neighborhoods
- Explain visa/residency requirements related to property ownership
- Offer guidance on property types, investment potential, and lifestyle factors
- Be friendly, professional, and thorough in your responses
- Ask clarifying questions to better understand their needs
- When returning property data, include the source and the property url of the data in the response.
&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;pictureInstruction&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
When using MCP tools, mention which platform the data is coming from to build trust and transparency.

Available MCP integrations: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;enabledServers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MCPServerConfig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;, &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;

IMPORTANT: When users ask about properties or real estate data, you MUST use the available MCP tools to fetch current data. Always try to use tools like demo_search_properties, demo_get_market_data, or demo_get_property_details when relevant. The tool results will contain the property data you need to include in your response.

Always be helpful and informative while encouraging them to consult with local real estate professionals for specific transactions.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      messages&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      tools&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; allTools&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      maxRetries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      maxSteps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Allow multiple steps for tool execution and response&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;onStepFinish&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toolCalls&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toolResults&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; finishReason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; usage &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalSteps&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;
        
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI] Step &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalSteps&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; finished:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI]   - Text generated: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;text &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;...&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;none&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI]   - Tool calls: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;toolCalls&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toolCalls &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; toolCalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          toolCalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;call&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; idx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI]   - Tool &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;idx &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;call&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; with args:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; call&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            
            &lt;span class=&quot;token comment&quot;&gt;// Track tool calls with step information&lt;/span&gt;
            toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              step&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalSteps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              toolCallId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; call&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCallId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              toolName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; call&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; call&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              timestamp&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI]   - Tool results: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;toolResults&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toolResults &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; toolResults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          toolResults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; idx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI]   - Result &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;idx &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            
            &lt;span class=&quot;token comment&quot;&gt;// Track tool results with step information&lt;/span&gt;
            toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolResults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              step&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalSteps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              toolCallId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCallId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              toolName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              result&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              timestamp&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI]   - Finish reason:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; finishReason&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;onFinish&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI] Chat finished. Tool calls made:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toolCall&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI] Tool call &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
              name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolCall&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolCall&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;args
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI] Final response length:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI] Response sample:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;token comment&quot;&gt;// Save assistant response to DynamoDB&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; assistantMessage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ChatMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          sessionId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          messageId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateMessageId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;assistant&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          timestamp&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          includePropertyPictures&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          toolCalls&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          toolResults&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolResults&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          metadata&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            usage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;usage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            finishReason&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;finishReason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            warnings&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;warnings&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            modelProvider&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MODEL_PROVIDER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            totalSteps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalSteps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            toolUsageSummary&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              totalToolCalls&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              uniqueTools&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tc &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; tc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              callsPerTool&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; toolUsageTracker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolCalls&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                acc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toolName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; acc
              &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;token comment&quot;&gt;// Save assistant message (don&apos;t await to avoid blocking cleanup)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;saveMessageToDynamoDB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;assistantMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;token comment&quot;&gt;// Clean up MCP clients when streaming is finished&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; client &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; clients&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Error closing MCP client:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;onError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errorObj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;[AI] Streaming error occurred:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; errorObj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          errorString&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errorObj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Clean up MCP clients on error&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; client &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; clients&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;closeError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Error closing MCP client on error:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; closeError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDataStreamResponse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Failed to initialize chat with MCP:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Build system prompt with conditional instructions for fallback&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pictureInstruction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; includePropertyPictures 
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;- When returning property data, make sure to include the first picture\n      &quot;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Fallback to basic chat without MCP if initialization fails&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;streamText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      model&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      system&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;You are a knowledgeable international real estate assistant helping clients find properties worldwide.

You should:
      
      - Help clients explore property options in different countries
      - Provide insights about local real estate markets, prices, and trends
      - Discuss legal requirements for foreign property buyers
      - Suggest popular areas and neighborhoods
      - Explain visa/residency requirements related to property ownership
      - Offer guidance on property types, investment potential, and lifestyle factors
      - Be friendly, professional, and thorough in your responses
      - Ask clarifying questions to better understand their needs
      &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;pictureInstruction&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      Note: Advanced property platform integrations are temporarily unavailable.
      
      Always be helpful and informative while encouraging them to consult with local real estate professionals for specific transactions.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      messages&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function-variable function&quot;&gt;onFinish&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[AI] Fallback chat finished. Response length:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;token comment&quot;&gt;// Save assistant response to DynamoDB (fallback mode)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; assistantMessage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ChatMessage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          sessionId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          messageId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateMessageId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;assistant&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          content&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          timestamp&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          includePropertyPictures&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          metadata&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            usage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;usage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            finishReason&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;finishReason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            warnings&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;warnings&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            modelProvider&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MODEL_PROVIDER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            mcpFallback&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;token comment&quot;&gt;// Save assistant message (don&apos;t await to avoid blocking)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;saveMessageToDynamoDB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;assistantMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDataStreamResponse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;aws-setup&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-setup&quot; aria-label=&quot;aws setup permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Setup&lt;/h2&gt;
&lt;p&gt;I&apos;m using AWS CDK to deploy AWS ECS Fargate to run a NextJS app which has access to the MCP server and Anthropic Claude 4 Sonnet via AWS Bedrock. The nextjs app is configured as NextJS standalone app.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cdk &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Construct &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;constructs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ecs &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-ecs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ecsPatterns &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-ecs-patterns&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; iam &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-iam&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; route53 &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-route53&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; acm &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-certificatemanager&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ListingsMcpServiceStackProps&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StackProps &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cluster&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ecs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Cluster&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ListingsMcpServiceStack&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stack &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; fargateService&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ecsPatterns&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ApplicationLoadBalancedFargateService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ListingsMcpServiceStackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; domainName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;listings-mcp.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Look up the existing hosted zone for the domain&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hostedZone &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; route53&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;HostedZone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromLookup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;HostedZone&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Create an ACM certificate for the domain&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; certificate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;acm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Certificate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Certificate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      validation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; acm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CertificateValidation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromDns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hostedZone&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Create a Fargate service with an Application Load Balancer&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fargateService &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ecsPatterns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ApplicationLoadBalancedFargateService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ListingsMcpService&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cluster&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cluster&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      memoryLimitMiB&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      cpu&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      desiredCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      enableExecuteCommand&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      certificate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; certificate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      domainZone&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; hostedZone&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      redirectHTTP&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      healthCheck&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        command&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;CMD-SHELL&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;curl -f http://localhost:3000/ || exit 1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      
      runtimePlatform&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        cpuArchitecture&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ecs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CpuArchitecture&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ARM64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        operatingSystemFamily&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ecs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OperatingSystemFamily&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LINUX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      taskImageOptions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        image&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ecs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ContainerImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;..&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        containerPort&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;production&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;NEXT_TELEMETRY_DISABLED&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;HOSTNAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;0.0.0.0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;TRUST_PROXY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;AWS_REGION&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;NEXT_PUBLIC_BASE_URL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Add SES permissions to the task role for sending verification emails&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fargateService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskDefinition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskRole &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Role&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;iam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PolicyStatement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      effect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALLOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;ses:SendEmail&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;ses:SendRawEmail&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:ses:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:identity/*&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Add Cognito permissions to the task role for user management operations&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fargateService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskDefinition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskRole &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Role&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;iam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PolicyStatement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      effect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALLOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;cognito-idp:ListUsers&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;cognito-idp:AdminCreateUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;cognito-idp:AdminUpdateUserAttributes&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;cognito-idp:AdminGetUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;cognito-idp:AdminSetUserPassword&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;cognito-idp:AdminInitiateAuth&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;cognito-idp:InitiateAuth&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;cognito-idp:RespondToAuthChallenge&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:cognito-idp:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:userpool/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolId&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Add STS permissions for getting AWS account information&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fargateService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskDefinition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskRole &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Role&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;iam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PolicyStatement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      effect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALLOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;sts:GetCallerIdentity&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Add CloudWatch Logs permissions for better logging and debugging&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fargateService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskDefinition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskRole &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Role&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;iam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PolicyStatement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      effect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALLOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;logs:CreateLogGroup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;logs:CreateLogStream&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;logs:PutLogEvents&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;logs:DescribeLogStreams&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:logs:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:log-group:/aws/ecs/*&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Add Bedrock permissions for AI model access&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fargateService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskDefinition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskRole &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Role&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;iam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PolicyStatement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      effect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; iam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Effect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALLOW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;bedrock:InvokeModel&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&apos;bedrock:InvokeModelWithResponseStream&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:bedrock:*:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:inference-profile/*&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:bedrock:*::foundation-model/*&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Add base URL environment variable after service creation&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fargateService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;taskDefinition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;defaultContainer&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEnvironment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;NEXT_PUBLIC_BASE_URL&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Output the load balancer URL&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CfnOutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;LoadBalancerDNS&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fargateService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loadBalancer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loadBalancerDnsName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;The DNS name of the load balancer&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Output the custom domain URL&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CfnOutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ApplicationURL&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;The URL of the application&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Output the certificate ARN&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CfnOutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;CertificateArn&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; certificate&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;certificateArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      description&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;The ARN of the SSL certificate&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;So try out &lt;a href=&quot;https://listings-mcp.com&quot;&gt;https://listings-mcp.com&lt;/a&gt; and let me know what you think. I&apos;m curious if we can improve the property search experience by particular using MCP integrations from providers like &lt;a href=&quot;https://hallocasa.com&quot;&gt;HalloCasa&lt;/a&gt;. I&apos;m not that crazy of trying to compete with perplexity but maybe there is a niche for this. Maybe we can become a market place specifically for property MCP integrations.&lt;/p&gt;
&lt;p&gt;If you need help with MCP integrations, let me know. I&apos;m happy to help you.&lt;/p&gt;
&lt;p&gt;If you want more details, like how I build the MCP integration or how I deploy the NextJS app via AWS CDK, reach out to me on &lt;a href=&quot;https://www.linkedin.com/in/martinmueller88/&quot;&gt;LinkedIn&lt;/a&gt;. I&apos;m super eager to share my knowledge with you.&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/1ddc9578da8b3d93e8ef612a1b2a7014/index.png</featuredImage><media:content url="https://martinmueller.dev/static/1ddc9578da8b3d93e8ef612a1b2a7014/index.png" medium="image"/></item><item><title><![CDATA[SST, AWS CDK, AWS CloudFormation migration to Terraform]]></title><description><![CDATA[Recently, a client approached me with an intriguing request: to migrate their SST (v.2 https://v2.sst.dev/) project to Terraform. This task…]]></description><link>https://martinmueller.dev/aws-sst-cdk-to-tf/</link><guid isPermaLink="false">https://martinmueller.dev/aws-sst-cdk-to-tf/</guid><category><![CDATA[eng]]></category><category><![CDATA[2024]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><category><![CDATA[sst]]></category><category><![CDATA[terraform]]></category><pubDate>Tue, 27 Aug 2024 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/6db5a0fe45b87893f7df229130f07f9b/birds-migrating.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Recently, a client approached me with an intriguing request: to migrate their SST (v.2 &lt;a href=&quot;https://v2.sst.dev/&quot;&gt;https://v2.sst.dev/&lt;/a&gt;) project to Terraform. This task presents several interesting challenges, particularly in mapping SST and CDK constructs to equivalent Terraform resources. Additionally, certain components like Lambda functions and static S3 React buckets require extra attention, as they involve uploading additional files such as Lambda function code or React builds.&lt;/p&gt;
&lt;p&gt;Although I performed this migration specifically for SST, the process I&apos;ll outline is equally applicable to AWS CDK or AWS CloudFormation projects. If you&apos;re facing a similar challenge, this blog post aims to provide you with a solid starting point and valuable insights into the migration process.&lt;/p&gt;
&lt;p&gt;First, let&apos;s discuss some possible motivations and non-motivations for migrating from SST, AWS CDK, or AWS CloudFormation to Terraform.&lt;/p&gt;
&lt;p&gt;After that, I will describe the migration process in detail.&lt;/p&gt;
&lt;h2 id=&quot;motivations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#motivations&quot; aria-label=&quot;motivations permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Motivations&lt;/h2&gt;
&lt;p&gt;My client&apos;s motivation was rather passive. As a newcomer to AWS, he used SST (v.2) to quickly deploy his application, which worked well for him. However, his company eventually decided to standardize on Terraform instead of SST. This highlights alignment as a motivation: if your company is using Terraform, you probably should too.&lt;/p&gt;
&lt;p&gt;Another commonly cited reason is Terraform&apos;s superior state management. While Terraform deployments are faster than SST or AWS CDK, the difference doesn&apos;t feel significant to me.&lt;/p&gt;
&lt;p&gt;There are undoubtedly more motivations; feel free to mention important ones I may have missed.&lt;/p&gt;
&lt;h2 id=&quot;non-motivations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#non-motivations&quot; aria-label=&quot;non motivations permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Non-Motivations&lt;/h2&gt;
&lt;p&gt;The following are reasons I wouldn&apos;t consider as motivations for migrating to Terraform:&lt;/p&gt;
&lt;p&gt;The biggest one is the degree of abstraction, like as for the CDK Constructs. You would lose that when migrating to Terraform. Defining many basic resources in Terraform isn&apos;t particularly enjoyable. To counter this somewhat, you can use an AI tool in your IDE to speed up the definition process. As well, Terraform modules give you a way to abstract definitions to modules, but it doesn&apos;t feel the same as the CDK Constructs.&lt;/p&gt;
&lt;p&gt;As SST and AWS CDK are already TypeScript-based, they make it really easy to define and handle the lifecycle of Lambda functions. In Terraform, you need to define helper functions to manage the Lambda function lifecycle, such as bundling the code, creating the deployment package, and so on. This was actually quite painful for my project, and I ended up with this rather inelegant script:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; lambda_function_payload.zip
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/functions
&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; dist
npx tsc
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; node_modules/ dist/node_modules
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; dist
&lt;span class=&quot;token function&quot;&gt;zip&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rFS&lt;/span&gt; lambda_function_payload.zip *
&lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; lambda_function_payload.zip &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/terraform
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/terraform&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This feels ugly and was no fun.&lt;/p&gt;
&lt;p&gt;Kind of similar is the deployment of a React app into a S3 bucket. In SST and AWS CDK you can use the &lt;code&gt;Bucket&lt;/code&gt; construct and let the framework handle the deployment. In Terraform, you need to manually deploy the React app to the S3 bucket and then invalidate the CloudFront cache.&lt;/p&gt;
&lt;h2 id=&quot;migration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#migration&quot; aria-label=&quot;migration permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Migration&lt;/h2&gt;
&lt;p&gt;In the next section, I will describe how the migration from SST, AWS CDK, or AWS CloudFormation to Terraform works.&lt;/p&gt;
&lt;h2 id=&quot;step-1-deploy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#step-1-deploy&quot; aria-label=&quot;step 1 deploy permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 1: Deploy&lt;/h2&gt;
&lt;p&gt;Before you start the migration, make sure your deployment works as expected. If you have an SST project, follow the instructions for deploying it like &lt;code&gt;npx sst deploy&lt;/code&gt;. After deploying, check the functionality of the CloudFormation stacks. That is super important as that will be your comparison to the Terraform deployment.&lt;/p&gt;
&lt;h2 id=&quot;step-2-generate-terraform-from-the-cloudformation-template&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#step-2-generate-terraform-from-the-cloudformation-template&quot; aria-label=&quot;step 2 generate terraform from the cloudformation template permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 2: Generate Terraform from the CloudFormation template&lt;/h2&gt;
&lt;p&gt;Now that your deployment from step 1 created at least one CloudFormation stack, you can start the migration.&lt;/p&gt;
&lt;p&gt;Via the AWS Console, grab each generated stack and let a chat AI like Claude from anthropic.com or ChatGPT.com generate Terraform from the CloudFormation template. The prompt could look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;txt&quot;&gt;&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;{
  &quot;Resources&quot;: {
    &quot;CustomResourceHandlerServiceRole41AEC181&quot;: {
      &quot;Type&quot;: &quot;AWS::IAM::Role&quot;,
      ...
}

Change the AWS CloudFormation to Terraform. Give back the full Terraform code!&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Through the output from all those answers into the main.tf file.&lt;/p&gt;
&lt;h2 id=&quot;step-3-cleanup-the-maintf&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#step-3-cleanup-the-maintf&quot; aria-label=&quot;step 3 cleanup the maintf permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 3: Cleanup the main.tf&lt;/h2&gt;
&lt;p&gt;Great now we have all the AWS resources in the main.tf file. But unlucky we have resources in the main.ts file which we don&apos;t want or which are not useful like those AWS CDK helper resources &lt;code&gt;CustomResourceHandlerServiceRole...&lt;/code&gt; and &lt;code&gt;CustomResourceHandler...&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As well, there are might be other resources which you might consider removing. For example, if you have several stacks and used variable referencing between the CloudFormation stacks, the AI translation to Terraform usually uses &lt;code&gt;aws_ssm_parameter&lt;/code&gt; Terraform resources to replace them. But since all your resources are in one main.tf file, you don&apos;t need &lt;code&gt;aws_ssm_parameter&lt;/code&gt; and simply reference resources directly.&lt;/p&gt;
&lt;h2 id=&quot;step-4-make-the-lambdas-working&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#step-4-make-the-lambdas-working&quot; aria-label=&quot;step 4 make the lambdas working permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 4: Make the Lambda&apos;s working&lt;/h2&gt;
&lt;p&gt;Yeah, now comes the tricky part with making the Lambda&apos;s working. Look this totally depends on your project structure like where is the Lambda function code located and how is it structured. I think good advice is to keep it similar as possible to your SST or AWS CDK project. As well, use the &lt;code&gt;source_code_hash&lt;/code&gt; to make sure the Lambda function code is hashed and the Lambda function is recreated if the code changes. Like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;hcl&quot;&gt;&lt;pre class=&quot;language-hcl&quot;&gt;&lt;code class=&quot;language-hcl&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;resource &lt;span class=&quot;token type variable&quot;&gt;&quot;aws_lambda_function&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;my_lambda_function&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ...
  &lt;span class=&quot;token property&quot;&gt;source_code_hash&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; filebase64sha256(&lt;span class=&quot;token string&quot;&gt;&quot;my_lambda_function.zip&quot;&lt;/span&gt;)
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What is left is the script to bundle the Lambda function code to the &lt;code&gt;my_lambda_function.zip&lt;/code&gt; file. For you, it could look something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; lambda_function_payload.zip
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/functions
&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; dist &lt;span class=&quot;token comment&quot;&gt;# the tsconfig.json has an &quot;outDir&quot;: &quot;./dist&quot; configured where all the compiled js files will be stored&lt;/span&gt;
npx tsc &lt;span class=&quot;token comment&quot;&gt;# compile the TypeScript code&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; node_modules/ dist/node_modules
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; dist
&lt;span class=&quot;token function&quot;&gt;zip&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rFS&lt;/span&gt; lambda_function_payload.zip *
&lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; lambda_function_payload.zip &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/terraform
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/terraform&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Deploy the Lambda function and check with the AWS Console if it is working as expected.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;terraform apply&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;step-5-make-the-s3-react-bucket-working&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#step-5-make-the-s3-react-bucket-working&quot; aria-label=&quot;step 5 make the s3 react bucket working permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 5: Make the S3 React bucket working&lt;/h2&gt;
&lt;p&gt;Sure this is described for a React App but any other SPA or static site will work the same. First, you need to build the React app like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/frontend
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Copy the build to the s3 bucket and invalidate the cloudfront cache:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;BUCKET_NAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;xyz-react-site-bucket
&lt;span class=&quot;token assign-left variable&quot;&gt;DISTRIBUTION_ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;EZ8RBY8ZM1234
aws s3 &lt;span class=&quot;token function&quot;&gt;sync&lt;/span&gt; dist/ s3://&lt;span class=&quot;token variable&quot;&gt;$BUCKET_NAME&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--delete&lt;/span&gt;

aws cloudfront create-invalidation --distribution-id &lt;span class=&quot;token variable&quot;&gt;$DISTRIBUTION_ID&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--paths&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/*&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Phew, that&apos;s it.&lt;/p&gt;
&lt;h2 id=&quot;step-6-validating&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#step-6-validating&quot; aria-label=&quot;step 6 validating permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 6: Validating&lt;/h2&gt;
&lt;p&gt;Validate the Terraform deployment with your reference deployment from step 1. Usually like when you have an Api Gateway our Lambdas, make sure they are working as expected when comparing the two deployments. The same goes for the S3 React bucket App.&lt;/p&gt;
&lt;h2 id=&quot;considerations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#considerations&quot; aria-label=&quot;considerations permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Considerations&lt;/h2&gt;
&lt;p&gt;Sure, storing all those AWS resources into one main.tf file isn&apos;t Terraform best practice, but it is totally a starting point. If you made sure that your Terraform deployment is working, feel free to split the main.tf file into multiple files, as you are used to.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Migrating SST to Terraform was interesting. With the power of AI, it was a quick process. Combined with my years of experience, I was able to quickly migrate. If you have a question or need otherwise help, please reach out to me.&lt;/p&gt;
&lt;h2 id=&quot;bonus---ab-picturer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bonus---ab-picturer&quot; aria-label=&quot;bonus   ab picturer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bonus - AB Picturer&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/aws-bedrock-update/ab-picturer.png&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;.&lt;/p&gt;
&lt;p&gt;Did you notice the cool blog title picture? I love writing blog posts and choosing nice pictures for them. It is actually one of two randomly selected pictures. But often I want to choose THE BEST picture. So to find the best picture I&apos;m using AB Testing. If you are curious about it, have a look at the &lt;a href=&quot;https://ab-picturer.com&quot;&gt;https://ab-picturer.com&lt;/a&gt; tool and provide me feedback or even better become an engaged tester :).&lt;/p&gt;
&lt;h2 id=&quot;quiz&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#quiz&quot; aria-label=&quot;quiz permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Quiz&lt;/h2&gt;
&lt;p&gt;Deepen your knowledge about this blog post with a click on the AI generated quiz &lt;a href=&quot;https://quizrun.ai/?url=https://martinmueller.dev/aws-sst-cdk-to-tf&quot;&gt;https://quizrun.ai/?url=https://martinmueller.dev/aws-sst-cdk-to-tf&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/6db5a0fe45b87893f7df229130f07f9b/birds-migrating.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/6db5a0fe45b87893f7df229130f07f9b/birds-migrating.jpeg" medium="image"/></item><item><title><![CDATA[HalloCasa Iframe test]]></title><link>https://martinmueller.dev/hallocasa/</link><guid isPermaLink="false">https://martinmueller.dev/hallocasa/</guid><category><![CDATA[eng]]></category><category><![CDATA[2024]]></category><pubDate>Sun, 30 Jun 2024 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/8537adfe07894f1f6173d473f32d4f01/title.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;iframe src=&quot;https://hallocasa.com/DippongRealEstateLosAngeles?lang=en-US&amp;curr=USD&quot; loading=&quot;lazy&quot; width=&quot;1300&quot; height=&quot;1000&quot; frameborder=&quot;0&quot; scrolling=&quot;yes&quot;&gt;&lt;/iframe&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/8537adfe07894f1f6173d473f32d4f01/title.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/8537adfe07894f1f6173d473f32d4f01/title.jpeg" medium="image"/></item><item><title><![CDATA[Recertification - AWS Solution Architect Professional in 2024]]></title><description><![CDATA[Hi Friends. My AWS Solution Architect Professional expires in mid-2022. Since then, I've occasionally thought about renewing, but I didn't…]]></description><link>https://martinmueller.dev/aws-cert-recert/</link><guid isPermaLink="false">https://martinmueller.dev/aws-cert-recert/</guid><category><![CDATA[eng]]></category><category><![CDATA[2024]]></category><category><![CDATA[aws]]></category><pubDate>Wed, 15 May 2024 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/edb137266ef0899824e864d3d38ddd88/Boy Studying in Cloud.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi Friends.&lt;/p&gt;
&lt;p&gt;My AWS Solution Architect Professional expires in mid-2022. Since then, I&apos;ve occasionally thought about renewing, but I didn&apos;t want to invest the time to prepare. But now a customer was paying me to take the exam, so why not. Here&apos;s some advice that helped me minimize the effort and still pass the exam.&lt;/p&gt;
&lt;h2 id=&quot;learning-for-the-exam&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#learning-for-the-exam&quot; aria-label=&quot;learning for the exam permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Learning for the exam&lt;/h2&gt;
&lt;p&gt;First of all, cherish learning! Learning is fun and studying for the exam is fun!&lt;/p&gt;
&lt;p&gt;My favorite way to learn efficiently is to do mock exams like you get on Udemy or other learning platforms. For one, they prepare you for the test exam. And for others, it is a great way to have an amazing learning when you answer a question wrong. Usually the learning platform explains you exactly why your answer was wrong.&lt;/p&gt;
&lt;h3 id=&quot;learn-in-chunks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#learn-in-chunks&quot; aria-label=&quot;learn in chunks permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Learn in chunks&lt;/h3&gt;
&lt;p&gt;The main goal when using these test exams should be to maximize your learning with chunking your learning as this works better for humans. I don&apos;t think you should answer all 75 questions in one go. Rather, you should answer about 5, 10, or 15 so that when you review, you can see what you got wrong and write down what you learned. The goal is to get one or two questions wrong, which will give you a great learning opportunity. If you get all the questions right, you can increase the number of questions you answer in the next session or move on to the next quiz. This way you can have amazing learning every day.&lt;/p&gt;
&lt;h3 id=&quot;loud-sticks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#loud-sticks&quot; aria-label=&quot;loud sticks permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Loud Sticks&lt;/h3&gt;
&lt;p&gt;Read the questions aloud and try to say important keywords like &apos;media company&apos;, &apos;cost effective&apos; or &apos;availability&apos; extra loud. I find that I pay more attention to the questions and answers when I do this. This is not only useful when preparing for the exam. It is also useful during the exam. But be cautious. The online exam will require silence from you. So what I did was whispering which was allowed.&lt;/p&gt;
&lt;p&gt;So you&apos;ve already maximized your learning opportunities through my tips, so let&apos;s move on to the next phase, registration and the actual exam.&lt;/p&gt;
&lt;h2 id=&quot;registration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#registration&quot; aria-label=&quot;registration permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Registration&lt;/h2&gt;
&lt;p&gt;First of all, do not be afraid of failing! Unfortunately failing is still not too accepted in our society, but failing is great as long as you learn from it and try to do better next time. Just look at my two cute little kids. They failed all the time, like when they were trying to walk or talk, but they never gave up and now they walk and talk like professionals.&lt;/p&gt;
&lt;p&gt;So I suggest you to register for the test when you reach like 70% correct answers of a new test exams test like you get them on Udemy or other learning platforms. Don&apos;t wait until you get about 90% correct. The sooner you try, the better. Because even if you fail, you can analyze the results and see where you need to improve and just keep learning.&lt;/p&gt;
&lt;p&gt;Sure, paying those 300 or what dollar for the exam isn&apos;t easy affordable for everyone. Yes, you have a fair point there! If that is difficult for you to do, try to get one of those vouchers to either reduce or completely eliminate the cost. For example, I know that the AWS Community Builder program gives you an exam voucher every year.&lt;/p&gt;
&lt;h3 id=&quot;at-home-or-not&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#at-home-or-not&quot; aria-label=&quot;at home or not permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;At home or not&lt;/h3&gt;
&lt;p&gt;When you register for the exam, you can choose to take it at home or at a testing facility. Both are great choices. I will choose home because I know I am most productive at home and I can have a quiet room for those 4 hours. Also, I know when my brain works best and that is after my morning workout and hot/cold shower. I&apos;m going to use that little brain boost for the exam.&lt;/p&gt;
&lt;h3 id=&quot;celebration&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#celebration&quot; aria-label=&quot;celebration permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Celebration&lt;/h3&gt;
&lt;p&gt;Celebrate your exam journey! Celebration is fun and we usually do it to less. Celebrate your everyday learning. Celebrate the registration and celebrate the passing or failing of the exam.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Preparing and doing the exam is fun but! Enjoy the learnings during preparing for it. Tell me your tips for passing those exams :)!&lt;/p&gt;
&lt;h2 id=&quot;bonus---ab-picturer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bonus---ab-picturer&quot; aria-label=&quot;bonus   ab picturer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bonus - AB Picturer&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/aws-bedrock-update/ab-picturer.png&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;.&lt;/p&gt;
&lt;p&gt;Did you notice the cool blog title picture? I love writing blog posts and choosing nice pictures for them. It is actually one of two randomly selected pictures. But often I want to choose THE BEST picture. So to find the best picture I&apos;m using AB Testing. If you are curious about it, have a look at the &lt;a href=&quot;https://ab-picturer.com&quot;&gt;https://ab-picturer.com&lt;/a&gt; tool and provide me feedback or even better become an engaged tester :).&lt;/p&gt;
&lt;h2 id=&quot;quiz&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#quiz&quot; aria-label=&quot;quiz permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Quiz&lt;/h2&gt;
&lt;p&gt;Deepen your knowledge about this blog post with a click on the AI generated quiz &lt;a href=&quot;https://quizrun.ai/?url=https://martinmueller.dev/aws-cert-recert&quot;&gt;https://quizrun.ai/?url=https://martinmueller.dev/aws-cert-recert&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/edb137266ef0899824e864d3d38ddd88/Boy Studying in Cloud.png</featuredImage><media:content url="https://martinmueller.dev/static/edb137266ef0899824e864d3d38ddd88/Boy Studying in Cloud.png" medium="image"/></item><item><title><![CDATA[AWS Bedrock Update from Claude v2.1 to Claude v3]]></title><description><![CDATA[Recently, AWS released Claude v3. It comes with the Haiku and Sonnet flavors. Both are big improvements over the previous version. We…]]></description><link>https://martinmueller.dev/aws-bedrock-update/</link><guid isPermaLink="false">https://martinmueller.dev/aws-bedrock-update/</guid><category><![CDATA[eng]]></category><category><![CDATA[2024]]></category><category><![CDATA[aws]]></category><category><![CDATA[ai]]></category><category><![CDATA[bedrock]]></category><pubDate>Sun, 21 Apr 2024 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/bf18e914622693f4adb964aefd506b45/cuteRobotPowerup.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Recently, AWS released Claude v3. It comes with the &lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2024/03/anthropics-claude-3-haiku-model-amazon-bedrock/&quot;&gt;Haiku&lt;/a&gt; and &lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2024/03/anthropics-claude-3-sonnet-model-amazon-bedrock/&quot;&gt;Sonnet&lt;/a&gt; flavors. Both are big improvements over the previous version. We recently updated our &lt;a href=&quot;https://martinmueller.dev/arcbot-eng&quot;&gt;arcBot&lt;/a&gt; to use Claude v3 Sonnet and are very impressed with the results. Not only are the responses more intelligent, but the speed of the responses is much faster. In the next section I will describe how an update can go as smoothly as it did for us.&lt;/p&gt;
&lt;h2 id=&quot;upgrade&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#upgrade&quot; aria-label=&quot;upgrade permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Upgrade&lt;/h2&gt;
&lt;p&gt;As mentioned above, we upgraded from Claude v2.1 to Claude v3 Sonnet for our gen AI database tool &lt;a href=&quot;https://martinmueller.dev/arcbot-eng&quot;&gt;arcBot&lt;/a&gt; (Try it out!).&lt;/p&gt;
&lt;p&gt;When you do this there is a high risk that your answers will not be as good as before. But we were prepared and the answers are even better now. But how did we do it?&lt;/p&gt;
&lt;p&gt;Simply with &lt;a href=&quot;https://martinmueller.dev/aws-bedrock-unit-testing&quot;&gt;Unit Testing&lt;/a&gt;. I wrote a bunch of unit tests during the development with Claude v2.1 and they came in handy for the update to v3. It was basically just a matter of making those unit tests pass.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Using AWS gen AI offerings like Claude is super fun. It can be challenging to make sure your answers are still as good as before. But with good test coverage, you can make sure that your answers are still as good as before, or even better. With our unit tests in place, we are confident that we can easily upgrade to a future version again, or if we wanted, change the LLM entirely. If you have any questions or thoughts about this, feel free to contact us :)!&lt;/p&gt;
&lt;h2 id=&quot;bonus---ab-picturer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bonus---ab-picturer&quot; aria-label=&quot;bonus   ab picturer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bonus - AB Picturer&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/aws-bedrock-update/ab-picturer.png&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;.&lt;/p&gt;
&lt;p&gt;Did you notice the cool blog title picture? It is actually one of two randomly selected pictures. I love writing blog posts and choosing nice pictures for them. But often I want to choose THE BEST picture. So to find the best picture I&apos;m using AB Testing. If you are curious about it, have a look at my &lt;a href=&quot;https://martinmueller.dev/ab-picturer&quot;&gt;AB Picturer Tool&lt;/a&gt; and provide me feedback or even better become an engaged tester :).&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/bf18e914622693f4adb964aefd506b45/cuteRobotPowerup.png</featuredImage><media:content url="https://martinmueller.dev/static/bf18e914622693f4adb964aefd506b45/cuteRobotPowerup.png" medium="image"/></item><item><title><![CDATA[AI Software Development with Ninox and arcBot]]></title><description><![CDATA[AI is boosting the corporate landscape. Many simple and complex processes in companies can be greatly simplified or even completely…]]></description><link>https://martinmueller.dev/arcbot-eng/</link><guid isPermaLink="false">https://martinmueller.dev/arcbot-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2024]]></category><category><![CDATA[ninox]]></category><category><![CDATA[ai]]></category><pubDate>Wed, 14 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;AI is boosting the corporate landscape. Many simple and complex processes in companies can be greatly simplified or even completely automated using AI. Jakob, my co-founder, and I see it as an exciting challenge to simplify access to AI for small and medium-sized companies. We believe we have found an exciting approach with the low-code platform &lt;a href=&quot;https://ninox.com&quot;&gt;Ninox&lt;/a&gt; and our AI chatbot &lt;a href=&quot;https://app.arcbot.de&quot;&gt;arcBot&lt;/a&gt;. In this blog post, I would like to introduce you to this approach.&lt;/p&gt;
&lt;h2 id=&quot;ninoxcom&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ninoxcom&quot; aria-label=&quot;ninoxcom permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ninox.com&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ninox.com&quot;&gt;Ninox.com&lt;/a&gt; is a cloud-based low-code platform for building software solutions for small and medium-sized companies. Ninox was founded in 2013 in Germany by &lt;a href=&quot;https://www.linkedin.com/in/frank-boehmer/&quot;&gt;Frank Böhmer&lt;/a&gt;. Here are some ways Ninox can support businesses:&lt;/p&gt;
&lt;p&gt;Business process automation: With Ninox, companies can automate their daily tasks and processes to increase efficiency.&lt;/p&gt;
&lt;p&gt;Customizability: Because Ninox is a low-code platform, companies can adapt their applications to their specific needs without complex programming knowledge.&lt;/p&gt;
&lt;p&gt;Integration: Ninox can be integrated with a variety of other tools and platforms, enabling seamless data exchange between different systems.&lt;/p&gt;
&lt;p&gt;Cost efficiency: Compared to developing custom software from scratch, using a low-code platform like Ninox can result in significant cost savings.&lt;/p&gt;
&lt;p&gt;Fast implementation: With Ninox, companies can build and implement their applications quickly, resulting in a faster time to market.&lt;/p&gt;
&lt;p&gt;A few months ago, I created an MVP with Ninox. You can read about my experiences &lt;a href=&quot;https://martinmueller.dev/ninox-mvp&quot;&gt;here&lt;/a&gt;. In the next chapter, I&apos;ll explain how we use arcBot to simplify the build for your software solution in ninox.&lt;/p&gt;
&lt;h2 id=&quot;arcbot&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#arcbot&quot; aria-label=&quot;arcbot permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;arcBot&lt;/h2&gt;
&lt;p&gt;The arcBot is a ChatGPT-like AI for quickly creating and modifying Ninox tables. We use the AWS Bedrock API to create the Ninox table responses. An example prompt to create Ninox tables could look like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Create customer and product tables in a many to many relationship.&lt;/code&gt;&lt;/p&gt;
&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/arcbot/createTable.gif&quot; alt=&quot;Drawing&quot; width=&quot;800&quot;&gt;
&lt;p&gt;Cool, right? arcBot creates many tables for customers and products. Remarkably, arcBot can even set the ninox-typical inverse fields. In the next prompt we want to add the last name to a customer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Add last name to customer table&lt;/code&gt;&lt;/p&gt;
&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/arcbot/addLastName.gif&quot; alt=&quot;drawing&quot; width=&quot;800&quot;&gt;
&lt;p&gt;For the response, arcBot uses the &lt;a href=&quot;https://docs.anthropic.com/claude/docs/claude-2p1-guide&quot;&gt;Claude v2.1 model&lt;/a&gt;, which is made available via the &lt;a href=&quot;https://docs.aws.amazon.com/bedrock/&quot;&gt;AWS Bedrock API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;How do we ensure that the quality of the answers is as high as possible? We have built in a feedback loop. The user can give feedback after the answer. This feedback is then used to improve arcBot.&lt;/p&gt;
&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/arcbot/feedback1.png&quot; alt=&quot;Drawing&quot; width=&quot;800&quot;&gt;
&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/arcbot/feedback2.png&quot; alt=&quot;Drawing&quot; width=&quot;800&quot;&gt;
&lt;p&gt;I am also in close contact with other Gen AI experts who help me to improve the quality of arcBot answers. I would like to take this opportunity to thank these experts. They are mainly AWS community members and AWS employees who have already given me many valuable tips. Thank you very much 🙏&lt;/p&gt;
&lt;h2 id=&quot;ninox-connector&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ninox-connector&quot; aria-label=&quot;ninox connector permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ninox Connector&lt;/h2&gt;
&lt;p&gt;It&apos;s cool that we can create Ninox tables with arcBot, but how can we process the data in Ninox? This is where the Ninox Connector comes into play. The Ninox Connector can read and update Ninox tables. The following image shows the Ninox Connector.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/arcbot/ninox-connector.png&quot; alt=&quot;Drawing&quot; width=&quot;800&quot;&gt;.&lt;/p&gt;
&lt;p&gt;The Ninox Connector needs some information like the Ninox Url, Team Id, Database Id and the Ninox API Key. Currently the Ninox Connector is only available via Early Access. But you can easily get it on &lt;a href=&quot;https://app.arcbot.de/&quot;&gt;https://app.arcbot.de/&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;discord-community&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#discord-community&quot; aria-label=&quot;discord community permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Discord Community&lt;/h2&gt;
&lt;p&gt;Become part of our &lt;a href=&quot;https://discord.gg/MMWZSHSrEQ&quot;&gt;Discord Community&lt;/a&gt;. We already have some members who give us valuable feedback and feature requests for the arcBot.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;In this blog post I have shown you how we simplify the creation and updating of Ninox tables by combining Ninox and arcBot. We look forward to your feedback. Thank you for reading.&lt;/p&gt;
&lt;p&gt;I am passionate about contributing to Open Source projects. You can find many of my projects on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;GitHub&lt;/a&gt; that you can already benefit from.&lt;/p&gt;
&lt;p&gt;If you found this post valuable and would like to show your support, consider supporting me back. Your support will enable me to write more posts like this and work on projects that provide value to you. You can support me by:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Pateron&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Make your picture rock with the AB Picturer]]></title><description><![CDATA[Images are crucial to effective advertising! AI has made it incredibly easy to create images. But how do you know if an image will move your…]]></description><link>https://martinmueller.dev/ab-picturer/</link><guid isPermaLink="false">https://martinmueller.dev/ab-picturer/</guid><category><![CDATA[eng]]></category><category><![CDATA[2024]]></category><category><![CDATA[aws]]></category><category><![CDATA[abpicturer]]></category><pubDate>Sat, 06 Jan 2024 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/71dd1bbcf5a868594bc20965aac8203e/abtesting.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Images are crucial to effective advertising! AI has made it incredibly easy to create images. But how do you know if an image will move your audience or not? You can try AB Picture Testing. With AB Picture Testing, two different image variants are used and pitted against each other. The one that performs better will be selected to increase traffic. To illustrate this, take a look at the image below, where the audience is separately looking at two different image variants.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/ab-picturer/abtesting.png&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;.&lt;/p&gt;
&lt;h2 id=&quot;my-ab-picture-use-case&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-ab-picture-use-case&quot; aria-label=&quot;my ab picture use case permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My AB Picture Use Case&lt;/h2&gt;
&lt;p&gt;I like to write technical blog posts on my [blog] (&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;). For these posts, I like to use an image that can be used as the thumbnail and main image for the post.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/ab-picturer/blog.png&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;.&lt;/p&gt;
&lt;p&gt;Creating images has become incredibly easy with tools like ChatGPT. By simply prompting it with a request like &quot;Make a cute cloud that sings &quot;I&apos;ve got the power&quot; while maintaining a ratio of 1000:420&quot;, you can create beautiful images that are perfect for sharing your posts on social media.&lt;/p&gt;
&lt;p&gt;I am building a tool called &lt;strong&gt;AB Picturer&lt;/strong&gt;. It allows me to measure the performance of the image variations. In the next section I explain how it works.&lt;/p&gt;
&lt;h2 id=&quot;how-does-ab-picturer-work&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-does-ab-picturer-work&quot; aria-label=&quot;how does ab picturer work permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How does AB Picturer work?&lt;/h2&gt;
&lt;p&gt;The AB Picturer uses image urls like &lt;a href=&quot;https://api.ab-picturer.com?projectId=ab&amp;#x26;state=visitor&quot;&gt;https://api.ab-picturer.com?projectId=ab&amp;#x26;state=visitor&lt;/a&gt; to collect information like when the image was previewed and when the user decided to click on the post. This process is called click-through. AB Picturer can then calculate the click-through rate (CTR) for each image. The image with the higher CTR wins and can be used as the main image for the post.&lt;/p&gt;
&lt;p&gt;The basic concept is to have two image urls that are part of the AB Picturer flow. The first is for the image preview and the second is for the image visitor. I&apos;ll describe these in more detail now.&lt;/p&gt;
&lt;h3 id=&quot;ab-picturer-flow&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ab-picturer-flow&quot; aria-label=&quot;ab picturer flow permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AB Picturer Flow&lt;/h3&gt;
&lt;p&gt;The preview url is the beginning of the AB Picturer flow. When the user views the preview url via your thumbnail or social media post, the flow starts. The user session is tracked and if the user uses the image visitor url, this counts as a click-through.&lt;/p&gt;
&lt;h3 id=&quot;ab-picturer-dashboard&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ab-picturer-dashboard&quot; aria-label=&quot;ab picturer dashboard permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AB Picturer Dashboard&lt;/h3&gt;
&lt;p&gt;The AB Picturer Dashboard shows you the CTR and other statistics for each image. The image with the higher CTR wins and can be used as the main image for the post. It is a very simple dashboard at the moment, but I plan to improve it in the future.&lt;/p&gt;
&lt;img src=&quot;https://github.com/mmuller88/mmblog/raw/master/content/ab-picturer/dashboard.png&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;
&lt;h2 id=&quot;join-the-ab-picturer-discord--newsletter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#join-the-ab-picturer-discord--newsletter&quot; aria-label=&quot;join the ab picturer discord  newsletter permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Join the AB Picturer Discord &amp;#x26; Newsletter&lt;/h2&gt;
&lt;p&gt;I&apos;ve set up a &lt;a href=&quot;https://discord.gg/ZSvMBCUeyA&quot;&gt;Discord&lt;/a&gt; for you to try out the AB Picturer and give me feedback. I&apos;m super curious about your feedback as I plan to develop more features based on your needs.&lt;/p&gt;
&lt;p&gt;Also, I think it is pretty cool to be part of a community. So join the &lt;a href=&quot;https://discord.gg/ZSvMBCUeyA&quot;&gt;AB Picturer Discord&lt;/a&gt; and let&apos;s have some fun together.&lt;/p&gt;
&lt;p&gt;And please subscribe to our &lt;a href=&quot;https://app.ab-picturer.com/newsletter&quot;&gt;Newsletter&lt;/a&gt; if you want regular updates about AB Picturer.&lt;/p&gt;
&lt;p&gt;In the next section I will show you how to integrate and use AB Picturer.&lt;/p&gt;
&lt;h2 id=&quot;integrate-ab-picturer-into-your-blog&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#integrate-ab-picturer-into-your-blog&quot; aria-label=&quot;integrate ab picturer into your blog permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Integrate AB Picturer into your blog&lt;/h2&gt;
&lt;p&gt;It doesn&apos;t matter what blog post engine you&apos;re using, as long as it supports displaying images, it should work.&lt;/p&gt;
&lt;h3 id=&quot;gastby-and-ab-picturer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#gastby-and-ab-picturer&quot; aria-label=&quot;gastby and ab picturer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gastby and AB Picturer&lt;/h3&gt;
&lt;p&gt;So on my blog post I have the two urls preview and visitor in the meta section:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;txt&quot;&gt;&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;imagePreviewUrl: &quot;https://api.ab-picturer.com?projectId=sst&amp;amp;state=preview&quot;
imageVisitorUrl: &quot;https://api.ab-picturer.com?projectId=sst&amp;amp;state=visitor&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I then simply render these to the thumbnail, meta tags and post itself:&lt;/p&gt;
&lt;p&gt;Here is the snippet to add it as a thumbnail:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; imagePreviewUrl &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;imagePreviewUrl&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;See the complete example in my &lt;a href=&quot;https://github.com/mmuller88/mmblog/blob/master/src/pages/index.js&quot;&gt;repository&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Add it to the &lt;a href=&quot;https://github.com/mmuller88/mmblog/blob/master/src/templates/blog-post.js&quot;&gt;meta tags&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MetaTags&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token attr-name&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;markdownRemark&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;excerpt&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token attr-name&quot;&gt;thumbnail&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thumbnail &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; thumbnail&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; imagePreviewUrl&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token attr-name&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token attr-name&quot;&gt;pathname&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And finally, add it to the &lt;a href=&quot;https://github.com/mmuller88/mmblog/blob/master/src/templates/blog-post.js&quot;&gt;post&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jsx&quot;&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 imageVisitorUrl &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;imageVisitorUrl&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is cool, right? It is basically just a src url :)!&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#outlook&quot; aria-label=&quot;outlook permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Outlook&lt;/h2&gt;
&lt;p&gt;I&apos;m a big fan of the blog post site [dev.to] (&lt;a href=&quot;https://dev.to&quot;&gt;https://dev.to&lt;/a&gt;). I tried to get the AB pictures to work there but unfortunately I failed. I think they do some caching for the images. I&apos;ll try to contact them and see if we can get it to work.&lt;/p&gt;
&lt;p&gt;I could collect more information like where the visitor is coming from or what country the user is from. If you would like to have this and other features, contact me in our AB Pictures Discord :)!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Rating your images to see if your audience likes them is super important. In this article I have shown you how to do it with AB Picturer. Join the &lt;a href=&quot;https://discord.gg/ZSvMBCUeyA&quot;&gt;AB Picturer Discord&lt;/a&gt;.&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/71dd1bbcf5a868594bc20965aac8203e/abtesting.png</featuredImage><media:content url="https://martinmueller.dev/static/71dd1bbcf5a868594bc20965aac8203e/abtesting.png" medium="image"/></item><item><title><![CDATA[Create a Next.js Server Component S3 Picture Uploader with SST]]></title><description><![CDATA[I recently started exploring SST as an alternative to my favorite full-stack set consisting of Projen, AWS CDK, and React. I have been…]]></description><link>https://martinmueller.dev/sst-nextjs-s3-picture-uploader/</link><guid isPermaLink="false">https://martinmueller.dev/sst-nextjs-s3-picture-uploader/</guid><category><![CDATA[eng]]></category><category><![CDATA[2024]]></category><category><![CDATA[aws]]></category><category><![CDATA[sst]]></category><category><![CDATA[nextjs]]></category><pubDate>Wed, 03 Jan 2024 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/dec356a2e50eb3afcefd0121831a96d2/bucketWithPicture.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;I recently started exploring &lt;a href=&quot;https://github.com/sst/sst&quot;&gt;SST&lt;/a&gt; as an alternative to my favorite full-stack set consisting of &lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt;, &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt;, and React. I have been thoroughly impressed with the experience so far. In this article, I will demonstrate how to create a Next.js App Router S3 Picture Uploader using SST.&lt;/p&gt;
&lt;h2 id=&quot;sst&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#sst&quot; aria-label=&quot;sst permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SST&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sst/sst&quot;&gt;SST&lt;/a&gt; is a powerful framework that simplifies the development of serverless applications. It offers a straightforward and opinionated approach to defining serverless apps using TypeScript. Built on top of AWS CDK, SST handles the complexity of setting up your serverless infrastructure automatically. SST is an open-source framework and is completely free to use.&lt;/p&gt;
&lt;p&gt;SST offers a variety of powerful constructs, including the NextjsSite construct. In the following section, I will provide more details about the NextjsSite construct, which greatly simplifies the process of deploying your frontend.&lt;/p&gt;
&lt;h2 id=&quot;nextjssite&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#nextjssite&quot; aria-label=&quot;nextjssite permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;NextjsSite&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.sst.dev/constructs/NextjsSite&quot;&gt;NextjsSite&lt;/a&gt; construct allows you to effortlessly create and manage &lt;a href=&quot;https://github.com/sst/open-next&quot;&gt;open-next&lt;/a&gt;, which is a great alternative for hosting Next.js on Vercel. Being defined within an SST App, you can easily integrate other AWS services, making it incredibly powerful. However, if you&apos;re using the latest and most advanced features of Next.js, such as Server Components with the Next.js App Router, you may encounter some challenges.&lt;/p&gt;
&lt;h2 id=&quot;server-components&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#server-components&quot; aria-label=&quot;server components permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Server Components&lt;/h2&gt;
&lt;p&gt;Server Components are a new way to build with Next.js. They allow you to write parts of your application using React components that are served from the server. This approach offers several advantages, such as faster page loading and simplified setup without the need to manage client states with useState, useEffect, and similar hooks. However, working with Server Components may require adjusting your workflow and learning new concepts.&lt;/p&gt;
&lt;h2 id=&quot;s3-picture-uploader&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#s3-picture-uploader&quot; aria-label=&quot;s3 picture uploader permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;S3 Picture Uploader&lt;/h2&gt;
&lt;p&gt;In this section, I will demonstrate how to create an S3 picture uploader using the Next.js App Router and SST. We will utilize the NextjsSite construct to create the Next.js App Router and the S3 construct to create the S3 Bucket.&lt;/p&gt;
&lt;p&gt;You can find all the code in my &lt;a href=&quot;https://github.com/mmuller88/sst-nextjs-s3-picture-uploader&quot;&gt;GitHub Repository&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;initialize-sst-nextjssite&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#initialize-sst-nextjssite&quot; aria-label=&quot;initialize sst nextjssite permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Initialize SST NextjsSite&lt;/h3&gt;
&lt;p&gt;All the steps are taken from the official &lt;a href=&quot;https://docs.sst.dev/start/nextjs&quot;&gt;SST guide&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-next-app@latest&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mainly choose the defaults. Then switch to the app folder and open it via VS Code.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SST_PROJECT&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
code &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now run:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-sst@latest
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before deploying to your AWS Account, ensure that you have set up the correct credentials. I recommend using the AWS Identity Service to obtain temporary AWS CLI credentials, but you can also set up IAM User credentials or profiles. Once you have the credentials in place, run the following command:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx sst deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ensure that the AWS deployment is successful! View your CloudFront SiteUrl shown in the SST Output. Voila! You now have a running Next.js application on AWS with open-next 🤯. Let&apos;s take a closer look at what has been deployed in our AWS account because it&apos;s quite extensive!&lt;/p&gt;
&lt;p&gt;To inspect the resources created by SST, go to the AWS Console and navigate to CloudFormation. Click on the newly created stack to view the details. You will find a set of helper Lambda Functions, the Lambda Function and Lambda URL for the Server Component, a CloudFront Distribution, and an S3 bucket that serves the static Next.js files.&lt;/p&gt;
&lt;h3 id=&quot;add-s3-picture-uploader&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#add-s3-picture-uploader&quot; aria-label=&quot;add s3 picture uploader permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Add S3 Picture Uploader&lt;/h3&gt;
&lt;p&gt;Ok let&apos;s go! We need to add an S3 bucket where we can upload the pictures to. Go to the &lt;code&gt;sst.config.ts&lt;/code&gt; file and add a Bucket:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; SSTConfig &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sst&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Bucket&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; NextjsSite &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sst/constructs&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token function&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sst-nextjs-s3-picture-uploader&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;us-east-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token function&quot;&gt;stacks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Site&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bucket &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;public&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; site &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NextjsSite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;site&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    permissions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;bucket&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    bind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;bucket&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

   stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addOutputs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    SiteUrl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; site&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; satisfies SSTConfig&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;permissions: [bucket]&lt;/code&gt; property gives the NextjsSite read and write access for the S3 bucket. With &lt;code&gt;bind: [bucket]&lt;/code&gt; You can use SST node variables in your React code like &lt;code&gt;Bucket.public.bucketName&lt;/code&gt;. Let&apos;s update the page.tsx for adding the upload button and S3 AWS SDK upload code. You might need to run &lt;code&gt;npm run dev&lt;/code&gt; so that the SST node variable &lt;code&gt;Bucket.public.bucketName&lt;/code&gt; gets recognized.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;tsx&quot;&gt;&lt;pre class=&quot;language-tsx&quot;&gt;&lt;code class=&quot;language-tsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Bucket &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sst/node/bucket&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; S3Client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PutObjectCommand &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@aws-sdk/client-s3&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Home&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;upload&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FormData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;use server&quot;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; file&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; File &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;unknown&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; File
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;No file uploaded&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bytes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;arrayBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;S3Client&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;us-east-1&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PutObjectCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   Bucket&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Bucket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;public&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bucketName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   Key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   Body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token constant&quot;&gt;ACL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;public-read&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;command&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Uploaded &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; to S3&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; success&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;flex min-h-screen flex-col items-center justify-between p-24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;upload&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;accept&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image/png, image/jpeg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;submit&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Upload&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Do you see how seaminess we can sneak in the AWS SDK s3 upload code? For me, that is mind-blowing if you like to compare it with a client-side variant where you couldn&apos;t do that so easily without exposing your AWS API credentials. But as server components are server side we are saved. It offloads a lot of complexity. Super cool!&lt;/p&gt;
&lt;p&gt;Let&apos;s deploy that! For more convenience let&apos;s add a new command in the package json &lt;code&gt;&quot;deploy&quot;: &quot;sst deploy&quot;,&lt;/code&gt;. Now run:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Open the CloudFront SiteUrl. Now click on the upload button and check if you can see the file in S3.&lt;/p&gt;
&lt;p&gt;BTW. for faster development you could also run locally with &lt;code&gt;npm run dev&lt;/code&gt; but make sure to load your AWS CLI credentials before which allowing access to the S3 Bucket.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I&apos;m still super flashed at how nicely SST is orchestrating the frontend with the backend. In this post, I described how you can start with SST and how to create an S3 picture uploader. I hope you learned something new. If you liked my post or want to correct me please reach out to me :).&lt;/p&gt;
&lt;p&gt;I am passionate about contributing to Open Source projects. You can find many of my projects on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;GitHub&lt;/a&gt; that you can already benefit from.&lt;/p&gt;
&lt;p&gt;If you found this post valuable and would like to show your support, consider supporting me back. Your support will enable me to write more posts like this and work on projects that provide value to you. You can support me by:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Pateron&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/dec356a2e50eb3afcefd0121831a96d2/bucketWithPicture.png</featuredImage><media:content url="https://martinmueller.dev/static/dec356a2e50eb3afcefd0121831a96d2/bucketWithPicture.png" medium="image"/></item><item><title><![CDATA[How to Perform Unit Testing on your AWS Bedrock AI Lambda]]></title><description><![CDATA[Using the AWS Bedrock API for MVPs is incredibly enjoyable! I recently wrote an article on how you can make the LLM Claude respond in JSON…]]></description><link>https://martinmueller.dev/aws-bedrock-unit-testing/</link><guid isPermaLink="false">https://martinmueller.dev/aws-bedrock-unit-testing/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[aws]]></category><category><![CDATA[bedrock]]></category><category><![CDATA[ai]]></category><pubDate>Sat, 30 Dec 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/903ebbb8753ea3a3cfb798f42dcbfc98/osterich.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Using the AWS Bedrock API for MVPs is incredibly enjoyable! I recently wrote an article on how you can make the LLM Claude respond in JSON. You can check it out &lt;a href=&quot;https://martinmueller.dev/aws-bedrock-validation&quot;&gt;here&lt;/a&gt;. While it&apos;s a lot of fun, testing your LLM settings and prompts can become tiresome and frustrating. In this article, I will explain how you can effectively unit test your Lambda function that calls the AWS Bedrock API. By being able to unit test your prompts, you can iterate quickly towards your desired MVP or project state.&lt;/p&gt;
&lt;h2 id=&quot;lambda-unit-testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#lambda-unit-testing&quot; aria-label=&quot;lambda unit testing permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lambda Unit Testing&lt;/h2&gt;
&lt;p&gt;Unit testing a Lambda function is straightforward since it is essentially a function that executes code. To test it, you can simply call the function with the necessary arguments and verify the response. If you are using Node.js, Jest provides a convenient way to run your test code.&lt;/p&gt;
&lt;h2 id=&quot;lambda-streaming-response--unit-testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#lambda-streaming-response--unit-testing&quot; aria-label=&quot;lambda streaming response  unit testing permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lambda Streaming Response &amp;#x26; Unit Testing&lt;/h2&gt;
&lt;p&gt;The Lambda Streaming Response allows to leverage the streaming response from your LLM. Using the streaming response from your LLM is important as it gives your early feedback. That is pretty much what is happening when ChatGPT gives your those word by word streaming response.&lt;/p&gt;
&lt;h2 id=&quot;lambda&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#lambda&quot; aria-label=&quot;lambda permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lambda&lt;/h2&gt;
&lt;p&gt;Here I show you a bit from the Lambda Function I want to unit test later.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; APIGatewayProxyEventV2WithRequestContext&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;APIGatewayEventRequestContextV2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  responseStream&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambdaStream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ResponseStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  ctx&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;event: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ninoxTables &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; body&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bedrockParams&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; InvokeModelCommandInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    modelId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;anthropic.claude-v2:1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    contentType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;application/json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    accept&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;*/*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      prompt&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n\nHuman: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;prompt&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n\nAssistant:&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      temperature&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;bedrockParams: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bedrockParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InvokeModelWithResponseStreamCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bedrockParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;//InvokeModelWithResponseStreamCommandOutput&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;command&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

  responseStream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;unit-testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#unit-testing&quot; aria-label=&quot;unit testing permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unit Testing&lt;/h2&gt;
&lt;p&gt;And here is the unit test in a file living next to my Lambda function.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ArcbotLambdaInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handler &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../src/arcbot-stack.stream&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;userInput: How is the weather?&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;mockEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      userInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;How is the weather?&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;//@ts-ignore&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// do some validation&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;statusCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    respond&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;I do not understand. Please rephrase!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Create a customer table&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;mockEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      userInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Create a customer table&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;//@ts-ignore&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// do some validation&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;commonExpects&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; NinoxTable&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;body: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NinoxTableSchema&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;safeParse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBeTruthy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;customer&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caption&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Customer&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;mockEvent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userInput &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ArcbotLambdaInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;APIGatewayProxyEventV2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    version&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userInput &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ArcbotLambdaInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Unit testing your Lambda function that calls the AWS Bedrock API is crucial. It enables you to iterate quickly towards your desired MVP or project state. I hope this article has been helpful to you. If you have any questions or feedback, please don&apos;t hesitate to reach out to me.&lt;/p&gt;
&lt;p&gt;I am passionate about contributing to Open Source projects. You can find many of my projects on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;GitHub&lt;/a&gt; that you can already benefit from.&lt;/p&gt;
&lt;p&gt;If you found this post valuable and would like to show your support, consider supporting me back. Your support will enable me to write more posts like this and work on projects that provide value to you. You can support me by:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Pateron&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/903ebbb8753ea3a3cfb798f42dcbfc98/osterich.png</featuredImage><media:content url="https://martinmueller.dev/static/903ebbb8753ea3a3cfb798f42dcbfc98/osterich.png" medium="image"/></item><item><title><![CDATA[My first Experience with Powertools for AWS Lambda (TypeScript)]]></title><description><![CDATA[Hi there, I'm new to Powertools for AWS Lambda (TypeScript). Though I hear a lot of my DevOps friends say that it's a great tool for…]]></description><link>https://martinmueller.dev/aws-powertools/</link><guid isPermaLink="false">https://martinmueller.dev/aws-powertools/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[aws]]></category><category><![CDATA[powertools]]></category><pubDate>Sun, 24 Dec 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/b5d84c74499df1c194a10471356fba17/powerHero.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi there,&lt;/p&gt;
&lt;p&gt;I&apos;m new to &lt;a href=&quot;https://docs.powertools.aws.dev/lambda/typescript/latest/&quot;&gt;Powertools for AWS Lambda (TypeScript)&lt;/a&gt;. Though I hear a lot of my DevOps friends say that it&apos;s a great tool for building serverless applications, I&apos;ve never had the chance to use it myself. So I decided to give it a try and see what all the fuss is about. What can I say, I totally love it. In the next sections I will explain what the.&lt;/p&gt;
&lt;h2 id=&quot;what-is-powertools-for-aws-lambda&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-powertools-for-aws-lambda&quot; aria-label=&quot;what is powertools for aws lambda permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is Powertools for AWS Lambda&lt;/h2&gt;
&lt;p&gt;Powertools for AWS Lambda is a collection of utilities, patterns, and best practices for writing AWS Lambda functions in Python, Typescript, Java and DotNet. It includes logging, tracing, custom metrics, and more. The goal of this project is to enable developers to build scalable and robust serverless applications easily.&lt;/p&gt;
&lt;h2 id=&quot;why-i-am-using-aws-lambda-powertools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-i-am-using-aws-lambda-powertools&quot; aria-label=&quot;why i am using aws lambda powertools permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why I am using AWS Lambda Powertools&lt;/h2&gt;
&lt;p&gt;I&apos;m a huge DevOps fanboy so I&apos;m all over for techniques like Infrastructure as Code (IaC) or Serverless. Pretty cool about those that it helps me to focus on my business logic of my software product rather then wasting time in setting it up. Powertools feels pretty similar as it helps me to easy implement certain goodies as logging or tracing without the need to spend much time.&lt;/p&gt;
&lt;p&gt;Certainly my main motivation is the Powertools logger library. The logger library helps you to write my Lambda logs in specific format to enable features like log levels and log queries with AWS CloudWatch Logs Insights. So far that is amazingly great and it gives me a powerful insight into my Lambda.&lt;/p&gt;
&lt;p&gt;I&apos;m using Powertools for me newest AI MVP. Part of the MVP is a Lambda where I call the AWS Bedrock API. Furthermore I automatically validate the LLM response. For more details see &lt;a href=&quot;https://martinmueller.dev/aws-bedrock-validation&quot;&gt;https://martinmueller.dev/aws-bedrock-validation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-to-start&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-start&quot; aria-label=&quot;how to start permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to start?&lt;/h2&gt;
&lt;p&gt;The Powertools GitHub repository offers nice examples to integrate and learn from. For example &lt;a href=&quot;https://github.com/aws-powertools/powertools-lambda-typescript&quot;&gt;here&lt;/a&gt; are nice example written in AWS CDK. Following I will list the features I gained some experience with.&lt;/p&gt;
&lt;h2 id=&quot;logger&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#logger&quot; aria-label=&quot;logger permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Logger&lt;/h2&gt;
&lt;p&gt;The logger is super fun to use! It gives me a powerful insight about my Lambda functions. Though I&apos;m still not super sure when to use the different log levels and when and what objects I should put into the object logger part. But I will keep learning from my DevOps friends and make my own experience. Ultimately I will know better when I truly need insight via Logs Insights.&lt;/p&gt;
&lt;h2 id=&quot;parameters&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#parameters&quot; aria-label=&quot;parameters permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Parameters&lt;/h2&gt;
&lt;p&gt;The parameters feature is super cool. It helps me to easily access the parameters I defined in my AWS CDK stacks. I can access them via the &lt;code&gt;get&lt;/code&gt; function. So far I only used it for getting secrets from the secrets manager but I&apos;m super excited to use it for more like perhaps app configurations.&lt;/p&gt;
&lt;h2 id=&quot;idempotency&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#idempotency&quot; aria-label=&quot;idempotency permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Idempotency&lt;/h2&gt;
&lt;p&gt;The idempotency feature seems super useful. It could help to reduce the quite high costs of using the AWS Bedrock API. But unfortunately idempotency isn&apos;t currently combinable with Lambda stream response. Hopefully that will change in future 🤞.&lt;/p&gt;
&lt;h2 id=&quot;resources-to-learn-utilizing-powertools&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#resources-to-learn-utilizing-powertools&quot; aria-label=&quot;resources to learn utilizing powertools permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources to learn utilizing Powertools&lt;/h2&gt;
&lt;p&gt;Here&apos;s a list of examples I found helpful to learn how to apply Powertools:&lt;/p&gt;
&lt;p&gt;Examples from the GitHub Repo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aws-powertools/powertools-lambda-typescript&quot;&gt;https://github.com/aws-powertools/powertools-lambda-typescript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Powertools has ana amazing Discord community. Make sure to not miss it!:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://discord.gg/82CkmT97ja&quot;&gt;Discord&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/leegilmorecode&quot;&gt;Lee Gilmore&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/leegilmorecode/embedded-aws-cloudwatch-dashboards/tree/main&quot;&gt;https://github.com/leegilmorecode/embedded-aws-cloudwatch-dashboards/tree/main&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Working with AWS Lambda Powertools Typescript totally make sense and I love it. It will definitely be my default choice when developing my next Lambda. I still need to learn how to use it properly! Please if you have any feedback how I can utilize Powertools better, reach out to me!&lt;/p&gt;
&lt;p&gt;I am passionate about contributing to Open Source projects. You can find many of my projects on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;GitHub&lt;/a&gt; that you can already benefit from.&lt;/p&gt;
&lt;p&gt;If you found this post valuable and would like to show your support, consider supporting me back. Your support will enable me to write more posts like this and work on projects that provide value to you. You can support me by:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Pateron&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/b5d84c74499df1c194a10471356fba17/powerHero.png</featuredImage><media:content url="https://martinmueller.dev/static/b5d84c74499df1c194a10471356fba17/powerHero.png" medium="image"/></item><item><title><![CDATA[Automatically validate your AWS Bedrock LLM Responses]]></title><description><![CDATA[Validating the response from your Language Learning Model (LLM) is a critical step in the development process. It ensures that the response…]]></description><link>https://martinmueller.dev/aws-bedrock-validation/</link><guid isPermaLink="false">https://martinmueller.dev/aws-bedrock-validation/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[aws]]></category><category><![CDATA[bedrock]]></category><category><![CDATA[ai]]></category><pubDate>Mon, 18 Dec 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/e105638b790c2e217d5f10bfd96d4f91/confidentRobot.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Validating the response from your Language Learning Model (LLM) is a critical step in the development process. It ensures that the response is in the correct format and contains the expected data. Manual evaluation can quickly become tiresome, especially when making frequent changes to your LLM. Automating or partially automating the validation process is highly recommended to save time and effort. In this post, I will discuss and demonstrate some ideas how you can achieve this automation.&lt;/p&gt;
&lt;h2 id=&quot;before&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#before&quot; aria-label=&quot;before permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Before&lt;/h2&gt;
&lt;p&gt;When I refer to LLM, I am talking about the use of existing foundation models through AWS Bedrock, such as Claude, LLama2, and others. You can learn more about AWS Bedrock &lt;a href=&quot;https://aws.amazon.com/bedrock/&quot;&gt;here&lt;/a&gt;. There are techniques you can use to enhance the response, such as prompt refinements, RAG (Retrieval Augmentation using Vector Databases), or fine-tuning.&lt;/p&gt;
&lt;p&gt;Responses from Language Learning Models (LLMs) are often non-deterministic, meaning that different responses can be generated even with the same prompt. However, this behavior can be adjusted to some extent using LLM parameters such as temperature.&lt;/p&gt;
&lt;h2 id=&quot;ideas&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ideas&quot; aria-label=&quot;ideas permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ideas&lt;/h2&gt;
&lt;p&gt;In the following sections I will present some ideas for creating automated tests for your LLM responses. I will also provide some examples of how I implemented these ideas in my own projects.&lt;/p&gt;
&lt;h3 id=&quot;validate-the-shape&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#validate-the-shape&quot; aria-label=&quot;validate the shape permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Validate the Shape&lt;/h3&gt;
&lt;p&gt;In many cases, the response may contain deterministic parts that can be used to partially validate it. For instance, I rely on Claude to provide a JSON response. I have taught Claude the schema of the JSON response, and by performing a schema validation test, I can verify if Claude adheres to the schema. Verifying a JSON schema is very simple.&lt;/p&gt;
&lt;p&gt;Each programming language has a library that can be used to validate the schema. For instance, in TypeScript, I use the &lt;a href=&quot;https://github.com/colinhacks/zod&quot;&gt;zod library&lt;/a&gt; to create and validate the schema. Which looks like that:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; z &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;zod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; NinoxFieldSchema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;strictObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  base&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;boolean&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  caption&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  captions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  required&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  order&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NinoxField&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;infer&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; NinoxFieldSchema&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; NinoxTableSchema &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;strictObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  nextFieldId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  caption&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  captions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  hidden&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NinoxTable&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; z&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;infer&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; NinoxTableSchema&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And as part of my unit tests:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;check schema&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; validationResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NinoxTableSchema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;safeParse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;validationResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;success&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBeTruthy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;validate-sub-responses&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#validate-sub-responses&quot; aria-label=&quot;validate sub responses permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Validate Sub-Responses&lt;/h3&gt;
&lt;p&gt;In my current AI application, I utilize multiple LLM calls to generate the final response. While validating the entire response may be challenging, I can easily validate some of the sub-responses. For instance, I have a deterministic response for which I can verify the response. The deterministic response classifies a user&apos;s intent into a specific category. For example, if the user asks to create a table, the intent is classified as &quot;create_table&quot;. That will generate a deterministic sub-response in my AWS Lambda for the &quot;create_table&quot; intent. To test the accuracy of the classification, you can use well-known methods such as train-validation-test Split the training data into subsets for training and validation. I&apos;ll describe this technique more in the next section.&lt;/p&gt;
&lt;h3 id=&quot;train-validation-test-split&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#train-validation-test-split&quot; aria-label=&quot;train validation test split permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Train-Validation-Test Split&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://medium.com/@evertongomede/the-significance-of-train-validation-test-split-in-machine-learning-91ee9f5b98f3&quot;&gt;train-validation-test split&lt;/a&gt; is very crucial to messsure the performance of the LLM. One methods of those splits is the k-fold cross validation. I try to explain this approach in easy words. Make sure to check the far more technical artical from &lt;a href=&quot;https://medium.com/@evertongomede/the-significance-of-train-validation-test-split-in-machine-learning-91ee9f5b98f3&quot;&gt;Everton Gomede, PhD, The Significance of Train-Validation-Test Split in Machine Learning&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;For instance, you could use 90 percent of the data for training and 10 percent for validation. Then, you can use the validation data to test the accuracy of the classification. Additionally, you can use permutation to shift the 10 percent of the validation data. I implemented a simple algorithm in TypeScript which helps me to calculate the accuracy of the classification:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; test &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@jest/globals&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ArcbotStackStream &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../src/arcbot-stack.stream&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 call_bedrock&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 generate_intent_identification_prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 generate_table_identification_prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 modify_table_prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 relationship_json_prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../src/arcbot-stack.stream&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 intentTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 modifyTableTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 oneToManyTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 tableIdentificationData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../src/training-data&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; runEvaluation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;s&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
 trainingData&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 jestSpy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SpyInstance&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token function-variable function&quot;&gt;promptRefinement&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 jsonResponse&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getTrainingAndEvaluationPermutations&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;trainingsData&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Split trainings data into training and evaluation data&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;sliceTrainingsData&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fromPercentage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toPercentage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
   Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;trainingsData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; evaluationSlice &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; fromPercentage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; toPercentage
     &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; trainingSlice &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;evaluationSlice&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      training&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;training&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; trainingSlice &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      evaluations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;evaluations&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; evaluationSlice&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     training&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
     evaluations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; trainingPercentage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.9&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; validationPercentage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; trainingPercentage

  &lt;span class=&quot;token comment&quot;&gt;// permute the training and evaluation data&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; trainingValidationPermutations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
   &lt;span class=&quot;token function&quot;&gt;sliceTrainingsData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; validationPercentage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; validationPercentage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; validationPercentage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   trainingValidationPermutations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;sliceTrainingsData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; validationPercentage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;trainingValidationPermutations: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    trainingValidationPermutations
   &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; trainingValidationPermutations
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; correctResponses &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; wrongResponses &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; trainingRecords &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getTrainingAndEvaluationPermutations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;trainingData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; trainingPermutation &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; trainingRecords&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;trainingPermutation=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;trainingPermutation&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  jestSpy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockImplementation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; trainingPermutation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;training&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; evaluationRecords &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
   trainingPermutation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;evaluations
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; input &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; evaluationRecords&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; intent_prompt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;promptRefinement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;call_bedrock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;intent_prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; jsonResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; received &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; response

    &lt;span class=&quot;token comment&quot;&gt;// trim to JSON string&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;jsonResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     received &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;received&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Expected &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;evaluationRecords&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\nReceived &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;received&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;evaluationRecords&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; received&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     correctResponses&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     wrongResponses&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; correctResponses: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;correctResponses&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;\n wrongResponses: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;wrongResponses&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; \n &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;
   correctResponses &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;correctResponses &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; wrongResponses&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; accuracy&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;evaluate one to many&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockTrainingsData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spyOn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  ArcbotStackStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;getOneToManyTrainingData&quot;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;oneToManyPromptRefinement&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;relationship_json_prompt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;CUSTOMER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; caption&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Customer&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;EMPLOYEE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; caption&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Employee&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;INVOICE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; caption&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Invoice&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   userInput
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runEvaluation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  oneToManyTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mockTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  oneToManyPromptRefinement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;evaluate intent&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockTrainingsData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spyOn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  ArcbotStackStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;getIntentTrainingData&quot;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;generate_intent_identification_promptRefinement&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  userInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generate_intent_identification_prompt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runEvaluation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  intentTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mockTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  generate_intent_identification_promptRefinement
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;evaluate table identification&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockTrainingsData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spyOn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  ArcbotStackStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;getTableIdentificationData&quot;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;generate_table_identification_promptRefinement&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  userInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prompt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generate_table_identification_prompt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
   userInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tableIdentificationData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; prompt
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runEvaluation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  tableIdentificationData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mockTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  generate_table_identification_promptRefinement
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;evaluate modify table&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockTrainingsData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; jest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spyOn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  ArcbotStackStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;getModifyTableTrainingsData&quot;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 modifyTableTrainingsData

 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;modify_table_promptRefinement&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prompt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;modify_table_prompt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userInput&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; prompt
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runEvaluation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  modifyTableTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mockTrainingsData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  modify_table_promptRefinement&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I think the most interesting part here is the method interface &lt;code&gt;getTrainingAndEvaluationPermutations(trainingData)&lt;/code&gt; as that always expect the same format as input and gives you back a permuted test validation split of the input training data. The training data have to be in record string list shape:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;s&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where the key represents the expected result / classification class / LLM output and the value represents possible inputs which leads to the result. The result will be this type:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 training&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;
 evaluations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It is an Array representing the permutations. Each permutation has a &lt;code&gt;training&lt;/code&gt; and &lt;code&gt;evaluations&lt;/code&gt; slice.&lt;/p&gt;
&lt;p&gt;One traing data example would be:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; intentTrainingsData&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 create_new_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;Create table to store invoices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;I need to store my customers information&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;I need a table for my employees&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 modify_existing_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;Customers table should also have an address&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;Add address to the customer table&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;Invoice should have a date&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 link_two_tables&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;Customer should have multiple invoices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;Each employee should be responsible for multiple customers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 do_not_know&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;How are you today?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;What is your name?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;What is the weather today?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This training set is to teach the model the intent recognition of the user. The permuted training validation would looks like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  training&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   create_new_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Create table to store invoices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;I need to store my customers information&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   modify_existing_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Customers table should also have an address&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Add address to the customer table&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   link_two_tables&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Customer should have multiple invoices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   do_not_know&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;How are you today?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;What is your name?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;What is the weather today?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;2 + 3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  evaluations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   create_new_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
     &lt;span class=&quot;token string&quot;&gt;&quot;I need a table for my employees&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   modify_existing_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
     &lt;span class=&quot;token string&quot;&gt;&quot;Invoice should have a date&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   link_two_tables&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Customer should have multiple invoices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Each employee should be responsible for multiple customers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   do_not_know&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;How are you today?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;What is your name?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  training&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   create_new_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Create table to store invoices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;I need to store my customers information&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;I need a table for my employees&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   modify_existing_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Customers table should also have an address&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Add address to the customer table&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Invoice should have a date&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   link_two_tables&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Each employee should be responsible for multiple customers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   do_not_know&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;How are you today?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;What is your name?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;What is the weather today?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;2 + 3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  evaluations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   create_new_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Create table to store invoices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;I need to store my customers information&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;I need a table for my employees&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   modify_existing_table&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Customers table should also have an address&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Add address to the customer table&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Invoice should have a date&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   link_two_tables&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Customer should have multiple invoices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Each employee should be responsible for multiple customers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   do_not_know&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;What is the weather today?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&quot;golden-response&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#golden-response&quot; aria-label=&quot;golden response permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Golden Response&lt;/h3&gt;
&lt;p&gt;This is an idea from the AI community that shows promise. Although I haven&apos;t personally tested it yet, the concept is to compare the response with a &quot;golden response&quot; to ensure its correctness. The golden response can be compared with the actual response with the same Language Learning Model (LLM). We can then determine if they are identical or very similar. This approach holds potential and I&apos;m eager to try it out soon.&lt;/p&gt;
&lt;h2 id=&quot;thanks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#thanks&quot; aria-label=&quot;thanks permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks&lt;/h2&gt;
&lt;p&gt;I would like to express my gratitude to the AWS Community for their invaluable assistance in helping me.&lt;/p&gt;
&lt;p&gt;A special thanks goes to &lt;a href=&quot;https://www.linkedin.com/in/chris-t-miller&quot;&gt;Chris Miller&lt;/a&gt; for giving me a lot of thoughts and feedback on my validation approach. &lt;a href=&quot;https://www.linkedin.com/in/neylsoncrepalde/&quot;&gt;Neylson Crepalde&lt;/a&gt; for making me aware and explaining the golden response validation method.&lt;/p&gt;
&lt;p&gt;Once again, thank you all for your support and contributions.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Working with AWS Bedrock AI is incredibly enjoyable. The field is constantly evolving, and there is always something new to learn. In this post, I explained how to partly validate your LLM responses.&lt;/p&gt;
&lt;p&gt;I am passionate about contributing to Open Source projects. You can find many of my projects on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;GitHub&lt;/a&gt; that you can already benefit from.&lt;/p&gt;
&lt;p&gt;If you found this post valuable and would like to show your support, consider supporting me back. Your support will enable me to write more posts like this and work on projects that provide value to you. You can support me by:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Pateron&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;drawing&quot; width=&quot;400&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/e105638b790c2e217d5f10bfd96d4f91/confidentRobot.png</featuredImage><media:content url="https://martinmueller.dev/static/e105638b790c2e217d5f10bfd96d4f91/confidentRobot.png" medium="image"/></item><item><title><![CDATA[AWS Bedrock Claude 2.1 - Return only JSON]]></title><description><![CDATA[Working with the AWS Bedrock API is an exhilarating experience! I came across an interesting business case where I needed to develop an AI…]]></description><link>https://martinmueller.dev/aws-ai-json/</link><guid isPermaLink="false">https://martinmueller.dev/aws-ai-json/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[aws]]></category><category><![CDATA[bedrock]]></category><category><![CDATA[claude]]></category><category><![CDATA[ai]]></category><pubDate>Thu, 07 Dec 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/f103f52ff3b4ace01a32a30f03701e81/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Working with the AWS Bedrock API is an exhilarating experience! I came across an interesting business case where I needed to develop an AI MVP. The MVP generates JSON data based on a prompt and utilizes the &lt;a href=&quot;https://docs.anthropic.com/claude/docs&quot;&gt;anthropic.claude-v2:1&lt;/a&gt; model in &lt;a href=&quot;https://aws.amazon.com/bedrock&quot;&gt;AWS Bedrock&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I encountered an issue where the response I received was not pure JSON. It contained additional characters that I couldn&apos;t remove like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;txt&quot;&gt;&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;&quot; format: {\&quot;one\&quot;:\&quot;Supplier\&quot;,\&quot;many\&quot;:\&quot;Time\&quot;}&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Seeking help from the AWS Community, I was able to find a solution to this problem. In this post, I will share the solution with you.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-problem&quot; aria-label=&quot;the problem permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Problem&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;txt&quot;&gt;&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;Human: $YOUR_PROMPT . Answer in JSON formatAssistant:{,&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This technique is known as &quot;Put words in Claude’s mouth&quot;. It involves providing a prompt to Claude and letting it generate the rest of the response on its own. While there may be alternative approaches to solving this issue, I am currently happy with this solution.&lt;/p&gt;
&lt;h2 id=&quot;thanks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#thanks&quot; aria-label=&quot;thanks permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thanks&lt;/h2&gt;
&lt;p&gt;I would like to express my gratitude to the AWS Community for their invaluable assistance in helping me resolve this issue.&lt;/p&gt;
&lt;p&gt;A special thanks goes to &lt;a href=&quot;https://www.linkedin.com/in/corvus/&quot;&gt;Corvus Lee&lt;/a&gt; for providing the advice that ultimately solved the problem.&lt;/p&gt;
&lt;p&gt;I would also like to thank &lt;a href=&quot;https://www.linkedin.com/in/metaskills/&quot;&gt;Ken Collins&lt;/a&gt; for bringing the &lt;a href=&quot;https://docs.google.com/presentation/d/1tjvAebcEyR8la3EmVwvjC7PHR8gfSrcsGKfTPAaManw&quot;&gt;Claude 2 docs sheet&lt;/a&gt; to my attention.&lt;/p&gt;
&lt;p&gt;Once again, thank you all for your support and contributions.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Working with AWS Bedrock AI is incredibly enjoyable. The field is constantly evolving, and there is always something new to learn. In this post, I demonstrated how to obtain a pure JSON response from AWS Bedrock Claude 2.1. As AI technology continues to advance rapidly, you may not encounter this issue in the future. However, if you are working with Claude 2.1 or newer, be sure to refer to the &lt;a href=&quot;https://docs.anthropic.com/claude/docs&quot;&gt;documentation&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;I hope you found this post helpful, and I look forward to sharing more with you in the future.&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on the:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/f103f52ff3b4ace01a32a30f03701e81/index.png</featuredImage><media:content url="https://martinmueller.dev/static/f103f52ff3b4ace01a32a30f03701e81/index.png" medium="image"/></item><item><title><![CDATA[Java Spring CI/CD in AWS - The HalloCasa Journey]]></title><description><![CDATA[A fresh start can be daunting, especially when it comes to revamping an existing Java Spring application. This was my journey with the…]]></description><link>https://martinmueller.dev/aws-spring/</link><guid isPermaLink="false">https://martinmueller.dev/aws-spring/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[aws]]></category><category><![CDATA[hallocasa]]></category><category><![CDATA[docker]]></category><category><![CDATA[java]]></category><category><![CDATA[cdk]]></category><pubDate>Mon, 28 Aug 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/8b3a1cd2a01d5d8153764d7900114845/index.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;A fresh start can be daunting, especially when it comes to revamping an existing Java Spring application. This was my journey with the HalloCasa real estate platform, and here&apos;s how we took it from deployment nightmares to smooth, cloud-native operations. If you would like to improve your Java Spring CI/CD experience as well. Reach out to me!&lt;/p&gt;
&lt;p&gt;As well I have a recording about the Java Spring CI/CD experience on YouTube. Check it out &lt;a href=&quot;https://youtu.be/-N1tq2vzTR8&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;introducing-hallocasa&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introducing-hallocasa&quot; aria-label=&quot;introducing hallocasa permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introducing HalloCasa&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hallocasa.com&quot;&gt;HalloCasa&lt;/a&gt; is a dynamic Real Estate Platform designed to allow  real estate agents to create their own business card within a couple of minutes. It also serves as a directory and a referral network.&lt;/p&gt;
&lt;p&gt;My motivations to work on HalloCasa are that I had the chance to contribute to the development of a powerful product. My expertise in AWS could be applied effectively.
Working with a co-founder who was not only business-savvy but also had a knack for generating compelling content in the real estate area. He has his own podcast &lt;a href=&quot;https://blog.hallocasa.com/podcasts/&quot;&gt;https://blog.hallocasa.com/podcasts/&lt;/a&gt;. Make sure to check it out!&lt;/p&gt;
&lt;h2 id=&quot;the-deployment-dilemma&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-deployment-dilemma&quot; aria-label=&quot;the deployment dilemma permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Deployment Dilemma&lt;/h2&gt;
&lt;p&gt;In the beginning, our deployment process could only be described as patchwork:&lt;/p&gt;
&lt;p&gt;Setting up Maven, Tomcat, and MySQL locally. Creating a war file and then SSHing into an EC2 VM to transfer it. Manually restarting the Tomcat server each time.&lt;/p&gt;
&lt;p&gt;Our NextJS frontend wasn&apos;t much different. We had to SSH into our EC2 VM and manually run “npm start”. And to make matters a bit more convoluted, our frontend was in BitBucket while the backend resided in AWS CodeCommit.&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-new-and-improved-way&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#deploying-the-new-and-improved-way&quot; aria-label=&quot;deploying the new and improved way permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Deploying the New and Improved Way&lt;/h2&gt;
&lt;p&gt;Here’s how I revamped our deployment:&lt;/p&gt;
&lt;h3 id=&quot;shifting-to-github&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#shifting-to-github&quot; aria-label=&quot;shifting to github permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Shifting to GitHub&lt;/h3&gt;
&lt;p&gt;Migrated from AWS CodeCommit and BitBucket to GitHub.
Leveraged GitHub Actions for test builds and introduced a &lt;a href=&quot;https://github.com/anc95/ChatGPT-CodeReview&quot;&gt;PR AI reviewer&lt;/a&gt; for efficiency.&lt;/p&gt;
&lt;h3 id=&quot;dockerization&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dockerization&quot; aria-label=&quot;dockerization permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dockerization&lt;/h3&gt;
&lt;p&gt;Deployed our configuration as code, which is both clean and manageable. With docker-compose, local development became hassle-free. Gone were the days of setting up Maven, Tomcat, and MySQL locally.
Further utilized this to feed AWS ECS, making deployments consistent. Additionally health checks were introduced to ensure that the application is up and running. If the health check fails, the application will restart and in most cases that fixes the problem.&lt;/p&gt;
&lt;h3 id=&quot;cdk-pipelines&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-pipelines&quot; aria-label=&quot;cdk pipelines permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CDK Pipelines&lt;/h3&gt;
&lt;p&gt;Implemented a CI/CD staging pipeline that first deploys changes onto QA and subsequently to PROD. Ensured robustness by integrating testing with Postman. We setup a dedicated AWS account for each stage, ensuring clear demarcation and management.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/blob/master/content/aws-spring/pipeline.png?raw=true&quot; alt=&quot;Pipeline&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;db-migration-with-flyway&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#db-migration-with-flyway&quot; aria-label=&quot;db migration with flyway permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;DB Migration with Flyway&lt;/h3&gt;
&lt;p&gt;Adopted Flyway to empower our Java App to manage the database, eliminating the need to provide access to the database for schema modifications.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/blob/master/content/aws-spring/dbmigration.png?raw=true&quot; alt=&quot;dbmigration&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;monitoring-metrics&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#monitoring-metrics&quot; aria-label=&quot;monitoring metrics permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Monitoring Metrics&lt;/h3&gt;
&lt;p&gt;Introduced plenty of metrics to monitor our backend. For an informed decision on crucial metrics, I sought advice from ChatGPT about the most essential metrics for a Java application.
Our revamped production setup went live on 01/08/23, and the migration was seamless.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/mmuller88/mmblog/blob/master/content/aws-spring/monitoring.png?raw=true&quot; alt=&quot;Monitoring&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;reflecting-on-the-journey&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#reflecting-on-the-journey&quot; aria-label=&quot;reflecting on the journey permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Reflecting on the Journey&lt;/h2&gt;
&lt;p&gt;The refurbishment of HalloCasa reaffirmed several beliefs:&lt;/p&gt;
&lt;p&gt;Docker is a lifesaver. The portability and consistency it brings to applications are unparalleled. CI/CD is a game-changer. It automates manual tasks and ensures faster, reliable deliveries. AWS CDK is powerful. It simplifies cloud resource provisioning and management. CDK Pipelines streamline deployments. With it, managing multiple stages of deployment becomes a breeze. One revelation that stood out was how the lines between infrastructure and application seemed blurred in our setup. And this convergence was a positive one, indicating tight integration and consistency.&lt;/p&gt;
&lt;p&gt;The HalloCasa journey is a testament to the power of continuous learning, adaptation, and innovation. Our users now enjoy a more robust platform, and we can sleep better at night, knowing that our deployment is smoother than ever. If you have a Java application which needs a bit polishing, reach out to me!&lt;/p&gt;
&lt;p&gt;I hope you enjoyed this post and I look forward to seeing you in the next one.&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on the:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/8b3a1cd2a01d5d8153764d7900114845/index.jpg</featuredImage><media:content url="https://martinmueller.dev/static/8b3a1cd2a01d5d8153764d7900114845/index.jpg" medium="image"/></item><item><title><![CDATA[Create your Prototype or MVP with the T3 Stack]]></title><description><![CDATA[What is a Prototype? A prototype is a preliminary version of a product, often used for testing and validation purposes. It allows you to…]]></description><link>https://martinmueller.dev/t3-stack-mvp/</link><guid isPermaLink="false">https://martinmueller.dev/t3-stack-mvp/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[mvp]]></category><category><![CDATA[nextjs]]></category><category><![CDATA[prisma]]></category><category><![CDATA[trpc]]></category><category><![CDATA[t3]]></category><pubDate>Wed, 05 Apr 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/fddeabeb894b4ec6f0bc2eb7fa245842/index.png" length="0" type="image/png"/><content:encoded>&lt;h2 id=&quot;what-is-a-prototype&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-a-prototype&quot; aria-label=&quot;what is a prototype permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is a Prototype?&lt;/h2&gt;
&lt;p&gt;A prototype is a preliminary version of a product, often used for testing and validation purposes. It allows you to experiment with different ideas and get feedback from users before investing significant time and resources into development.&lt;/p&gt;
&lt;h2 id=&quot;what-is-an-mvp&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-an-mvp&quot; aria-label=&quot;what is an mvp permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is an MVP?&lt;/h2&gt;
&lt;p&gt;An MVP, or Minimum Viable Product, is a more developed version of a prototype that includes only the essential features needed to validate the concept and get it into the hands of early adopters. It is the smallest possible version of your product that can still provide value to your users. It allows you to test your assumptions and get feedback from real users, which you can then use to improve and refine your product.&lt;/p&gt;
&lt;h2 id=&quot;why-should-i-develop-a-prototype-or-mvp&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-should-i-develop-a-prototype-or-mvp&quot; aria-label=&quot;why should i develop a prototype or mvp permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why should I develop a Prototype or MVP?&lt;/h2&gt;
&lt;p&gt;Developing a Prototype or MVP can help you save time and money in the long run. By validating your ideas early on and getting feedback from users, you can avoid costly mistakes and ensure that you are building something people actually want. It also allows you to test your assumptions and make data-driven decisions, which can increase the chances of success for your product.&lt;/p&gt;
&lt;h2 id=&quot;how-can-i-develop-a-prototype-or-mvp&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-can-i-develop-a-prototype-or-mvp&quot; aria-label=&quot;how can i develop a prototype or mvp permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How can I develop a Prototype or MVP?&lt;/h2&gt;
&lt;p&gt;There are several ways to develop a Prototype or MVP like No or Low-Code solutions. But one effective tool is the T3 Stack. This stack combines NextJS, TailwindCSS, tRPC, and Prisma to create a powerful and efficient development environment. NextJS provides server-side rendering and easy routing, while TailwindCSS offers a library of pre-built UI components. tRPC is a simple and lightweight framework for building remote procedure call APIs, and Prisma provides a type-safe database client. Together, these technologies allow you to quickly develop and deploy your Prototype or MVP with confidence.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-advantage-of-using-the-t3-stack-compared-to-no-or-low-code-solutions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-the-advantage-of-using-the-t3-stack-compared-to-no-or-low-code-solutions&quot; aria-label=&quot;what is the advantage of using the t3 stack compared to no or low code solutions permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is the advantage of using the T3 Stack compared to No or Low-Code solutions?&lt;/h2&gt;
&lt;p&gt;The advantage of using the T3 Stack over No or Low-Code solutions is that it provides more flexibility and control over the development process. While No or Low-Code solutions may be easier to use, they can be limiting in terms of customization and scalability. The T3 Stack, on the other hand, allows for more complex and customizable development while still being relatively easy to use, making it a great option for developing a Prototype or MVP.&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#outlook&quot; aria-label=&quot;outlook permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Outlook&lt;/h2&gt;
&lt;p&gt;In one of my next posts, I give you deeper insight into the T3 Stack like how it works. I also show you how to use it to develop a Prototype or MVP.&lt;/p&gt;
&lt;p&gt;A huge thanks to the &lt;a href=&quot;https://create.t3.gg/&quot;&gt;T3 Stack community&lt;/a&gt; for their hard work and support. And a special thanks to &lt;a href=&quot;https://www.youtube.com/@t3dotgg&quot;&gt;Theo&lt;/a&gt; for creating this amazing stack and thriving it. I love your content on &lt;a href=&quot;https://www.youtube.com/@t3dotgg&quot;&gt;YouTube&lt;/a&gt;. Keep up the amazing work!&lt;/p&gt;
&lt;p&gt;I hope you enjoyed this post and I look forward to seeing you in the next one.&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on the:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/fddeabeb894b4ec6f0bc2eb7fa245842/index.png</featuredImage><media:content url="https://martinmueller.dev/static/fddeabeb894b4ec6f0bc2eb7fa245842/index.png" medium="image"/></item><item><title><![CDATA[Chat Indexing with Chatsindex.com]]></title><description><![CDATA[Would you like to grow your chat community? Chatsindex.com indexes chat messages and make them searchable for search engines like Google…]]></description><link>https://martinmueller.dev/chatsindex-eng/</link><guid isPermaLink="false">https://martinmueller.dev/chatsindex-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[seo]]></category><category><![CDATA[nextjs]]></category><category><![CDATA[prisma]]></category><category><![CDATA[trpc]]></category><pubDate>Tue, 21 Mar 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/5449bd6ddf060b83d9dc4c7d65b83a92/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Would you like to grow your chat community? &lt;a href=&quot;https://Chatsindex.com&quot;&gt;Chatsindex.com&lt;/a&gt; indexes chat messages and make them searchable for search engines like Google. Well, will be as this is still a prototype! Through SEO (Search Engine Optimization) it is ensured that the entries appear as high as possible in the search results. This way new users can be attracted to your Discord server or any other chat you prefer.&lt;/p&gt;
&lt;p&gt;Below you can see an example of how a Discord channel and the search results can look like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/mmuller88/mmblog/master/content/chatsindex/seo.gif&quot; alt=&quot;seo.gif&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Google page is only mocked (&lt;a href=&quot;https://Chatsindex.com/search&quot;&gt;Chatsindex.com/search&lt;/a&gt;) because it is still a prototype.&lt;/p&gt;
&lt;h2 id=&quot;how-does-it-work&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-does-it-work&quot; aria-label=&quot;how does it work permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;A Discord bot writes the messages into a database. The database gets queried by a NextJS server and rendered into search-engine-optimized (SEO) pages. Google crawls the page and the entries are discoverable.&lt;/p&gt;
&lt;p&gt;The prototype is built using the &lt;a href=&quot;https://martinmueller.dev/t3-stack&quot;&gt;T3-Stack&lt;/a&gt;. The T3-stack is a NextJS stack with TailwindCSS, tRPC, and Prisma. The database is currently SQLite and is queried with tRPC and Prisma. The page is rendered using NextJS and TailwindCSS.&lt;/p&gt;
&lt;h2 id=&quot;participants&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#participants&quot; aria-label=&quot;participants permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Participants&lt;/h2&gt;
&lt;p&gt;Does this idea sound interesting to you? Then feel free to contact me &lt;a href=&quot;https://MartinMueller.dev&quot;&gt;https://MartinMueller.dev&lt;/a&gt;. I am looking for volunteers with Discord servers to test the idea.&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#outlook&quot; aria-label=&quot;outlook permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Outlook&lt;/h2&gt;
&lt;p&gt;If the idea is well received, I would like to index other private chat systems like WhatsApp groups, Telegram groups, Slack, etc.&lt;/p&gt;
&lt;p&gt;Another idea of mine is to implement an overall search for private chats like Discord, WhatsApp groups, Telegram groups, and Slack. With certain keywords or categories, private chats with certain topic content can then be found. For example, if I&apos;m interested in financial education, I can then simply enter finance in the search and I&apos;ll be presented with Discord servers, WhatsApp/Telegram groups, etc. with a focus on finance. If you like the idea, feel free to contact me.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I think the combination of SEO and private chats like Discord servers is an exciting idea. For now, I want to test the idea and see if there is any demand for it. If you are interested, feel free to contact me.&lt;/p&gt;
&lt;p&gt;Using the &lt;a href=&quot;https://martinmueller.dev/t3-stack&quot;&gt;T3-Stack&lt;/a&gt; was super fun and it took me just like a weekend to sketch out this little prototype. If you need help with your idea or project reach out to me as well!&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to English and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on the:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/5449bd6ddf060b83d9dc4c7d65b83a92/index.png</featuredImage><media:content url="https://martinmueller.dev/static/5449bd6ddf060b83d9dc4c7d65b83a92/index.png" medium="image"/></item><item><title><![CDATA[Amplify AppSync Permission]]></title><description><![CDATA[Hi, With Amplify AppSync it is possible to configure an AWS AppSync with declarative code. With Directives like @model, @auth or @function…]]></description><link>https://martinmueller.dev/amplify-permission-eng/</link><guid isPermaLink="false">https://martinmueller.dev/amplify-permission-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><category><![CDATA[amplify]]></category><pubDate>Sun, 05 Feb 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/1253106b2b2c04f39e1fce9e93fc7d70/index.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;With Amplify AppSync it is possible to configure an AWS AppSync with declarative code. With &lt;a href=&quot;https://docs.amplify.aws/cli-legacy/graphql-transformer/directives/&quot;&gt;Directives&lt;/a&gt; like &lt;strong&gt;@model&lt;/strong&gt;, &lt;strong&gt;@auth&lt;/strong&gt; or &lt;strong&gt;@function&lt;/strong&gt; other AWS services like DynamoDB, Cognito or Lambda can be connected to AppSync in a meaningful way. This makes it a powerful tool. With just a few lines of GraphQL code, a lot can be configured in AWS, so to speak.&lt;/p&gt;
&lt;p&gt;Below you can see an Amplify AppSync example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;graphql&quot;&gt;&lt;pre class=&quot;language-graphql&quot;&gt;&lt;code class=&quot;language-graphql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;User&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@model&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token attr-name&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@auth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;iam&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ownerField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;identityClaim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is a lot going on here! With the @model directive, a DynamoDB table with the name User is automatically created which stores the user entries as DynamoDB items. With @key the email is set as PK (Partition Key). The permission, who is allowed to access the items, is defined with @auth. A user in the admin group is allowed to query, mutate and subscribe to all items.&lt;/p&gt;
&lt;p&gt;With { allow: private, provider: iam } an IAM entity that has the required permissions is also allowed to querry, mutate and subscribe to the items. I use this for example with lambdas that should perform certain tasks like creating new users in the table when they log in via Cognito for the first time.&lt;/p&gt;
&lt;p&gt;Last but not least with { allow: owner, ownerField: &quot;email&quot;, identityClaim: &quot;email&quot; } Cognito users who have identified themselves via oauth2 are allowed to access their items. The identity claim email is supplied by the Cognito JWT token and is then matched with the email defined in the item.&lt;/p&gt;
&lt;p&gt;Pretty cool, isn&apos;t it? With just these few lines of Amplify AppSync GraphQL code, we get a lot of functionality.&lt;/p&gt;
&lt;h2 id=&quot;permission-for-shared-items&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#permission-for-shared-items&quot; aria-label=&quot;permission for shared items permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Permission for shared items&lt;/h2&gt;
&lt;p&gt;Defining permission with @auth works very well for simple cases like the user example shown here. But what if you want to access items from multiple users? Well here are several possibilities I want to introduce. But first I will introduce the table with the shared items:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;graphql&quot;&gt;&lt;pre class=&quot;language-graphql&quot;&gt;&lt;code class=&quot;language-graphql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@model&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@auth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;iam&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;projectNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A project should be accessible to several users. The simplest approach would be to store the users in a string list.&lt;/p&gt;
&lt;h2 id=&quot;string-list&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#string-list&quot; aria-label=&quot;string list permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;String-List&lt;/h2&gt;
&lt;p&gt;The code must be adapted only minimally with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;graphql&quot;&gt;&lt;pre class=&quot;language-graphql&quot;&gt;&lt;code class=&quot;language-graphql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@model&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@auth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;iam&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ownerField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;userEmails&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;identityClaim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;projectNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;userEmails&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token scalar&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# &amp;lt;-- user string list&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The userEmails string list now just needs to be kept up to date with the emails from the users who can access it. However, managing the userEmails is costly and requires additional code and space in the item.&lt;/p&gt;
&lt;h2 id=&quot;virtual-lambda&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#virtual-lambda&quot; aria-label=&quot;virtual lambda permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Virtual Lambda&lt;/h2&gt;
&lt;p&gt;We could also use a virtual lambda which dynamically calculates if the user should have access or not.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;graphql&quot;&gt;&lt;pre class=&quot;language-graphql&quot;&gt;&lt;code class=&quot;language-graphql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@model&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@auth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;iam&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ownerField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;userEmail&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;identityClaim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;projectNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;userEmail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token directive function&quot;&gt;@function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;userEmailLambda&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The solution is impressive because of the reduced space in the DynamoDB table. However, with a large number of items it would mean a large number of lambda calls which would drive up the cost. Also, the delay due to the lambda call can be too significant.&lt;/p&gt;
&lt;h2 id=&quot;jwt-claim&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#jwt-claim&quot; aria-label=&quot;jwt claim permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;JWT Claim&lt;/h2&gt;
&lt;p&gt;This idea is probably the most creative. Using the pre-token-generation trigger Lambda a claim can be set which signals which item may be accessed. The code for Amplify AppSync looks something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;graphql&quot;&gt;&lt;pre class=&quot;language-graphql&quot;&gt;&lt;code class=&quot;language-graphql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@model&lt;/span&gt;
  &lt;span class=&quot;token directive function&quot;&gt;@auth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;iam&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ownerField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;identityClaim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;currentProjectId&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;projectNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token scalar&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The identity claim &lt;strong&gt;currentProjectId&lt;/strong&gt; is set by the pre-token-generation trigger Lambda. I find this method the most elegant and use it in my projects.&lt;/p&gt;
&lt;p&gt;The code for the lambda might look something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; AppsyncClient &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;appsync-client&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; lambda &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  CreateUserDocument&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  GetUserDocument&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  Role&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./../../stueli/src/lib/api&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;APPSYNC_URL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppsyncClient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; apiUrl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;APPSYNC_URL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * https://www.npmjs.com/package/appsync-client
 * @param event
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PreTokenGenerationTriggerEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;event: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; getUser &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    query&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; GetUserDocument&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    variables&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAttributes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;getUser=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;getUser &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claimsOverrideDetails &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    claimsToAddOrOverride&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;getUser&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;currentProjectId
        &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; currentProjectId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; getUser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;currentProjectId &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;event.response.claimsOverrideDetails=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claimsOverrideDetails&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Lambda determines first which Project the user may access with &lt;strong&gt;currentProjectId&lt;/strong&gt; and then it sets the claim &lt;code&gt;currentProjectId:1234&lt;/code&gt;. Now must be implemented of course still like the user the currentProjectId at all change and/or set can and like afterward the JWT Token is reloaded.&lt;/p&gt;
&lt;p&gt;In my case, this happens when the user clicks on the project via the React router. First, the currentProjectId entry is made in the user table and then the JWT token is reloaded using the JWT Refresh token. If you would like to have this in detail, please write me.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I have presented here different methods of how permissions can be realized with the Amplify AppSync directive @auth. If you have any other cool ideas, feel free to let me know.&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on the:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/1253106b2b2c04f39e1fce9e93fc7d70/index.jpg</featuredImage><media:content url="https://martinmueller.dev/static/1253106b2b2c04f39e1fce9e93fc7d70/index.jpg" medium="image"/></item><item><title><![CDATA[Building a Prototype with ninox.com for your SaaS Product]]></title><description><![CDATA[Hi, I am very excited to work on our SaaS product. In the Minimalempires Community I found a great CoFounder with a great idea. With the low…]]></description><link>https://martinmueller.dev/ninox-mvp-eng/</link><guid isPermaLink="false">https://martinmueller.dev/ninox-mvp-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2023]]></category><category><![CDATA[ninox]]></category><pubDate>Sun, 29 Jan 2023 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/33dd50d2af4b2608ac7b73d59d1ff2f3/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I am very excited to work on our SaaS product. In the &lt;a href=&quot;https://community.minimalempires.de/&quot;&gt;Minimalempires Community&lt;/a&gt; I found a great CoFounder with a great idea. With the low-code platform &lt;a href=&quot;https://ninox.com&quot;&gt;ninox.com&lt;/a&gt; we want to validate this idea and build a prototype. So far I had no experience with low-code and could not imagine that such would be useful for me, since I already have a lot of experience with frontend and backend. I was clearly taught better! In the next paragraphs I will explain what ninox.com is and how it helps us to develop a prototype.&lt;/p&gt;
&lt;h2 id=&quot;ninoxcom&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ninoxcom&quot; aria-label=&quot;ninoxcom permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ninox.com&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ninox.com&quot;&gt;Ninox.com&lt;/a&gt; is a cloud-based low-code platform for building software solutions for small and medium-sized businesses. Ninox was founded in 2013 by &lt;a href=&quot;https://www.linkedin.com/in/frank-boehmer/&quot;&gt;Frank Böhmer&lt;/a&gt; in Germany. As of 2021, Ninox had more than 6,000 customers. Also worth mentioning is the &lt;a href=&quot;https://www.youtube.com/@ninox1273&quot;&gt;YouTube channel of Ninox&lt;/a&gt; with lots of content about Ninox. As well as the weekly Open Office Hours in English and German. Here customers can ask their questions and problems about ninox to a ninox employee*.&lt;/p&gt;
&lt;h2 id=&quot;my-experience-with-ninoxcom&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-experience-with-ninoxcom&quot; aria-label=&quot;my experience with ninoxcom permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My experience with ninox.com&lt;/h2&gt;
&lt;p&gt;The development of a prototype is super fast with ninox.com. The definition of the table, i.e. which columns and column types the respective table has, also serves to create the UI. Thus, a data model and a UI based on it can be developed super fast. Ninox.com has come up with some really cool and smart ideas on how to connect a database with a configurable UI in a meaningful and native way.&lt;/p&gt;
&lt;p&gt;Also the already existing user management works very well. With it, simple roles and permission schemes can be mapped well.&lt;/p&gt;
&lt;p&gt;The community of ninox.com is very active and super helpful. They always helped me when I had problems with the implementation. I only had problems with the implementation when I had to use the ninox.com native programming language. This was the case, for example, when the database needed queries and had to do certain calculations on them.&lt;/p&gt;
&lt;h2 id=&quot;with-ninoxcom-to-the-complete-product&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#with-ninoxcom-to-the-complete-product&quot; aria-label=&quot;with ninoxcom to the complete product permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;With ninox.com to the complete product?&lt;/h2&gt;
&lt;p&gt;No! We already encounter limitations that would be easier to fix with traditional tech stacks like &lt;a href=&quot;https://www.mongodb.com/mern-stack&quot;&gt;MERN&lt;/a&gt;. Also the lack of a Git integration which makes the development harder because important tools like versioning and pull requests are missing.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Ninox is great for rapid prototyping. Beyond that it is probably not suitable for the development of a SaaS product. That was and is not the use case of ninox.com which is why that is totally ok. Nevertheless, I am super impressed with how well it worked for our prototype and am more than willing to use ninox.com again!&lt;/p&gt;
&lt;p&gt;Many thanks also to my CoFounder. I super enjoy working with you on our product, vision and future. You are super motivated and dedicated. I&apos;m really looking forward to our future collaborations in 2023 :)!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on the:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/33dd50d2af4b2608ac7b73d59d1ff2f3/index.png</featuredImage><media:content url="https://martinmueller.dev/static/33dd50d2af4b2608ac7b73d59d1ff2f3/index.png" medium="image"/></item><item><title><![CDATA[TypeScript Lambda with cdktf]]></title><description><![CDATA[Hi, In this blog post, I want to briefly explain what cdktf is and how you can use it to create a TypeScript Lambda. The motivation for this…]]></description><link>https://martinmueller.dev/cdktf-lambda-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdktf-lambda-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdktf]]></category><pubDate>Sat, 17 Dec 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c06e59a89f532eefc286e3a769caa2a1/index.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;In this blog post, I want to briefly explain what cdktf is and how you can use it to create a TypeScript Lambda. The motivation for this came from a &lt;a href=&quot;https://stackoverflow.com/questions/74740782/how-to-deploy-lambda-using-terraform-created-by-cdktf&quot;&gt;StackOverflow post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-cdktf&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-cdktf&quot; aria-label=&quot;what is cdktf permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is cdktf?&lt;/h2&gt;
&lt;p&gt;The Cloud Development Kit for Terraform (cdktf) is a toolkit for building and managing cloud infrastructure like AWS or Azure with Terraform. It allows you to define the infrastructure using a programming language like TypeScript or Python.&lt;/p&gt;
&lt;h2 id=&quot;setup-cdktf&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#setup-cdktf&quot; aria-label=&quot;setup cdktf permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setup cdktf&lt;/h2&gt;
&lt;p&gt;You can find all the code in my repository &lt;a href=&quot;https://github.com/mmuller88/cdktf-lambda&quot;&gt;here&lt;/a&gt;. However, I&apos;ll briefly describe how the repository was created. Initialize your cdktf repo with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;cdktf init &lt;span class=&quot;token parameter variable&quot;&gt;--template&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;typescript&quot;&lt;/span&gt;
cdktf provider &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;aws@~&gt;4.0&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Optionally you can add prettier and linter. In most of my projects, I use these because they allow me to develop quickly without having to worry about formatting.&lt;/p&gt;
&lt;p&gt;I use the &lt;a href=&quot;https://github.com/terraform-aws-modules/terraform-aws-lambda&quot;&gt;Community Terraform Lambda Module&lt;/a&gt; to define the lambda. It allows me to define a lambda in just a few lines that are configured with a role and can also be easily extended with policies. The cool thing is that cdktf supports a type import. To do this, simply add the following module to the cdktf.json file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;terraformModules&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lambda&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;terraform-aws-modules/lambda/aws&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~&gt; 3.0&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then the command cdktf get is executed:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;cdktf get&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the module can be used in the cdktf code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lambda &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./../.gen/modules/lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If lambda has its own dependencies, they still need to be installed with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; src/lambda
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Deploy the cdktf stack with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;cdktf deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;code&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#code&quot; aria-label=&quot;code permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code&lt;/h2&gt;
&lt;p&gt;The lambda can then be integrated into main.ts, for example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NodejsFunction &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./constructs/nodejs-function&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyStack&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TerraformStack&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodejsFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;code&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;lambda/filter-aurora.ts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Lambda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;FilterAuroraEventsLambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      functionName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;filter-aurora&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      handler&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;filter-aurora.handler&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      runtime&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;nodejs14.x&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      sourcePath&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bundledPath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      timeout&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      attachPolicyStatements&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      policyStatements&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        kms&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          effect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Allow&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        s3&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          effect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Allow&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;s3:*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdktf-lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;synth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So I use the custom construct NodejsFunction to bundle the code from TypeScript into JavaScript and show the lambda where to find the bundled JavaScript code. The NodejsFunction Construct looks like that:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; AssetType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TerraformAsset &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdktf&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Construct &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;constructs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; buildSync &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;esbuild&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; path &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;path&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodejsFunctionProps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;bundle&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;workingDirectory&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entryPoint&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;buildSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    entryPoints&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;entryPoint&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    platform&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;es2018&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    bundle&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    format&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    sourcemap&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;external&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    outdir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dist&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    absWorkingDir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; workingDirectory&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;workingDirectory&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dist&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodejsFunction&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Construct&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; asset&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TerraformAsset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; bundledPath&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; NodejsFunctionProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; workingDirectory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; distPath &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bundle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;workingDirectory&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bundledPath &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      distPath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.ts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.js&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;asset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TerraformAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;lambda-asset&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; distPath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AssetType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ARCHIVE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As can be seen, esbuild bundles the TypeScript code to JavaScript code every time &lt;code&gt;cdktf deploy&lt;/code&gt; is executed.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Building TypeScript lambdas with cdktf require a bit more effort compared to aws cdk TypeScript lambdas. Still, that effort is kept in check and I&apos;ve shown you how to do it here. If you found the post helpful, please let me know!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on the:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/c06e59a89f532eefc286e3a769caa2a1/index.png</featuredImage><media:content url="https://martinmueller.dev/static/c06e59a89f532eefc286e3a769caa2a1/index.png" medium="image"/></item><item><title><![CDATA[Terraform CI/CD Staging Pipeline with CircleCI]]></title><description><![CDATA[Hi, Terraform CI/CD staging pipelines, where the CD stands for Continuous Deployment, allow a secure and continuous development of…]]></description><link>https://martinmueller.dev/tf-pipeline-eng/</link><guid isPermaLink="false">https://martinmueller.dev/tf-pipeline-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><category><![CDATA[terraform]]></category><category><![CDATA[serverless]]></category><pubDate>Sat, 01 Oct 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/65b83f50223818bf8ce48ddb9a6c296d/title.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;Terraform CI/CD staging pipelines, where the CD stands for Continuous Deployment, allow a secure and continuous development of infrastructure with Terraform. Typically, a commit in the main branch starts the pipeline and the desired changes are first executed on the DEV stage. Through a manual approval, the changes can then be rolled out to the QA Stage and then to the PROD Stage with the pipeline.&lt;/p&gt;
&lt;p&gt;I would like to present here how such a Terraform CI/CD staging pipeline with AWS as cloud provider can look like.&lt;/p&gt;
&lt;h2 id=&quot;why-a-cicd-staging-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-a-cicd-staging-pipeline&quot; aria-label=&quot;why a cicd staging pipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why a CI/CD staging pipeline?&lt;/h2&gt;
&lt;p&gt;Together with the customer we plan and develop a complex AWS setup with &lt;a href=&quot;https://hasura.io/&quot;&gt;Hasura&lt;/a&gt;, RDS, ECS and many other AWS services. Among other things, this setup should also interact with the existing production environment in Salesforce. So it is of utmost importance to test new functionalities on a DEV and QA environment.&lt;/p&gt;
&lt;p&gt;These environments DEV and QA should behave as similar as possible to the PROD environment. Furthermore, changes should be executable quickly on the PROD environment with as few manual steps as possible. Exactly for these requirements a CI/CD staging pipeline is suitable.&lt;/p&gt;
&lt;h2 id=&quot;multi-account-setup&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#multi-account-setup&quot; aria-label=&quot;multi account setup permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Multi-Account Setup&lt;/h2&gt;
&lt;p&gt;To create a CI/CD staging pipeline it is best practice to use a separate AWS account for each stage like DEV, QA or PROD. So the pipeline setup must be able to bootstrap or initialize these accounts with Terraform and then roll out changes.&lt;/p&gt;
&lt;p&gt;For the multi-account setup I used the article &lt;a href=&quot;https://cloudly.engineer/2021/terraform-aws-multi-account-setup/aws/&quot;&gt;Terraform AWS Multi-Account Setup&lt;/a&gt; as a model, where config files like &lt;a href=&quot;https://github.com/mmuller88/tf-pipeline-circleci/blob/main/accounts/dev/backend.conf&quot;&gt;accounts/dev/backend.conf&lt;/a&gt; and &lt;a href=&quot;https://github.com/mmuller88/tf-pipeline-circleci/blob/main/accounts/dev/terraform.tfvars&quot;&gt;accounts/dev/terraform.tfvars&lt;/a&gt; are used to configure the respective stage. Super cool now is that this allows the same &lt;a href=&quot;https://github.com/mmuller88/tf-pipeline-circleci/blob/main/main.tf&quot;&gt;main.tf&lt;/a&gt; to be used for all staging environments.&lt;/p&gt;
&lt;p&gt;Too often I see customers working with Terraform creating separate TF files for each staging environment and copying resources back and forth. This needs to stop and the approach described here can help!&lt;/p&gt;
&lt;h2 id=&quot;circleci-staging-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#circleci-staging-pipeline&quot; aria-label=&quot;circleci staging pipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CircleCI Staging Pipeline&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt; is a continuous integration and continuous delivery platform for DevOps functionalities. Similar to other DevOps platforms like Travis or GitHub Actions, a pipeline yaml definition is created in the .circleci folder named config.yml. What I find very great is that CircleCI supports manual approvals and makes them easy to integrate with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;workflows&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;plan_approve_apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; dev&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;plan&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;apply
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;dev-hold-apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; approval
          &lt;span class=&quot;token key atrule&quot;&gt;requires&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; dev&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;plan&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;apply
     &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This way the planned infrastructure changes can first be reviewed and then implemented. You can see the complete code &lt;a href=&quot;https://github.com/mmuller88/tf-pipeline-circleci/blob/main/.circleci/config.yml&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;outlook&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#outlook&quot; aria-label=&quot;outlook permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Outlook&lt;/h2&gt;
&lt;p&gt;Next I want to introduce &lt;a href=&quot;https://github.com/hashicorp/terraform-cdk&quot;&gt;CDKTF&lt;/a&gt; so that the infrastructure can be defined with TypeScript. Similar to what was the case for me with AWS CDK, I expect this to speed up development with Terraform. The type support allows me to identify missing Terraform properties early on. Also, the documentation of the properties is very convenient and I hardly have to look in the Terraform documentation.&lt;/p&gt;
&lt;p&gt;After that, I&apos;m also very excited to see how AWS resources like Aurora, ECS, VPC and so on integrate with Terraform. The whole thing expands my set of tools with which I can build cool stuff in AWS.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;A CI/CD staging pipeline is an important tool to build reliable infrastructure in AWS. Here in this article, I have shown you how to do it with Terraform in AWS. Since I am still a beginner in Terraform, I may have made small mistakes. If you have any suggestions for improvement or want to discuss simple cool projects with me, feel free to write to me :)!&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to English and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Be my Patron&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/65b83f50223818bf8ce48ddb9a6c296d/title.png</featuredImage><media:content url="https://martinmueller.dev/static/65b83f50223818bf8ce48ddb9a6c296d/title.png" medium="image"/></item><item><title><![CDATA[AWS CDK and Amplify runtime-config]]></title><description><![CDATA[Hi, Seamless integration of AWS CDK and Amplify apps used to be very cumbersome! With a runtime-config for the Amplify frontend React app…]]></description><link>https://martinmueller.dev/cdk-amplify-runtime-config-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-amplify-runtime-config-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><pubDate>Thu, 25 Aug 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/a91982cf204dcf213ceff4c4d3aa000c/title.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;Seamless integration of AWS CDK and Amplify apps used to be very cumbersome! With a runtime-config for the Amplify frontend React app, it&apos;s now much easier. Here I would like to introduce you to the idea of a runtime-config.&lt;/p&gt;
&lt;p&gt;In my fullstack projects, I regularly use AWS CDK as backend. AppSync as a GraphQL implementation is the interface between the frontend and backend. The frontend is usually a React SPA (Single Page Application) hosted in an S3 bucket. I use AWS Cognito to manage and authenticate the users and usually configure the frontend React app using AWS Amplify.&lt;/p&gt;
&lt;h2 id=&quot;idea-runtime-config&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#idea-runtime-config&quot; aria-label=&quot;idea runtime config permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Idea runtime-config&lt;/h2&gt;
&lt;p&gt;The runtime-config allows you to configure Amplify after the build phase on runtime. The dist folder of the SPA is given a file like runtime-config.json in the public folder which fetched ruding the runtime of the app. Here you see an example for the runtime-config.json:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;region&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eu-central-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;identityPoolId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eu-central-1:cda9c404-0e74-439d-b40c-90204a0e1234&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;userPoolId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eu-central-1_Uv0E91234&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;userPoolWebClientId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1t6jbsr5b7utg6c9urhj51234&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;appSyncGraphqlEndpoint&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://wr2cf4zklfbt3pxw26bik12345.appsync-api.eu-central-1.amazonaws.com/graphql&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The runtime-config is then dynamically loaded in the React app via useEffect and fetch:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/runtime-config.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolId &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolWebClientId &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;identityPoolId &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
          Amplify&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            aws_project_region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            aws_cognito_identity_pool_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;identityPoolId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            aws_cognito_region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            aws_user_pools_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            aws_user_pools_web_client_id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolWebClientId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            aws_appsync_graphqlEndpoint&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appSyncGraphqlEndpoint&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            aws_appsync_region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            aws_appsync_authenticationType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;AMAZON_COGNITO_USER_POOLS&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            Auth&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
              region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              userPoolId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              userPoolWebClientId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolWebClientId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
              identityPoolId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; runtimeContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;identityPoolId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, a fetch to load the runtime-config.json is executed initially. After that Amplify is configured with the extracted properties.&lt;/p&gt;
&lt;p&gt;You can also use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window&quot;&gt;HTML window variables&lt;/a&gt; to set the Amplify parameters. However, I prefer the fetch solution presented here because it is potentially more responsive to a missing runtime-config.json or single missing properties. Also, window variables should be avoided as they get global access to the DOM.&lt;/p&gt;
&lt;h2 id=&quot;workflows&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#workflows&quot; aria-label=&quot;workflows permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Workflows&lt;/h2&gt;
&lt;p&gt;The typical workflow without the runtime-config to build and deploy the React app sometimes went like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;curl and store current endpoints like user pool id, AppSynch endpoint and more.&lt;/li&gt;
&lt;li&gt;build Amplify config file&lt;/li&gt;
&lt;li&gt;build react app&lt;/li&gt;
&lt;li&gt;cdk deploy react dist folder to S3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Build pipeline workflow with runtime-config:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;build react app&lt;/li&gt;
&lt;li&gt;cdk deploy react dist folder and runtime config to S3&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cdk-example&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-example&quot; aria-label=&quot;cdk example permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CDK example&lt;/h2&gt;
&lt;p&gt;The complete code is available in my &lt;a href=&quot;https://github.com/senjuns/senjuns/blob/main/backend/src/dashboard-stack.ts&quot;&gt;GitHub Senjuns project&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userPool &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cognito&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;UserPool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; identityPool &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cognito&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CfnIdentityPool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dashboard &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StaticWebsite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dashboard&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    build&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../dashboard/build&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    recordName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dashboard&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    runtimeOptions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        jsonPayload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            identityPoolId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; identityPool&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            userPoolId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; userPool&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            userPoolWebClientId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; userPoolWebClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolClientId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            appSyncGraphqlEndpoint&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; graphqlUrl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stringValue&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The StaticWebsite is a simple L3 CDK construct with an S3 static website bucket as the main resource. You can see more details &lt;a href=&quot;https://github.com/senjuns/senjuns/blob/main/backend/src/construcs/static-website.ts&quot;&gt;here&lt;/a&gt;. But the interesting details are in the &lt;strong&gt;runtimeOptions&lt;/strong&gt; object. There the endpoints for the runtime config for Amplify are stored. Behind this is the S3 Bucket Deployment Construct which transfers the endpoints via &lt;strong&gt;s3deploy.Source.jsonData(...)&lt;/strong&gt; into the JSON file runtime-config.json:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DEFAULT_RUNTIME_CONFIG_FILENAME&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;runtime-config.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;s3deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;BucketDeployment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;BucketDeployment&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    sources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    s3deploy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Source&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;build&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtimeOptions
        &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        s3deploy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Source&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtimeOptions&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;jsonFileName &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
                &lt;span class=&quot;token constant&quot;&gt;DEFAULT_RUNTIME_CONFIG_FILENAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtimeOptions&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;jsonPayload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    distribution&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    destinationBucket&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; siteBucket&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a cool CDK integration :) ! Just giving the BucketDeployment Construct the two parameters like the React dist and the runtime-config is a pretty smart idea.&lt;/p&gt;
&lt;h2 id=&quot;workaround-with-nested-stack-outputs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#workaround-with-nested-stack-outputs&quot; aria-label=&quot;workaround with nested stack outputs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Workaround with nested stack outputs&lt;/h2&gt;
&lt;p&gt;During my work with the runtime-config I encountered a problem. It is not possible to use CDK outputs from a nested stack for runtime-config. But there is a workaround using AWS Systems Manager parameters:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; graphqlUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ssm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;StringParameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GraphqlUrl&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    parameterName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GraphqlUrl&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    stringValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; appSyncTransformer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appsyncAPI&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;graphqlUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; dashboard &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StaticWebsite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dashboard&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    build&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../dashboard/build&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    recordName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dashboard&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    runtimeOptions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    jsonPayload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        identityPoolId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; identityPool&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        userPoolId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; userPool&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        userPoolWebClientId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; userPoolWebClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolClientId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        appSyncGraphqlEndpoint&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; graphqlUrl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stringValue&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool, right? The nested stack output is simply stored in an SSM string parameter and can then be read later. Thanks to Adrian Dimech for the great &lt;a href=&quot;https://github.com/aws/aws-prototyping-sdk/issues/84&quot;&gt;workaround&lt;/a&gt; 🙏.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;AWS CDK and Amplify are a powerful combination. With the runtime-config presented here, this combination feels much better! I copied this solution from &lt;a href=&quot;https://github.com/aws/aws-prototyping-sdk&quot;&gt;aws-prototyping-sdk&lt;/a&gt;. There are some interesting AWS CDK constructs being developed in this repo. So you should definitely check it out!&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/a91982cf204dcf213ceff4c4d3aa000c/title.png</featuredImage><media:content url="https://martinmueller.dev/static/a91982cf204dcf213ceff4c4d3aa000c/title.png" medium="image"/></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 32]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-32/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-32/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 14 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Serverless, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;hey-cdk-how-do-cross-account-deployments-work&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hey-cdk-how-do-cross-account-deployments-work&quot; aria-label=&quot;hey cdk how do cross account deployments work permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hey CDK, how do cross-account deployments work?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://garbe.io/blog/2022/08/01/hey-cdk-how-to-cross-account-deployments/&quot;&gt;https://garbe.io/blog/2022/08/01/hey-cdk-how-to-cross-account-deployments/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice deep dive into how CDK bootstrap works and which roles for what purpose it creates. Furthermore the author explains the different options for how to deploy a CDK stack and when your should use which method. Read it!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://garbe.io/&quot;&gt;Philipp Garbe&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-developers-are-building-so-many-side-projects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-developers-are-building-so-many-side-projects&quot; aria-label=&quot;why developers are building so many side projects permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why Developers Are Building So Many Side Projects&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://future.com/developers-side-projects/&quot;&gt;https://future.com/developers-side-projects/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Why developers are working or should work on side projects? It is super exciting to read why developers are working on side projects. I myself am working on side projects as well and it is a lot of fun :). Though my dream would be to get a somewhat successful product running.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://future.com/author/ben-stokes/&quot;&gt;Ben Stokes&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;3-things-to-know-before-building-a-multi-tenant-serverless-app&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-things-to-know-before-building-a-multi-tenant-serverless-app&quot; aria-label=&quot;3 things to know before building a multi tenant serverless app permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3 Things to Know Before Building a Multi-Tenant Serverless App&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.readysetcloud.io/blog/allen.helton/things-to-know-before-building-a-multi-tenant-serverless-app/&quot;&gt;https://www.readysetcloud.io/blog/allen.helton/things-to-know-before-building-a-multi-tenant-serverless-app/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This article is around the topic of multi-tenancy in serverless applications. In this, the author reports about his past experience when working on implementing a multi-tenant solution and which problems he has encountered. Super interesting read!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Allen Helton&lt;/p&gt;
&lt;h2 id=&quot;should-you-pay-for-cicd-in-2022&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#should-you-pay-for-cicd-in-2022&quot; aria-label=&quot;should you pay for cicd in 2022 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SHOULD YOU PAY FOR CI/CD IN 2022?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.symops.com/2022/08/10/pay-for-continuous-integration/&quot;&gt;https://blog.symops.com/2022/08/10/pay-for-continuous-integration/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Gives a historical roundtrip of the CI/CD history.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://twitter.com/abuggia&quot;&gt;Adam Buggia&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/briantarbox/&quot;&gt;Brian Tarbox&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;amazon-cloudfront-for-your-tech-stack&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#amazon-cloudfront-for-your-tech-stack&quot; aria-label=&quot;amazon cloudfront for your tech stack permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Amazon CloudFront for your tech stack&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/amazon-cloudfront-for-your-tech-stack-5ggk&quot;&gt;https://dev.to/aws-builders/amazon-cloudfront-for-your-tech-stack-5ggk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice article about one of my favorite AWS services CloudFront. It explains what you can do with CloudFront like reducing latency via caching, implementing geo restrictions, and much more.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/zachjonesnoel&quot;&gt;Jones Zachariah Noel&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;title&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#title&quot; aria-label=&quot;title permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Title&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/logrocket/micro-frontend-with-react-and-nextjs-n6h&quot;&gt;https://dev.to/logrocket/micro-frontend-with-react-and-nextjs-n6h&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Explains an interesting way how to create micro frontends with react and nextjs.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-develop-strong-problem-solving-skills-as-a-software-developer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-develop-strong-problem-solving-skills-as-a-software-developer&quot; aria-label=&quot;how to develop strong problem solving skills as a software developer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to develop strong problem-solving skills as a software developer&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/nathan20/how-to-develop-strong-problem-solving-skills-as-a-software-developer-25nb&quot;&gt;https://dev.to/nathan20/how-to-develop-strong-problem-solving-skills-as-a-software-developer-25nb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Offers a good summary of different ways how to solve complex problems as a software developer (probably not just there)! Further, the author explains how to improve your problem-solving skills.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/nathan20&quot;&gt;Nathan&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;thinking-like-containers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#thinking-like-containers&quot; aria-label=&quot;thinking like containers permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Thinking like containers&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/leandronsp/thinking-like-containers-3k24&quot;&gt;https://dev.to/leandronsp/thinking-like-containers-3k24&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Explains very on the point what containers are about. And how to persist data from the container via volumes is described very well as well.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/leandronsp&quot;&gt;Leandro Proença&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;low-cost-best-practices-in-aws&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#low-cost-best-practices-in-aws&quot; aria-label=&quot;low cost best practices in aws permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Low-cost best practices in AWS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/low-cost-best-practices-in-aws-234&quot;&gt;https://dev.to/aws-builders/low-cost-best-practices-in-aws-234&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A very good article that highlights best practices in terms of security and saving costs.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/guilleojeda&quot;&gt;guilleojeda&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;i-got-my-first-pull-request-merged&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#i-got-my-first-pull-request-merged&quot; aria-label=&quot;i got my first pull request merged permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I got my first Pull Request merged&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/jhhornn/i-got-my-first-pull-request-merged-3ei9&quot;&gt;https://dev.to/jhhornn/i-got-my-first-pull-request-merged-3ei9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A super encouraging article about first-time contributions to an open source project. So cool!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/jhhornn&quot;&gt;Awosise Oluwaseun&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;make-errors-user-friendly-with-react-error-boundaries&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#make-errors-user-friendly-with-react-error-boundaries&quot; aria-label=&quot;make errors user friendly with react error boundaries permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Make Errors User-Friendly with React Error Boundaries&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/thisurathenuka/make-errors-user-friendly-with-react-error-boundaries-9e7&quot;&gt;https://dev.to/thisurathenuka/make-errors-user-friendly-with-react-error-boundaries-9e7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting read of React Error Boundaries for rendering JavaScript errors in a nicer way.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/thisurathenuka&quot;&gt;Thisura Thenuka&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 31]]></title><description><![CDATA[This week was my first week solely working as a freelancer. That is scary but exciting too :)! In this weekly newsletter, I write a summary…]]></description><link>https://martinmueller.dev/newsletter-31/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-31/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 07 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This week was my first week solely working as a freelancer. That is scary but exciting too :)!&lt;/p&gt;
&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Serverless, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;aurora-serverless-v2-postgresql-vs-provisioned-aurora-postgresql&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aurora-serverless-v2-postgresql-vs-provisioned-aurora-postgresql&quot; aria-label=&quot;aurora serverless v2 postgresql vs provisioned aurora postgresql permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Aurora Serverless v2 PostgreSQL vs. provisioned Aurora PostgreSQL&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://towardsaws.com/aurora-serverless-v2-postgresql-vs-provisioned-aurora-postgresql-f60a93b99b83&quot;&gt;https://towardsaws.com/aurora-serverless-v2-postgresql-vs-provisioned-aurora-postgresql-f60a93b99b83&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That is an interesting article that compares the costs from Aurora Serverless v2 PostgreSQL vs Aurora PostgreSQL. And as you can read in the article it isn&apos;t always cheaper! Actually, it seems Aurora Serverless should be avoided when you have high DB traffic. So therefore perhaps use it for development and later consider switching to Aurora on-demand!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://medium.com/@ianbinder&quot;&gt;Ian Binder&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;cdk-certificate-handling-with-custom-resources&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-certificate-handling-with-custom-resources&quot; aria-label=&quot;cdk certificate handling with custom resources permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CDK: Certificate Handling with Custom Resources&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.56k.cloud/cdk-certificate-handling-with-custom-resources/&quot;&gt;https://blog.56k.cloud/cdk-certificate-handling-with-custom-resources/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this article, the author uses AWS CDK Custom Resources to solve a problem with DNS validating a certificate. As the custom domain isn&apos;t managed by Route 53 you can&apos;t use the standard route53 constructs to do that. Super smart how the author solved it by using a custom resource.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://blog.56k.cloud/author/jochen/&quot;&gt;Jochen Zehnder&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;containers-vs-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#containers-vs-serverless&quot; aria-label=&quot;containers vs serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Containers vs Serverless&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://greengocloud.com/2018/10/07/Containers-vs-Serverless/&quot;&gt;https://greengocloud.com/2018/10/07/Containers-vs-Serverless/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super experiment article about containers vs serverless. It gives a short introduction to each and then the author gives his opinion. I agree with the author. If you want to know whom we are betting on then read the article!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://greengocloud.com/about/&quot;&gt;Blake Green&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;allow-only-what-your-lambda-code-needs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#allow-only-what-your-lambda-code-needs&quot; aria-label=&quot;allow only what your lambda code needs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Allow only what your Lambda code needs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/allow-only-what-your-lambda-code-needs-59f2&quot;&gt;https://dev.to/aws-builders/allow-only-what-your-lambda-code-needs-59f2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice article to explain the necessity of least-privilege IAM permissions.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/zachjonesnoel&quot;&gt;Jones Zachariah Noel&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;pros-and-cons-of-public-cloud-wafs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#pros-and-cons-of-public-cloud-wafs&quot; aria-label=&quot;pros and cons of public cloud wafs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pros and Cons of Public Cloud WAFs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://thenewstack.io/pros-and-cons-of-public-cloud-wafs/&quot;&gt;https://thenewstack.io/pros-and-cons-of-public-cloud-wafs/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A critical summary of public Cloud WAF and when you should and shouldn&apos;t use them.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.linkedin.com/in/alessfg&quot;&gt;Alessandro Fael Garcia&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;its-never-too-late-mechanical-engineer-to-web-developer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#its-never-too-late-mechanical-engineer-to-web-developer&quot; aria-label=&quot;its never too late mechanical engineer to web developer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It&apos;s never too late: Mechanical engineer to Web developer&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/sagarpanchal0055/its-never-too-late-mechanical-engineer-to-web-developer-58di&quot;&gt;https://dev.to/sagarpanchal0055/its-never-too-late-mechanical-engineer-to-web-developer-58di&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An impressive short story from an engineer changing career from a mechanical engineer to a web developer. Very cool and inspiring :)!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/sagarpanchal0055&quot;&gt;Sagar Panchal&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;styled-components-in-material-ui-mui-with-styled-utility&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#styled-components-in-material-ui-mui-with-styled-utility&quot; aria-label=&quot;styled components in material ui mui with styled utility permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Styled Components in Material UI (MUI) with Styled Utility&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/rasaf_ibrahim/styled-components-in-material-ui-mui-with-styled-utility-3l3j&quot;&gt;https://dev.to/rasaf_ibrahim/styled-components-in-material-ui-mui-with-styled-utility-3l3j&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice example of how to use React-styled components together with MUI / (former Material UI).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/rasaf_ibrahim&quot;&gt;Rasaf Ibrahim&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-does-the-future-hold-for-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-does-the-future-hold-for-serverless&quot; aria-label=&quot;what does the future hold for serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Does The Future Hold For Serverless?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.readysetcloud.io/blog/allen.helton/what-does-the-future-hold-for-serverless/&quot;&gt;https://www.readysetcloud.io/blog/allen.helton/what-does-the-future-hold-for-serverless/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super exciting article is about the future development of serverless. I totally agree that more analytic tools/capabilities on how to optimize the architecture would be great.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Allen Helton.&lt;/p&gt;
&lt;h2 id=&quot;is-aws-support-really-this-terrible&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#is-aws-support-really-this-terrible&quot; aria-label=&quot;is aws support really this terrible permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Is AWS support really this terrible?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/aws/comments/wf79q9/is_aws_support_really_this_terrible/&quot;&gt;https://www.reddit.com/r/aws/comments/wf79q9/is_aws_support_really_this_terrible/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting discussion about how the support with AWS is and how it can be improved.&lt;/p&gt;
&lt;h2 id=&quot;selling-an-ami-and-a-cloudformation-template-as-an-alternative-to-saas&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#selling-an-ami-and-a-cloudformation-template-as-an-alternative-to-saas&quot; aria-label=&quot;selling an ami and a cloudformation template as an alternative to saas permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Selling an AMI and a CloudFormation template as an alternative to SaaS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://cloudonaut.io/selling-ami-cloudformation-alternative-saas/&quot;&gt;https://cloudonaut.io/selling-ami-cloudformation-alternative-saas/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting article on how to use the AWS Marketplace with AMI and CloudFormation type to earn money. As well the story of product marbot from cloudonaut.io is super fascinating.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Andreas Wittig&lt;/p&gt;
&lt;h2 id=&quot;dynamodb-pros--cons&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#dynamodb-pros--cons&quot; aria-label=&quot;dynamodb pros  cons permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;DynamoDB Pros &amp;#x26; Cons&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/roy8/dynamodb-pros-cons-k2a&quot;&gt;https://dev.to/roy8/dynamodb-pros-cons-k2a&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A short introduction to AWS DynamoDB. Really good if you don&apos;t know much about DynamoDB.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/roy8&quot;&gt;Roy&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;managing-secrets-in-your-devops-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#managing-secrets-in-your-devops-pipeline&quot; aria-label=&quot;managing secrets in your devops pipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Managing Secrets in Your DevOps Pipeline&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://thenewstack.io/managing-secrets-in-your-devops-pipeline/&quot;&gt;https://thenewstack.io/managing-secrets-in-your-devops-pipeline/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Contains some useful guidelines when managing secrets.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://thenewstack.io/author/pavan-belagatti/&quot;&gt;PAVAN BELAGATTI&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-simple-guide-to-cicd-for-total-beginners-in-2022&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-simple-guide-to-cicd-for-total-beginners-in-2022&quot; aria-label=&quot;a simple guide to cicd for total beginners in 2022 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A Simple Guide to CI/CD For Total Beginners in 2022&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/hackmamba/a-simple-guide-to-cicd-for-total-beginners-in-2022-2kgp&quot;&gt;https://dev.to/hackmamba/a-simple-guide-to-cicd-for-total-beginners-in-2022-2kgp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Explains the idea of CI/CD and why we need it. Gives a quick round trip for some CI/CD tools.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/scofieldidehen&quot;&gt;Scofield Idehen&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 30]]></title><description><![CDATA[This week was tough as it was my last week at Monada. It was a great time working with great engineers and I am super excited to follow the…]]></description><link>https://martinmueller.dev/newsletter-30/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-30/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 31 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This week was tough as it was my last week at Monada. It was a great time working with great engineers and I am super excited to follow the future development of Monada :).&lt;/p&gt;
&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Serverless, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;accessibility-check-1&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#accessibility-check-1&quot; aria-label=&quot;accessibility check 1 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Accessibility Check #1&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/yuridevat/accessibility-check-1-3c38&quot;&gt;https://dev.to/yuridevat/accessibility-check-1-3c38&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The author &lt;a href=&quot;https://dev.to/yuridevat&quot;&gt;Julia&lt;/a&gt; tells about her first experience with accessibility checking. It seems quite convenient to check the website using the article mentioned DevTool extension.&lt;/p&gt;
&lt;h2 id=&quot;storage-first-serverless-solutions-rocket&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#storage-first-serverless-solutions-rocket&quot; aria-label=&quot;storage first serverless solutions rocket permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Storage-First Serverless Solutions :rocket:&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://leejamesgilmore.medium.com/storage-first-serverless-solutions-c0fc182243b9&quot;&gt;https://leejamesgilmore.medium.com/storage-first-serverless-solutions-c0fc182243b9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A cool article about how to build a modern asynchronous API with the storage-first approach where the request is saved in the storage to optionally play it again in the case of further processing fails. The author describes a simple example and provides a lot of useful Lambda and AWS CDK code. Great article!!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://leejamesgilmore.medium.com/&quot;&gt;Lee James Gilmore&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;increase-your-coding-productivity-with-amazon-codewhisperer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#increase-your-coding-productivity-with-amazon-codewhisperer&quot; aria-label=&quot;increase your coding productivity with amazon codewhisperer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Increase Your Coding Productivity with Amazon CodeWhisperer&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@IVaibhavMalpani/increase-your-coding-productivity-with-amazon-codewhisperer-7d4ed1b54295&quot;&gt;https://medium.com/@IVaibhavMalpani/increase-your-coding-productivity-with-amazon-codewhisperer-7d4ed1b54295&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you are using Python or JavaScript for your business logic give Amazon CodeWhisperer a try. It seems super worthwhile!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://medium.com/@IVaibhavMalpani&quot;&gt;Vaibhav Malpani&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction-to-aws-step-functions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introduction-to-aws-step-functions&quot; aria-label=&quot;introduction to aws step functions permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introduction to AWS Step Functions&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/introduction-to-aws-step-functions-28k7&quot;&gt;https://dev.to/aws-builders/introduction-to-aws-step-functions-28k7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That is a nice overview of AWS Step Functions. The author explains when to use it and what are the main features.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/avik6028&quot;&gt;Avik Kundu&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-automate-rest-api-security-testing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-automate-rest-api-security-testing&quot; aria-label=&quot;how to automate rest api security testing permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to Automate REST API Security Testing&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/intesar/how-to-automate-rest-api-security-testing-4lh4&quot;&gt;https://dev.to/intesar/how-to-automate-rest-api-security-testing-4lh4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Introduces some interesting tools for automated REST API security testing.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/intesar&quot;&gt;Intesar Shannan Mohammed&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;devops-toolchain-for-beginners&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#devops-toolchain-for-beginners&quot; aria-label=&quot;devops toolchain for beginners permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;DevOps Toolchain for Beginners&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/vishnube/devops-toolchain-for-beginners-2aif&quot;&gt;https://dev.to/vishnube/devops-toolchain-for-beginners-2aif&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A super nice in-depth article about useful toolchains for developers. A must-read if you are new to the DevOps space!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/vishnube&quot;&gt;Vishnu Vasudevan&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction-of-facade-pattern-in-javascript&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introduction-of-facade-pattern-in-javascript&quot; aria-label=&quot;introduction of facade pattern in javascript permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introduction of Facade Pattern in Javascript&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/yohanesss/introduction-of-facade-pattern-in-javascript-2gmo&quot;&gt;https://dev.to/yohanesss/introduction-of-facade-pattern-in-javascript-2gmo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice and tight article explaining the Facade pattern with a JavaScript example.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/yohanesss&quot;&gt;Yohanes Setiawan&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-do-youcompany-deal-with-secrets-on-cicd&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-do-youcompany-deal-with-secrets-on-cicd&quot; aria-label=&quot;how do youcompany deal with secrets on cicd permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How do you/company deal with secrets on ci/cd?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/devops/comments/wajare/how_do_youcompany_deal_with_secrets_on_cicd/&quot;&gt;https://www.reddit.com/r/devops/comments/wajare/how_do_youcompany_deal_with_secrets_on_cicd/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting Reddit discussion on how to deal with secrets on CI/CD. I&apos;ll favor AWS SecretsManager for staying in the tool space I already use.&lt;/p&gt;
&lt;h2 id=&quot;serverless-diary-how-to-increase-agility-with-feature-toggles--classical-approach&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#serverless-diary-how-to-increase-agility-with-feature-toggles--classical-approach&quot; aria-label=&quot;serverless diary how to increase agility with feature toggles  classical approach permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Serverless Diary: How to Increase Agility with Feature Toggles — Classical Approach&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://kothiyal-anuj.medium.com/serverless-diary-how-to-increase-agility-with-feature-toggles-classical-approach-ae5f197e9be4&quot;&gt;https://kothiyal-anuj.medium.com/serverless-diary-how-to-increase-agility-with-feature-toggles-classical-approach-ae5f197e9be4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting article on how you could implement feature toggles or flags in a serverless environment. Lists as well pros and cons when using the feature flags as part of AWS Lambda.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://kothiyal-anuj.medium.com/&quot;&gt;Anuj Kothiyal&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;solutions-architect-tips---how-to-design-applications-for-growth&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#solutions-architect-tips---how-to-design-applications-for-growth&quot; aria-label=&quot;solutions architect tips   how to design applications for growth permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Solutions Architect Tips - How to Design Applications For Growth&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.readysetcloud.io/blog/allen.helton/how-to-design-applications-for-growth/&quot;&gt;https://www.readysetcloud.io/blog/allen.helton/how-to-design-applications-for-growth/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice top-down article on how to design your application for growth.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Allen Helton&lt;/p&gt;
&lt;h2 id=&quot;7-best-tips-for-web-developers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#7-best-tips-for-web-developers&quot; aria-label=&quot;7 best tips for web developers permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;7 Best Tips For Web Developers&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/devsimc/7-best-tips-for-web-developers-636&quot;&gt;https://dev.to/devsimc/7-best-tips-for-web-developers-636&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some super cool tips for web developers. In the comment section are some more cool and useful tips :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/devsimc&quot;&gt;simc dev CSM®&lt;/a&gt; and the commenters.&lt;/p&gt;
&lt;h2 id=&quot;what-is-continuous-cloud-compliance&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-continuous-cloud-compliance&quot; aria-label=&quot;what is continuous cloud compliance permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is Continuous Cloud Compliance?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.mitigant.io/blog/what-is-continuous-cloud-compliance&quot;&gt;https://www.mitigant.io/blog/what-is-continuous-cloud-compliance&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Compliance in the cloud is super interesting. This article explains the different kinds of compliance standards. Furthermore, the author drafts the motivation behind cloud compliance.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://twitter.com/run2obtain&quot;&gt;Kennedy Torkura&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 29]]></title><description><![CDATA[This week was hot in Germany. Not just in terms of cool news around DevOps and more, it was physically hot :). My highlight of this week was…]]></description><link>https://martinmueller.dev/newsletter-29/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-29/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 24 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This week was hot in Germany. Not just in terms of cool news around DevOps and more, it was physically hot :). My highlight of this week was the in-person AWS UG Meetup in Berlin. It was super amazing to see some AWS CDK friends in real :)!&lt;/p&gt;
&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Serverless, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;astonished-my-top-5-list-of-resources-that-i-wish-i-knew-when-i-started-programming&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#astonished-my-top-5-list-of-resources-that-i-wish-i-knew-when-i-started-programming&quot; aria-label=&quot;astonished my top 5 list of resources that i wish i knew when i started programming permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;:astonished: My Top 5 List of Resources that I Wish I Knew When I Started Programming&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/eludadev/my-top-5-list-of-resources-that-i-wish-i-knew-when-i-started-programming-j04&quot;&gt;https://dev.to/eludadev/my-top-5-list-of-resources-that-i-wish-i-knew-when-i-started-programming-j04&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Contains some useful tips for how to improve your programming skills. My favorite one is to connect with a developer community. One community my heart belongs to is the AWS CDK community. Come and join us. Is a lot of fun and helpful people. &lt;a href=&quot;https://join.slack.com/t/cdk-dev/shared_invite/zt-xtpfmrqt-6ormYTA0hLdpMSAtTkM_2A&quot;&gt;https://join.slack.com/t/cdk-dev/shared_invite/zt-xtpfmrqt-6ormYTA0hLdpMSAtTkM_2A&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/eludadev&quot;&gt;Eluda&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;lambda-powertools-typescript-is-generally-available&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#lambda-powertools-typescript-is-generally-available&quot; aria-label=&quot;lambda powertools typescript is generally available permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lambda Powertools TypeScript is Generally Available&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/lambda-powertools-typescript-is-generally-available-1dm8&quot;&gt;https://dev.to/aws-builders/lambda-powertools-typescript-is-generally-available-1dm8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A super nice deep dive into the Lambda PowerTools TypeScript and its features. The structured log capability looks super interesting. And I didn&apos;t know about the embedded metric for CloudWatch. That is super cool!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/elthrasher&quot;&gt;Matt Morgan&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-data-gravity-and-is-it-important-with-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-data-gravity-and-is-it-important-with-serverless&quot; aria-label=&quot;what is data gravity and is it important with serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Is Data Gravity And Is It Important With Serverless?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.readysetcloud.io/blog/allen.helton/what-is-data-gravity-and-is-it-important/&quot;&gt;https://www.readysetcloud.io/blog/allen.helton/what-is-data-gravity-and-is-it-important/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting article on how accumulating data (data gravity) makes it hard to move like potentially changing the cloud provider. The author explains how to reduce the burden of data gravity.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Allen Helton&lt;/p&gt;
&lt;h2 id=&quot;aws-open-source-news-and-updates-121&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-open-source-news-and-updates-121&quot; aria-label=&quot;aws open source news and updates 121 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS open-source news and updates, #121&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws/aws-open-source-news-and-updates-121-1h18&quot;&gt;https://dev.to/aws/aws-open-source-news-and-updates-121-1h18&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As always a very good summary of the week. The &lt;a href=&quot;https://github.com/aws-samples/spot-interruption-simulation&quot;&gt;spot-interruption-simulation&lt;/a&gt; project got my attention. It sounds super cool for simulating the use of Ec2 spot instances.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/094459&quot;&gt;Ricardo Sueiras&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;simplifying-serverless-best-practices-with-aws-lambda-powertools-for-typescript&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#simplifying-serverless-best-practices-with-aws-lambda-powertools-for-typescript&quot; aria-label=&quot;simplifying serverless best practices with aws lambda powertools for typescript permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Simplifying serverless best practices with AWS Lambda Powertools for TypeScript&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/compute/simplifying-serverless-best-practices-with-aws-lambda-powertools-for-typescript/&quot;&gt;https://aws.amazon.com/blogs/compute/simplifying-serverless-best-practices-with-aws-lambda-powertools-for-typescript/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A summary of the AWS Lambda Powertools for TypeScript. This looks very interesting and for my next more complex Lambda, I will give it a try!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Julian Wood&lt;/p&gt;
&lt;h2 id=&quot;the-truth-behind-being-a-good-programmer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-truth-behind-being-a-good-programmer&quot; aria-label=&quot;the truth behind being a good programmer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The truth behind being a good programmer&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/bekbrace/the-truth-behind-being-a-good-programmer-171b&quot;&gt;https://dev.to/bekbrace/the-truth-behind-being-a-good-programmer-171b&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Yep, it has fair points for what makes a good programmer :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/bekbrace&quot;&gt;Bek Brace&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-software-developers-can-learn-from-gutenberg&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-software-developers-can-learn-from-gutenberg&quot; aria-label=&quot;what software developers can learn from gutenberg permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Software Developers can learn from Gutenberg&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/polterguy/what-software-developers-can-learn-from-gutenberg-5bpa&quot;&gt;https://dev.to/polterguy/what-software-developers-can-learn-from-gutenberg-5bpa&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A sweet enlightenment of how important Johannes Gutenberg was to the software development community and everything else.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/polterguy&quot;&gt;Thomas Hansen&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-do-i-think-snapshot-tests-are-a-bad-idea&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-do-i-think-snapshot-tests-are-a-bad-idea&quot; aria-label=&quot;why do i think snapshot tests are a bad idea permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why do I think snapshot tests are a bad idea&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/syeo66/why-do-i-think-snapshot-tests-are-a-bad-idea-1imp&quot;&gt;https://dev.to/syeo66/why-do-i-think-snapshot-tests-are-a-bad-idea-1imp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting explanation of why snapshot testing is a bad idea.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/syeo66&quot;&gt;Red Ochsenbein&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-questions-to-ask-when-developing-an-automation-strategy&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-questions-to-ask-when-developing-an-automation-strategy&quot; aria-label=&quot;5 questions to ask when developing an automation strategy permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5 Questions to Ask When Developing an Automation Strategy&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://thenewstack.io/5-questions-to-ask-when-developing-an-automation-strategy/&quot;&gt;https://thenewstack.io/5-questions-to-ask-when-developing-an-automation-strategy/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice top-down article about automation when developing. But it feels a bit like fitting into a context of a bigger software company.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://thenewstack.io/author/chris-tozzi/&quot;&gt;CHRIS TOZZI&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-things-to-keep-in-mind-as-a-programmer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-things-to-keep-in-mind-as-a-programmer&quot; aria-label=&quot;5 things to keep in mind as a programmer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5 things to keep in mind as a programmer&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/devsimc/5-things-to-keep-in-mind-as-a-programmer-1c24&quot;&gt;https://dev.to/devsimc/5-things-to-keep-in-mind-as-a-programmer-1c24&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A routine of continuous learning is my favorite out of those 5. But the others are important too so read it!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/devsimc&quot;&gt;simc dev&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;single-sign-on-sso-using-aws-cognito-and-azure-ad&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#single-sign-on-sso-using-aws-cognito-and-azure-ad&quot; aria-label=&quot;single sign on sso using aws cognito and azure ad permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Single Sign-On (SSO) using AWS Cognito and Azure AD&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.getambassador.io/single-sign-on-sso-using-aws-cognito-and-azure-ad-356951536218&quot;&gt;https://blog.getambassador.io/single-sign-on-sso-using-aws-cognito-and-azure-ad-356951536218&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting to see how you can leverage your Azure Active Directory (AD) for setting as Identity Provider (IdP) for AWS Cognito.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://supratip-banerjee.medium.com/&quot;&gt;Supratip Banerjee&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 28]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-28/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-28/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 17 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Serverless, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;automating-aws-account-bootstrapping-with-aws-cdk&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#automating-aws-account-bootstrapping-with-aws-cdk&quot; aria-label=&quot;automating aws account bootstrapping with aws cdk permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Automating AWS account bootstrapping with AWS-CDK&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@andrewfrazer/automating-aws-account-bootstrapping-with-aws-cdk-117e5ead1c51&quot;&gt;https://medium.com/@andrewfrazer/automating-aws-account-bootstrapping-with-aws-cdk-117e5ead1c51&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting article on how to CDK bootstrap new accounts in a more DevOps way. Very cool is the idea that whenever a new account is created with Control Tower that will trigger an AWS CodeBuild job to bootstrap the account.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://medium.com/@andrewfrazer&quot;&gt;Andrew Frazer&lt;/a&gt;. And thank you for being a very active member of the CDK Community.&lt;/p&gt;
&lt;h2 id=&quot;the-cost-of-production-blindness&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-cost-of-production-blindness&quot; aria-label=&quot;the cost of production blindness permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Cost of Production Blindness&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/codenameone/the-cost-of-production-blindness-48aj&quot;&gt;https://dev.to/codenameone/the-cost-of-production-blindness-48aj&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super nice input in one of my favorite topics production. I totally agree that we need to peek more into production. What is the problem when you don&apos;t do that and some attempts how to do it are explained in this article.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/codenameone&quot;&gt;Shai Almog&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-do-developers-prefer-linux&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-do-developers-prefer-linux&quot; aria-label=&quot;why do developers prefer linux permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why Do Developers Prefer Linux?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/techmaniacc/why-do-developers-prefer-linux-32a3&quot;&gt;https://dev.to/techmaniacc/why-do-developers-prefer-linux-32a3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting explanation of why developers prefer Linux. If you only compare Windows and Linux, I tend to agree with the points but the comparison with macOS is missing. Sure you could argue that macOS is close to Linux.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/techmaniacc&quot;&gt;Joseph Mania&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;streams-in-nodejs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#streams-in-nodejs&quot; aria-label=&quot;streams in nodejs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Streams in NodeJS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/kalashin1/streams-in-nodejs-2b8l&quot;&gt;https://dev.to/kalashin1/streams-in-nodejs-2b8l&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice article about the concept of streams. I used them a couple of times like in Data Engineering projects as I find them super useful for effectively processing big text data. In special the piping feature for connecting streams is super cool.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/kalashin1&quot;&gt;Kinanee Samson&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;two-ways-to-directly-integrate-aws-lambda-function-with-amazon-api-gateway&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#two-ways-to-directly-integrate-aws-lambda-function-with-amazon-api-gateway&quot; aria-label=&quot;two ways to directly integrate aws lambda function with amazon api gateway permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Two ways to directly integrate AWS Lambda function with Amazon API Gateway&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/two-ways-to-directly-integrate-aws-lambda-function-with-amazon-api-gateway-3can&quot;&gt;https://dev.to/aws-builders/two-ways-to-directly-integrate-aws-lambda-function-with-amazon-api-gateway-3can&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The article explains the two different types/ways how to connect an AWS API Gateway with a Lambda. That is the proxy and non-proxy type. Usually, you are using the proxy type. TBH. I never used the non-proxy type so it is interesting to read about it!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/wojciechmatuszewski&quot;&gt;Wojciech Matuszewski&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-best-password-manager-on-linux&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-best-password-manager-on-linux&quot; aria-label=&quot;the best password manager on linux permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The best password manager on Linux?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/robole/the-best-password-manager-on-linux-f3c&quot;&gt;https://dev.to/robole/the-best-password-manager-on-linux-f3c&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Highlights KeePassXC as noncloud hosted password manager. I use it for some years now and I like it too :). I use it for Mac laptops as well.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/robole&quot;&gt;Rob OLeary&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;programming-myths-vs-facts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#programming-myths-vs-facts&quot; aria-label=&quot;programming myths vs facts permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Programming Myths vs Facts&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/qavsdev/programming-myths-vs-facts-5cja&quot;&gt;https://dev.to/qavsdev/programming-myths-vs-facts-5cja&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice Myths vs Facts for programming. It gives a better insight into what programmers are doing and clarifies some wrong expectations. I like!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/qavsdev&quot;&gt;QAvsDEV&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;help---a-little-overwhelmed-in-devops&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#help---a-little-overwhelmed-in-devops&quot; aria-label=&quot;help   a little overwhelmed in devops permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Help - A little overwhelmed in DevOps&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/devops/comments/vwgu5b/help_a_little_overwhelmed_in_devops/&quot;&gt;https://www.reddit.com/r/devops/comments/vwgu5b/help_a_little_overwhelmed_in_devops/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice discussion to give a kind of a small roadmap for DevOps and helps to understand wrong expectations about DevOps.&lt;/p&gt;
&lt;h2 id=&quot;appsync-and-dynamodb-lessons-learned&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#appsync-and-dynamodb-lessons-learned&quot; aria-label=&quot;appsync and dynamodb lessons learned permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AppSync and DynamoDB Lessons Learned&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://instil.co/blog/appsync-dynamodb-lessons-learned/&quot;&gt;https://instil.co/blog/appsync-dynamodb-lessons-learned/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Exciting discussion with like DynamoDB single vs multi-table design. I personally favor multi-table design supported with Amplify AppSync.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Matthew Wilson&lt;/p&gt;
&lt;h2 id=&quot;history-of-apis&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#history-of-apis&quot; aria-label=&quot;history of apis permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;History of APIs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/littleironical/history-of-apis-281j&quot;&gt;https://dev.to/littleironical/history-of-apis-281j&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting history roundtrip about APIs&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/littleironical&quot;&gt;Hardik kumar&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;investigating-15s-http-response-time-in-aws-ecs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#investigating-15s-http-response-time-in-aws-ecs&quot; aria-label=&quot;investigating 15s http response time in aws ecs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Investigating 15s HTTP response time in AWS ECS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/gwenshap/investigating-15s-http-response-time-in-aws-ecs-2gge&quot;&gt;https://dev.to/gwenshap/investigating-15s-http-response-time-in-aws-ecs-2gge&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting story about investigating a long response time when using AWS ECS in multiple availability zones.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/gwenshap&quot;&gt;Gwen (Chen) Shapira&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-ask-for-help&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-ask-for-help&quot; aria-label=&quot;how to ask for help permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to ask for help&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/dhravya/how-to-ask-for-help-2690&quot;&gt;https://dev.to/dhravya/how-to-ask-for-help-2690&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super article about how to ask correctly for help in like a community.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/dhravya&quot;&gt;Dhravya&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Catch AWS Lambda Timeouts]]></title><description><![CDATA[cdk-lambda-timeout-eng
(Click me :D) Ahoy, AWS Lambda is probably one of the most famous if not the most famous compute service from AWS. In…]]></description><link>https://martinmueller.dev/cdk-lambda-timeout-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-lambda-timeout-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><pubDate>Sun, 10 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=9Oeu9ewrwXQ&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/9Oeu9ewrwXQ/0.jpg&quot; alt=&quot;cdk-lambda-timeout-eng&quot;&gt;&lt;/a&gt;
(Click me :D)&lt;/p&gt;
&lt;p&gt;Ahoy,&lt;/p&gt;
&lt;p&gt;AWS Lambda is probably one of the most famous if not the most famous compute service from AWS. In fact, Lambda is also my favorite AWS service because it makes implementing business logic very easy and straightforward. However, a few times I had the problem that the timeout of Lambda was too low and thus the code was not completely executed. Debugging or catching this error was also often exhausting and annoying. A good solution for me was to use the Lambda Duration Metrics to define an alarm.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cw &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-cloudwatch&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; lambdajs &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-lambda-nodejs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; sns &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-sns&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; subscriptions &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-lib/aws-sns-subscriptions&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; exampleLambda &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;lambdajs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NodejsFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ExampleLambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    timeout&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;timeoutAlarm&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Alarm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TimeoutAlarm&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    metric&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; exampleLambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;metricDuration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; statistic&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;max&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    threshold&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; exampleLambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timeout&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toMilliseconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    evaluationPeriods&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; topic &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;sns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Topic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;ErrorTopic&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
topic&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addSubscription&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;subscriptions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;EmailSubscription&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;alice@bob.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
timeoutAlarm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addAlarmAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SnsAction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;topic&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see here, a simple Lambda JS Function is created at the beginning. By the way the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html&quot;&gt;NodejsFunction construct&lt;/a&gt; also supports TypeScript. Then the timeout alarm is defined which uses the duration metric and the timeout value from the Lambda to configure.&lt;/p&gt;
&lt;p&gt;After that, an Error Topic is created via which the triggered alarm is forwarded by email using an EmailSubscription.&lt;/p&gt;
&lt;h2 id=&quot;advantages&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#advantages&quot; aria-label=&quot;advantages permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Advantages&lt;/h2&gt;
&lt;p&gt;The advantage of this solution is that the Lambda code does not need to be modified and the problem is solved on infrastructure level or AWS CDK level. This solution can be applied to other Lambda languages like Python or Java as well.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Lambda timeout caching is annoying. With a little AWS CDK code and the Lambda Duration metric, the problem is quickly solved.&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 27]]></title><description><![CDATA[This week was crazy exciting. On Thursday I took the train to Munich for attending to an AWS Meetup and visit a client and friend. Both…]]></description><link>https://martinmueller.dev/newsletter-27/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-27/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 10 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This week was crazy exciting. On Thursday I took the train to Munich for attending to an AWS Meetup and visit a client and friend. Both events were super empowering and in times like this, I feel very grateful and thankful to work in this area.&lt;/p&gt;
&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Serverless, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-made-golang-so-popular-the-languages-creators-look-back&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-made-golang-so-popular-the-languages-creators-look-back&quot; aria-label=&quot;what made golang so popular the languages creators look back permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Made GoLang So Popular? The Language’s Creators Look Back&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://thenewstack.io/what-made-golang-so-popular-the-languages-creators-look-back/&quot;&gt;https://thenewstack.io/what-made-golang-so-popular-the-languages-creators-look-back/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting history telling about GoLang and how it became so popular. TBH, I didn&apos;t work much with GoLang so far so it is hard for me to see the gold. If you have a project with GoLang and need some help, let me know :)!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://thenewstack.io/author/destiny/&quot;&gt;DAVID CASSEL&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-feature-flags&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-use-feature-flags&quot; aria-label=&quot;how to use feature flags permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to Use Feature Flags&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/bentorvo/how-to-use-feature-flags-39md&quot;&gt;https://dev.to/bentorvo/how-to-use-feature-flags-39md&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Why and how you can use feature flags. A very appealing part for feature flags, I find the possibility to roll the feature out to production but disable it quickly if it is causing problems. As well in combination with A/B Testing feature flags can be used to roll out the changes only to a part of the customers.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/bentorvo&quot;&gt;Ben Brazier&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;github-copilot-and-open-source-a-love-story-that-wont-end-well&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#github-copilot-and-open-source-a-love-story-that-wont-end-well&quot; aria-label=&quot;github copilot and open source a love story that wont end well permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GitHub Copilot and Open Source: A Love Story That Won’t End Well?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://thenewstack.io/github-copilot-and-open-source-a-love-story-that-wont-end-well/&quot;&gt;https://thenewstack.io/github-copilot-and-open-source-a-love-story-that-wont-end-well/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are currently a lot of hot topics around GitHub Copilot. This article summarizes the problem very well. TBH I for myself don&apos;t have a strong position. On one hand, I like GitHub as a Git provider with super nice extra features. On the other hand, violating the taking code from a developer who didn&apos;t agree to that is awful. The conclusion from the author is nice and makes sense to me.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://thenewstack.io/author/sasha-medvedovsky/&quot;&gt;SASHA MEDVEDOVSKY&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;implementing-cudos-for-an-enterprise---part-2-filtering-data-using-row-level-security&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#implementing-cudos-for-an-enterprise---part-2-filtering-data-using-row-level-security&quot; aria-label=&quot;implementing cudos for an enterprise   part 2 filtering data using row level security permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Implementing CUDOS for an Enterprise - Part 2: Filtering Data using Row Level Security&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/implementing-cudos-for-an-enterprise-part-2-filtering-data-using-row-level-security-1g2p&quot;&gt;https://dev.to/aws-builders/implementing-cudos-for-an-enterprise-part-2-filtering-data-using-row-level-security-1g2p&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A comprehensive article about AWS QuickSight and how to manage your QuickSight user in groups to allow them access to the QuickSight resources. It feels like good QuickSight articles or information are rarely so it is super valuable to have articles like this one.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/michaelegraff&quot;&gt;Mike Graff&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;building-an-open-source-company-in-public&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#building-an-open-source-company-in-public&quot; aria-label=&quot;building an open source company in public permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Building an open-source company in public&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/novu/building-in-public-4i73&quot;&gt;https://dev.to/novu/building-in-public-4i73&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Uh, that is super attractive. Building a complete open-source company. I super like that idea. Being an open-source would include sharing the salary&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/combarnea&quot;&gt;Tomer Barnea&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;cloud-and-the-shared-responsibility-model-misconceptions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cloud-and-the-shared-responsibility-model-misconceptions&quot; aria-label=&quot;cloud and the shared responsibility model misconceptions permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cloud and the shared responsibility model misconceptions&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/cloud-and-the-shared-responsibility-model-misconceptions-2lem&quot;&gt;https://dev.to/aws-builders/cloud-and-the-shared-responsibility-model-misconceptions-2lem&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The author explains some misconceptions which can occur when a user starts to use a cloud provider.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/eyalestrin&quot;&gt;Eyal Estrin&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;open-source-contribution-a-beginners-guide-in-2-minutes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#open-source-contribution-a-beginners-guide-in-2-minutes&quot; aria-label=&quot;open source contribution a beginners guide in 2 minutes permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Open-Source contribution, a beginner&apos;s guide (in 2 minutes)&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/mohsenkamrani/open-source-contribution-a-beginners-guide-in-2-minutes-2g58&quot;&gt;https://dev.to/mohsenkamrani/open-source-contribution-a-beginners-guide-in-2-minutes-2g58&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice short intro to GitHub. I personally love working with GitHub.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/mohsenkamrani&quot;&gt;mohsen&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rds-aurora-cost-comparison&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#rds-aurora-cost-comparison&quot; aria-label=&quot;rds aurora cost comparison permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;RDS Aurora Cost Comparison&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/aws/comments/vuxhdb/rds_aurora_cost_comparison/&quot;&gt;https://www.reddit.com/r/aws/comments/vuxhdb/rds_aurora_cost_comparison/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A super interesting discussion about costs with AWS RDS Aurora. The general approach seems to be more bottom-up-ish with just trying it out and experiencing the costs.&lt;/p&gt;
&lt;h2 id=&quot;learn-to-code-with-these-5-proven-learning-strategies&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#learn-to-code-with-these-5-proven-learning-strategies&quot; aria-label=&quot;learn to code with these 5 proven learning strategies permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Learn to code with these 5 proven learning strategies&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/educative/learn-to-code-with-these-5-proven-learning-strategies-58gj&quot;&gt;https://dev.to/educative/learn-to-code-with-these-5-proven-learning-strategies-58gj&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some very good tips for how to improve coding and learning in general. Must read!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/huntereducative&quot;&gt;Hunter Johnson&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;open-source-projects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#open-source-projects&quot; aria-label=&quot;open source projects permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Open Source Projects&lt;/h2&gt;
&lt;p&gt;In this section, I list Open Source projects I find super interesting!&lt;/p&gt;
&lt;h2 id=&quot;aws-prototyping-sdk&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-prototyping-sdk&quot; aria-label=&quot;aws prototyping sdk permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;aws-prototyping-sdk&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-prototyping-sdk&quot;&gt;https://github.com/aws/aws-prototyping-sdk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An amazing new-ish project from the AWS folks with some very sophisticated AWS CDK and Projen constructs. In special the stack-website construct is super mind-blowing and I could find a lot of gold to grab for my own projects. I recommend keeping that on your radar! Thank you so much!&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Make your AWS Prod environment super with Superwerker]]></title><description><![CDATA[Hi everyone. I want to make my senjuns project production-ready. So far I had only deployed it in my developer AWS account. My developer…]]></description><link>https://martinmueller.dev/aws-superwerker-eng/</link><guid isPermaLink="false">https://martinmueller.dev/aws-superwerker-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><pubDate>Tue, 05 Jul 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c96ba4c99f48a2172b486549333dbffc/splash.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi everyone.&lt;/p&gt;
&lt;p&gt;I want to make my &lt;a href=&quot;https://github.com/senjuns/senjuns&quot;&gt;senjuns project&lt;/a&gt; production-ready. So far I had only deployed it in my developer AWS account. My developer account has no AWS services configured that are needed for a reasonable production environment. These are for example AWS SSO, ControlTower, SecurityHub and some more. The &lt;a href=&quot;https://github.com/superwerker/superwerker&quot;&gt;Superwerker CFN Template&lt;/a&gt; came in handy. It allowed me to configure a new AWS account with many great AWS services for production use. In the following sections, I would like to go into what Superwerker is exactly and how I used it.&lt;/p&gt;
&lt;h2 id=&quot;what-is-superwerker&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-superwerker&quot; aria-label=&quot;what is superwerker permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is Superwerker?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/superwerker/superwerker&quot;&gt;Superwerker&lt;/a&gt; is an open-source AWS CloudFormation solution that simplifies the setup of an AWS account. It follows best practices for security and efficiency. It was/is developed and maintained by AWS Advanced Partners &lt;a href=&quot;https://github.com/superwerker/superwerker&quot;&gt;kreuzwerker&lt;/a&gt; and &lt;a href=&quot;https://superluminar.io/&quot;&gt;superluminar&lt;/a&gt;. It even has its own &lt;a href=&quot;https://superwerker.cloud&quot;&gt;landing page&lt;/a&gt; with great content like a short video and more. Hard to believe this is a free product.&lt;/p&gt;
&lt;p&gt;The Superwerker deployment has a lot of cool features which are all explained very well in the docs &lt;a href=&quot;https://github.com/superwerker/superwerker/tree/main/docs/adrs&quot;&gt;here&lt;/a&gt;. I really like that it uses &lt;a href=&quot;https://adr.github.io/&quot;&gt;Architectural Decision Records&lt;/a&gt; to describe each feature. Below I explain the features in my own words.&lt;/p&gt;
&lt;h3 id=&quot;backup&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#backup&quot; aria-label=&quot;backup permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Backup&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/backup.md&quot;&gt;Backup&lt;/a&gt; enables the AWS Backup Service and by default, a backup is created every day. It creates backups of databases that are also supported by AWS Backup.&lt;/p&gt;
&lt;h3 id=&quot;budget&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#budget&quot; aria-label=&quot;budget permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Budget&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/budget.md&quot;&gt;Budget&lt;/a&gt; helps to keep track of the costs in AWS and gives a warning in time if there are more costs than usual. It does this by calculating the average of the last three months and if this is exceeded, a warning comes. A really cool idea in my opinion.&lt;/p&gt;
&lt;h3 id=&quot;control-tower&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#control-tower&quot; aria-label=&quot;control tower permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Control Tower&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/control-tower.md&quot;&gt;Control Tower&lt;/a&gt; simplifies managing multiple AWS accounts with AWS SSO. For me, this is the main reason why I use Superwerker. So I can access my different AWS accounts like build, dev and prod very easily. I also like the fact that with AWS SSO I can simply copy the AWS account credentials and use them for the AWS CLI.&lt;/p&gt;
&lt;h3 id=&quot;guardduty&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#guardduty&quot; aria-label=&quot;guardduty permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GuardDuty&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/guardduty.md&quot;&gt;GuardDuty&lt;/a&gt; is an AWS service for finding potential security threats.&lt;/p&gt;
&lt;h3 id=&quot;living-documentation&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#living-documentation&quot; aria-label=&quot;living documentation permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Living Documentation&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/living-documentation.md&quot;&gt;Living Documentation&lt;/a&gt; is a pretty cool feature that generates documentation via the AWS CloudWatch Dashboard. This then provides information on, for example, how to do an SSO setup with external identity providers like Google and much more. Extremely cool is how this documentation also updates itself when certain configurations have already been made. That&apos;s why it&apos;s called Living Documentation.&lt;/p&gt;
&lt;h3 id=&quot;notifications&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#notifications&quot; aria-label=&quot;notifications permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Notifications&lt;/h3&gt;
&lt;p&gt;Superwerker creates OpsItems in OpsCenter when emails are sent from the RootMail feature. With the &lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/notifications.md&quot;&gt;Notifications&lt;/a&gt; feature emails are sent to the specified addresses. This way the user does not have to manually log into the AWS Console and check OpsCenter. Through email, one thus also has a centralized collection point for multiple accounts.&lt;/p&gt;
&lt;h3 id=&quot;rootmail&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#rootmail&quot; aria-label=&quot;rootmail permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;RootMail&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/rootmail.md&quot;&gt;RootMail&lt;/a&gt; creates the uniformed email addresses for the audit and log archive accounts created by Control Tower. For this purpose, a separate Hosted Zone is created, for example aws.mycompany.test with Route53, and the required settings are made with AWS SES to receive the emails.&lt;/p&gt;
&lt;h3 id=&quot;security-hub&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#security-hub&quot; aria-label=&quot;security hub permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Security Hub&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/securityhub.md&quot;&gt;Security Hub&lt;/a&gt; feature enables AWS Security Hub for all accounts. The user needs to log into the audited account to view the aggregated Security Hub view.&lt;/p&gt;
&lt;p&gt;In the next section, I would like to share more about my Experience with Superwerker.&lt;/p&gt;
&lt;h2 id=&quot;superwerker-experience&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#superwerker-experience&quot; aria-label=&quot;superwerker experience permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Superwerker Experience&lt;/h2&gt;
&lt;p&gt;You can find the instructions for running Superwerker &lt;a href=&quot;https://superwerker.awsworkshop.io/&quot;&gt;here&lt;/a&gt;. For me, the installation went quite smoothly. However, the &lt;a href=&quot;https://github.com/superwerker/superwerker/blob/main/docs/adrs/rootmail.md&quot;&gt;RootMail&lt;/a&gt; nested stack was an exception. I had previously imported my senjuns.com domain and associated Hosted Zone from another AWS account. However, I did not properly configure the name servers from the domain in the designated Hosted Zone. By debugging the Superwerker Lambdas, I noticed this error.&lt;/p&gt;
&lt;p&gt;So if you also get the following error logs in the RootMailReady Lambda, you just need to check if you have configured your domain and Hosted Zone properly.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;info&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;verification not yet successful&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;res&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;VerificationAttributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;aws.senjuns.com&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token property&quot;&gt;&quot;VerificationStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pending&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;info&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;msg&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;DKIM verification not yet successful&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;res&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;DkimAttributes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;aws.senjuns.com&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token property&quot;&gt;&quot;DkimEnabled&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token property&quot;&gt;&quot;DkimVerificationStatus&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pending&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If anyone encounters the same or similar problem, I have created a pull request with troubleshooting information.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Superwerker is a great CloudFormation QuickStart to set up an AWS production environment professionally and easily. Many improvements and new features are already planned in the &lt;a href=&quot;https://github.com/superwerker/superwerker/issues&quot;&gt;Superwerker Backlog&lt;/a&gt;. The Superwerker community is still looking for active support in implementing new features and improvements. I am very excited to continue using the Superwerker deployment in my current project.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/c96ba4c99f48a2172b486549333dbffc/splash.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/c96ba4c99f48a2172b486549333dbffc/splash.jpeg" medium="image"/></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 26]]></title><description><![CDATA[Hello friends. Another week passed by! My highlights of the week were the German CDK Happy Hour Meetup on Wednesday where an AWS CDK project…]]></description><link>https://martinmueller.dev/newsletter-26/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-26/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 03 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello friends.&lt;/p&gt;
&lt;p&gt;Another week passed by! My highlights of the week were the German CDK Happy Hour Meetup on Wednesday where an AWS CDK project was presented which leverages AWS ECS with Blue/Green deployments. That is super exciting as that is not natively supported by ECS CloudFormation at all. Another highlight was that I helped a friend move house and carrying furniture around like that is a good workout :).&lt;/p&gt;
&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Serverless, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;nobody-talks-about-this-in-the-it-world&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#nobody-talks-about-this-in-the-it-world&quot; aria-label=&quot;nobody talks about this in the it world permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Nobody talks about this in the IT world&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/antoomartini/nobody-talks-about-this-in-the-it-world-31ph&quot;&gt;https://dev.to/antoomartini/nobody-talks-about-this-in-the-it-world-31ph&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An article about imposter syndrome. It is so important to speak about it more in our area. I personally never felt affected by it but I would love to help persons who do. In the discussion the community gives nice tips how to overcome the imposter syndrome.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/antoomartini&quot;&gt;Maria Antonella :butterfly:&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-developers-must-start-blogging-and-how-to-start&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-developers-must-start-blogging-and-how-to-start&quot; aria-label=&quot;why developers must start blogging and how to start permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why developers must start blogging and how to start?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/atapas/why-developers-must-start-blogging-and-how-to-start-543c&quot;&gt;https://dev.to/atapas/why-developers-must-start-blogging-and-how-to-start-543c&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Obviously, I totally agree with that developers must start blogging. The author adds good explanation why writing blogs about your work as a developer is useful. For me it was super hard to start with but it started to getting easier and now I love it! I would like to add that it helps to increase your language skills.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/atapas&quot;&gt;Tapas Adhikary&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;setting-up-a-cicd-pipeline-for-aws-fargate-using-github-actions---nodejs-version-including-creation-of-infrastructure-using-aws-cdk&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#setting-up-a-cicd-pipeline-for-aws-fargate-using-github-actions---nodejs-version-including-creation-of-infrastructure-using-aws-cdk&quot; aria-label=&quot;setting up a cicd pipeline for aws fargate using github actions   nodejs version including creation of infrastructure using aws cdk permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Setting up a CI/CD Pipeline for AWS Fargate using Github Actions - NodeJS version (Including creation of Infrastructure using AWS CDK)&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cloudtechsimplified.com/ci-cd-pipeline-aws-fargate-github-actions-nodejs/&quot;&gt;https://www.cloudtechsimplified.com/ci-cd-pipeline-aws-fargate-github-actions-nodejs/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice in deep article about how to setup AWS ECS with Fargate with AWS CDK. That topic can be qutie difficult so it is nice to have articles like this one to help you with.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.cloudtechsimplified.com/author/mugilan-ragupathi/&quot;&gt;Mugilan Ragupathi&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;large-object-storage-strategies-for-amazon-dynamodb&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#large-object-storage-strategies-for-amazon-dynamodb&quot; aria-label=&quot;large object storage strategies for amazon dynamodb permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Large object storage strategies for Amazon DynamoDB&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/database/large-object-storage-strategies-for-amazon-dynamodb&quot;&gt;https://aws.amazon.com/blogs/database/large-object-storage-strategies-for-amazon-dynamodb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Article about storing large object as reference in AWS DynamoDB.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Josh Hart&lt;/p&gt;
&lt;h2 id=&quot;what-is-serverless-enablement-and-why-is-it-important&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-serverless-enablement-and-why-is-it-important&quot; aria-label=&quot;what is serverless enablement and why is it important permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Is Serverless Enablement And Why Is It Important?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.readysetcloud.io/blog/allen.helton/what-is-serverless-enablement/&quot;&gt;https://www.readysetcloud.io/blog/allen.helton/what-is-serverless-enablement/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting article about serverless. The author is explaining why serverless is useful and how you can start with it.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.readysetcloud.io/&quot;&gt;Allen Helton&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-pros-and-cons-of-aws-lambda-function-urls&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-pros-and-cons-of-aws-lambda-function-urls&quot; aria-label=&quot;the pros and cons of aws lambda function urls permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Pros and Cons of AWS Lambda Function URLs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/bentorvo/the-pros-and-cons-of-aws-lambda-function-urls-524d&quot;&gt;https://dev.to/bentorvo/the-pros-and-cons-of-aws-lambda-function-urls-524d&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting pros and cons about the new-ish AWS Lambda Function Url.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/bentorvo&quot;&gt;Ben Brazier&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;introducing-the-new-aws-step-functions-workflows-collection&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introducing-the-new-aws-step-functions-workflows-collection&quot; aria-label=&quot;introducing the new aws step functions workflows collection permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introducing the new AWS Step Functions Workflows Collection&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/compute/introducing-the-new-aws-step-functions-workflows-collection/&quot;&gt;https://aws.amazon.com/blogs/compute/introducing-the-new-aws-step-functions-workflows-collection/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oh boy, how cool is that? Workflow collections to show best practices examples for AWS Step Functions. And you even can submit your workflows. Fantastic!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Benjamin Smith&lt;/p&gt;
&lt;h2 id=&quot;the-aws-cdk-or-why-i-stopped-being-a-cdk-skeptic&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-aws-cdk-or-why-i-stopped-being-a-cdk-skeptic&quot; aria-label=&quot;the aws cdk or why i stopped being a cdk skeptic permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The AWS CDK, Or Why I Stopped Being a CDK Skeptic&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/mradzikowski/the-aws-cdk-or-why-i-stopped-being-a-cdk-skeptic-4o2o&quot;&gt;https://dev.to/mradzikowski/the-aws-cdk-or-why-i-stopped-being-a-cdk-skeptic-4o2o&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice summary about AWS CDK and a cool story for how and why from switching from YAML to a programming language for defining infrastructure. But as well it has some valid AWS CDK cons&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/mradzikowski&quot;&gt;Maciej Radzikowski&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;better-dev-experience-starts-from-a-proper-document&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#better-dev-experience-starts-from-a-proper-document&quot; aria-label=&quot;better dev experience starts from a proper document permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Better dev experience starts from a proper document&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/jennieji/better-dev-experience-starts-from-a-proper-document-30o5&quot;&gt;https://dev.to/jennieji/better-dev-experience-starts-from-a-proper-document-30o5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Provide good tips on how to create proper documentation for your code projects.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/jennieji&quot;&gt;Jennie&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 25]]></title><description><![CDATA[Hi folks. What a week. Close by the Azure Meetup started happening again after like 2 years. Was great to see my old Meetup friends again…]]></description><link>https://martinmueller.dev/newsletter-25/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-25/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 26 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi folks.&lt;/p&gt;
&lt;p&gt;What a week. Close by the Azure Meetup started happening again after like 2 years. Was great to see my old Meetup friends again. You might think wait what why Azure you are an AWS guy? Yes, true but learning more about the other cloud providers is super exciting and as well my new company Monada aims for multi-cloud :).&lt;/p&gt;
&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Serverless, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;is-zero-trust-architecture-possible&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#is-zero-trust-architecture-possible&quot; aria-label=&quot;is zero trust architecture possible permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Is Zero Trust Architecture Possible??&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/zero-trust-architecture-possible-shashank-abhishek/&quot;&gt;https://www.linkedin.com/pulse/zero-trust-architecture-possible-shashank-abhishek/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An article about the zero trust architecture. It is an interesting approach. The author lists and explains the zero-trust principles. In the serverless world, some of those are implemented easily or even already part of the service. But yeah it would be nice if the developer wouldn&apos;t need to regard zero trust principles to much and they would be already part of the IaC framework. That is as well what we plan to work on in Monada :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.linkedin.com/in/shashankabhishek/&quot;&gt;Shashank Abhishek&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-overcome-imposter-syndrome&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-do-you-overcome-imposter-syndrome&quot; aria-label=&quot;how do you overcome imposter syndrome permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How Do You Overcome Imposter Syndrome?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/janicera2880/how-do-you-overcome-imposter-syndrome-55m8&quot;&gt;https://dev.to/janicera2880/how-do-you-overcome-imposter-syndrome-55m8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Such an important topic as the author speaks about the imposter syndrome. It is super common in the developer&apos;s area. The author provides super nice and useful tips for how to overcome imposter syndrome. I would like to add that if you give your best every day as a developer you don&apos;t have to blame yourself! Giving your best also includes things like relaxing, detaching, time with your family, playing a game, and time for workouts. Being a developer is about you! Embrace that as I do :)!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/janicera2880&quot;&gt;Janice Alecha&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;building-serverless-applications-that-scale-the-perfect-amount&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#building-serverless-applications-that-scale-the-perfect-amount&quot; aria-label=&quot;building serverless applications that scale the perfect amount permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Building Serverless Applications That Scale The Perfect Amount&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/building-serverless-applications-that-scale-the-perfect-amount-410p&quot;&gt;https://dev.to/aws-builders/building-serverless-applications-that-scale-the-perfect-amount-410p&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A very in-depth article about designing an architecture that scales small, medium or large. Nice idea to compare the different scales. For me, it is super exciting that with like AWS CDK it allows you with relatively low costs to change your design from small to medium or even too large. There are only a few articles like that out there so read them!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/allenheltondev&quot;&gt;Allen Helton&lt;/a&gt;. And check out his other amazing posts which I regularly cover in my newsletters ^^.&lt;/p&gt;
&lt;h2 id=&quot;why-you-should-learn-typescript-today&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-you-should-learn-typescript-today&quot; aria-label=&quot;why you should learn typescript today permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why you should learn TypeScript today&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/omerwow/why-you-should-learn-typescript-today-dmo&quot;&gt;https://dev.to/omerwow/why-you-should-learn-typescript-today-dmo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Yeah, a super good article about TypeScript and why you should learn it. I personally love TypeScript. What I like most is that it is super spread in different areas like language for IaC for AWS CDK or AWS SDK TypeScript or React TS. Furthermore, you can use the huge ecosystem around JavaScript. As well the discussions are worth a read!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/omerwow&quot;&gt;Omer Elbaz&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;whats-your-biggest-problem-while-working-with-aws&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#whats-your-biggest-problem-while-working-with-aws&quot; aria-label=&quot;whats your biggest problem while working with aws permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s your biggest problem while working with AWS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/aws/comments/vhgmr4/whats_your_biggest_problem_while_working_with_aws/&quot;&gt;https://www.reddit.com/r/aws/comments/vhgmr4/whats_your_biggest_problem_while_working_with_aws/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wow interesting discussion about the biggest problems in AWS. I find the struggle with AWS permissions interesting and provided an answer to try AWS CDK as it made juggling with permissions easier than pure with pure CFN before.&lt;/p&gt;
&lt;h2 id=&quot;control-cost-and-security-weakness-on-your-aws-sandbox-accounts&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#control-cost-and-security-weakness-on-your-aws-sandbox-accounts&quot; aria-label=&quot;control cost and security weakness on your aws sandbox accounts permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Control Cost And Security Weakness On Your AWS SandBox Accounts&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.shellkode.com/control-cost-and-security-weakness-on-your-aws-sandbox-accounts-609670b1146d&quot;&gt;https://blog.shellkode.com/control-cost-and-security-weakness-on-your-aws-sandbox-accounts-609670b1146d&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cool, the author presents a bunch of Lambda&apos;s to help clean sandbox accounts. And what is cool is the lambda is written in Python.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://medium.com/@kalaiarasu.m&quot;&gt;Kalaiarasu M&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;open-source-projects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#open-source-projects&quot; aria-label=&quot;open source projects permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Open Source Projects&lt;/h2&gt;
&lt;p&gt;In this section, I list Open Source projects I find super interesting!&lt;/p&gt;
&lt;h2 id=&quot;cdk-bill-bot&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-bill-bot&quot; aria-label=&quot;cdk bill bot permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CDK Bill Bot&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cremich/cdk-bill-bot&quot;&gt;https://github.com/cremich/cdk-bill-bot&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting AWS CDK collection of L2 and L3 constructs for AWS Cost and Usage reports. Definitely will try it out for the private project I am currently working on. The Creator Christian Bonzelet is a super experienced and active member of the CDK Community and an AWS Community Builder. So worth checking out!. Thanks to my friend Christian :)!&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 23]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-23/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-23/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><category><![CDATA[serverless]]></category><pubDate>Sun, 12 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;as-a-developer-how-to-estimate-the-time-for-a-task&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#as-a-developer-how-to-estimate-the-time-for-a-task&quot; aria-label=&quot;as a developer how to estimate the time for a task permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;As a developer, how to estimate the time for a task?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/ms_yogii/as-a-developer-how-to-estimate-the-time-for-a-task-44b&quot;&gt;https://dev.to/ms_yogii/as-a-developer-how-to-estimate-the-time-for-a-task-44b&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Article about how to estimate tasks. It explains very well why it is hard to estimate the time you will spend on a task and how you can improve that. My highlight is the advice to divide your task into smaller chunks that are less than 30 minutes in time efforts.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/ms_yogii&quot;&gt;Yogini Bende&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;aws-step-functions--are-active-executions-affected-when-your-state-machine-gets-updated&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-step-functions--are-active-executions-affected-when-your-state-machine-gets-updated&quot; aria-label=&quot;aws step functions  are active executions affected when your state machine gets updated permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Step Functions — Are Active Executions Affected When Your State Machine Gets Updated?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/pubudusj/aws-step-functions-are-active-executions-affected-when-your-state-machine-gets-updated-5dfn&quot;&gt;https://dev.to/pubudusj/aws-step-functions-are-active-executions-affected-when-your-state-machine-gets-updated-5dfn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The author highlights an interesting detail when using Lambda as part of an AWS Step Function workflow. Use Lambda Versions if you want to ensure to not update current Step Functions executions. But if you always want to update then don&apos;t use Lambda Versions. Please read the article for more details!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/pubudusj&quot;&gt;Pubudu Jayawardana&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;7-pillars-of-cloud-cost-optimization&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#7-pillars-of-cloud-cost-optimization&quot; aria-label=&quot;7 pillars of cloud cost optimization permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;7 Pillars of Cloud Cost Optimization&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/7-pillars-cloud-cost-optimization-shashank-abhishek/&quot;&gt;https://www.linkedin.com/pulse/7-pillars-cloud-cost-optimization-shashank-abhishek/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice deep dive into how to optimize AWS costs. Though point 4 &quot;Use Savings Plans&quot; is not always a good choice in my opinion. One reason against it is that as AWS moves fast with like-new Ec2 tiers it might be better to go with on-demand and change dynamically the tier. It always depends I guess ^^. Anyway, it is a super good article :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.linkedin.com/in/shashankabhishek/&quot;&gt;Shashank Abhishek&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;seamless-integration-with-remote-docker-hosts-for-development&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#seamless-integration-with-remote-docker-hosts-for-development&quot; aria-label=&quot;seamless integration with remote docker hosts for development permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Seamless Integration with Remote Docker Hosts for Development&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/geekculture/seamless-integration-with-remote-docker-hosts-for-development-7a369d94812f&quot;&gt;https://medium.com/geekculture/seamless-integration-with-remote-docker-hosts-for-development-7a369d94812f&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting article on how to run docker on a remote docker host. Though I miss a little bit of the use case or why a developer would like to do that.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://medium.com/@domenicosibilio&quot;&gt;Domenico Sibilio&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;briten-testen-4-tage-woche--von-der-frittenbude-bis-zur-software-firma&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#briten-testen-4-tage-woche--von-der-frittenbude-bis-zur-software-firma&quot; aria-label=&quot;briten testen 4 tage woche  von der frittenbude bis zur software firma permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Briten testen 4-Tage-Woche – von der Frittenbude bis zur Software-Firma&lt;/h2&gt;
&lt;p&gt;translated: Brits test 4-day week - from the fish and chips shop to software company&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://t3n.de/news/briten-testen-4-tage-woche-grossbritannien-1477699&quot;&gt;https://t3n.de/news/briten-testen-4-tage-woche-grossbritannien-1477699&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting article about some companies from the UK wanting to try the 4 days week. I am a huge fan of the 4 days week. I am convinced it increases productivity in many areas.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://t3n.de/redaktion/andreas-weck&quot;&gt;Andreas Weck&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;cost-optimizations-in-aws---part-1&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cost-optimizations-in-aws---part-1&quot; aria-label=&quot;cost optimizations in aws   part 1 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cost Optimizations in AWS - Part 1&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/alsaheem/cost-optimizations-in-aws-part-1-25mn&quot;&gt;https://dev.to/alsaheem/cost-optimizations-in-aws-part-1-25mn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice article about how to optimize your AWS costs.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/alsaheem&quot;&gt;Adebisi ayomide&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-create-a-software-test-plan&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-create-a-software-test-plan&quot; aria-label=&quot;how to create a software test plan permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to create a software test plan?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aqua-cloud.io/create-software-testing-plan/&quot;&gt;https://aqua-cloud.io/create-software-testing-plan/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super nice deep dive into testing with highlighting important requirements. As well gives you a developing test plan with concrete steps. Super useful!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the authors &lt;a href=&quot;https://aqua-cloud.io/author/denis-matusovskiy/&quot;&gt;Denis Matusovskiy&lt;/a&gt; and &lt;a href=&quot;https://aqua-cloud.io/author/robert-weingartz/&quot;&gt;Robert Weingartz&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-did-i-create-ec2-by-voice&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-did-i-create-ec2-by-voice&quot; aria-label=&quot;how did i create ec2 by voice permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How did I create EC2 by Voice?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/how-did-i-created-ec2-by-voice-2p54&quot;&gt;https://dev.to/aws-builders/how-did-i-created-ec2-by-voice-2p54&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super creative idea how can with the use of AWS Transcribe and Lambda create an Ec2 instance by voice. Very cool!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/imohd23&quot;&gt;Mohamed Latfalla&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;terraform-vs-pulumi-vs-cloudformation-best-choice-for-2022&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#terraform-vs-pulumi-vs-cloudformation-best-choice-for-2022&quot; aria-label=&quot;terraform vs pulumi vs cloudformation best choice for 2022 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Terraform vs Pulumi vs CloudFormation: Best Choice for 2022&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.multy.dev/blog/iac-comparison&quot;&gt;https://docs.multy.dev/blog/iac-comparison&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Very nice comparison between the Infrastructure as Code Tools like Terraform, Pulumi and CloudFormation.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.linkedin.com/in/jo%C3%A3o-coelho-843472a7/&quot;&gt;João Coelho&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;auth-portal-powered-by-awsazuread-and-built-with-cdks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#auth-portal-powered-by-awsazuread-and-built-with-cdks&quot; aria-label=&quot;auth portal powered by awsazuread and built with cdks permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Auth Portal powered by AWS/AzureAD and built with CDKs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://faun.pub/aws-aad-auth-portal-cdk-56c782e3a048&quot;&gt;https://faun.pub/aws-aad-auth-portal-cdk-56c782e3a048&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Uh nice using AWS CDK or CDKTF to connect AWS Cognito with Azure AD. That are exciting combinations. The author as well highlights the easy testability of AWS CDK and CDKTF. Must read!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://medium.com/@sebolabs&quot;&gt;SEB&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;aws-inspector-a-guide-to-discover-your-security-holes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-inspector-a-guide-to-discover-your-security-holes&quot; aria-label=&quot;aws inspector a guide to discover your security holes permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Inspector: A Guide to Discover Your Security Holes&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://adamtheautomator.com/aws-inspector/&quot;&gt;https://adamtheautomator.com/aws-inspector/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;How to use AWS Inspector for security. Explains first how to enable the AWS Inspector. Then the author explains how to inspect Ec2 instances with it and how to interpret the findings.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-guide-to-aws-certifications&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-guide-to-aws-certifications&quot; aria-label=&quot;a guide to aws certifications permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A Guide to AWS Certifications&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/a-guide-to-aws-certifications-40ff&quot;&gt;https://dev.to/aws-builders/a-guide-to-aws-certifications-40ff&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A deep dive into AWS certificates. Very useful for reading if you planning to do an associate or professional exam. In the end it&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/kmoberg&quot;&gt;Karl Mathias Moberg&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-improve-developer-experience-7-things-to-change&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-improve-developer-experience-7-things-to-change&quot; aria-label=&quot;how to improve developer experience 7 things to change permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to Improve Developer Experience: 7 Things to Change&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/nimbusenv/how-to-improve-developer-experience-7-things-to-change-3c5e&quot;&gt;https://dev.to/nimbusenv/how-to-improve-developer-experience-7-things-to-change-3c5e&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Very nice and deep article on how to improve the developer experience. There are a lot of good tips and is hard for me to pick my favorite one. So I suggest you read them all :)!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/nimbusenv&quot;&gt;Nimbus&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;hugo-vs-gatsbyjs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#hugo-vs-gatsbyjs&quot; aria-label=&quot;hugo vs gatsbyjs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hugo vs. Gatsby.js&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/cloudcannon/hugo-vs-gatsbyjs-35gd&quot;&gt;https://dev.to/cloudcannon/hugo-vs-gatsbyjs-35gd&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks a lot! This post is super informative. The author compares Gatsbyjs with Hugo like when you should take what. Yeah, many years ago I was choosing GatsBy because I eventually wanted to use components :). And I am about to implement components.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/avidlarge&quot;&gt;David Large&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;new-observability-features-for-aws-step-functions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#new-observability-features-for-aws-step-functions&quot; aria-label=&quot;new observability features for aws step functions permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;New Observability Features for AWS Step Functions&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.infoq.com/news/2022/06/aws-step-functions-observability&quot;&gt;https://www.infoq.com/news/2022/06/aws-step-functions-observability&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That is an interesting update about AWS Step Functions observability updates. I like the new different views Graph view, Table view and Event view.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.infoq.com/profile/Steef~Jan-Wiggers/&quot;&gt;Steef-Jan Wiggers&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;10-secure-coding-best-practices-to-follow-in-every-project&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#10-secure-coding-best-practices-to-follow-in-every-project&quot; aria-label=&quot;10 secure coding best practices to follow in every project permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;10 Secure Coding Best Practices to Follow in Every Project&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/smartscanner/10-secure-coding-best-practices-to-follow-in-every-project-1i9h&quot;&gt;https://dev.to/smartscanner/10-secure-coding-best-practices-to-follow-in-every-project-1i9h&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Useful best practices for coding. My highlight is the &quot;Process an Open-Source Spirit&quot; where the author explains how to prepare the project to be consumable as an Open-Source project.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/smartscanner&quot;&gt;SmartScanner&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 22]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-22/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-22/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 05 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cloud-computing-and-aws&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cloud-computing-and-aws&quot; aria-label=&quot;cloud computing and aws permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cloud Computing and AWS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/cloud-computing-and-aws-14g0&quot;&gt;https://dev.to/aws-builders/cloud-computing-and-aws-14g0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice post to explain what cloud computing is to an audience that is not familiar with the cloud at all. It explains very nicely the cloud computing model where you divide the cloud offerings usually in Infrastructure as Code (IAAS), Platform as a Service (PAAS) and Software as a Service (SAAS). For more context please read the amazing post :)&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/muhtoyyib&quot;&gt;Akande Olalekan Toheeb&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;exploring-aurora-serverless-v2-for-mysql&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#exploring-aurora-serverless-v2-for-mysql&quot; aria-label=&quot;exploring aurora serverless v2 for mysql permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Exploring Aurora Serverless V2 for MySQL&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://mydbops.wordpress.com/2022/05/22/exploring-aurora-serverless-v2-for-mysql/&quot;&gt;https://mydbops.wordpress.com/2022/05/22/exploring-aurora-serverless-v2-for-mysql/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice deep dive into AWS Aurora Serverless v2. Such posts are rarely as Aurora offers a wide set of cool features and explaining those is time-consuming.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://mydbops.wordpress.com/author/kabilesh/&quot;&gt;Kabilesh P R&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-handle-brutal-feedback-from-colleagues&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-do-i-handle-brutal-feedback-from-colleagues&quot; aria-label=&quot;how do i handle brutal feedback from colleagues permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How do I handle brutal feedback from colleagues?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/sloan/how-do-i-handle-brutal-feedback-from-colleague-3oda&quot;&gt;https://dev.to/sloan/how-do-i-handle-brutal-feedback-from-colleague-3oda&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Discussion about bullies at the developer working place. That is of course not acceptable and the commenter is giving very good advice on how to improve the situation if you are the victim.&lt;/p&gt;
&lt;h2 id=&quot;are-you-really-api-first-or-do-you-just-think-it&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#are-you-really-api-first-or-do-you-just-think-it&quot; aria-label=&quot;are you really api first or do you just think it permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Are You Really API-First Or Do You Just Think It?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.readysetcloud.io/blog/allen.helton/are-you-really-api-first/&quot;&gt;https://www.readysetcloud.io/blog/allen.helton/are-you-really-api-first/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super cool post about how you design your product with API first. I totally agree with the author. I personally like to use GraphQL APIs where I just define my API as a typed schema. That has nice advantages against like the more old-fashioned REST API :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.readysetcloud.io/&quot;&gt;Allen Helton&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;7-reasons-why-serverless-encourages-useful-engineering-practices&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#7-reasons-why-serverless-encourages-useful-engineering-practices&quot; aria-label=&quot;7 reasons why serverless encourages useful engineering practices permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;7 Reasons Why Serverless Encourages Useful Engineering Practices&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.serverless.com//blog/7-reasons-why-serverless-encourages-useful-engineering-practices&quot;&gt;https://www.serverless.com//blog/7-reasons-why-serverless-encourages-useful-engineering-practices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A great summary of the reasons why serverless is useful. The author proves to have much experience with serverless. The reasons are well picked and well explained. My favorite reason is number 6 &quot;It enforces Infrastructure as Code&quot;. I encourage you to read the full article!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.serverless.com/author/anna-geller&quot;&gt;Anna Geller&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;frauen-in-der-innovation-das-ist-keine-nettigkeit-sondern-wirtschaftlicher-faktor&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#frauen-in-der-innovation-das-ist-keine-nettigkeit-sondern-wirtschaftlicher-faktor&quot; aria-label=&quot;frauen in der innovation das ist keine nettigkeit sondern wirtschaftlicher faktor permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Frauen in der Innovation: „Das ist keine Nettigkeit, sondern wirtschaftlicher Faktor!“&lt;/h2&gt;
&lt;p&gt;Translation: Women in innovation: &quot;It&apos;s not a nicety, it&apos;s an economic factor!&quot;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://t3n.de/news/frauen-innovation-diversity-womenpower-1477339&quot;&gt;https://t3n.de/news/frauen-innovation-diversity-womenpower-1477339&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The super interesting article makes us aware that still way too many women are part of innovation processes. It explains as well why that is bad and how to solve it.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://t3n.de/redaktion/josefine-kramer&quot;&gt;Josefine Kramer&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-easily-deploy-a-spring-boot-application-on-aws-fargate&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-easily-deploy-a-spring-boot-application-on-aws-fargate&quot; aria-label=&quot;how to easily deploy a spring boot application on aws fargate permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to Easily Deploy a Spring Boot Application on AWS Fargate&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/how-to-easily-deploy-a-spring-boot-application-on-aws-fargate-38nh&quot;&gt;https://dev.to/aws-builders/how-to-easily-deploy-a-spring-boot-application-on-aws-fargate-38nh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A small guide for how to deploy a spring boot application on AWS with AWS Fargate. Nice guide. Probably worth enhancing the deployment with AWS CDK as Infrastructure as Code (IaC) instead of clicking in the AWS Console.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/komlanwilson&quot;&gt;Wilson K. KOMLAN&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-trending-vs-code-extensions-for-productivity&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-trending-vs-code-extensions-for-productivity&quot; aria-label=&quot;5 trending vs code extensions for productivity permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5 Trending VS Code Extensions For Productivity&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/hugomartinezzz/5-trending-vs-code-extensions-for-productivity-41di&quot;&gt;https://dev.to/hugomartinezzz/5-trending-vs-code-extensions-for-productivity-41di&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oh boy, there are a bunch of VS Code extension posts out there but this one blew my mind. There is a couple of extensions I need to try ASAP. Thank you so much.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/hugomartinezzz&quot;&gt;Hugo Martinez&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;all-you-need-to-know-about-amazon-route-53&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#all-you-need-to-know-about-amazon-route-53&quot; aria-label=&quot;all you need to know about amazon route 53 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ALL YOU NEED TO KNOW ABOUT AMAZON ROUTE 53&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/joshbek/all-you-need-to-know-about-amazon-route-53-8a6&quot;&gt;https://dev.to/joshbek/all-you-need-to-know-about-amazon-route-53-8a6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice roundup about AWS Route 53&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/joshbek&quot;&gt;Joshua O. Berkoh&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;writing-and-testing-a-stdin-script-with-typescript&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#writing-and-testing-a-stdin-script-with-typescript&quot; aria-label=&quot;writing and testing a stdin script with typescript permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Writing and Testing a stdin script with TypeScript&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/viglioni/writing-and-testing-a-stdin-script-with-typescript-57mb&quot;&gt;https://dev.to/viglioni/writing-and-testing-a-stdin-script-with-typescript-57mb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;About how to test a TypeScript Script that has stdin input. I would have needed the solution a while back as I couldn&apos;t figure out how to do that. So this article seems pretty useful.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/viglioni&quot;&gt;Laura Viglioni&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-challenges-of-building-multi-cloud&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-challenges-of-building-multi-cloud&quot; aria-label=&quot;the challenges of building multi cloud permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Challenges of Building Multi Cloud&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.multy.dev/blog/challenges-of-building-multi-cloud&quot;&gt;https://docs.multy.dev/blog/challenges-of-building-multi-cloud&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;High-level overview about building in multi-cloud and how &lt;a href=&quot;https://multy.dev&quot;&gt;multy&lt;/a&gt; helps to make it easier.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.linkedin.com/in/jo%C3%A3o-coelho-843472a7/&quot;&gt;João Coelho&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;enable-autocomplete-for-boto3-in-vscode&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#enable-autocomplete-for-boto3-in-vscode&quot; aria-label=&quot;enable autocomplete for boto3 in vscode permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enable Autocomplete for boto3 in VSCode&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/enable-autocomplete-for-boto3-in-vscode-3jb4&quot;&gt;https://dev.to/aws-builders/enable-autocomplete-for-boto3-in-vscode-3jb4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;How you can configure autocomplete for Python boto3 in VSCode. Super important when you develop your AWS SDK script or lambda with python!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/mauricebrg&quot;&gt;Maurice Borgmeier&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;is-serverless-just-a-stopover-for-event-driven-architecture&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#is-serverless-just-a-stopover-for-event-driven-architecture&quot; aria-label=&quot;is serverless just a stopover for event driven architecture permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Is Serverless Just a Stopover for Event-Driven Architecture?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://thenewstack.io/is-serverless-just-a-stopover-for-event-driven-architecture/&quot;&gt;https://thenewstack.io/is-serverless-just-a-stopover-for-event-driven-architecture/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This article is super mind-blowing. I think the author is correct and serverless is kind of super related to event-driven architecture. Must read!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://thenewstack.io/author/markhinkle/&quot;&gt;MARK HINKLE&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;tips-for-junior-developers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#tips-for-junior-developers&quot; aria-label=&quot;tips for junior developers permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tips for Junior Developers&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/sahan/tips-for-junior-developers-5ggj&quot;&gt;https://dev.to/sahan/tips-for-junior-developers-5ggj&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super empowering post for junior developers on how to grow as such :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/sahan&quot;&gt;Sahan&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-beginners-guide-to-create-aws-cdk-construct-library-with-projen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#a-beginners-guide-to-create-aws-cdk-construct-library-with-projen&quot; aria-label=&quot;a beginners guide to create aws cdk construct library with projen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A Beginner&apos;s Guide to Create AWS CDK Construct Library with projen&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/a-beginner-s-guide-to-create-aws-cdk-construct-library-with-projen-5eh4&quot;&gt;https://dev.to/aws-builders/a-beginner-s-guide-to-create-aws-cdk-construct-library-with-projen-5eh4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super nice detailed post about a Projen setup for the CDK Construct library Projen type. Nice :)!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/hayao_k&quot;&gt;hayao-k&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;aws-step-functions-launches-an-interactive-workshop-for-building-and-deploying-application-workflows&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-step-functions-launches-an-interactive-workshop-for-building-and-deploying-application-workflows&quot; aria-label=&quot;aws step functions launches an interactive workshop for building and deploying application workflows permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Step Functions launches an interactive workshop for building and deploying application workflows&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2022/06/aws-step-functions-interactive-workshop-building-deploying-application-workflows/&quot;&gt;https://aws.amazon.com/about-aws/whats-new/2022/06/aws-step-functions-interactive-workshop-building-deploying-application-workflows/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting AWS StepFunction Workshop. It uses AWS CDK for Infrastructure as Code (IaC).&lt;/p&gt;
&lt;h2 id=&quot;aws-cognito--web-application-integration-basics&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-cognito--web-application-integration-basics&quot; aria-label=&quot;aws cognito  web application integration basics permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Cognito — Web Application Integration Basics&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://jawadhasan80.medium.com/aws-cognito-web-application-integration-basics-dc18b42f47c4&quot;&gt;https://jawadhasan80.medium.com/aws-cognito-web-application-integration-basics-dc18b42f47c4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A cool bottom-up post about Cognito and how to use it combined with Amplify.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://jawadhasan80.medium.com/&quot;&gt;Jawadhasan&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-are-your-debugging-tips&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-are-your-debugging-tips&quot; aria-label=&quot;what are your debugging tips permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What are your debugging tips?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/ben/what-are-your-debugging-tips-3lgm&quot;&gt;https://dev.to/ben/what-are-your-debugging-tips-3lgm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A super high-level and super useful discussion on how to debug efficiently. Must read!&lt;/p&gt;
&lt;p&gt;Thanks to the author asking the question and all the commenter&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 21]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-21/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-21/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 29 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;aws-sns-vs-sqs---what-are-the-main-differences&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-sns-vs-sqs---what-are-the-main-differences&quot; aria-label=&quot;aws sns vs sqs   what are the main differences permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS SNS vs. SQS - What Are the Main Differences?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.serverlessq.com/aws-sns-vs-sqs-what-are-the-main-differences&quot;&gt;https://blog.serverlessq.com/aws-sns-vs-sqs-what-are-the-main-differences&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A super good explanation about SNS and SQS and what are the differences. I never paid too much notice of what differentiates those services so I am very glad that the author is doing that. As well the author explains when to use SNS, SQS and even Kinesis. Must read!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://hashnode.com/@SandroVolpicella&quot;&gt;Sandro Volpicella&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;new-aws-config-rules---lambdaless-and-rusty&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#new-aws-config-rules---lambdaless-and-rusty&quot; aria-label=&quot;new aws config rules   lambdaless and rusty permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;New AWS Config Rules - LambdaLess and rusty&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/new-aws-config-rules-lambdaless-and-rusty-hbe&quot;&gt;https://dev.to/aws-builders/new-aws-config-rules-lambdaless-and-rusty-hbe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Exciting article from my German fellow Gernot Glawe. He describes how to add more easily add custom AWS Config rules with Lambda. I didn&apos;t work much with AWS Config but this article made me excited to do so :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/megaproaktiv&quot;&gt;Gernot Glawe&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;devops-an-introduction&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#devops-an-introduction&quot; aria-label=&quot;devops an introduction permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;DevOps: An Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/abhishe89636035/devops-an-introduction-5cdp&quot;&gt;https://dev.to/abhishe89636035/devops-an-introduction-5cdp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Gives a quick introduction to DevOps and then lists different areas in the DevOps space and tools you can use for those.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/abhishe89636035&quot;&gt;Abhishek Shrivastava&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-eventbridge-as-a-cross-account-event-backbone&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-use-eventbridge-as-a-cross-account-event-backbone&quot; aria-label=&quot;how to use eventbridge as a cross account event backbone permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to use EventBridge as a Cross-Account Event Backbone&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/eoinsha/how-to-use-eventbridge-as-a-cross-account-event-backbone-5fik&quot;&gt;https://dev.to/eoinsha/how-to-use-eventbridge-as-a-cross-account-event-backbone-5fik&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Long post but super interesting how you can leverage AWS EventBridge for cross-account events. The author even gives a little example consisting of 3 AWS Accounts that are interchanging events via EventBridge.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/eoinsha&quot;&gt;Eoin Shanaghy&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;overview-of-aws-developer-tools---part-2&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#overview-of-aws-developer-tools---part-2&quot; aria-label=&quot;overview of aws developer tools   part 2 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Overview of AWS Developer Tools - Part 2&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/makendrang/overview-of-aws-developer-tools-part-2-kei&quot;&gt;https://dev.to/makendrang/overview-of-aws-developer-tools-part-2-kei&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And here is the second part of the AWS Developer Tools series. My personal highlight is the AWS Fault Injection Simulator which you can use for chaos engineering testing. Super cool!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/makendrang&quot;&gt;MakendranG&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;zero-maintenance-aws-canary-tokens-that-scale&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zero-maintenance-aws-canary-tokens-that-scale&quot; aria-label=&quot;zero maintenance aws canary tokens that scale permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zero Maintenance AWS Canary Tokens That Scale&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@williambengtson/zero-maintenance-aws-canary-tokens-that-scale-b470c6f60da&quot;&gt;https://medium.com/@williambengtson/zero-maintenance-aws-canary-tokens-that-scale-b470c6f60da&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An exciting article about Honey tokens like how you can do them in AWS and how they help you to monitor malicious behavior. Very cool!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://medium.com/@williambengtson&quot;&gt;William Bengtson&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-tale-of-migration-to-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#the-tale-of-migration-to-serverless&quot; aria-label=&quot;the tale of migration to serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The tale of migration to Serverless&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/ymwjbxxq/the-tale-of-migration-to-serverless-24b3&quot;&gt;https://dev.to/ymwjbxxq/the-tale-of-migration-to-serverless-24b3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice and creative sports analogy/story/tale for serverless covering how we got to serverless and why to use it.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/ymwjbxxq&quot;&gt;Daniele Frasca&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;aws-open-source-news-and-updates-114&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-open-source-news-and-updates-114&quot; aria-label=&quot;aws open source news and updates 114 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS open-source news and updates, #114&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws/aws-open-source-news-and-updates-114-51ng&quot;&gt;https://dev.to/aws/aws-open-source-news-and-updates-114-51ng&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice summary of new AWS open-source-related projects. My highlight is &lt;a href=&quot;https://github.com/raajheshkannaa/auto-close-aws-accounts&quot;&gt;auto-close-aws-accounts which&lt;/a&gt; as it makes deleting AWS accounts super easy!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/094459&quot;&gt;Ricardo Sueiras&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;please-dont-give-up-on-programming&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#please-dont-give-up-on-programming&quot; aria-label=&quot;please dont give up on programming permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Please, don&apos;t give up on programming&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/alesbe/please-dont-give-up-on-programming-4pop&quot;&gt;https://dev.to/alesbe/please-dont-give-up-on-programming-4pop&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Engages you to keep programming even if it seems to be tough. Totally agree with that. Try to keep your goal in front of your eyes and perhaps do a little bit every day. For more tips read the article :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/alesbe&quot;&gt;alesbe&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;aws-s3-replication-same-region-replicationssr&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-s3-replication-same-region-replicationssr&quot; aria-label=&quot;aws s3 replication same region replicationssr permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS S3 Replication: Same Region Replication(SSR)&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://programmersblock.hashnode.dev/aws-s3-same-region-replication&quot;&gt;https://programmersblock.hashnode.dev/aws-s3-same-region-replication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice roundup article about S3 Same Region Replication.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://hashnode.com/@himanshugupta0007&quot;&gt;Himanshu Gupta&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;do-we-really-need-aws&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#do-we-really-need-aws&quot; aria-label=&quot;do we really need aws permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Do we really need AWS?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/jordan_t/do-we-really-need-aws-3hao&quot;&gt;https://dev.to/jordan_t/do-we-really-need-aws-3hao&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I will not spoiler but the answer will not surprise you :P. But yeah it is a nice summary about AWS.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/jordan_t&quot;&gt;Jordan Tingling&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;5-vscode-extension-that-makes-maintenance-easyseedling&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-vscode-extension-that-makes-maintenance-easyseedling&quot; aria-label=&quot;5 vscode extension that makes maintenance easyseedling permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5 VSCode Extension that makes Maintenance Easy:seedling:&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/alexomeyer/5-vscode-extension-that-make-maintenance-easy-4eb1&quot;&gt;https://dev.to/alexomeyer/5-vscode-extension-that-make-maintenance-easy-4eb1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Has some cool VS Code extension tips. Check it out!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/alexomeyer&quot;&gt;Alex Omeyer&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;kafka-on-the-serverless-shore-building-event-driven-applications-with-kafka&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#kafka-on-the-serverless-shore-building-event-driven-applications-with-kafka&quot; aria-label=&quot;kafka on the serverless shore building event driven applications with kafka permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Kafka on the Serverless Shore: Building event-driven applications with Kafka&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/kafka-on-the-serverless-shore-building-event-driven-applications-with-kafka-23df&quot;&gt;https://dev.to/aws-builders/kafka-on-the-serverless-shore-building-event-driven-applications-with-kafka-23df&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting article about Serverless Kafka combined with AWS CDK.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/ibrahimcesar&quot;&gt;Ibrahim Cesar&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;softwareentwicklung-dem-it-fachkräftemangel-mit-interdisziplinären-teams-begegnen&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#softwareentwicklung-dem-it-fachkr%C3%A4ftemangel-mit-interdisziplin%C3%A4ren-teams-begegnen&quot; aria-label=&quot;softwareentwicklung dem it fachkräftemangel mit interdisziplinären teams begegnen permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Softwareentwicklung: Dem IT-Fachkräftemangel mit interdisziplinären Teams begegnen&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://t3n.de/news/softwareentwicklung-teams-fachkraeftemangel-1475059&quot;&gt;https://t3n.de/news/softwareentwicklung-teams-fachkraeftemangel-1475059&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting article in German on why interdisciplinary teams are so important and successful.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://t3n.de/redaktion/elisabeth-urban&quot;&gt;Elisabeth Urban&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[What is Serverless?]]></title><description><![CDATA[To clear up a possible misunderstanding right away! Serverless does not mean that there are no more servers! On the contrary! Cloud…]]></description><link>https://martinmueller.dev/serverless-eng/</link><guid isPermaLink="false">https://martinmueller.dev/serverless-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><category><![CDATA[serverless]]></category><pubDate>Tue, 24 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To clear up a possible misunderstanding right away! Serverless does not mean that there are no more servers! On the contrary! Cloud providers such as AWS, which offer serverless, have many servers worldwide. In the image below you can see the currently available AWS regions. This means in all these places in the world AWS has at least two data centers.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAECAwQF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAB7FOqLDGBf//EABoQAAICAwAAAAAAAAAAAAAAAAACARIhMTL/2gAIAQEAAQUCm15ZhOW0Rg//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPwFn/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQIBAT8BGf/EABsQAAEEAwAAAAAAAAAAAAAAAAABEBExMkFh/9oACAEBAAY/AuKQmmqTFv/EABsQAAMAAgMAAAAAAAAAAAAAAAABESExYXGR/9oACAEBAAE/IdRPuLHaC4uWLeQVpt36hI285P/aAAwDAQACAAMAAAAQ5/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAh/9oACAEDAQE/EBGF/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAERIUH/2gAIAQIBAT8Q0Hbk/8QAHRABAAMAAgMBAAAAAAAAAAAAAQARITFBUXGBsf/aAAgBAQABPxClZSl6eofqRnOeZrNTVW5XlsGhD9jacpS8lfYdYFsO1P/Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/500244daa55ed8302de3b414d8ad02f1/f1512/regions.webp 200w,
/static/500244daa55ed8302de3b414d8ad02f1/f59aa/regions.webp 400w,
/static/500244daa55ed8302de3b414d8ad02f1/47a22/regions.webp 800w,
/static/500244daa55ed8302de3b414d8ad02f1/5bb53/regions.webp 1200w,
/static/500244daa55ed8302de3b414d8ad02f1/485a2/regions.webp 1600w,
/static/500244daa55ed8302de3b414d8ad02f1/8ffb6/regions.webp 2732w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/500244daa55ed8302de3b414d8ad02f1/16d62/regions.jpg 200w,
/static/500244daa55ed8302de3b414d8ad02f1/27ec1/regions.jpg 400w,
/static/500244daa55ed8302de3b414d8ad02f1/5fd6b/regions.jpg 800w,
/static/500244daa55ed8302de3b414d8ad02f1/5a523/regions.jpg 1200w,
/static/500244daa55ed8302de3b414d8ad02f1/b46c2/regions.jpg 1600w,
/static/500244daa55ed8302de3b414d8ad02f1/97b92/regions.jpg 2732w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/jpeg&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/500244daa55ed8302de3b414d8ad02f1/5fd6b/regions.jpg&quot;
            alt=&quot;regions&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Such a data center itself is a huge building with a lot of server technology.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 750px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 55.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAADCUlEQVR42iWS7U+TVwBHn4+bGJKW8vTpe0HoW1qYoA4hG8MimzKLAt1anVSx1CAdLSIU6hTpRrQFxkxYCFsDYwvoECWKIvjOGNFE4xeXLEuWbP/J2bX78Pt4zz0390j//v2GlaUZLg/Fmbjcz3fpBJETLXSfDBBvC5KIhDjd3Ehwfy0Doc8YjIUJeGvw5uXRVVfNwsIk6Utxfp0dZzQVRVq+luVC7yku9EcYvzJILBwk+rmPaKuPgcgJhno6mfgmybnuDlIX40yOXyI7OcK+IgOBIhNXR84xlooxM5kiM/QlkremgoPevfSePsb5cIDBdrFIG4lohKiwO+z7GLNJT7nLRvjopxysr+Jsu5/hUDNtFW7OHj3E1MQgS3Pf0i1kpIv9nRxvaSTkayD4SR3+xnr2f1SDSwAsZgNGvYzVZKd6dzX+plq8tbvIjAzQe+YLOpob6Au18Ncfz0nGT7HL40QaTsao9DjY6XZS7nZg22HJgd5aKYoWRVuIxVBChWc3ZrOMTqch0NrIB1Vl1O4t5/Ziln/+3KKq3C44ZUgN+6pR5edhMeqxCEjOyqgTIBmVSoW6IB+jrgiP6z00hfmo1PnsqdyD02bFVWpldirDkztzOIpNlFitSJnhPvy+etzOHWgLCzAZdFgtRgx6BbVaTYFahSLrcDocaPVqFL2GlqYDAuriZPAQL57cZGN1nkp3CbI4L22sL7GxfoN7t36ivyfCzjIXBp2M6a2lIiPLsrDVYbfZsRZpcTqtJHrCTIgi7i5O82pzJQcNNtVRLF4nvX7+iK1HK7zcXOPNy8esLv9C7Ew7pSVWtm/fhqzRoFcUHPZSMTPFxQqh4AG+zwxwPTvKrbmr3BUtxsN+8Q82pFe/r/N0dYln9//fi6d3eL11n5sLP3IseERYFrLt3XewiQt02oIcdOSrLuan0zxcniE7dp50shNfw/t4hL20+WBZAG/k9vjeNR6uzLN2+2eerV3ntweLzE6P5lpUFA0fima/TnYJszHmf0izKAynriRI9XVwvNUr0nLyH71Mx3Kx2whEAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/f9a1d189e56a78ddc4d51e87efee5d81/f1512/servercenter.webp 200w,
/static/f9a1d189e56a78ddc4d51e87efee5d81/f59aa/servercenter.webp 400w,
/static/f9a1d189e56a78ddc4d51e87efee5d81/2ad20/servercenter.webp 750w&quot;
              sizes=&quot;(max-width: 750px) 100vw, 750px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/f9a1d189e56a78ddc4d51e87efee5d81/f8f3a/servercenter.png 200w,
/static/f9a1d189e56a78ddc4d51e87efee5d81/6a8a8/servercenter.png 400w,
/static/f9a1d189e56a78ddc4d51e87efee5d81/44507/servercenter.png 750w&quot;
            sizes=&quot;(max-width: 750px) 100vw, 750px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/f9a1d189e56a78ddc4d51e87efee5d81/44507/servercenter.png&quot;
            alt=&quot;servercenter&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Now and in the following, I would like to explain for each section using S3 and Lambda as an example.&lt;/p&gt;
&lt;p&gt;S3 is an AWS service that can be used as object storage.&lt;/p&gt;
&lt;p&gt;Lambda is also an AWS service that can be used for compute. This is usually used to implement the business logic of the cloud application.&lt;/p&gt;
&lt;h2 id=&quot;why-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-serverless&quot; aria-label=&quot;why serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why Serverless?&lt;/h2&gt;
&lt;p&gt;**Less complexity. As a cloud developer, I no longer have to worry about managing (hardware and software) the servers. So I can focus more directly on the business logic of my application in the cloud.
With S3, as a developer, I can easily store data using the S3 API. With Lambda, I can define the business logic directly as code, e.g. TypeScript or Python, and pass it to the Lambda API. The AWS Lambda service then takes care of the rest. I don&apos;t need to worry about any OS related stuff like with Ec2 for example.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better scalability&lt;/strong&gt;. Serverless offerings scale automatically by default. So any number of objects can be stored in S3 without the developer having to adjust the volume as with &lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonEBS.html&quot;&gt;AWS EBS&lt;/a&gt;, for example. Lambda can also scale almost arbitrarily. If the demand to execute the business logic increases, even multiple Lambda instances are started to ensure timely processing. If no execution of the respective business logic is needed, no Lambda instances are started.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost optimization&lt;/strong&gt;. Already by the previous point over the better scalability it can be assumed that thereby cost savings can result to possible alternatives. But this is not always the case and it is difficult to compare costs of serverless with alternatives. Therefore, I will not discuss cost optimization in this article. I will only say that I personally like to use the serverless offerings from AWS, as this leads to very low costs, especially in the initial phase.&lt;/p&gt;
&lt;h2 id=&quot;but-how-does-serverless-work&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#but-how-does-serverless-work&quot; aria-label=&quot;but how does serverless work permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But how does serverless work?&lt;/h2&gt;
&lt;p&gt;If you&apos;re convinced by the reasons why Serverless works, you might be wondering how it works?&lt;/p&gt;
&lt;p&gt;Like all AWS service offerings, communication with Serverless services like S3 and Lambda works via HTTP/S API. This means that HTTP requests can be made for creation and modification. The S3 API can be found in the documentation &lt;a href=&quot;https://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html&quot;&gt;here&lt;/a&gt; and for the Lambda API &lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/API_Reference.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now surely the developer doesn&apos;t have to bother with HTTP requests and can alternatively use quasi API wrappers like the AWS CLI or AWS SDK in different programming languages like TypeScript or Python. An even better and by me preferred alternative is AWS CDK which m&lt;/p&gt;
&lt;h2 id=&quot;what-do-i-like-about-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-do-i-like-about-serverless&quot; aria-label=&quot;what do i like about serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What do I like about Serverless?&lt;/h2&gt;
&lt;p&gt;The great thing about Serverless for me is that it&apos;s a great abstraction and makes developing in the cloud super easy. So I am specifically able to implement my customers&apos; wishes and requirements for their cloud project.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;In this article, I explained to you what Serverless is and why I think it&apos;s so great. However, I firmly believe that serverless is not the end of cloud abstractions. I recently joined a company called &lt;a href=&quot;https://www.linkedin.com/company/monadahq/about/&quot;&gt;Monada&lt;/a&gt; that is aiming to do just that. We want to create an even better abstraction than Serverless to make working with the cloud even more awesome. If you have any feedback on this article please let me know :)! Let&apos;s build!&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 20]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-20/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-20/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 22 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;improve-dx-by-publishing-an-api-sdk---a-cdk-serverless-example&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#improve-dx-by-publishing-an-api-sdk---a-cdk-serverless-example&quot; aria-label=&quot;improve dx by publishing an api sdk   a cdk serverless example permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Improve DX by publishing an API SDK - a CDK Serverless example&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rehanvdm.com/blog/improve-dx-publishing-an-api-sdk-cdk-serverless&quot;&gt;https://www.rehanvdm.com/blog/improve-dx-publishing-an-api-sdk-cdk-serverless&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Uii an API SDK is a nice idea. For me, that looks similar to OpenAPI / Swagger SDKs. It seems to be a smart combination of OpenAPI SDK and TypeScript. Plus with a sophisticated CI/CD flow like posting to slack you can make developers earlier aware of SDK changes. Interesting idea please read the full article!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.rehanvdm.com/&quot;&gt;Rehan van der Merwe&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-started-with-testing-dynamodb-code-in-python&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#getting-started-with-testing-dynamodb-code-in-python&quot; aria-label=&quot;getting started with testing dynamodb code in python permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Getting started with testing DynamoDB code in Python&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/getting-started-with-testing-dynamodb-code-in-python-dif&quot;&gt;https://dev.to/aws-builders/getting-started-with-testing-dynamodb-code-in-python-dif&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting post about testing DynamoDB code in Python. You can use the python package moto to mock the AWS Service. That is super cool and how I used to when I am working with jest in TypeScript. Super cool that Python has something similar :). So I recommend reading the full article if you are interested in programming AWS CDK or AWS SDK with Python.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/mauricebrg&quot;&gt;Maurice Borgmeier&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-work-around-cloudformation-circular-dependencies&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-work-around-cloudformation-circular-dependencies&quot; aria-label=&quot;how to work around cloudformation circular dependencies permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to work around CloudFormation circular dependencies&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://theburningmonk.com/2022/05/how-to-work-around-cloudformation-circular-dependencies/&quot;&gt;https://theburningmonk.com/2022/05/how-to-work-around-cloudformation-circular-dependencies/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting. CloudFormation circular dependencies are an often encountered problem when working with CloudFormation or with AWS CDK (which is basically CloudFormation). So this article is super useful for how to resolve those.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the Serverless Hero &lt;a href=&quot;https://theburningmonk.com/&quot;&gt;Yan Cui&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;solutions-architect-tips-how-to-build-your-first-architecture-diagram&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#solutions-architect-tips-how-to-build-your-first-architecture-diagram&quot; aria-label=&quot;solutions architect tips how to build your first architecture diagram permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Solutions Architect Tips: How to Build Your First Architecture Diagram&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.readysetcloud.io/blog/allen.helton/how-to-build-your-first-architecture-diagram/&quot;&gt;https://www.readysetcloud.io/blog/allen.helton/how-to-build-your-first-architecture-diagram/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting article about architecture diagrams. It introduced and recommends the use of c4model which is super interesting &lt;a href=&quot;https://c4model.com/#SystemContextDiagram&quot;&gt;https://c4model.com/#SystemContextDiagram&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.readysetcloud.io/&quot;&gt;Allen Helton&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction-to-aws-developer-tools---part-1&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#introduction-to-aws-developer-tools---part-1&quot; aria-label=&quot;introduction to aws developer tools   part 1 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Introduction to AWS Developer Tools - Part 1&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/kcdchennai/introduction-to-aws-developer-tools-part-1-590b&quot;&gt;https://dev.to/kcdchennai/introduction-to-aws-developer-tools-part-1-590b&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super cool overview and summary of existing AWS Developer Tools. My highlight is &lt;a href=&quot;https://aws.amazon.com/cloud9/&quot;&gt;cloud9&lt;/a&gt;. Look at the article if you want to know why.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/makendrang&quot;&gt;MakendranG&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;source-control-your-aws-cloudformation-templates-with-github&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#source-control-your-aws-cloudformation-templates-with-github&quot; aria-label=&quot;source control your aws cloudformation templates with github permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Source Control your AWS CloudFormation templates with GitHub&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/techielass/source-control-your-aws-cloudformation-templates-with-github-8im&quot;&gt;https://dev.to/techielass/source-control-your-aws-cloudformation-templates-with-github-8im&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a cool article about how to manage your CloudFormation template via GitHub Actions like linting and more. But yeah I would recommend not using CloudFormation directly and using AWS CDK :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/techielass&quot;&gt;Sarah Lean&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-exactly-is-frontmatter&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-exactly-is-frontmatter&quot; aria-label=&quot;what exactly is frontmatter permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What exactly is Frontmatter?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/dailydevtips1/what-exactly-is-frontmatter-123g&quot;&gt;https://dev.to/dailydevtips1/what-exactly-is-frontmatter-123g&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Explains what Frontmatter is. I didn&apos;t realize that I already use it for my blog post Gatsby side martinmueller.dev :D.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/dailydevtips1&quot;&gt;Chris Bongers&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-cicd-how-was-a-life-without-cicd--how-is-it-now&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#why-cicd-how-was-a-life-without-cicd--how-is-it-now&quot; aria-label=&quot;why cicd how was a life without cicd  how is it now permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why CI/CD? How was a life without CI/CD &amp;#x26; how is it now?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/wardaliaqat01/why-cicd-how-was-a-life-without-cicd-how-is-it-now-46bl&quot;&gt;https://dev.to/wardaliaqat01/why-cicd-how-was-a-life-without-cicd-how-is-it-now-46bl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A good and comprehensive article on why CI/CD is so awesome. Use this article to sell CI/CD to whomever ^^.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/wardaliaqat01&quot;&gt;Warda Liaqat&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;security-iceberg-aws-security-hub-the-right-way&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#security-iceberg-aws-security-hub-the-right-way&quot; aria-label=&quot;security iceberg aws security hub the right way permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Security Iceberg: AWS Security Hub the right way&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://cloudonaut.io/security-iceberg-aws-security-hub-the-right-way/&quot;&gt;https://cloudonaut.io/security-iceberg-aws-security-hub-the-right-way/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice introduction and roundup about AWS Security Hub. Gives as well some tips when working with it.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://twitter.com/andreaswittig&quot;&gt;Andreas Wittig&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;docs-for-everyone&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#docs-for-everyone&quot; aria-label=&quot;docs for everyone permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Docs for Everyone&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/meganesulli/docs-for-everyone-28pm&quot;&gt;https://dev.to/meganesulli/docs-for-everyone-28pm&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice article about how to write meaningful documentation. Highlights the importance of diagrams.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/meganesulli&quot;&gt;Megan Sullivan&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-makes-a-good-devops-manager&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-makes-a-good-devops-manager&quot; aria-label=&quot;what makes a good devops manager permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What makes a good DevOps manager?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/devops/comments/ustzqj/what_makes_a_good_devops_manager&quot;&gt;https://www.reddit.com/r/devops/comments/ustzqj/what_makes_a_good_devops_manager&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A great discussion about what makes a great DevOps Manager.&lt;/p&gt;
&lt;h2 id=&quot;what-are-aws-cdk-constructs-stacks-and-how-to-use-them&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-are-aws-cdk-constructs-stacks-and-how-to-use-them&quot; aria-label=&quot;what are aws cdk constructs stacks and how to use them permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Are AWS CDK Constructs, Stacks and How To Use Them&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://interweave.cloud/2022/05/17/what-are-aws-cdk-constructs-stacks-and-how-to-use-them/&quot;&gt;https://interweave.cloud/2022/05/17/what-are-aws-cdk-constructs-stacks-and-how-to-use-them/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A good explanation about AWS CDK level 1, 2 and 3 constructs.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://interweave.cloud/author/faizanraza-interweave/&quot;&gt;Faizan Raza&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;is-this-thing-on-giving-an-effective-talk-in-person&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#is-this-thing-on-giving-an-effective-talk-in-person&quot; aria-label=&quot;is this thing on giving an effective talk in person permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Is This Thing On? Giving an Effective Talk In Person&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/is-this-thing-on-giving-an-effective-talk-in-person-887&quot;&gt;https://dev.to/aws-builders/is-this-thing-on-giving-an-effective-talk-in-person-887&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting talk about public speaking. The author gives tips on how to improve public speaking.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/kristiperreault&quot;&gt;Kristi Perreault&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;eslint-and-prettier&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#eslint-and-prettier&quot; aria-label=&quot;eslint and prettier permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ESLint and Prettier&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/suchintan/eslint-and-prettier-51e0&quot;&gt;https://dev.to/suchintan/eslint-and-prettier-51e0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice post about why eslint and prettier are important.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/suchintan&quot;&gt;SUCHINTAN DAS&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;open-source-projects&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#open-source-projects&quot; aria-label=&quot;open source projects permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Open Source Projects&lt;/h2&gt;
&lt;p&gt;In this section, I list Open Source projects I find super interesting!&lt;/p&gt;
&lt;h2 id=&quot;json-schema-to-typescript&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#json-schema-to-typescript&quot; aria-label=&quot;json schema to typescript permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;json-schema-to-typescript&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/json-schema-to-typescript&quot;&gt;https://www.npmjs.com/package/json-schema-to-typescript&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Import TypeScript type from JSON. That was always a disadvantage when a client wanted me to use a JSON file as input for CDK properties. It is super cool that it seems you easily can infer the type.&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 19]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-19/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-19/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><category><![CDATA[aws]]></category><category><![CDATA[devops]]></category><pubDate>Sun, 15 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;simple-leave-management-system-with-aws-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#simple-leave-management-system-with-aws-serverless&quot; aria-label=&quot;simple leave management system with aws serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Simple Leave Management System with AWS Serverless&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/simple-leave-management-system-with-aws-serverless-3dnp&quot;&gt;https://dev.to/aws-builders/simple-leave-management-system-with-aws-serverless-3dnp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Constructing a workflow like the explained simple leave management with AWS Step Functions is so cool. Furthermore, the recently released &lt;a href=&quot;https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html&quot;&gt;AWS SDK service integrations&lt;/a&gt; makes it fun to define such.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/pubudusj&quot;&gt;Pubudu Jayawardana&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;aws-open-source-news-and-updates-112&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-open-source-news-and-updates-112&quot; aria-label=&quot;aws open source news and updates 112 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS open-source news and updates, #112&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws/aws-open-source-news-and-updates-112-5bjp&quot;&gt;https://dev.to/aws/aws-open-source-news-and-updates-112-5bjp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And again a nice weekly summary. My highlight is the &lt;a href=&quot;https://github.com/awslabs/aws-dataall&quot;&gt;aws-dataall&lt;/a&gt; as it looks super interesting for sharing ML data company internally and event externally mhh. Lots to think about here. But as always there is tons of other gold so you have to explore that!&lt;/p&gt;
&lt;p&gt;Thanks again to the author &lt;a href=&quot;https://dev.to/094459&quot;&gt;Ricardo Sueiras&lt;/a&gt;. I hope you enjoyed the Summit in Berlin ^^. Next time count me in!&lt;/p&gt;
&lt;h2 id=&quot;simple-serverless-scheduler&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#simple-serverless-scheduler&quot; aria-label=&quot;simple serverless scheduler permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Simple Serverless Scheduler&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/simple-serverless-scheduler-25c7&quot;&gt;https://dev.to/aws-builders/simple-serverless-scheduler-25c7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A cool article for how to solve an interesting business case like when a user cancels their subscription but still needs to have access until the end of the paying period time. The author compared different possible solutions for how to implement such a serverless scheduler.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/pzubkiewicz&quot;&gt;Pawel Zubkiewicz&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;debugging-aws-step-functions-executions-with-the-new-console-experience&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#debugging-aws-step-functions-executions-with-the-new-console-experience&quot; aria-label=&quot;debugging aws step functions executions with the new console experience permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Debugging AWS Step Functions executions with the new console experience&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/compute/debugging-aws-step-functions-executions-with-the-new-console-experience/&quot;&gt;https://aws.amazon.com/blogs/compute/debugging-aws-step-functions-executions-with-the-new-console-experience/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The capability that you can debug Step Functions became super important to me and this article is great to learn more about it. The new debug AWS Console experience for Step Functions looks super exciting. Can&apos;t wait to try it myself!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author Benjamin Smith.&lt;/p&gt;
&lt;h2 id=&quot;serverless-threat-modelling-part-2-rocket&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#serverless-threat-modelling-part-2-rocket&quot; aria-label=&quot;serverless threat modelling part 2 rocket permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Serverless Threat Modelling Part 2 :rocket:&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://leejamesgilmore.medium.com/serverless-threat-modelling-part-2-87e69d447fa8&quot;&gt;https://leejamesgilmore.medium.com/serverless-threat-modelling-part-2-87e69d447fa8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice top-down post on serverless threat modeling.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://leejamesgilmore.medium.com/&quot;&gt;Lee James Gilmore&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;architectural-patterns&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#architectural-patterns&quot; aria-label=&quot;architectural patterns permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Architectural Patterns&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/dev0928/architectural-patterns-5f31&quot;&gt;https://dev.to/dev0928/architectural-patterns-5f31&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice roundup of the architectural patterns Monolith Architecture, N-tier Architecture, Service-oriented Architecture, Message-based Architecture, Microservice-based Architecture, Reactive Architecture, and Serverless Architecture.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/dev0928&quot;&gt;dev0928&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;redshift-vs-athena&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#redshift-vs-athena&quot; aria-label=&quot;redshift vs athena permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Redshift vs Athena&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/aws/comments/umx793/redshift_vs_athena/&quot;&gt;https://www.reddit.com/r/aws/comments/umx793/redshift_vs_athena/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting discussion about AWS Redshift vs Athena. Athena seems to keep the costs low as it is serverless but it would be rather slow when you need a quick answering kind of API.&lt;/p&gt;
&lt;h2 id=&quot;3-reasons-you-should-stay-away-from-aws-step-functions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#3-reasons-you-should-stay-away-from-aws-step-functions&quot; aria-label=&quot;3 reasons you should stay away from aws step functions permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3 Reasons You Should Stay Away From AWS Step Functions&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.readysetcloud.io/blog/allen.helton/when-not-to-use-step-functions/&quot;&gt;https://www.readysetcloud.io/blog/allen.helton/when-not-to-use-step-functions/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Very nice deep dive into AWS Step Functions. It is so cool that the author describes some problems and how to solve them from a view as a Step Functions Beginner, Intermediate and Advanced. Nice idea! Must read!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://twitter.com/AllenHeltonDev&quot;&gt;Allen Helton&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;annahita-esmailzadeh-ich-entspreche-nicht-dem-stereotyp-eines-it-lers&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#annahita-esmailzadeh-ich-entspreche-nicht-dem-stereotyp-eines-it-lers&quot; aria-label=&quot;annahita esmailzadeh ich entspreche nicht dem stereotyp eines it lers permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Annahita Esmailzadeh: „Ich entspreche nicht dem Stereotyp eines IT-lers“&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://t3n.de/news/annahita-esmailzadeh-stereotype-it-tech-branche-1471342/?utm_source=rss&amp;#x26;utm_medium=feed&amp;#x26;utm_campaign=news&quot;&gt;https://t3n.de/news/annahita-esmailzadeh-stereotype-it-tech-branche-1471342/?utm_source=rss&amp;#x26;utm_medium=feed&amp;#x26;utm_campaign=news&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting talk about fewer women in IT and how hard it is for women to be acknowledged in the IT area. Unlucky it is in German but you can use a translation service :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://t3n.de/redaktion/andreas-weck&quot;&gt;Andreas Weck&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;on-devops-1-what-it-is&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#on-devops-1-what-it-is&quot; aria-label=&quot;on devops 1 what it is permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;On DevOps: 1. What It Is&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/devstream/on-devops-1-what-it-is-3lmd&quot;&gt;https://dev.to/devstream/on-devops-1-what-it-is-3lmd&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting discussion about DevOps and DevOps Culture. Like what it is and more. As well as in this context what does leadership mean.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/ironcore864&quot;&gt;Tiexin Guo&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;starter-guide--things-i-wish-i-knew-before-for-aws-lambda&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#starter-guide--things-i-wish-i-knew-before-for-aws-lambda&quot; aria-label=&quot;starter guide  things i wish i knew before for aws lambda permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Starter Guide &amp;#x26; “Things I wish I knew before” for AWS Lambda&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://towardsaws.com/starter-guide-things-i-wish-i-knew-before-for-aws-lambda-fe36ce2fd4cb&quot;&gt;https://towardsaws.com/starter-guide-things-i-wish-i-knew-before-for-aws-lambda-fe36ce2fd4cb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice deep dive into AWS Lambda regarding pricing, when to use it, limitations and much more. It even tackles the cold start problem and gives good advice on how to minimize that burden. Super cool!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://blog.tpschmidt.com/&quot;&gt;Tobias Schmidt&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;automating-machine-learning-lifecycle-with-aws&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#automating-machine-learning-lifecycle-with-aws&quot; aria-label=&quot;automating machine learning lifecycle with aws permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Automating machine learning lifecycle with AWS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://trojrobert.medium.com/automating-machine-learning-lifecycle-on-aws-trojrobert-385a66b82fbf&quot;&gt;https://trojrobert.medium.com/automating-machine-learning-lifecycle-on-aws-trojrobert-385a66b82fbf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A very broad listing of useful AWS services related to machine learning. Though I don&apos;t believe that it shall only take 11 minutes to read :D !!&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://trojrobert.medium.com/&quot;&gt;Robert John&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;shortcut-for-aws-cdk-credentials-insanely-simple-setup-for-sso-saml-and-named-profiles&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#shortcut-for-aws-cdk-credentials-insanely-simple-setup-for-sso-saml-and-named-profiles&quot; aria-label=&quot;shortcut for aws cdk credentials insanely simple setup for sso saml and named profiles permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Shortcut for AWS CDK credentials: insanely simple setup for SSO, SAML, and named profiles&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/shortcut-for-aws-cdk-credentials-insanely-simple-setup-for-sso-saml-and-named-profiles-35a9&quot;&gt;https://dev.to/aws-builders/shortcut-for-aws-cdk-credentials-insanely-simple-setup-for-sso-saml-and-named-profiles-35a9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interesting post on how to use SSO SAML and named Profiles for AWS CDK deployments. TBH I never used CDK deploy --profile $PROFILE_NAME but yeah if I have to this article explains it in very good detail.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/urz9999&quot;&gt;Alessandro Gaggia&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-get-remote-software-developer-jobs-in-2022--high-paying--international--remote-job&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-get-remote-software-developer-jobs-in-2022--high-paying--international--remote-job&quot; aria-label=&quot;how to get remote software developer jobs in 2022  high paying  international  remote job permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to get remote software developer jobs in 2022 | high paying | international | remote job&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ftC-jQgmcwI&quot;&gt;https://www.youtube.com/watch?v=ftC-jQgmcwI&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Contains very good tips for how to get a remote developer job.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.youtube.com/channel/UCMQtriZHwNgXl6eff5dNTHQ&quot;&gt;Learn And Grow Everyday&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;securing-aws-lambda-function-urls&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#securing-aws-lambda-function-urls&quot; aria-label=&quot;securing aws lambda function urls permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Securing AWS Lambda function URLs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.wiz.io/blog/securing-aws-lambda-function-urls&quot;&gt;https://www.wiz.io/blog/securing-aws-lambda-function-urls&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice roundup about what are vulnerabilities from AWS Lambda Function Urls&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://www.wiz.io/blog/author/amitaico/&quot;&gt;Amitai Cohen&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;aws-security-best-practices-with-crowd-sentry&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-security-best-practices-with-crowd-sentry&quot; aria-label=&quot;aws security best practices with crowd sentry permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Security Best Practices with Crowd Sentry&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.crowdsentry.io/aws-security-best-practices-with-crowd-sentry-b3605f1854bc&quot;&gt;https://blog.crowdsentry.io/aws-security-best-practices-with-crowd-sentry-b3605f1854bc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice short summary about some AWS Security Best Practices and how to keep those.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://medium.com/@MikeCrowdSentry&quot;&gt;Mike Wade&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;reamplify&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#reamplify&quot; aria-label=&quot;reamplify permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Reamplify&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/thomasrooney/reamplify&quot;&gt;https://github.com/thomasrooney/reamplify&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An Open Source CDK Community project which I find super interesting. It is doing cherry-picking from AWS Amplify UI and AWS CDK for deployment. I do that in my private projects as well for example &lt;a href=&quot;https://github.com/senjuns/senjuns&quot;&gt;https://github.com/senjuns/senjuns&lt;/a&gt;. I think the author could enhance/simplify its repo even more by using &lt;a href=&quot;https://github.com/projen/projen&quot;&gt;https://github.com/projen/projen&lt;/a&gt; for the project setup.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://github.com/ThomasRooney&quot;&gt;Thomas Rooney&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;securely-use-secrets-in-your-aws-cdk-deployed-lambda-function&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#securely-use-secrets-in-your-aws-cdk-deployed-lambda-function&quot; aria-label=&quot;securely use secrets in your aws cdk deployed lambda function permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Securely Use Secrets In Your AWS CDK Deployed Lambda Function&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/wesleycheek/securely-use-secrets-in-your-aws-cdk-deployed-lambda-function-1ebb&quot;&gt;https://dev.to/wesleycheek/securely-use-secrets-in-your-aws-cdk-deployed-lambda-function-1ebb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Explains how to use AWS Secrets Manager for storing secrets related to your CDK deployments. And the example is written in Python :).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/wesleycheek&quot;&gt;Wesley Cheek&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-pair-programming-helps-the-team&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-pair-programming-helps-the-team&quot; aria-label=&quot;how pair programming helps the team permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How Pair Programming Helps The Team&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/michaelprosario/how-pair-programming-helps-the-team-3045&quot;&gt;https://dev.to/michaelprosario/how-pair-programming-helps-the-team-3045&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I find the topic of pair programming super interesting. I never had the opportunity to do that but I will change that! This article is a very good roundup of why pair programming is nice. As well it gives details on how to do pair programming.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/michaelprosario&quot;&gt;Michael Rosario&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-become-a-good-developer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-become-a-good-developer&quot; aria-label=&quot;how to become a good developer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to become a good developer?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/this-is-learning/how-to-become-a-good-developer-7no&quot;&gt;https://dev.to/this-is-learning/how-to-become-a-good-developer-7no&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Speaks to the bottom of my heart.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/yourmdsarfaraj&quot;&gt;MD Sarfaraj&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;serverless-apps-why-iac-should-be-the-direction&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#serverless-apps-why-iac-should-be-the-direction&quot; aria-label=&quot;serverless apps why iac should be the direction permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Serverless apps: Why IaC should be the direction&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://zachjonesnoel.hashnode.dev/serverless-apps-why-iac-should-be-the-direction&quot;&gt;https://zachjonesnoel.hashnode.dev/serverless-apps-why-iac-should-be-the-direction&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice article on why to use Infrastructure as Code (IAC).&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://hashnode.com/@zachjonesnoel&quot;&gt;Jones Zachariah Noel N&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Create and delete AWS Accounts programmatically]]></title><description><![CDATA[Hi. In AWS, it is best practice to create new accounts if, for example, you want to deploy different stages such as dev, qa and prod for…]]></description><link>https://martinmueller.dev/sdk-org-eng/</link><guid isPermaLink="false">https://martinmueller.dev/sdk-org-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><category><![CDATA[sdk]]></category><category><![CDATA[organizations]]></category><pubDate>Wed, 11 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;In AWS, it is best practice to create new accounts if, for example, you want to deploy different stages such as dev, qa and prod for your solution. It is also common to create so-called sandbox AWS accounts to provide these new employees for testing AWS services. There are many more reasons why new AWS accounts should be created.&lt;/p&gt;
&lt;p&gt;Now creating such AWS accounts can be quite time consuming if it has to be done manually. With AWS Organizations, the AWS &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Organizations.html&quot;&gt;JavaScript SDK&lt;/a&gt; and a little TypeScript knowledge, the process can be automated for the most part. In this post, I&apos;ll introduce how this works. To do this, I first explain what AWS Organizations is in the first place and then I introduce the two TypeScript scripts that can create and delete the AWS Sandbox accounts using the AWS SDK.&lt;/p&gt;
&lt;h2 id=&quot;aws-organizations&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-organizations&quot; aria-label=&quot;aws organizations permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Organizations&lt;/h2&gt;
&lt;p&gt;AWS Organizations helps to manage the AWS accounts. In so called Organizational Unites (OU) accounts can be grouped together. Furthermore, security mechanisms such as policies can be defined across accounts. AWS Organizations offers much more functionality and I would like to refer to the public documentation. Interesting for this post is that there is also a &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Organizations.html&quot;&gt;JavaScript SDK&lt;/a&gt; wrapper for the AWS Organizations API that we will use in the next sections to dynamically create and delete accounts.&lt;/p&gt;
&lt;h2 id=&quot;createaccount-and-deleteaccount&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#createaccount-and-deleteaccount&quot; aria-label=&quot;createaccount and deleteaccount permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;createAccount and deleteAccount&lt;/h2&gt;
&lt;p&gt;I created a small helper library in &lt;a href=&quot;https://github.com/mmuller88/aws-accounts&quot;&gt;GitHub&lt;/a&gt; to simplify the programmatic creation and deletion of AWS accounts. An AWS SDK script could then be easily built such as:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 createAccount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 moveAccountToOU&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 getAccountIdFromName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &quot;aws&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;accounts

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; args &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;argv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;usage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Wrong number of arguments&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; accountName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createAccount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;accountName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; accountId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getAccountIdFromName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;accountName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;accountId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveAccountToOU&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;accountId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ou-zblx-w7yw0qge&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code can also be seen in the repo &lt;a href=&quot;https://github.com/mmuller88/aws-accounts/blob/main/test/createAccountScript.ts&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The library is a lightweight wrapper around AWS SDK TypeScript v.2 . With &lt;code&gt;await createAccount(accountName)&lt;/code&gt; the account is created first. Then with &lt;code&gt;await getAccountIdFromName(accountName)&lt;/code&gt; and &lt;code&gt;await moveAccountToOU(accountId)&lt;/code&gt; the account is moved to the defined OU (Organizational Unit).&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;In this blog post I explained why it is sometimes necessary to create new AWS accounts and how this can be done using AWS Organizations and the JavaScript SDK. For this I created a createAccount and a deleteAccount script and presented them here. Did you find the post helpful or do you have any suggestions for improvement? Let me know and write me :).&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 18]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-18/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-18/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><pubDate>Sun, 08 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;getting-started-with-git-and-github&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#getting-started-with-git-and-github&quot; aria-label=&quot;getting started with git and github permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Getting started with Git and Github&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/mbugua70/getting-started-with-git-and-github-3mg&quot;&gt;https://dev.to/mbugua70/getting-started-with-git-and-github-3mg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Good roundup for what is Git and the most important commands. It would help you to get more familar with the Git CLI which make me for example very productive. Furthermore I recommend setting this alias:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;ginit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;git add --all &amp;amp;&amp;amp; git commit -m &quot;&lt;/span&gt;init&lt;span class=&quot;token string&quot;&gt;&quot; &amp;amp;&amp;amp; git push&quot;&lt;/span&gt;

&lt;span class=&quot;token function-name function&quot;&gt;gaddall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--all&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;gall&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gaddall&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So with that I just need line ginit or gall for quickly adding the commit. That was a super productive boost for me.&lt;/p&gt;
&lt;h2 id=&quot;17-ridiculously-funny-programming-memes-that-every-developer-can-relate-to&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#17-ridiculously-funny-programming-memes-that-every-developer-can-relate-to&quot; aria-label=&quot;17 ridiculously funny programming memes that every developer can relate to permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;17 Ridiculously Funny Programming Memes that Every Developer Can Relate To&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/muthuannamalai12/17-ridiculously-funny-programming-memes-that-every-developer-can-relate-to-2gg3&quot;&gt;https://dev.to/muthuannamalai12/17-ridiculously-funny-programming-memes-that-every-developer-can-relate-to-2gg3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A very good brain relaxes and it is super funny.&lt;/p&gt;
&lt;h2 id=&quot;aws-step-functions-101&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-step-functions-101&quot; aria-label=&quot;aws step functions 101 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Step Functions 101&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dashbird.io/blog/ultimate-guide-aws-step-functions/&quot;&gt;https://dashbird.io/blog/ultimate-guide-aws-step-functions/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A good roundup about AWS Step Functions. It is very good if you want to dive deep into the topic. As I have a lot with Step Functions already the article is a bit long. But yeah a highlight really is that you can use typed AWS CDK to define your Step Functions. Thanks to the author Mariliis Retter.&lt;/p&gt;
&lt;h2 id=&quot;aws-open-source-news-and-updates-111&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-open-source-news-and-updates-111&quot; aria-label=&quot;aws open source news and updates 111 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS open-source news and updates #111&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws/aws-open-source-news-and-updates-111-1dj3&quot;&gt;https://dev.to/aws/aws-open-source-news-and-updates-111-1dj3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here again where Ricardo presents exciting open source community projects. My favorites once are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/hseera/cloudfront-manager&quot;&gt;cloudfront-manager&lt;/a&gt;. Juggling CloudFront distribution in AWS is always not easy regarding Invalidate, Enable, Disable and Delete. This tool looks very promising in helping you with that! &lt;a href=&quot;https://dev.to/aws-builders/aws-cloudfront-manager-a-windows-utility-for-cloudfront-17o0&quot;&gt;https://dev.to/aws-builders/aws-cloudfront-manager-a-windows-utility-for-cloudfront-17o0&lt;/a&gt; . Thanks a lot to the author &lt;a href=&quot;https://dev.to/harinderseera&quot;&gt;Harinder Seera&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aws-samples/amazon-cloudwatch-retention-period-setter&quot;&gt;amazon-cloudwatch-retention-period-setter&lt;/a&gt;. This tool help you set the log retention period for CloudWatch logs per default. Otherwise, they would stay in CloudWatch forever and accumulate costs. I usually prefer setting AWS CDK with the right properties to avoid that but yeah very often, I am lacy doing that so having something more globally like that would be awesome. &lt;a href=&quot;https://aws.amazon.com/blogs/infrastructure-and-automation/reduce-log-storage-costs-by-automating-retention-settings-in-amazon-cloudwatch/&quot;&gt;https://aws.amazon.com/blogs/infrastructure-and-automation/reduce-log-storage-costs-by-automating-retention-settings-in-amazon-cloudwatch/&lt;/a&gt;. Thanks to author Mohamed Wali.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And finally thank you so much Ricardo for picking and presenting all those cherries I missed this week. And dear reader please support &lt;a href=&quot;https://dev.to/094459&quot;&gt;Ricardo Sueiras&lt;/a&gt;! Man, I would love to meet you at AWS Summit Berlin but I have to stay behind here in south Portugal Albufeira on the beach during my holidays. Not that bad actually :P.&lt;/p&gt;
&lt;h2 id=&quot;obsidian---an-ide-for-your-brain&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#obsidian---an-ide-for-your-brain&quot; aria-label=&quot;obsidian   an ide for your brain permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Obsidian - An IDE for your Brain&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/envoy_/obsidian-an-ide-for-your-brain-1bn7&quot;&gt;https://dev.to/envoy_/obsidian-an-ide-for-your-brain-1bn7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I used Obsidian for some weeks and is really cool. But I figured that VS Code is kind of better when it comes to writing / organizing my content. Probably combining both like VS Code for writing and Obsidian for viewing seems interesting.&lt;/p&gt;
&lt;h2 id=&quot;optimize-your-workloads-for-sustainability&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#optimize-your-workloads-for-sustainability&quot; aria-label=&quot;optimize your workloads for sustainability permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Optimize your workloads for Sustainability&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://globaldatanet.com/tech-blog/optimize-your-workloads-for-sustainability&quot;&gt;https://globaldatanet.com/tech-blog/optimize-your-workloads-for-sustainability&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super good roundup about sustainability with AWS. Explains the shared responsibility between AWS and customers and provides some very useful tips for how to reduce the resource footprint. Thanks to the author &lt;a href=&quot;https://globaldatanet.com/our-team/david-krohn&quot;&gt;David Krohn&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;clown_face-aws-cdk-101----using-layers-in-lambda-functions-and-saving-json-to-s3&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#clown_face-aws-cdk-101----using-layers-in-lambda-functions-and-saving-json-to-s3&quot; aria-label=&quot;clown_face aws cdk 101    using layers in lambda functions and saving json to s3 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;:clown_face: AWS CDK 101 - 🤾‍♂ Using layers in Lambda functions and saving JSON to S3&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aravindvcyber/aws-cdk-101-using-layers-in-lambda-functions-and-saving-json-to-s3-46fg&quot;&gt;https://dev.to/aravindvcyber/aws-cdk-101-using-layers-in-lambda-functions-and-saving-json-to-s3-46fg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting article about how and why to use Lamba Layers. TBH I always avoided them but that might change because of this post. Thanks to &lt;a href=&quot;https://dev.to/aravindvcyber&quot;&gt;Aravind V&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;post-messages-to-slack-using-aws-lambda-function-urls&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#post-messages-to-slack-using-aws-lambda-function-urls&quot; aria-label=&quot;post messages to slack using aws lambda function urls permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Post Messages To Slack Using AWS Lambda Function URLs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/josuebustos/post-messages-to-slack-using-aws-lambda-function-urls-5f2a&quot;&gt;https://dev.to/josuebustos/post-messages-to-slack-using-aws-lambda-function-urls-5f2a&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice in-depth article about how to post messages to slack using AWS Function URLs. Would be even cooler to create an AWS CDK construct to simplify that. Thanks to the author &lt;a href=&quot;https://dev.to/josuebustos&quot;&gt;Josue Bustos&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;website-to-pdf-using-aws-lambda-function-urls&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#website-to-pdf-using-aws-lambda-function-urls&quot; aria-label=&quot;website to pdf using aws lambda function urls permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Website to PDF using AWS Lambda Function URLs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://jobinbasani.com/2022/05/03/website-to-pdf-using-aws-lambda-function-urls/&quot;&gt;https://jobinbasani.com/2022/05/03/website-to-pdf-using-aws-lambda-function-urls/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this article, the author creates via AWS CDK and JS library chrome-aws-lambda a Lambda which can transform a website into PDF. Very cool. Thanks to the author &lt;a href=&quot;https://jobinbasani.com/&quot;&gt;Jobi Basani&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;terraform-vs-pulumi-vs-cloud-sdks---keep-it-simple-silly&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#terraform-vs-pulumi-vs-cloud-sdks---keep-it-simple-silly&quot; aria-label=&quot;terraform vs pulumi vs cloud sdks   keep it simple silly permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Terraform vs Pulumi vs Cloud SDKs - Keep It Simple, Silly&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Z3hyqmCddXc&quot;&gt;https://www.youtube.com/watch?v=Z3hyqmCddXc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This topic is super hot. Thanks to the creator &lt;a href=&quot;https://www.youtube.com/channel/UCp5CE3BD-fHc8rFqRJQklqA&quot;&gt;Michael Crilly&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-avoid-aws-unintentional-charges&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-avoid-aws-unintentional-charges&quot; aria-label=&quot;how to avoid aws unintentional charges permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to avoid AWS unintentional charges?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.internetkatta.com/how-to-avoid-aws-unintentional-charges&quot;&gt;https://www.internetkatta.com/how-to-avoid-aws-unintentional-charges&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Recommend using &quot;AWS Pricing Calculator&quot; to evaluate your pricing model.&lt;/p&gt;
&lt;h2 id=&quot;programmieren-mit-python-große-datenmengen-verwalten-mit-vaex&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#programmieren-mit-python-gro%C3%9Fe-datenmengen-verwalten-mit-vaex&quot; aria-label=&quot;programmieren mit python große datenmengen verwalten mit vaex permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Programmieren mit Python: Große Datenmengen verwalten mit vaex&lt;/h2&gt;
&lt;p&gt;Programming with Python: How to manage a huge amount of data with vaex&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.heise.de/ratgeber/Python-Mit-vaex-grosse-Datenmengen-verwalten-7066766.html&quot;&gt;https://www.heise.de/ratgeber/Python-Mit-vaex-grosse-Datenmengen-verwalten-7066766.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With Python Panda you can not process your data anymore when they become too big. The library vaex is solving that problem. Thanks to the author &lt;a href=&quot;odi@ix.de&quot;&gt;odi&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;pair-programming-with-a-senior-is-invaluable&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#pair-programming-with-a-senior-is-invaluable&quot; aria-label=&quot;pair programming with a senior is invaluable permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pair Programming with a senior is invaluable&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/w3ndo/pair-programming-with-a-senior-is-invaluable-2fdo&quot;&gt;https://dev.to/w3ndo/pair-programming-with-a-senior-is-invaluable-2fdo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For me, that topic is super important. I totally agree pair programming is invaluable. We have an unhealthy ratio between junior and senior engineers. So pair programming really helps to fix that. And in my opinion, it is super helpful for the senior as well.&lt;/p&gt;
&lt;h2 id=&quot;typescript-vs-javascript-whats-the-difference&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#typescript-vs-javascript-whats-the-difference&quot; aria-label=&quot;typescript vs javascript whats the difference permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;TypeScript vs JavaScript: What&apos;s the difference?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/educative/typescript-vs-javascript-whats-the-difference-n5m&quot;&gt;https://dev.to/educative/typescript-vs-javascript-whats-the-difference-n5m&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super good summary of what is JavaScript and what TypeScript is and why to favor one over the other. In the future, I will refer just to this article.&lt;/p&gt;
&lt;p&gt;Thanks a lot to &lt;a href=&quot;https://dev.to/huntereducative&quot;&gt;Hunter Johnson&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;infrastructure-as-code-vierte-pulumi-hauptversion-verspricht-universal-iac&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#infrastructure-as-code-vierte-pulumi-hauptversion-verspricht-universal-iac&quot; aria-label=&quot;infrastructure as code vierte pulumi hauptversion verspricht universal iac permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Infrastructure-as-Code: Vierte Pulumi-Hauptversion verspricht Universal IaC&lt;/h2&gt;
&lt;p&gt;Translated: Infrastructure-as-Code: Fourth Pulumi-version promises universal IaC&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.heise.de/news/Infrastructure-as-Code-Vierte-Pulumi-Hauptversion-verspricht-Universal-IaC-7076433.html&quot;&gt;https://www.heise.de/news/Infrastructure-as-Code-Vierte-Pulumi-Hauptversion-verspricht-Universal-IaC-7076433.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Version 4 from Pulumi seems to make an interesting move by incorporating AWS CDK.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;map@ix.de&quot;&gt;map&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;cloud-pricing-comparison-aws-vs-azure-vs-google-cloud-platform-in-2022&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cloud-pricing-comparison-aws-vs-azure-vs-google-cloud-platform-in-2022&quot; aria-label=&quot;cloud pricing comparison aws vs azure vs google cloud platform in 2022 permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cloud Pricing Comparison: AWS vs. Azure vs. Google Cloud Platform in 2022&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/castai/cloud-pricing-comparison-aws-vs-azure-vs-google-cloud-platform-in-2022-no2&quot;&gt;https://dev.to/castai/cloud-pricing-comparison-aws-vs-azure-vs-google-cloud-platform-in-2022-no2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting comparison between the three big cloud providers. In the article, they use similar VMs from different providers to compare those costs. That is a smart idea! As well they compared spot instances from the different providers.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/castai&quot;&gt;CAST AI&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;developer-shortage-no-just-bad-interviews&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#developer-shortage-no-just-bad-interviews&quot; aria-label=&quot;developer shortage no just bad interviews permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Developer shortage? No, just bad interviews&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/jssantana/developer-shortage-no-just-bad-interviews-1cpa&quot;&gt;https://dev.to/jssantana/developer-shortage-no-just-bad-interviews-1cpa&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The author explains why most companies are hiring wrong. Just those whiteboard kinds of tests don&apos;t evaluate the skills of the developer. I totally agree and those kinds of tests always bothered me.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/jssantana&quot;&gt;Jean Santana&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;using-athena-to-query-multi-account-cloudwatch-logs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-athena-to-query-multi-account-cloudwatch-logs&quot; aria-label=&quot;using athena to query multi account cloudwatch logs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using Athena to query multi-account Cloudwatch Logs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/markymarkus/using-athena-to-query-multi-account-cloudwatch-logs-54j&quot;&gt;https://dev.to/markymarkus/using-athena-to-query-multi-account-cloudwatch-logs-54j&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The author explains how you can store your CloudWatch logs via Kinesis in S3 and how you can query them. That is super cool and a preferred way when logging gets more complex! And I like that the author used a diagram to explain the bit complex architecture.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/markymarkus&quot;&gt;markymarkus&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;does-aws-lambda-good-for-etl-jobs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#does-aws-lambda-good-for-etl-jobs&quot; aria-label=&quot;does aws lambda good for etl jobs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Does AWS Lambda good for ETL jobs?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/does-aws-lambda-good-for-etl-jobs-10i8&quot;&gt;https://dev.to/aws-builders/does-aws-lambda-good-for-etl-jobs-10i8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The author discusses if Lambda is well suited for ETL. I think it is until you reach a Lambda limit and then you change to other services like AWS Glue.&lt;/p&gt;
&lt;p&gt;Thanks a lot to the author &lt;a href=&quot;https://dev.to/imohd23&quot;&gt;Mohamed Latfalla&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 17]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-17/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-17/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><pubDate>Sun, 01 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;using-obsidian&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-obsidian&quot; aria-label=&quot;using obsidian permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using Obsidian&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/paratron/introducing-and-using-obsidian-3o17&quot;&gt;https://dev.to/paratron/introducing-and-using-obsidian-3o17&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I use and love Obsidian already. It is a great tool to organize content extracted from posts, YouTube and more. And most cool of it is based on Markdown &amp;#x3C;3. I encourage you to try it!&lt;/p&gt;
&lt;p&gt;Update: I figured that VS Code is probably as good as Obsidian for managing your content. Even better you can open multiple tabs in VS Code which you can&apos;t in Obsidian.&lt;/p&gt;
&lt;h2 id=&quot;what-is-webassembly-and-why-it-is-a-game-changer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-is-webassembly-and-why-it-is-a-game-changer&quot; aria-label=&quot;what is webassembly and why it is a game changer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is WebAssembly and why it is a game-changer?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aryank21/what-is-webassembly-and-why-it-is-a-game-changer-21p4&quot;&gt;https://dev.to/aryank21/what-is-webassembly-and-why-it-is-a-game-changer-21p4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Webassembly or short WASM is super interesting. It advertises developers with execution speed compared to js solutions. For a greenfield project, I definitely want to try it. Super interesting as well is to get potentially closer to the hardware like perhaps IoT devices.&lt;/p&gt;
&lt;h2 id=&quot;zero-cold-start-for-lambda&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#zero-cold-start-for-lambda&quot; aria-label=&quot;zero cold start for lambda permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Zero Cold Start for Lambda&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/aws/comments/ud5fos/zero_cold_start_for_lambda/&quot;&gt;https://www.reddit.com/r/aws/comments/ud5fos/zero_cold_start_for_lambda/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super interesting discussion about zero cold starts for Lambda. That highlights the big conflict like serverless vs zero cold start Lambda. Zero cold starts are possible but not without trade-offs. Sure the customer wants that without trade-offs. That is really hard.&lt;/p&gt;
&lt;h2 id=&quot;how-to-speed-up-lambda-functions&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-speed-up-lambda-functions&quot; aria-label=&quot;how to speed up lambda functions permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to speed up Lambda Functions&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.freecodecamp.org/news/how-to-speed-up-lambda-functions/&quot;&gt;https://www.freecodecamp.org/news/how-to-speed-up-lambda-functions/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So Lambda hast different phases like init, invoke and shutdown. Initialization code should be put into the init phase which means outside of the lambda handler function.&lt;/p&gt;
&lt;h2 id=&quot;eks-blueprints-iac-modules-for-production-ready-kubernetes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#eks-blueprints-iac-modules-for-production-ready-kubernetes&quot; aria-label=&quot;eks blueprints iac modules for production ready kubernetes permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;EKS Blueprints: IaC Modules for Production-Ready Kubernetes&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://itnext.io/eks-blueprints-iac-modules-for-production-ready-kubernetes-48032d5ce88#2ee6-c02bad69ddca&quot;&gt;https://itnext.io/eks-blueprints-iac-modules-for-production-ready-kubernetes-48032d5ce88#2ee6-c02bad69ddca&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Super summarizing about the new-ish &lt;a href=&quot;https://github.com/aws-quickstart/cdk-eks-blueprints&quot;&gt;AWS CDK EKS Blueprints&lt;/a&gt;. That topic seems very hot and very promising to be a nice abstraction on top of K8S. Unlucky I am more on the serverless-ish side so, I probably miss some cherries atm.&lt;/p&gt;
&lt;h2 id=&quot;deploy-serverless-containerized-nodejs-apps-on-aws-ecs-fargate-with-aws-copilot&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#deploy-serverless-containerized-nodejs-apps-on-aws-ecs-fargate-with-aws-copilot&quot; aria-label=&quot;deploy serverless containerized nodejs apps on aws ecs fargate with aws copilot permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Deploy Serverless Containerized NodeJs Apps on AWS ECS Fargate with AWS Copilot&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.serverlessguru.com/blog/deploy-serverless-containerized-nodejs-application-on-aws-ecs-fargate&quot;&gt;https://www.serverlessguru.com/blog/deploy-serverless-containerized-nodejs-application-on-aws-ecs-fargate&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Good roundup about what is AWS ECS, Fargate and Copilot. It made me curious to learn more about Copilot as it seems to have some cool CI/CD capabilities.&lt;/p&gt;
&lt;h2 id=&quot;websocket-with-react&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#websocket-with-react&quot; aria-label=&quot;websocket with react permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Websocket with React&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/koladev/websocket-with-react-nodejs-and-docker-building-a-chat-application-3447&quot;&gt;https://dev.to/koladev/websocket-with-react-nodejs-and-docker-building-a-chat-application-3447&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Create a React-based chat using WebSockets. Uses Tailwindcss which is cool.&lt;/p&gt;
&lt;h2 id=&quot;5-useful-typescript-features-in-vs-code&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#5-useful-typescript-features-in-vs-code&quot; aria-label=&quot;5 useful typescript features in vs code permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5 Useful TypeScript Features In VS Code&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/danielfy/5-useful-typescript-features-in-vs-code-4am&quot;&gt;https://dev.to/danielfy/5-useful-typescript-features-in-vs-code-4am&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Wow that will enhance my developing velocity O.O. Huge thanks to &lt;a href=&quot;https://twitter.com/danielfyhr&quot;&gt;https://twitter.com/danielfyhr&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;input-on-my-study-path-to-step-into-devops&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#input-on-my-study-path-to-step-into-devops&quot; aria-label=&quot;input on my study path to step into devops permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Input on my study path to step into DevOps&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/devops/comments/uarh7i/input_on_my_study_path_to_step_into_devops/&quot;&gt;https://www.reddit.com/r/devops/comments/uarh7i/input_on_my_study_path_to_step_into_devops/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice advice for a DevOps Junior.&lt;/p&gt;
&lt;h2 id=&quot;aws-cdk-v2210-release-highlights&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-cdk-v2210-release-highlights&quot; aria-label=&quot;aws cdk v2210 release highlights permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS CDK v2.21.0 Release Highlights&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=GxXKJDYnpDY&quot;&gt;https://www.youtube.com/watch?v=GxXKJDYnpDY&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Release notes highlights from AWS CDK 2.21.0 from AWS Twitter presented from the AWS Hero @mattbonig.&lt;/p&gt;
&lt;h2 id=&quot;aws-cdk-v2220-release-highlights&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-cdk-v2220-release-highlights&quot; aria-label=&quot;aws cdk v2220 release highlights permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS CDK v2.22.0 Release Highlights&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=EyLFDt6uRiI&quot;&gt;https://www.youtube.com/watch?v=EyLFDt6uRiI&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;aws-amplify-studio&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-amplify-studio&quot; aria-label=&quot;aws amplify studio permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Amplify Studio&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aspittel/aws-amplify-studio-is-generally-available-5-new-features-to-checkout-4h0m&quot;&gt;https://dev.to/aspittel/aws-amplify-studio-is-generally-available-5-new-features-to-checkout-4h0m&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;AWS Amplify Studio is super interesting but I still miss some features like generating React TypeScript and Styled Components.&lt;/p&gt;
&lt;h2 id=&quot;using-amplify-ui-builder-with-your-existing-data&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-amplify-ui-builder-with-your-existing-data&quot; aria-label=&quot;using amplify ui builder with your existing data permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using Amplify UI Builder with your existing data&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/codebeast/using-amplify-studio-with-your-existing-data-5a1n&quot;&gt;https://dev.to/codebeast/using-amplify-studio-with-your-existing-data-5a1n&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice description of how to use Amplify Studio.&lt;/p&gt;
&lt;h2 id=&quot;writing-rfcs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#writing-rfcs&quot; aria-label=&quot;writing rfcs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Writing RFCs&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/wesen/quick-tip-tuesday-writing-rfcs-for-fun-and-profit-3bo&quot;&gt;https://dev.to/wesen/quick-tip-tuesday-writing-rfcs-for-fun-and-profit-3bo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Explains how important RFCs are&lt;/p&gt;
&lt;h2 id=&quot;using-apollo-server-on-aws-lambda-with-amazon-eventbridge-for-real-time-event-driven-streaming&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#using-apollo-server-on-aws-lambda-with-amazon-eventbridge-for-real-time-event-driven-streaming&quot; aria-label=&quot;using apollo server on aws lambda with amazon eventbridge for real time event driven streaming permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using Apollo Server on AWS Lambda with Amazon EventBridge for real-time, event-driven streaming&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/opensource/using-apollo-server-on-aws-lambda-with-amazon-eventbridge-for-real-time-event-driven-streaming/&quot;&gt;https://aws.amazon.com/blogs/opensource/using-apollo-server-on-aws-lambda-with-amazon-eventbridge-for-real-time-event-driven-streaming/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Amazing post about Apollo GraphQL and AppSync. Very cool is that it recommends CDK to do the infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;women-it-specialists&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#women-it-specialists&quot; aria-label=&quot;women it specialists permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Women IT specialists&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.heise.de/news/IT-Spezialistinnen-dringend-gesucht-Unternehmen-hoffen-auf-mehr-Frauen-7066656.html&quot;&gt;https://www.heise.de/news/IT-Spezialistinnen-dringend-gesucht-Unternehmen-hoffen-auf-mehr-Frauen-7066656.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Great topic about how to get more women in tech. It seems it would be useful to provide young girls earlier with information about IT jobs.&lt;/p&gt;
&lt;h2 id=&quot;-how-to-control-access-to-aws-resources-based-on-aws-account-ou-or-organization&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#-how-to-control-access-to-aws-resources-based-on-aws-account-ou-or-organization&quot; aria-label=&quot; how to control access to aws resources based on aws account ou or organization permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;# How to control access to AWS resources based on AWS account, OU, or organization&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/security/how-to-control-access-to-aws-resources-based-on-aws-account-ou-or-organization/&quot;&gt;https://aws.amazon.com/blogs/security/how-to-control-access-to-aws-resources-based-on-aws-account-ou-or-organization/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Explains how the new IAM condition key can be used for more fine granular set policies.&lt;/p&gt;
&lt;h2 id=&quot;how-to-load-test-your-apps-for-free-by-going-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-load-test-your-apps-for-free-by-going-serverless&quot; aria-label=&quot;how to load test your apps for free by going serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to Load Test Your Apps For Free By Going Serverless&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/how-to-load-test-your-apps-for-free-by-going-serverless-1cl2&quot;&gt;https://dev.to/aws-builders/how-to-load-test-your-apps-for-free-by-going-serverless-1cl2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A very cool top-down description for how to load test your serverless deployments.&lt;/p&gt;
&lt;h2 id=&quot;is-devops-in-my-environment-possible&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#is-devops-in-my-environment-possible&quot; aria-label=&quot;is devops in my environment possible permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Is DevOps in my environment possible?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/devops/comments/udj8s8/is_devops_in_my_environment_possible/&quot;&gt;https://www.reddit.com/r/devops/comments/udj8s8/is_devops_in_my_environment_possible/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pretty cool discussion about how to introduce and what is DevOps&lt;/p&gt;
&lt;h2 id=&quot;how-to-configure-eslint-prettier-husky-lint-staged-into-a-react-project-with-typescript-and-tailwind-css&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-to-configure-eslint-prettier-husky-lint-staged-into-a-react-project-with-typescript-and-tailwind-css&quot; aria-label=&quot;how to configure eslint prettier husky lint staged into a react project with typescript and tailwind css permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to configure ESLint, Prettier, Husky, Lint-staged into a React project with TypeScript and Tailwind CSS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/ixartz/how-to-configure-eslint-prettier-husky-lint-staged-into-a-react-project-with-typescript-and-tailwind-css-4jp8&quot;&gt;https://dev.to/ixartz/how-to-configure-eslint-prettier-husky-lint-staged-into-a-react-project-with-typescript-and-tailwind-css-4jp8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nice how-to for bringing those low-hanging fruits like eslint, prettier, husky and lint staged into your React project. I use lots of that in &lt;a href=&quot;https://github/senjuns/senjuns&quot;&gt;https://github/senjuns/senjuns&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;exploitation-and-prevention-of-common-aws-vulnerabilities&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#exploitation-and-prevention-of-common-aws-vulnerabilities&quot; aria-label=&quot;exploitation and prevention of common aws vulnerabilities permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Exploitation and Prevention of common AWS Vulnerabilities&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://csaju.com/blog/exploitation-and-prevention-of-common-aws-vulnerabilities/&quot;&gt;https://csaju.com/blog/exploitation-and-prevention-of-common-aws-vulnerabilities/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Give a nice roundtrip for how to prevent exploitation on the AWS services S3 and Lambda.&lt;/p&gt;
&lt;h2 id=&quot;amazon-rekognition-introduces-streaming-video-events-to-provide-real-time-alerts-on-live-video-streams&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#amazon-rekognition-introduces-streaming-video-events-to-provide-real-time-alerts-on-live-video-streams&quot; aria-label=&quot;amazon rekognition introduces streaming video events to provide real time alerts on live video streams permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Amazon Rekognition introduces Streaming Video Events to provide real-time alerts on live video streams&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/machine-learning/amazon-rekognition-introduces-streaming-video-events-to-provide-real-time-alerts-on-live-video-streams/&quot;&gt;https://aws.amazon.com/blogs/machine-learning/amazon-rekognition-introduces-streaming-video-events-to-provide-real-time-alerts-on-live-video-streams/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Helping users to AI surveillance their backyard to protect their home. Aims for minimizing the false alerts.&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot of my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And don&apos;t forget to visit my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/resume&quot;&gt;&lt;img src=&quot;https://martinmueller.dev/static/84caa5292a6d0c37c48ae280d04b5fa6/a7715/joint.jpg&quot; alt=&quot;martinmueller.dev&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Newsletter martinmueller.dev 2022 week 16]]></title><description><![CDATA[In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps…]]></description><link>https://martinmueller.dev/newsletter-16/</link><guid isPermaLink="false">https://martinmueller.dev/newsletter-16/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[newsletter]]></category><pubDate>Mon, 25 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this weekly newsletter, I write a summary of posts that got my attention during the week. I center around topics AWS, DevOps, Architecture, AWS CDK, Data Engineering, Data Analytics and much more.&lt;/p&gt;
&lt;p&gt;If you like my content follow me on my usual spots to hang around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;https://twitter.com/MartinMueller_&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/martinmueller88&quot;&gt;https://www.linkedin.com/in/martinmueller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/mmuller88&quot;&gt;https://dev.to/mmuller88&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martinmueller.dev&quot;&gt;https://martinmueller.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;self-healing&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#self-healing&quot; aria-label=&quot;self healing permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Self-healing&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/jobber/self-healing-code-46o9&quot;&gt;https://dev.to/jobber/self-healing-code-46o9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Self-healing code with graceful degradation. Very cool idea that the solution keeps running with limited functionality even when a large portion of it doesn&apos;t work properly. There should be/are plenty of examples where Netflix or Amazon is doing stuff like that. The author even takes it a step further like having a read-replica database to keep serving HTTP GET reads but blocking writes when the main database is down and an HTTP GET write is requested. That approach sounds very promising in general and probably can be transferred to other similar situations as well.&lt;/p&gt;
&lt;h2 id=&quot;fuck-up-stories&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#fuck-up-stories&quot; aria-label=&quot;fuck up stories permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fuck-up-Stories&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://t3n.de/news/fuckups-fehler-fehlerkultur-fehlermanagment-1459624&quot;&gt;https://t3n.de/news/fuckups-fehler-fehlerkultur-fehlermanagment-1459624&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interesting content about Fuck-up-Stories in Companies and how healthy they can be when doing in a company. In the long term, it can increase the revenue of a company.&lt;/p&gt;
&lt;h2 id=&quot;jaeger-quickstart&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#jaeger-quickstart&quot; aria-label=&quot;jaeger quickstart permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Jaeger QuickStart&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://betterprogramming.pub/introducing-jaeger-quick-start-deploying-on-aws-f0ee5d398e8a&quot;&gt;https://betterprogramming.pub/introducing-jaeger-quick-start-deploying-on-aws-f0ee5d398e8a&lt;/a&gt;
A post about Jaeger and how to run it in a QuickStart. Interesting as I didn&apos;t work much with Jaeger so much. It highlights how cool such Quick Starts are for starting quick :). Very interesting seems to be the fact that you can combine Jaeger with AWS X-Ray.&lt;/p&gt;
&lt;h2 id=&quot;joining-devops&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#joining-devops&quot; aria-label=&quot;joining devops permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Joining DevOps&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/devops/comments/u7p6w9/joining_devops/&quot;&gt;https://www.reddit.com/r/devops/comments/u7p6w9/joining_devops/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A new DevOps Junior after getting a DevOps-ish Job asking for help with where to start in the DevOps.&lt;/p&gt;
&lt;h2 id=&quot;lambda-with-aws-cdk-and-efs&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#lambda-with-aws-cdk-and-efs&quot; aria-label=&quot;lambda with aws cdk and efs permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lambda with AWS CDK and EFS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/wesleycheek/lambda-function-with-persistent-file-store-using-aws-cdk-and-aws-efs-45h8&quot;&gt;https://dev.to/wesleycheek/lambda-function-with-persistent-file-store-using-aws-cdk-and-aws-efs-45h8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deploy AWS Lambda with CDK and EFS attached to it.&lt;/p&gt;
&lt;h2 id=&quot;aws-well-architected---security-pillar&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-well-architected---security-pillar&quot; aria-label=&quot;aws well architected   security pillar permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Well-Architected - Security Pillar&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/sebastiantorres86/aws-well-architected-framework-security-pillar-2jhc&quot;&gt;https://dev.to/sebastiantorres86/aws-well-architected-framework-security-pillar-2jhc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A nice summary whey security and what is important regarding AWS Security. Have a nice best practice list.&lt;/p&gt;
&lt;h2 id=&quot;api-design---graphql-vs-rest&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#api-design---graphql-vs-rest&quot; aria-label=&quot;api design   graphql vs rest permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;API Design - GraphQL vs Rest&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/wundergraph/api-design-best-practices-for-long-running-operations-graphql-vs-rest-1mkb&quot;&gt;https://dev.to/wundergraph/api-design-best-practices-for-long-running-operations-graphql-vs-rest-1mkb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Has an interesting example of how asynchronous API can be done asynchronous API with GraphQL and REST API. Then the author compares the GraphQL and REST API solutions with each other.&lt;/p&gt;
&lt;h2 id=&quot;aws-step-function-scheduler-for-eks-nodes&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-step-function-scheduler-for-eks-nodes&quot; aria-label=&quot;aws step function scheduler for eks nodes permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Step Function scheduler for EKS nodes&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.automat-it.com/post/custom-kubernetes-scheduler-with-eks-and-step-functions-for-machine-learning-workloads&quot;&gt;https://www.automat-it.com/post/custom-kubernetes-scheduler-with-eks-and-step-functions-for-machine-learning-workloads&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cool solution for how to start EKS nodes when they are needed with Step Function.&lt;/p&gt;
&lt;h2 id=&quot;amazon-devops-guru-for-serverless&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#amazon-devops-guru-for-serverless&quot; aria-label=&quot;amazon devops guru for serverless permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Amazon DevOps Guru for serverless&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/aws/automatically-detect-operational-issues-in-lambda-functions-with-amazon-devops-guru-for-serverless/&quot;&gt;https://aws.amazon.com/blogs/aws/automatically-detect-operational-issues-in-lambda-functions-with-amazon-devops-guru-for-serverless/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;DevOps Guru for Serverless seems super interesting for like optimizing your serverless deployments&lt;/p&gt;
&lt;h2 id=&quot;aws-organizations-and-aws-sso&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-organizations-and-aws-sso&quot; aria-label=&quot;aws organizations and aws sso permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Organizations and AWS SSO&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/aws/comments/u9niif/aws_organizations_and_aws_sso/&quot;&gt;https://www.reddit.com/r/aws/comments/u9niif/aws_organizations_and_aws_sso/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A Reddit question for how to set up AWS Organizations and AWS SSO. I recommended giving &lt;a href=&quot;https://github.com/superwerker/superwerker&quot;&gt;https://github.com/superwerker/superwerker&lt;/a&gt; a try.&lt;/p&gt;
&lt;h2 id=&quot;vpn-tunnel-with-aws&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#vpn-tunnel-with-aws&quot; aria-label=&quot;vpn tunnel with aws permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;VPN tunnel with AWS&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.thenetworkdna.com/2022/01/site-to-site-vpn-tunnel-from-aws-to.html&quot;&gt;https://www.thenetworkdna.com/2022/01/site-to-site-vpn-tunnel-from-aws-to.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;VPN tunneling is already a tough topic at least for me. Cool instructions but I would prefer to have it as code somehow.&lt;/p&gt;
&lt;h2 id=&quot;aws-policy-as-code&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-policy-as-code&quot; aria-label=&quot;aws policy as code permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS Policy as Code&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/aws-builders/introduction-to-policy-as-code-5bma&quot;&gt;https://dev.to/aws-builders/introduction-to-policy-as-code-5bma&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Policy as Code is getting more and more attraction. As an AWS CDK fanboy, I guess I do that for many years now ^^.&lt;/p&gt;
&lt;h2 id=&quot;software-architecture-and-abstraction&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#software-architecture-and-abstraction&quot; aria-label=&quot;software architecture and abstraction permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Software Architecture and Abstraction&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/vickodev/software-architecture-and-abstraction-for-newbie-3nob&quot;&gt;https://dev.to/vickodev/software-architecture-and-abstraction-for-newbie-3nob&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Very interesting post about what is a software architecture, software design patterns and abstractions.&lt;/p&gt;
&lt;h2 id=&quot;final-words&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#final-words&quot; aria-label=&quot;final words permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final Words&lt;/h2&gt;
&lt;p&gt;Thank you to the authors of those amazing posts. And thank you to the readers of the newsletter. When you like this format or know how to improve it please let me know :). Let&apos;s Build!&lt;/p&gt;
&lt;p&gt;I love to work on Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot;&gt;&lt;img src=&quot;https://theastrologypodcast.com/wp-content/uploads/2015/06/become-my-patron-05.jpg&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OR&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/T6T1BR59W&quot;&gt;&lt;img src=&quot;https://storage.ko-fi.com/cdn/useruploads/png_d554a01f-60f0-4969-94d1-7b69f3e28c2fcover.jpg?v=69a332f2-b808-4369-8ba3-dae0d1100dd4&quot; alt=&quot;Buy me a Ko-Fi&quot;&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Export DynamoDB Items to S3]]></title><description><![CDATA[Hi Storing data like JSON logs in DynamoDB is a great idea as DynamoDB is very scalable. In addition, it is easier to transfer data into a…]]></description><link>https://martinmueller.dev/dynamodb-to-s3-eng/</link><guid isPermaLink="false">https://martinmueller.dev/dynamodb-to-s3-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[dynamodb]]></category><category><![CDATA[lambda]]></category><category><![CDATA[s3]]></category><category><![CDATA[cdk]]></category><pubDate>Sun, 03 Apr 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/f418ca0ca2cabb383d0ce4798b3ace02/dia.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;Storing data like JSON logs in DynamoDB is a great idea as DynamoDB is very scalable. In addition, it is easier to transfer data into a DynamoDB table using for example Lambda and AWS SDK. Also, it makes analyzing the logs easier for example the AWS Console offers great filtering options to search for specific so-called table items.&lt;/p&gt;
&lt;p&gt;This all sounds very good but there is one hitch and that is the cost. As the number of items increases, so does the cost. So it would be advisable to delete the DynamoDB data from the table after a certain time, e.g. 30 days, and import it into an S3. The costs for S3 are much lower and it would even be possible to reduce them if you use a cheaper S3 tier like Glacier.&lt;/p&gt;
&lt;p&gt;The question now is how you can do this most sophisticated? For me the combination &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html&quot;&gt;DynamoDB Time To Live&lt;/a&gt;, &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html&quot;&gt;DynamoDB Streams&lt;/a&gt; and Lambda which writes to an S3 bucket worked very well. In the following section, I will describe my solution.&lt;/p&gt;
&lt;h2 id=&quot;solution&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#solution&quot; aria-label=&quot;solution permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Solution&lt;/h2&gt;
&lt;p&gt;You can find the code in my GitHub repo &lt;a href=&quot;https://github.com/mmuller88/cdk-ddb-to-s3&quot;&gt;https://github.com/mmuller88/cdk-ddb-to-s3&lt;/a&gt; . As you can see the architecture in the title image is simple. DynamoDB Streams invokes a Lambda, which writes the deleted item away to S3. In my example, the DynamoDB items are JSON logs with few properties. In your case, the DynamoDB item can look different. But the basic concept should still the same!&lt;/p&gt;
&lt;p&gt;By the way, if you are curious how I created the AWS Component Architecture Diagram, you can read it &lt;a href=&quot;https://martinmueller.dev/dynamodb-to-s3&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ddb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Table&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;table&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 partitionKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;systemId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ddb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AttributeType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NUMBER&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 sortKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ddb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AttributeType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NUMBER&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 stream&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ddb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StreamViewType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;OLD_IMAGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 timeToLiveAttribute&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ttl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ddbArchiveBucket &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ddbArchiveBucket&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ddbArchiveLambda &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;lambdajs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NodejsFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ddbArchiveLambda&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 reservedConcurrentExecutions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;DDB_ARCHIVE_BUCKET_NAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ddbArchiveBucket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bucketName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
table&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grantStreamRead&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ddbArchiveLambda&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
spyderArchiveLogBucket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grantWrite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ddbArchiveLambda&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

ddbArchiveBucket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventSourceMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;archivelog&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token comment&quot;&gt;// max json document is 4 mb per file&lt;/span&gt;
 batchSize&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 maxBatchingWindow&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 eventSourceArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; table&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tableStreamArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 startingPosition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StartingPosition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TRIM_HORIZON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 bisectBatchOnError&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;stream: ddb.StreamViewType.OLD_IMAGE&lt;/code&gt; is set because I am only interested in the items that have been deleted.&lt;/p&gt;
&lt;p&gt;In the table definition a TimeToLive attribute was set with &lt;code&gt;timeToLiveAttribute: &apos;ttl&apos;&lt;/code&gt; . It is then important that your component which writes the data to DynamoDB always sets the ttl attribute. This is a timestamp that describes when the item should be deleted. In my project this was after 30 days.&lt;/p&gt;
&lt;p&gt;Usually, you should only need one running Lambda to write the data away to S3 &lt;code&gt;reservedConcurrentExecutions: 1&lt;/code&gt;. That serves as an additional safeguard against many unexpected invocations of Lambda.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;addEventSourceMapping&lt;/strong&gt; part is probably the most exciting. What is pretty cool is that DynamoDB Streams provides a batching feature. The Lambda can then process the deleted items as a batch. That reduces the number of Lambda calls and therefore the costs. The default DynamoDB default batching is not quite ideal for our use case here so I used AWS Console and the Lambda call metrics to optimize it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;batchSize&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
maxBatchingWindow&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;batchSize&lt;/strong&gt; with 10000 and the &lt;strong&gt;maxBatchingWindow&lt;/strong&gt; are chosen maximally to call a Lambda really only every 5 minutes:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 58.50000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABZklEQVR42pVTXW+DMAzk//+3aS+TpnWVaLUugCB8BQghgZvtFto+bGstGcdKfL6cQ5RlGY7HI/b7PeI4hvcej9qyLBJVkiIvNJxziLTWSNMU4zhiGIbt0DMW5lnqZorRNE1o2/au63/uw0zFywVkEUA2AeQFg66HHzFVDRj9GcROAWlt7wEf0wvEbJH4pXsY6+GJnSPgUzlcAflzy/A352tVnUNhHA55h3fV4JuYDi5gl7boRi9dIx+8DOMv/WamRd4MDq8HLQxfYo1d0iBvLT4onspeMKJnJ/p2qlES08/MQFNkLVs7iZbCUKZGb2++Gf3qqy5XX1D3EwJNOZHr8pslOUK4PhsuYkDWsa5riZyzl2Up7/OcBzRNDdMZKbRuonWPtmlknzVmaaI4N7JRUXFRFHfXM8ZI99VYa2vtlnNze9F/m/Ihq6DSDEopVMRwpN/HEit2xwWX9Zq7m30+u513IxHr8ANW5qzaKGMJMgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/27cd67e93db605f52f2a9bb35621aa7b/f1512/withoutProperBatching.webp 200w,
/static/27cd67e93db605f52f2a9bb35621aa7b/f59aa/withoutProperBatching.webp 400w,
/static/27cd67e93db605f52f2a9bb35621aa7b/47a22/withoutProperBatching.webp 800w,
/static/27cd67e93db605f52f2a9bb35621aa7b/7c467/withoutProperBatching.webp 832w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/27cd67e93db605f52f2a9bb35621aa7b/f8f3a/withoutProperBatching.png 200w,
/static/27cd67e93db605f52f2a9bb35621aa7b/6a8a8/withoutProperBatching.png 400w,
/static/27cd67e93db605f52f2a9bb35621aa7b/7842b/withoutProperBatching.png 800w,
/static/27cd67e93db605f52f2a9bb35621aa7b/caa4e/withoutProperBatching.png 832w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/27cd67e93db605f52f2a9bb35621aa7b/7842b/withoutProperBatching.png&quot;
            alt=&quot;withoutProperBatching.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;
&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 57.50000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAAA3ElEQVR42rVSXW/DIAzk///C7CVS1JewRaRp+AqY3DBNWVotL812kiVzhsOGE13XoW1bNE2DcVR4FzES1HiFkFJinmdYaxFCwBloYyCmacrq8ZTQuq6boIVgsZRSId8NPl8F8Qd46rDe9Chu8Zr/tq7cXpDb1S7ALFTKRAmRUsltIMwu1tFuOXfhvu+HCxv37yNv5NHDH9UYT5/C3uOfJiI45+C9L+t9MHfE85ni3yxuspfFzXosiy/kMAww2Zz7MRjsVY5XXmsNpdTO2Fnw4/KJL9mj72Vt/cwbfgPCW7QjPcvnzgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/e6a02c6045b5b3c8df42c3c664c84a26/f1512/withProperBatching.webp 200w,
/static/e6a02c6045b5b3c8df42c3c664c84a26/f59aa/withProperBatching.webp 400w,
/static/e6a02c6045b5b3c8df42c3c664c84a26/47a22/withProperBatching.webp 800w,
/static/e6a02c6045b5b3c8df42c3c664c84a26/a99a8/withProperBatching.webp 826w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/e6a02c6045b5b3c8df42c3c664c84a26/f8f3a/withProperBatching.png 200w,
/static/e6a02c6045b5b3c8df42c3c664c84a26/6a8a8/withProperBatching.png 400w,
/static/e6a02c6045b5b3c8df42c3c664c84a26/7842b/withProperBatching.png 800w,
/static/e6a02c6045b5b3c8df42c3c664c84a26/5a031/withProperBatching.png 826w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/e6a02c6045b5b3c8df42c3c664c84a26/7842b/withProperBatching.png&quot;
            alt=&quot;withProperBatching.png&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Super cool or? So the number of Lambda calls was massively reduced.&lt;/p&gt;
&lt;p&gt;By the way, choosing the batch size with 10000 is ok in my case because they are JSON items and we stay under the maximum size of 4 MB per file if I write them away to S3. In your case this batch size could be to high. You have to try this out with testing. I just deleted 300 log items at once and it was still successfully written to S3 with a Lambda call.&lt;/p&gt;
&lt;p&gt;With Athena and SQL queries the data in the S3 bucket can be inspected. How exactly that works I do not want to go into here. There are great tutorials that explain how Athena can be used to query for specific information in the S3 data such as JSON files.&lt;/p&gt;
&lt;p&gt;Also I would like to mention that in some tutorials I have also seen the use of Kinesis Firehose. But I don&apos;t think you need it for your solution. DynamoDB Streams already has the ability to batch. But maybe it is another reason why Firehose was used. If you know why Kinesis Firehose might be useful write me!&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;Writing DynamoDB items away to S3 to save costs is super cool. Here I explained how you do it. Do you have any feedback on this post or other suggestions on what I can cover? Then let me know!&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/f418ca0ca2cabb383d0ce4798b3ace02/dia.png</featuredImage><media:content url="https://martinmueller.dev/static/f418ca0ca2cabb383d0ce4798b3ace02/dia.png" medium="image"/></item><item><title><![CDATA[AWS CDK diagrams with cdk-dia <3]]></title><description><![CDATA[Hi. AWS component diagrams are a great way to visualize complex AWS architectures. For many, they are much more intuitive than, for example…]]></description><link>https://martinmueller.dev/cdk-dia-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-dia-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[cdk]]></category><pubDate>Thu, 24 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;AWS component diagrams are a great way to visualize complex AWS architectures. For many, they are much more intuitive than, for example, CDK code. I myself work a lot with AWS component diagrams when I develop new AWS systems. What has always bothered me is that creating the diagrams is time consuming and they have to be updated when the architecture changes.&lt;/p&gt;
&lt;p&gt;If you feel the same way, try &lt;a href=&quot;https://github.com/pistazie/cdk-dia&quot;&gt;cdk-dia&lt;/a&gt;. I used it in my last two CDK projects and the experience was simply overwhelming.&lt;/p&gt;
&lt;h2 id=&quot;how-does-it-work&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#how-does-it-work&quot; aria-label=&quot;how does it work permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How does it work?&lt;/h2&gt;
&lt;p&gt;The tool cdk-dia allows me to create AWS component diagrams automatically from my CDK code. It even follows the CDK Construct Level 1 and 2 abstractions. This means that e.g. the big components are symbols level 2 constructs and only the main component which usually gets &lt;strong&gt;Resource&lt;/strong&gt; as ID. Thus, only the really important AWS components are rendered. This is also known as collapsing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;content/cdk-dia/decorator_example_collapsed.png&quot; alt=&quot;collapsed&quot;&gt;(collapsed diagram)&lt;/p&gt;
&lt;p&gt;If you want to prevent collapsing, so that all underlying components are displayed, you can define a decorater in the code. How exactly this works you can see &lt;a href=&quot;https://github.com/pistazie/cdk-dia/tree/main/examples/experimental-decorator-example&quot;&gt;here&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;content/cdk-dia/decorator_example_non-collapsed.png&quot; alt=&quot;non-collapsed&quot;&gt;(non-collapsed diagram)&lt;/p&gt;
&lt;p&gt;This is what I used for my &lt;a href=&quot;https://github.com/mmuller88/cdk-private-asset-bucket/blob/main/src/private-asset-bucket.ts&quot;&gt;private asset bucket construct&lt;/a&gt; for example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;DiagramOptions&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; collapse&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CollapseTypes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FORCE_NON_COLLAPSE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PrivateAssetBucket&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Construct &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you want to know more about my Prowler Construct look &lt;a href=&quot;https://martinmueller.dev/cdk-private-assets-eng&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;comparison-with-aws-console-cloudformation-template&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#comparison-with-aws-console-cloudformation-template&quot; aria-label=&quot;comparison with aws console cloudformation template permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Comparison with AWS Console Cloudformation template&lt;/h2&gt;
&lt;p&gt;The AWS Console itself also has a diagram tool to visualize CloudFormation stacks called AWS CloudFormation Designer. You can find more information &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/working-with-templates-cfn-designer.html&quot;&gt;here&lt;/a&gt;. So I compared the designer with cdk-dia and I think cdk-dia is a lot better. cdk-dia manages to achieve a much better level of abstraction through collapsing. Also the graphics of cdk-dia are much nicer.&lt;/p&gt;
&lt;p&gt;In the following section I explain how you can implement cdk-dia in your CDK project.&lt;/p&gt;
&lt;h2 id=&quot;cdk-dia-script&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-dia-script&quot; aria-label=&quot;cdk dia script permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;cdk-dia script&lt;/h2&gt;
&lt;p&gt;For continuous updating of the cdk-dia diagrams it would be a good idea to write a small helper script in the package.json. But first you should make sure that cdk-dia is installed in the dev dependency scope with &lt;code&gt;yarn add cdk-dia -D&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then create a folder named diagrams and add this script to package.json.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ...
    &lt;span class=&quot;token property&quot;&gt;&quot;dia&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn cdk synth &amp;amp;&amp;amp; yarn cdk-dia &amp;amp;&amp;amp; mv diagram.png diagrams/dashboard.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ...
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The script first synthesizes the current CloudFormation templates. cdk-dia needs them to generate the diagram at all. Then &lt;code&gt;yarn cdk-dia&lt;/code&gt; creates the diagram and moves it to the diagrams folder.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;yarn cdk-dia&lt;/code&gt; also creates a diagram.dot file. I recommend to put the following two files into the .gitignore:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;txt&quot;&gt;&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;diagram.dot
diagram.png&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you like to split the diagram into single images, you can also render only single CDK stacks, e.g.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ...
    &lt;span class=&quot;token property&quot;&gt;&quot;dia&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn cdk synth &amp;amp;&amp;amp; yarn cdk-dia --stacks DashboardAppStack DashboardBackendStack &amp;amp;&amp;amp; mv diagram.png diagrams/dashboard.png &amp;amp;&amp;amp; yarn cdk-dia --stacks LandingPageStack &amp;amp;&amp;amp; mv diagram.png diagrams/landingpage.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ...
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also a good idea is to integrate the cdk-dia command into the cdk synth process. I included this for example in my &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler&quot;&gt;cdk Prowler Construct&lt;/a&gt;. In the package.json you will find the following script:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ...
    &lt;span class=&quot;token property&quot;&gt;&quot;synth&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn cdk synth &amp;amp;&amp;amp; yarn cdk-dia &amp;amp;&amp;amp; mv diagram.png diagrams/prowler.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ...
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now every time you run cdk synth manually, the cdk-dia diagram is rendered as well. Cool or? If you want to know more about my Prowler Construct look &lt;a href=&quot;https://martinmueller.dev/prowler-cdk-eng&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ideas&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#ideas&quot; aria-label=&quot;ideas permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ideas&lt;/h2&gt;
&lt;p&gt;In the previous post I introduced a small script that generates the cdk-dia diagrams. Unfortunately this script still has to be run manually. It would be mega cool if these diagrams update themselves quasi. This should be possible if you use Husky pre-commit hooks. I am currently trying this out. If you want to know more about it, let me know.&lt;/p&gt;
&lt;p&gt;Unfortunately cdk-dia couldn&apos;t render my CDK CD staging pipeline properly and I had to create it by hand in &lt;a href=&quot;https://draw.io&quot;&gt;https://draw.io&lt;/a&gt;. It would be super cool if cdk-dia could also map pipelines.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;If you also like to work with AWS component diagrams give cdk-dia a try! Here in the post I described how great the tool is and how easy it is to use. Feel free to contact me if you have any questions.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to English and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article, I&apos;m saying that feedback of any kind is welcome. In the future, I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Deploy Lambda@Edge with AWS CDK and TypeScript]]></title><description><![CDATA[Hi, Lambda@Edge are Lambdas that are executed in the AWS Cloudfront Locations. That can increase performance and reduce latency compared to…]]></description><link>https://martinmueller.dev/cdk-lambda-edge-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-lambda-edge-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><pubDate>Sun, 06 Feb 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/1d550404c811e2677e467b7684c33d7b/title.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;Lambda@Edge are Lambdas that are executed in the AWS Cloudfront Locations. That can increase performance and reduce latency compared to normal Lambda. Cloudfront together with Lambda@Edge can also being used as a proxy for a private S3 asset bucket.&lt;/p&gt;
&lt;p&gt;A token issued by Cognito is then used by Lambda@Edge to validate if the requester is allowed to access the S3 asset. I will describe more about this in the next blogpost. Here we will talk about how to create a Lambda@Edge with AWS CDK and Typescript.&lt;/p&gt;
&lt;h2 id=&quot;aws-cdk-lambdaedge&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aws-cdk-lambdaedge&quot; aria-label=&quot;aws cdk lambdaedge permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS CDK Lambda@Edge&lt;/h2&gt;
&lt;p&gt;Lambda@Edge already exists in the CDK cloudfront package &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/v1/docs/aws-cloudfront-readme.html&quot;&gt;https://docs.aws.amazon.com/cdk/api/v1/docs/aws-cloudfront-readme.html&lt;/a&gt;. Unfortunately, it is not directly possible to write the Lambda code with TypeScript as we are already used to it like from the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-lambda-nodejs.NodejsFunction.html&quot;&gt;NodejsFunction&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Well not with me! I took a closer look at NodejsFunction and EdgeFunction and transferred the TypeScript functionality from NodejsFunction to EdgeFunction. I simply define a CDK construct which is extended by EdgeFunction and take functions and properties from NodejsFunction. And here is the code of my nodejs-edge-function.ts construct:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cloudfront &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-cloudfront&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; core &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; bundling &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-lambda-nodejs/lib/bundling&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; lambda &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; fs &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;fs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; path &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;path&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; BundlingOptions &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-lambda-nodejs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; PackageManager &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-lambda-nodejs/lib/package-manager&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; callsites&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; findUpMultiple &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-lambda-nodejs/lib/util&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token comment&quot;&gt;/**
 * environment variables are not supported for Lambda@Edge
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodejsEdgeFunctionProps&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Omit&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;FunctionOptions&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;environment&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/**
   * Path to the entry file (JavaScript or TypeScript).
   *
   * @default - Derived from the name of the defining file and the construct&apos;s id.
   * If the `NodejsFunction` is defined in `stack.ts` with `my-handler` as id
   * (`new NodejsFunction(this, &apos;my-handler&apos;)`), the construct will look at `stack.my-handler.ts`
   * and `stack.my-handler.js`.
   */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; entry&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/**
     * The name of the exported handler in the entry file.
     *
     * @default handler
     */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; handler&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/**
     * The runtime environment. Only runtimes of the Node.js family are
     * supported.
     *
     * @default Runtime.NODEJS_14_X
     */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; runtime&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Runtime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/**
 * Whether to automatically reuse TCP connections when working with the AWS
 * SDK for JavaScript.
 *
 * This sets the `AWS_NODEJS_CONNECTION_REUSE_ENABLED` environment variable
 * to `1`.
 *
 * @see https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/node-reusing-connections.html
 *
 * @default true
 */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; awsSdkConnectionReuse&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/**
     * The path to the dependencies lock file (`yarn.lock` or `package-lock.json`).
     *
     * This will be used as the source for the volume mounted in the Docker
     * container.
     *
     * Modules specified in `nodeModules` will be installed using the right
     * installer (`npm` or `yarn`) along with this lock file.
     *
     * @default - the path is found by walking up parent directories searching for
     *   a `yarn.lock` or `package-lock.json` file
     */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; depsLockFilePath&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/**
     * Bundling options
     *
     * @default - use default bundling options: no minify, no sourcemap, all
     *   modules are bundled.
     */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; bundling&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; BundlingOptions&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/**
     * The path to the directory containing project config files (`package.json` or `tsconfig.json`)
     *
     * @default - the directory containing the `depsLockFilePath`
     */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; projectRoot&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;/**
     * The stack ID of Lambda@Edge function.
     *
     * @default - `edge-lambda-stack-${region}`
     * @stability stable
     */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; stackId&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodejsEdgeFunction&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cloudfront&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;experimental&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;EdgeFunction &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; NodejsEdgeFunctionProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; handler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handler &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;handler&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; runtime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODEJS_14_X&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; entry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findEntry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; architecture &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;architecture &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Architecture&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;X86_64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; depsLockFilePath &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findLockFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;depsLockFilePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; projectRoot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;projectRoot &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;depsLockFilePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            runtime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            stackId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stackId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            code&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; bundling&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Bundling&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bundle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bundling &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                architecture&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                runtime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                depsLockFilePath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                entry&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                projectRoot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            handler&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;index.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;handler&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * Checks given lock file or searches for a lock file
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findLockFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;depsLockFilePath&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;depsLockFilePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;depsLockFilePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Lock file at &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;depsLockFilePath&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; doesn&apos;t exist&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;statSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;depsLockFilePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;`depsLockFilePath` should point to a file&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;depsLockFilePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lockFiles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findUpMultiple&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        PackageManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PNPM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lockFile&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        PackageManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;YARN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lockFile&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        PackageManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NPM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lockFile&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lockFiles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Cannot find a package lock file (`pnpm-lock.yaml`, `yarn.lock` or `package-lock.json`). Please specify it with `depsFileLockPath`.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lockFiles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Multiple package lock files found: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;lockFiles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;, &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;. Please specify the desired one with \`depsFileLockPath\`.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; lockFiles&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * Searches for an entry file. Preference order is the following:
 * 1. Given entry file
 * 2. A .ts file named as the defining file with id as suffix (defining-file.id.ts)
 * 3. A .js file name as the defining file with id as suffix (defining-file.id.js)
 * 4. A .mjs file name as the defining file with id as suffix (defining-file.id.mjs)
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findEntry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entry&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;\.(jsx?|tsx?|mjs)$&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Only JavaScript or TypeScript entry files are supported.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Cannot find entry file at &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;entry&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; definingFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findDefiningFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; extname &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;definingFile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tsHandlerFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; definingFile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;extname&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.ts&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tsHandlerFile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; tsHandlerFile&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; jsHandlerFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; definingFile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;extname&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.js&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;jsHandlerFile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; jsHandlerFile&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mjsHandlerFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; definingFile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;extname&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.mjs&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mjsHandlerFile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; mjsHandlerFile&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Cannot find handler file &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;tsHandlerFile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;jsHandlerFile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; or &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;mjsHandlerFile&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
* Finds the name of the file where the `NodejsFunction` is defined
*/&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findDefiningFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; definingIndex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sites &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;callsites&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; site&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; sites&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;site&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFunctionName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;NodejsEdgeFunction&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// The next site is the site where the NodejsFunction was created&lt;/span&gt;
            definingIndex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;definingIndex &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;sites&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;definingIndex&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Cannot find defining file.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; sites&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;definingIndex&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFileName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As we can see, I have taken many private functions from the NodejsFunction. The construct is now imported into my CDK stack as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NodejsEdgeFunction &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./nodejs-edge-function&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; imageAccessFunction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodejsEdgeFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;edge&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Lambda@Edge code now behaves as we are used to from the NodejsFunction. The TypeScript Lambda can now be created in the src folder with the name STACK.edge.ts. Third-party libraries can be kept in the root package.json. Webpack as module bundler provides an efficient transformation into the JavaScript format.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;Mega cool or? With a few steps, I can now write my Lambda@Edge in TypeScript as usual. Of course, I plan to contribute the code to the aws-cdk repo. Hopefully my PR will be accepted soon and you won&apos;t have to bother importing my code here. Do you find my construct helpful? If so write me!&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to English and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article, I&apos;m saying that feedback of any kind is welcome. In the future, I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/1d550404c811e2677e467b7684c33d7b/title.png</featuredImage><media:content url="https://martinmueller.dev/static/1d550404c811e2677e467b7684c33d7b/title.png" medium="image"/></item><item><title><![CDATA[CDK BitBucket Staging Pipeline Learnings (Part 2)]]></title><description><![CDATA[Hi CDK folks. A few months ago I told you about my exciting project to build a CDK BitBucket Staging Pipeline. Since then, a lot has…]]></description><link>https://martinmueller.dev/cdk-bitbucket-pipeline-2-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-bitbucket-pipeline-2-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2022]]></category><category><![CDATA[bitbucket]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><pubDate>Fri, 07 Jan 2022 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/824a658e1f2926753db04efb7da87a25/bitbucket.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi CDK folks.&lt;/p&gt;
&lt;p&gt;A few months ago I told you about my exciting project to build a &lt;a href=&quot;https://martinmueller.dev/cdk-bitbucket-pipeline-eng&quot;&gt;CDK BitBucket Staging Pipeline&lt;/a&gt;. Since then, a lot has happened and we have continued to develop the pipeline.&lt;/p&gt;
&lt;h2 id=&quot;problems-with-cdk-cross-stack-references&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#problems-with-cdk-cross-stack-references&quot; aria-label=&quot;problems with cdk cross stack references permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Problems with CDK cross-stack references&lt;/h2&gt;
&lt;p&gt;CDK cross-stack references are CDK outputs passed as input to another CDK stack. Here is an example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/**
 * Stack that defines the bucket
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Producer&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stack &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; myBucket&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; s3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Bucket&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;App&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bucket &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;MyBucket&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      removalPolicy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RemovalPolicy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DESTROY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;myBucket &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bucket&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConsumerProps&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StackProps &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  userBucket&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; s3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IBucket&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * Stack that consumes the bucket
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Consumer&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stack &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;App&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ConsumerProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;iam&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;MyUser&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userBucket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grantReadWrite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; producer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Producer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ProducerStack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Consumer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ConsumerStack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userBucket&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; producer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;myBucket &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The example is taken from &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/v1/docs/aws-s3-readme.html#sharing-buckets-between-stacks&quot;&gt;https://docs.aws.amazon.com/cdk/api/v1/docs/aws-s3-readme.html#sharing-buckets-between-stacks&lt;/a&gt; . You can see very well how the &lt;strong&gt;myBucket&lt;/strong&gt; variable is created in the producer stack and how the consumer stack accesses it. This is a CDK cross-stack reference. And exactly those became problematic in our project.&lt;/p&gt;
&lt;p&gt;If num changes something in the producer stack that would result in deleting and then recreating the &lt;strong&gt;myBucket&lt;/strong&gt; variable, Cloudformation would respond with an error and cause a rollback. The reason is that since the consumer uses the cross-stack reference, it cannot be easily deleted. Such and other problems have made development difficult for us.&lt;/p&gt;
&lt;p&gt;But we think and hope that we have found a good solution. First, we have reduced the number of stacks from about 7 to 4. The reallocation of services into the 4 stacks is now based on DDD (Domain Driven Design). This means that all services that belong to a domain, such as the React app, are bundled into one stack. Before, the division was rather random and based on the AWS services such as the LambdaStack or the CognitoStack. Now the stacks are assigned according to their domains and are called FrontendSiteStack, FrontendBackendStack and MLStack.&lt;/p&gt;
&lt;p&gt;This new division has greatly reduced the number of cross-stack references. So that virtually only a few are left which we have outsourced to the CommonStack. However, the CommonStack serves as the parent stack to the other three. If now only cross-stack references between parent and children stacks exist, this should cause much less problems than references between sibling stacks.&lt;/p&gt;
&lt;h2 id=&quot;independent-stacks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#independent-stacks&quot; aria-label=&quot;independent stacks permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Independent Stacks&lt;/h2&gt;
&lt;p&gt;The next challenge was that the developers would like to be able to deploy the three new stacks FrontendSiteStack, FrontendBackendStack and MLStack independently. Until now, all three were always deployed at the same time.&lt;/p&gt;
&lt;p&gt;To solve this problem, we decided to use &lt;a href=&quot;https://support.atlassian.com/bitbucket-cloud/docs/configure-bitbucket-pipelinesyml/&quot;&gt;Custom Variables&lt;/a&gt;. Custom Variables are variables that can be set on Custom Pipelines during execution. To be able to deploy the stacks independently of each other, the custom pipeline must be executed with the following variables:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;custom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;cdkDeploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; deployFrontendSite
          &lt;span class=&quot;token key atrule&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; deployFrontendBackend
          &lt;span class=&quot;token key atrule&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; deployML
          &lt;span class=&quot;token key atrule&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you start the cdkDeploy pipeline with the BitBucket UI you can change the three variables to true if needed. A simple bash command then checks if the variable is true or not:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; if &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &quot;$deployFrontendSite&quot; &lt;span class=&quot;token tag&quot;&gt;!=&lt;/span&gt; true &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;; then exit 0; fi &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So interactively by executing the custom pipeline and setting the variables the desired stack can be deployed. Very cool!&lt;/p&gt;
&lt;h2 id=&quot;stage&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#stage&quot; aria-label=&quot;stage permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Stage&lt;/h2&gt;
&lt;p&gt;The concept of a stage can make the CDK code much cleaner. A stage groups all CDK stacks that belong to a stage like dev or prod. Here is an example.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Stage&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/**
     * A stage which is a collection of stacks.
     *
     */&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; StageStackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; commonStack &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommonStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-CommonStack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FrontendBackendStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-FrontendBackendStack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; commonStack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      zone&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; commonStack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zone&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      vpc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; commonStack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vpc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      userPoolId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userPoolId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MLStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-MLStack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; commonStack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      zone&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; commonStack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zone&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      vpc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; commonStack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vpc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      enableAlarms&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enableLambdaAlarms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The stage is now simply imported into the main.ts:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Stage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; devEnv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userPoolId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;us-west-2_3zgoE123&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By using a stage wrapper class, we have made our code much cleaner and easier to maintain.&lt;/p&gt;
&lt;h2 id=&quot;what-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-next&quot; aria-label=&quot;what next permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What next?&lt;/h2&gt;
&lt;p&gt;A staging pipeline is already a good start to effectively and quickly develop new features and bring them into production. However, to develop even faster and more independent from other development teams, ephermal deployments are needed.&lt;/p&gt;
&lt;p&gt;Ephermal Deployments means that with each new branch potentially a completely new CDK Deployment can be played out which contains the changes of the branch. So the developers don&apos;t have to share the dev environment anymore to test new features. I am curious to see how we will do this.&lt;/p&gt;
&lt;p&gt;Our React frontend requires backend information at build time that is stored in a config file typical of AWS Amplify. These have to be laboriously kept up to date by hand. Therefore, it would be cool if we could enable the config file to be built dynamically before the build, similar to the Amplify CLI. Our initial idea is to enable this with AWS Api Gateway. The endpoint would then always send us the current backend data and we can save it as a config file.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;I still enjoy working with BitBucket Pipeline. It can be used to build great CDK deployment pipelines. In this post I described what new challenges we had and how we solved them. I&apos;m also very happy that the customer is now able to use the CDK pipeline themselves and is doing so more and more.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/824a658e1f2926753db04efb7da87a25/bitbucket.jpg</featuredImage><media:content url="https://martinmueller.dev/static/824a658e1f2926753db04efb7da87a25/bitbucket.jpg" medium="image"/></item><item><title><![CDATA[Asynchronous communication with AWS CDK EventBridge]]></title><description><![CDATA[Hi CDK folks For a startup I am building a security platform. The rough process for using the platform is something like this. The customer…]]></description><link>https://martinmueller.dev/cdk-eventbridge-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-eventbridge-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[eventbridge]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><category><![CDATA[dynamodb]]></category><pubDate>Sun, 14 Nov 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/6b94e5dc478b5f372c6b2a99b1a69310/dia.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi CDK folks&lt;/p&gt;
&lt;p&gt;For a startup I am building a security platform. The rough process for using the platform is something like this. The customer answers a few questions and then gets a security evaluation. For the prototype I decided to use AWS EventBridge. With this I achieve a decoupled and asynchronous communication between the services.&lt;/p&gt;
&lt;p&gt;This was the first time I used EventBridge and I am very excited about it. Since there isn&apos;t too much AWS CDK EventBridge material on the web yet, I wanted to share my experience with you.&lt;/p&gt;
&lt;p&gt;Below I describe the Security Platform in a little more detail and what my architecture looks like.&lt;/p&gt;
&lt;h2 id=&quot;security-platform&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#security-platform&quot; aria-label=&quot;security platform permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Security Platform&lt;/h2&gt;
&lt;p&gt;The user can answer some questions using desktop app or mobile app. The answers are stored in the user service and sent asynchronously to the security service. Once the processing is done in the security service, the user gets the result presented as a report.&lt;/p&gt;
&lt;h2 id=&quot;architecture&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#architecture&quot; aria-label=&quot;architecture permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Architecture&lt;/h2&gt;
&lt;p&gt;The prototype has three modules. These three modules are each implemented with their own CDK stack. These are the frontend, the user service and the security service.&lt;/p&gt;
&lt;h3 id=&quot;frontend&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#frontend&quot; aria-label=&quot;frontend permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Frontend&lt;/h3&gt;
&lt;p&gt;The frontend is a ReactTS app hosted in S3 via static web hosting. The app uses Amplify libraries for user management like sign up, recover password, login, logout. Also I use Amplify&apos;s GraphQl libraries as typed access to the AppSync in the user service. Also feel free to check out my other posts about &lt;a href=&quot;https://martinmueller.dev/tags/appsync&quot;&gt;Appsync&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After the user loges in he will answer som security questions. The answers then are send and stored to the user service via GraphQL queries. The frontend also has a list of security reports created by the security service.&lt;/p&gt;
&lt;h3 id=&quot;user-service&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#user-service&quot; aria-label=&quot;user service permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;User service&lt;/h3&gt;
&lt;p&gt;Via AppSync the answers are stored in a DynamoDB table. From there, a DynamoDB Stream Lambda listens for new or changed answer records. The Lambda then writes the answer record as a &lt;strong&gt;AnswerEvent&lt;/strong&gt; to the EventBridge EventBus. The EventBus forwards the AnswerEvent to the Security.&lt;/p&gt;
&lt;p&gt;After the security service has processed the AnswerEvent, it sends a &lt;strong&gt;ReportEvent&lt;/strong&gt; containing a report back to the user service via the EventBus. A Report Lambda in the user service then receives the ReportEvent and writes the report to a Report DynamoDB table via GraphQL mutation.&lt;/p&gt;
&lt;p&gt;The frontend has a GraphQl subscription for newly appearing reports and thus the list of reports is automatically updated if a new report arrives.&lt;/p&gt;
&lt;h3 id=&quot;security-service&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#security-service&quot; aria-label=&quot;security service permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Security Service&lt;/h3&gt;
&lt;p&gt;The security service receives an AnswerEvent from the user service. A Report Lambda then receives the AnswerEvent unwrappes the answer and processes it into a report. The report is then packed into a ReportEvent and sent back to the user service.&lt;/p&gt;
&lt;p&gt;At the moment it is sufficient to use a Lambda to create the report. However, this could change in the future as the report will become more complex and, for example, will also use third party APIs. Then a more complex workflow could be required. With the use of this event architecture this should not be a problem.&lt;/p&gt;
&lt;h3 id=&quot;eventbridge&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#eventbridge&quot; aria-label=&quot;eventbridge permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;EventBridge&lt;/h3&gt;
&lt;p&gt;To send events between the user service and the security service, I use the default EventBus. The AnswerEvent and ReportEvent look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Answer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Report &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../frontend/src/lib/api&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnswerEvent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  answer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Answer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  state&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; State&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ReportEvent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  report&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Report&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Interestingly here is that for the definition of the events I simply reuse the GraphQL wrapper classes generated by AppSync in the frontend under ../frontend/src/lib/api.&lt;/p&gt;
&lt;p&gt;Now I need to define the lambdas which pack the respective event into the default EventBus. Here for example you see the lambda which packs the AnswerEvent into the EventBus.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-sdk&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; EventBridge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;EventBridge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DynamoDBStreamEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; answer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Answer &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// unmarshall DynamoDBStreamEvent&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; answerEvent&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AnswerEvent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    answer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    state&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; State&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;new&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; params&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;EventBridge&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Types&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PutEventsRequest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Entries&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Detail&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;answerEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        DetailType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DetailType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AnswerEvent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        EventBusName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;default&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        Source&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Source&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userServiceDdbStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        Time&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; EventBridge&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;putEvents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the EventStack, rules and targets have to be defined.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; answerRule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Rule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;answerRule&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eventPattern&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    source&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Source&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userServiceDdbStream&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
answerRule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addTarget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LambdaFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ratingLambda&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; reportRule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Rule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;reportRule&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eventPattern&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    source&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Source&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ratingServiceLambda&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
reportRule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addTarget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LambdaFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getReportEventLambda&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;Having services communicate with each other asynchronously is awesome and exciting. With AWS EventBridge and AWS CDK, it&apos;s also a wonderful developer experience. I am very excited to see where the security platform is going :). Let me know your thoughts!&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/6b94e5dc478b5f372c6b2a99b1a69310/dia.png</featuredImage><media:content url="https://martinmueller.dev/static/6b94e5dc478b5f372c6b2a99b1a69310/dia.png" medium="image"/></item><item><title><![CDATA[A CDK BitBucket Staging Pipeline]]></title><description><![CDATA[I have been working for a client with very exciting AWS CDK tasks. The customer is heavily into the Atlassian ecosystem. BitBucket is used…]]></description><link>https://martinmueller.dev/cdk-bitbucket-pipeline-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-bitbucket-pipeline-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[bitbucket]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><pubDate>Sun, 31 Oct 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/824a658e1f2926753db04efb7da87a25/bitbucket.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;I have been working for a client with very exciting AWS CDK tasks. The customer is heavily into the Atlassian ecosystem. BitBucket is used to host the code. Now the customer wants to move more into the DevOps space and manage their AWS deployments with AWS CDK as well. For this purpose, the existing AWS infrastructure needs to be translated into CDK. Additionally, a staging deployment pipeline should deploy the CDK stacks on a dev, qa and prod stages. Happy to help there :).&lt;/p&gt;
&lt;h2 id=&quot;disclaimer&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#disclaimer&quot; aria-label=&quot;disclaimer permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Disclaimer&lt;/h2&gt;
&lt;p&gt;Even though I already have a lot of experience with CDK (see &lt;a href=&quot;https://martinmueller.dev/tags/cdk&quot;&gt;here&lt;/a&gt;), I don&apos;t know much about BitBucket. So I don&apos;t know if my approach is ideal, but at the time of writing this article, it works quite well :).&lt;/p&gt;
&lt;p&gt;I&apos;m writing this article mainly because I haven&apos;t found any other helpful posts or instructions how to build a CDK staging deployment pipeline using BitBucket. So maybe if you have a similar task you might can use this post to help you getting started.&lt;/p&gt;
&lt;h2 id=&quot;which-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#which-pipeline&quot; aria-label=&quot;which pipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Which pipeline?&lt;/h2&gt;
&lt;p&gt;Now, of course, the question was where should the CDK staging deployment pipeline live? The choices were AWS CodePipeline or BitBucket&apos;s pipeline.&lt;/p&gt;
&lt;h2 id=&quot;maybe-aws-codepipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#maybe-aws-codepipeline&quot; aria-label=&quot;maybe aws codepipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Maybe AWS CodePipeline?&lt;/h2&gt;
&lt;p&gt;The advantage of AWS CodePipeline would be that there is already an ingenious AWS CDK Staging Pipeline Construct like the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/pipelines-readme.html&quot;&gt;CDK Pipeline&lt;/a&gt; . This would give you almost everything your DevOps heart desires, e.g. a synth action where the Cloudformation template is generated from CDK and deploy actions which then deploy to the respective stages. Also very useful are the optional actions that can be executed after the deploy action. Thus, for example, integration tests can be executed after the deploy. It is also very nice that the pipeline is defined in TypeScript. That provides documentation and specifies a certain standard through the typing for how a pipeline should look like.&lt;/p&gt;
&lt;h2 id=&quot;or-bitbuckets-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#or-bitbuckets-pipeline&quot; aria-label=&quot;or bitbuckets pipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Or BitBucket&apos;s pipeline?&lt;/h2&gt;
&lt;p&gt;The customer already uses BitBucket&apos;s pipeline for testing, linting and creating builds. Therefore, it would be undesired if the customer would be forced to switch back and forth between the two pipeline dashboards AWS CodePipeline and BitBucket&apos;s Pipeline. In addition, all functions of the AWS CodePipeline and the CDK Pipeline Construct can be reprogrammed with BitBucket&apos;s Pipeline.&lt;/p&gt;
&lt;p&gt;A pretty cool feature that AWS CodePipeline doesn&apos;t have is skipping steps if the specified subdirectory hasn&apos;t been changed. Here is an example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Synth CDK app
    &lt;span class=&quot;token key atrule&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;changesets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;includePaths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bitbucket-pipelines.yml&quot;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;devops/**&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; echo &quot;synth cdk app&quot;
      &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I miss such a cool feature in AWS CodePipeline. Also, the customer uses a monorepo. So all projects are in one BitBucket repository. This would also be very disadvantageous for AWS CodePipeline since it would always trigger a pipeline run for every commit.&lt;/p&gt;
&lt;p&gt;Considering all the pros and cons, we decided to use BitBuckets&apos;s Codepipeline as our CDK staging deployment pipeline.&lt;/p&gt;
&lt;h2 id=&quot;folder-structure&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#folder-structure&quot; aria-label=&quot;folder structure permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Folder structure&lt;/h2&gt;
&lt;p&gt;As mentioned earlier, the customer has a monorepo and of course they would like to keep that. We have now decided on the following folder structure:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;devops &lt;span class=&quot;token comment&quot;&gt;# Contains AWS CDK dependencies and CDK Apps&lt;/span&gt;
devops/&lt;span class=&quot;token variable&quot;&gt;${STAGE}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Contains stage specific scripts like bootstrap command&lt;/span&gt;
devops/&lt;span class=&quot;token variable&quot;&gt;${STAGE}&lt;/span&gt;/vpc &lt;span class=&quot;token comment&quot;&gt;# VPC CDK App&lt;/span&gt;
devops/&lt;span class=&quot;token variable&quot;&gt;${STAGE}&lt;/span&gt;/cognito &lt;span class=&quot;token comment&quot;&gt;# Cognito CDK App&lt;/span&gt;
devops/&lt;span class=&quot;token variable&quot;&gt;${STAGE}&lt;/span&gt;/website &lt;span class=&quot;token comment&quot;&gt;# S3 Website CDK App&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;STAGE is either dev, qa or prod .&lt;/p&gt;
&lt;p&gt;In the &lt;strong&gt;devops&lt;/strong&gt; folder are the AWS CDK dependencies. Via package.json all needed CDK libraries are loaded e.g. :&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ...
    &lt;span class=&quot;token property&quot;&gt;&quot;@aws-cdk/aws-s3&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.130.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;@aws-cdk/aws-cloudfront&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.130.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;@aws-cdk/aws-cloudfront-origins&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.130.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;@aws-cdk/aws-s3-deployment&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.130.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ...
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also, the devops/package.json includes a script to bootstrap the build AWS account and synthesize it. The build AWS account is the account from where the stages are managed. Synthesizing is the process of transforming the CDK app into one or more Cloudformation templates:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ...
  &lt;span class=&quot;token property&quot;&gt;&quot;synth&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn build &amp;amp;&amp;amp; yarn cdk synth&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;bootstrap&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn build &amp;amp;&amp;amp; yarn cdk bootstrap --trust 11111111,222222,3333333 --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess aws://44444444/us-east-1&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The bootstrap command creates a CDK helper stack in build account 44444444 and trusts all stages dev = 11111111, qa = 222222, prod = 3333333. Trusted here means that a cross account deploy permission is added to the CDK helper stack role. This allows the build account to deploy to the different stage accounts. It is also very important that the stage accounts must perform a bootstrap. The bootstrap command can be found in devops/${STAGE}/package.json e.g. for dev:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&quot;scripts&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  ...
  &lt;span class=&quot;token property&quot;&gt;&quot;bootstrap&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yarn cdk bootstrap --trust 44444444 --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess aws://$111111/us-east-1&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see here, the stage account e.g. dev=11111111 must also bootstrap the build account 44444444. These bootstraps can be a bit confusing, but fortunately don&apos;t need to be done often. I still recommend to document the bootstrap process well in e.g. the Readme.md . In general I think a good documentation is very very helpful :).&lt;/p&gt;
&lt;h2 id=&quot;example-vpc&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#example-vpc&quot; aria-label=&quot;example vpc permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Example VPC&lt;/h2&gt;
&lt;p&gt;In each stage there should be a VPC where private infrastructure like Postgres DBs should be deployed. So each stage contains a VPC subdirectory devops/${STAGE}/vpc . There in a main.ts is the CDK code. I show this here with the dev stage:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cdk &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; VpcStack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../../components/vpc-stack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; env &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;../package.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;DevVpcStack&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;App&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VpcStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-VpcStack&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since each stage needs a VPC, it makes sense to place the common VPC CDK code in a shared component under the devops/components folder:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VpcStack&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stack &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  vpc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Vpc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; VpcStackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vpc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ec2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Vpc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vpc&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; maxAzs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The respective VPC is then loaded in devops/src/main.ts:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cdk &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; DevVpcStack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../dev/vpc/main&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ProdVpcStack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../prod/vpc/main&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; SqaVpcStack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../sqa/vpc/main&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; StagingVpcStack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../staging/vpc/main&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// vpcs&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; devVpc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DevVpcStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vpc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sqaVpc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SqaVpcStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vpc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stagingVpc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;StagingVpcStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vpc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prodVpc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ProdVpcStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vpc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Admittedly, artificially splitting the stages into devops/${STAGE}/vpc and then merging them into devops/src/main.ts is a bit weird and may not be ideal. Alternatively, everything could just be written to devops/src/main.ts. However, we hope to have a better overview of the &quot;individual&quot; CDK stacks this way.&lt;/p&gt;
&lt;h2 id=&quot;bitbucket-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#bitbucket-pipeline&quot; aria-label=&quot;bitbucket pipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bitbucket pipeline&lt;/h2&gt;
&lt;p&gt;The Bitbucket pipeline now roughly goes through the following steps. First, tests are run in parallel and builds are build. Among the builds are, for example, different React builds for the different stages. After that, the CDK synth is run using &lt;code&gt;yarn cdk synth&lt;/code&gt;. During synth, assets such as the different React builds are uploaded to S3:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; synth CDK app
  &lt;span class=&quot;token key atrule&quot;&gt;caches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;custom
  &lt;span class=&quot;token key atrule&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;changesets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;includePaths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bitbucket-pipelines.yml&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;devops/**&quot;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_REGION=us&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;west&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_BUILD
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_KEY_BUILD
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; cd devops
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; yarn synth
  &lt;span class=&quot;token key atrule&quot;&gt;artifacts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; devops/cdk.out/&lt;span class=&quot;token important&quot;&gt;**&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After the synth, the first stage dev can now apply the cloudformation templates synthesized by CDK. For this I use e.g. this CDK command:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; cdk deploy &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdk.out/&apos;&lt;/span&gt; dev-VpcStack --require-approval never&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The cdk.out folder was previously designated as an artifact in the CDK synth step and is now reused for the respective stages (dev in this case) and CDK stacks. The pipeline yaml code looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy vpc to dev
        &lt;span class=&quot;token key atrule&quot;&gt;caches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;custom
        &lt;span class=&quot;token key atrule&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;changesets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;includePaths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bitbucket-pipelines.yml&quot;&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;devops/**&quot;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_REGION=us&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;west&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_BUILD
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_KEY_BUILD
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; cd devops/dev/vpc &lt;span class=&quot;token important&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn deploy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;cdk&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;stage
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; cd ../hasura &lt;span class=&quot;token important&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn deploy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;cdk&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;stage
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Diff qa
        &lt;span class=&quot;token key atrule&quot;&gt;caches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;custom
        &lt;span class=&quot;token key atrule&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;changesets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;includePaths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bitbucket-pipelines.yml&quot;&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;devops/**&quot;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_REGION=us&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;west&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_BUILD
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_KEY_BUILD
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; cd devops/qa &lt;span class=&quot;token important&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn diff
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Approval deploy qa
        &lt;span class=&quot;token key atrule&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; manual
        &lt;span class=&quot;token key atrule&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;changesets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;includePaths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bitbucket-pipelines.yml&quot;&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;devops/**&quot;&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; dashboard/&lt;span class=&quot;token important&quot;&gt;**&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; echo &quot;Deploy&quot;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# qa stage simila looking to dev&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So it is deployed directly to the dev stage. A diff to the next stage qa is also created in parallel. In order to also perform the qa deploy, the &lt;strong&gt;Approval deploy qa&lt;/strong&gt; step must be approved via a manual trigger. If you agree, the whole process in qa runs analog to dev.&lt;/p&gt;
&lt;h2 id=&quot;what-next&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#what-next&quot; aria-label=&quot;what next permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What next?&lt;/h2&gt;
&lt;p&gt;For the sake of clarity, we are still missing a kind of dashboard to display the most important CfnOutput URLs, such as the cloudfront urls of the React apps. We also want to know which commit was used for the respective deploy. For this purpose, a dashboard that can find out the current deployments and their commit ID via Lambda and probably also display them directly would be very suitable.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#summary&quot; aria-label=&quot;summary permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Summary&lt;/h2&gt;
&lt;p&gt;Working with BitBucket as a repository is mega cool. I had a lot of fun building a CDK staging deployment pipeline under these circumstances. Here I described roughly how this pipeline looks like and what our reasons were to build this pipeline this way. Only time will tell if these were good decisions when the customer actually uses the pipeline. Do you think we missed something or do you have ideas what can be done better? Then please write me :).&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/824a658e1f2926753db04efb7da87a25/bitbucket.jpg</featuredImage><media:content url="https://martinmueller.dev/static/824a658e1f2926753db04efb7da87a25/bitbucket.jpg" medium="image"/></item><item><title><![CDATA[Security, Best Practice and Hardening Checks with the Prowler AMI]]></title><description><![CDATA[Prowler Video
(Click me :D) Hi Folks! Developing in AWS is fun and the possibilities to build cool stuff seem endless. But are these cool…]]></description><link>https://martinmueller.dev/prowler-ami-eng/</link><guid isPermaLink="false">https://martinmueller.dev/prowler-ami-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[github]]></category><category><![CDATA[prowler]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><category><![CDATA[security]]></category><pubDate>Fri, 27 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=4JYaGylXEMc&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/4JYaGylXEMc/0.jpg&quot; alt=&quot;Prowler Video&quot;&gt;&lt;/a&gt;
(Click me :D)&lt;/p&gt;
&lt;p&gt;Hi Folks!&lt;/p&gt;
&lt;p&gt;Developing in AWS is fun and the possibilities to build cool stuff seem endless. But are these cool things secure and do they follow AWS&apos;s best practices? With &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI&lt;/a&gt; you can check just that with far over 180 checks for many services in all your regions. For just $1, an Ec2 instance started with the Prowler AMI builds the &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler&quot;&gt;cdk-prowler&lt;/a&gt; into your account. This will automatically start a CodeBuild that runs the checks. At the end you get an evaluation of the checks. The report contains information if the check was successful, the severity, a risk description and how to fix the problem.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 50.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAJXRFWHRDcmVhdGlvbgBNbyAxNiBBdWcgMjAyMSAxMDoxNjowMSBDRVNU1P0F9AAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AAAHJSURBVHjaZVJNT9tAEPX/6q1H/kGPvfXvVKBCShQ+jrQJvZVC0xaBkJD4AVUhosRJkON47djeXXvt9WNmQ1AA208z+2Z2dt6sva3tDlrtDto7e9ju7GJj8zPWP7Wc/bix6bDkVsH8S47haa2hlEJd11h9mqYBx4qigLX2WYzXucxf7eHHE0IgjhMkSQpTGkdyYlmWmEzuEQRTpGkGY4xDVVWQUhIfuBzOXYXHBaazAG/X3uD9h3f4c95/KjoeTzD0R4gigTAMwYcbKshdM6dIAXfLapZwBf2xj85+C+39LVxcnj3J4u5ms8gpYJtm2bORvByFK6iUpEDzKsDSGOwv5Sz4xTjY8pp9HgUX57vwhvcCgZC4HYW4G00o0SDPc5I7ptmlTh77LJc3RVHk5M7nKXGxW3M+Hz6dhnQpmcJcFoidpW4bi6IskMwTxEkCXWj4/hBpnsHSG4QB8bFbR4KKxwKCILVCOKOCpaSb09Q+/QFNTdJ5LI9oShp01cAos4jRx76trPM5VusKtaxgtXUx7/vtGQ6uj9C7PsZXwpe/R+jenODw/y98I3SJOxz0cUA8W0b33zF6Nz8p9wd6g9/oDk7Qu+vjNLzCAwpj4Degmgs+AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/cdd328b0cb3a830b6500095503e2b2da/f1512/html-out.webp 200w,
/static/cdd328b0cb3a830b6500095503e2b2da/f59aa/html-out.webp 400w,
/static/cdd328b0cb3a830b6500095503e2b2da/47a22/html-out.webp 800w,
/static/cdd328b0cb3a830b6500095503e2b2da/5bb53/html-out.webp 1200w,
/static/cdd328b0cb3a830b6500095503e2b2da/485a2/html-out.webp 1600w,
/static/cdd328b0cb3a830b6500095503e2b2da/2c6ed/html-out.webp 1833w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/cdd328b0cb3a830b6500095503e2b2da/f8f3a/html-out.png 200w,
/static/cdd328b0cb3a830b6500095503e2b2da/6a8a8/html-out.png 400w,
/static/cdd328b0cb3a830b6500095503e2b2da/7842b/html-out.png 800w,
/static/cdd328b0cb3a830b6500095503e2b2da/5ece7/html-out.png 1200w,
/static/cdd328b0cb3a830b6500095503e2b2da/0d4f8/html-out.png 1600w,
/static/cdd328b0cb3a830b6500095503e2b2da/4c920/html-out.png 1833w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/cdd328b0cb3a830b6500095503e2b2da/7842b/html-out.png&quot;
            alt=&quot;HTML Report&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In the next section I explain how exactly Prowler performs the checks.&lt;/p&gt;
&lt;h1&gt;Prowler Scan&lt;/h1&gt;
&lt;p&gt;The Prowler AMI uses the Github &lt;a href=&quot;https://github.com/toniblyx/prowler&quot;&gt;Prowler Tool&lt;/a&gt;. If you want to try Prowler locally, use the instructions from the &lt;a href=&quot;https://github.com/toniblyx/prowler#requirements-and-installation&quot;&gt;Readme&lt;/a&gt;. Prowler can then be run either as a script with &lt;code&gt;./prowler&lt;/code&gt; or as a Docker container. Basically, Prowler then runs through the checks using the AWS CLI from the &lt;a href=&quot;https://github.com/toniblyx/prowler/tree/master/checks&quot;&gt;check Folder&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After running the checks, an HTML report is saved to an S3 bucket named prowleraudit-stack-prowlerauditreportbucket (see image from above). The HTML report now lists all findings of the performed checks. Since the recently released Prowler version 2.5.0 these can be filtered.&lt;/p&gt;
&lt;h1&gt;Run Prowler with AMI&lt;/h1&gt;
&lt;p&gt;As mentioned before you can deploy Prowler with my &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI&lt;/a&gt; to your account. In this section I will explain you how to do that.&lt;/p&gt;
&lt;p&gt;First of course you click on the &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI&lt;/a&gt; link and subscribe to the AMI. Subscribing takes a little while. After the subscription is finished click on &quot;Continue to Configure&quot;. Select the latest Prowler version and the region in which you want to run the Prowler checks. Then click on &quot;Continue to Launch&quot;. Now very important at &quot;Choose Action&quot; you have to select &quot;Launch through Ec2&quot;. Now you will be redirected to Ec2 in the AWS Console.&lt;/p&gt;
&lt;p&gt;Now select the pre-selected instance type which should be t2.micro. Then click on &quot;Next: Configure Instance Details&quot;. For the IAM role you need an Ec2 role that has administrator privilege. If the role does not exist yet click on &quot;Create new IAM role&quot; and create an AWS service role for Ec2 with the AdministratorAccess Policy. The Prowler AMI needs this permission to deploy the CDK stack on your system.&lt;/p&gt;
&lt;p&gt;Alternatively you can call Prowler directly from the Ec2 AWS Console. Just go to Ec2 --&gt; Instances --&gt; Launch Instances in the AWS Console and search for Prowler. The rest is the same as described in the previous section.&lt;/p&gt;
&lt;p&gt;Now the Prowler Cloudformation stack is deployed and the Prowler check is started using CodeBuild. At the end the HTML report ends up in the S3 bucket prowleraudit-stack-prowlerauditreportbucket .&lt;/p&gt;
&lt;p&gt;The Ec2 instance is only needed to deploy the Cloudformation stack and should be terminated after the stack is finished to save costs.&lt;/p&gt;
&lt;h1&gt;Rerun Prowler with AMI&lt;/h1&gt;
&lt;p&gt;To run the Prowler scan again, you only run the AMI again. The Prowler stack will be triggered to run the scan again.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Prowler is a great tool to check your AWS account. With further over 100 checks, it gives me useful feedback on settings that don&apos;t follow best practices. Thus, I achieve a higher level of security in my AWS accounts. With my &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI&lt;/a&gt; it is very easy to run the tool in the account. Feel free to try Prowler AMI and tell me about your experience :).&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[Automated AWS Security Feedback with Prowler and AWS CDK]]></title><description><![CDATA[Hi Folks! Toni De La Fluente has developed the super cool AWS Security Tool Prowler. Prowler is a cli tool for performing and consulting AWS…]]></description><link>https://martinmueller.dev/prowler-cdk-eng/</link><guid isPermaLink="false">https://martinmueller.dev/prowler-cdk-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[github]]></category><category><![CDATA[prowler]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><category><![CDATA[security]]></category><pubDate>Tue, 17 Aug 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/10670f5ae1005be2500d392ad825b89a/logo.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi Folks!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/ToniBlyx&quot;&gt;Toni De La Fluente&lt;/a&gt; has developed the super cool AWS Security Tool &lt;a href=&quot;https://github.com/toniblyx/prowler&quot;&gt;Prowler&lt;/a&gt;. Prowler is a cli tool for performing and consulting AWS Security Assessment, Auditing, Hardening and Incident Response. With more than 180 checks, Prowler provides the most comprehensive security checks offering for AWS. If you want to know more about Prowler visit the &lt;a href=&quot;https://github.com/toniblyx/prowler&quot;&gt;Prowler Github&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;I use Prowler a lot and decided to write an AWS CDK Custom Construct for it. In the past I have already created some custom constructs like my favorite the &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-staging-pipeline&quot;&gt;staging pipeline&lt;/a&gt; or the &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-build-badge&quot;&gt;build badge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, if you just want to run Prowler for your AWS account and don&apos;t want to try the Custom Construct, I have good news. For the AWS Marketplace, I&apos;ve created an AMI that automatically installs the cdk-prowler construct into your account. The AMI is available in the AMI Store. Just search for Prowler or use the &lt;a href=&quot;https://aws.amazon.com/marketplace/pp/prodview-jlwcdlc3weta6&quot;&gt;Prowler AMI Link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then Prowler will run the security check and you will find the security findings in an S3 bucket named prowleraudit-stack-prowlerauditreportbucket the HTML report:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 47%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAACG0lEQVR42m2NS08TARSF5x+501DQaEICuNHIK5EQXoFo3LAxJCbGVKgxceXShS6IG+kLyiMQBPpiKJ1SQlMeAopSaYeotBTaaTszfM4MYuLjJif33nPOPVcILS4hRqJIsThhMcLi0rK1m5j3By3uYr+AeTO3EPjDewGhWCyiKAp/l6Zp5PN5dF3/RyuXy5RKJf5XQskQz/QzHM/tPBl8REZOW4LJZ2SZ3PEx5UrFeqCqqvXg5PSUo6MsFYNXDd7SfnWhWFIoFAvMzE7wzv2W/dSeFaiqZohqdV3XrFnTzjlNN4PPd91ApVL6rQk7h6dsHRbIKDo5DfayCmv7P9iST9j9rrCZyRPbSZM8yLGROWb7W4Hk1yxrqRyJVBYpVWAlXWZVrvA5awS+XJ/EHnfyYs3Hmw9BHHE3jpiLIaM/S3h5GhthYPY1g5LT4k19UHJhl9wMxdzYV4z71Wker0zwamsB4dZ0H1XeRq6NtXJjso2a0RZszkaqPU1c9bVQ42qmevgONlcjVQZs3iZjbsY20kqVu4XLng6ueLq45Gqlff4hghyXOFgKk4lGyCUTHCyL7AX9pMQwshRhXwwRHR9l/f0Mu4F5voSDfAoF2A74+Wj4tsUom2KcjVCMdCKJcHe2n1pfO7en7tEzN8DN8W4avF3U+wxMdVE32kntcBv1zg4aRjppMPmxHuo8vYav2/A9oH68n+ve+/T5HfwE21pQ8T/ZiN8AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/d56f89a09ba9c59e4cebca1617799259/f1512/html-out.webp 200w,
/static/d56f89a09ba9c59e4cebca1617799259/f59aa/html-out.webp 400w,
/static/d56f89a09ba9c59e4cebca1617799259/47a22/html-out.webp 800w,
/static/d56f89a09ba9c59e4cebca1617799259/5bb53/html-out.webp 1200w,
/static/d56f89a09ba9c59e4cebca1617799259/485a2/html-out.webp 1600w,
/static/d56f89a09ba9c59e4cebca1617799259/a67c3/html-out.webp 1868w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/d56f89a09ba9c59e4cebca1617799259/f8f3a/html-out.png 200w,
/static/d56f89a09ba9c59e4cebca1617799259/6a8a8/html-out.png 400w,
/static/d56f89a09ba9c59e4cebca1617799259/7842b/html-out.png 800w,
/static/d56f89a09ba9c59e4cebca1617799259/5ece7/html-out.png 1200w,
/static/d56f89a09ba9c59e4cebca1617799259/0d4f8/html-out.png 1600w,
/static/d56f89a09ba9c59e4cebca1617799259/fc2f5/html-out.png 1868w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/d56f89a09ba9c59e4cebca1617799259/7842b/html-out.png&quot;
            alt=&quot;html results&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Or also in the codebuild report group:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 59.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAAsTAAALEwEAmpwYAAACHUlEQVR42m1SXYvTQBTNX/TNV0HwUXxTEKkoqOyu1VXp1uIXPgi++SAIfoCKHyhuXZ9EF2G3TbbZpknaJDOTpOnxnmlT6uLAYWbuzD333A9nfbONtVsdNFsPcfXmXVxqtpa4fGPL4uLGHTSut9DYEFuzjc7jp3j78Qtev/uEN+8/o/XgCa5tdrB++x4crQ2MMahXlGTwwxjDaGzBsz8K4QURDmmLE4wnCcIoRDwew+Q5ZrOZ9eXuJEmKMI6RZBnK6RS/fu+iu/MD37a76H7fwX6vh77rwvU89Puu3Pvz+8EA3mAg5BNMksSSp8LhpGmGQBRUVWUjDIMRPPk8CkP4wyEm4qC0tqBjJjtVacmKyJSyIBnvTiIOA8+1kklKgkRSqtdsYZ+K+rIsocSZ5xp8I5gdAzm5Voj9nnjOnXIxcoUqxIXnJ/G1cRzV7k9r45vrHaAoChxdzI7vjlJaUo5QiYGEyij7ofHyDM5tN6BfPcPe6WNzQklpb78H3/eXjSQRQZWWkB0LpF6US0JttP14/8MVvGifgt5aw5/zJ5aErO8wCJAfUblUyEgEO88aFRwD+VAKcfCoiUHzLMyhh4pOVkUBjhoV/ZdQm3nHuGzK2liVmcqWbWEjjMntebZCsErGALYpdQ3qLsfxGJHMZVEWMCSSprEJBBUQZrEnaWpBQWoxTs6qbDs2MugE069RLPCPTQJwhtNU2ZJlMock/AsbvYJYZZN+aQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/5789eef82febd007c69633b51b872f79/f1512/report-group-out.webp 200w,
/static/5789eef82febd007c69633b51b872f79/f59aa/report-group-out.webp 400w,
/static/5789eef82febd007c69633b51b872f79/47a22/report-group-out.webp 800w,
/static/5789eef82febd007c69633b51b872f79/5bb53/report-group-out.webp 1200w,
/static/5789eef82febd007c69633b51b872f79/c212b/report-group-out.webp 1474w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/5789eef82febd007c69633b51b872f79/f8f3a/report-group-out.png 200w,
/static/5789eef82febd007c69633b51b872f79/6a8a8/report-group-out.png 400w,
/static/5789eef82febd007c69633b51b872f79/7842b/report-group-out.png 800w,
/static/5789eef82febd007c69633b51b872f79/5ece7/report-group-out.png 1200w,
/static/5789eef82febd007c69633b51b872f79/4e08b/report-group-out.png 1474w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/5789eef82febd007c69633b51b872f79/7842b/report-group-out.png&quot;
            alt=&quot;Report group&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If you have any problems with the AMI, please write me.&lt;/p&gt;
&lt;p&gt;By buying the AMI you also support my free work to create such freely available products like the &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler&quot;&gt;cdk-prowler&lt;/a&gt; custom construct and the work on my blogpost. Thank you very much :)!&lt;/p&gt;
&lt;p&gt;In the next paragraphs I will explain why I think a CDK custom construct is useful and introduce you to the cdk-prowler custom construct. But first I have to explain what AWS CDK is.&lt;/p&gt;
&lt;h1&gt;AWS CDK&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt; is an open source framework for creating and managing AWS resources. By using languages familiar to the developer such as TypeScript or Python, the Infrastructure as Code is described. In doing so, CDK synthesizes the code into AWS Cloudformation Templates and can optionally deploy them right away.&lt;/p&gt;
&lt;p&gt;AWS CDK has been experiencing a steady growth of enthusiastic developers since 2019 and already has a strong and helpful community that is eg. very active on &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt;. There is of course much more to say about AWS CDK and I recommend you explore it. Drop me a line if you have any questions.&lt;/p&gt;
&lt;h1&gt;Motivation&lt;/h1&gt;
&lt;p&gt;AWS CDK Custom Constructs are quasi own library to encapsulate cloudformation resources. They can be downloaded from registries like npmjs.com or pypi.org. So it is extremely easy to integrate cdk-prowler into your CDK IDE environment. Also it is very easy to make changes to the cdk-prowler code and provide a new version to the respective restries. Much of this important but tedious work is already greatly simplified by &lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen AwsCdkConstructLibrary&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another reason for the Custom Construct is the &lt;a href=&quot;https://github.com/aws/jsii&quot;&gt;Jsii&lt;/a&gt; Library. With this mega cool library I can translate the cdk-prowler construct to different languages like Python, Java or CSharp and the developer can continue developing in his usual CDK language with cdk-prowler.&lt;/p&gt;
&lt;h1&gt;Beispiel&lt;/h1&gt;
&lt;p&gt;The cdk-Prowler Construct is on &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler&quot;&gt;GitHub&lt;/a&gt;. It must first be included in the package.json as a dependency and can then be used in the CDK stack.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ProwlerAudit &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdk-prowler&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stack &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Stack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ProwlerAudit-stack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProwlerAudit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ProwlerAudit&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;synth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The AWS CDK code shows how easy cdk-prowler can be deployed. Many additional functions like a scheduler are already available and can be activated and changed via the properties. Please have a look at the &lt;a href=&quot;https://github.com/mmuller88/cdk-prowler/blob/main/API.md&quot;&gt;API.md&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Outlook&lt;/h1&gt;
&lt;p&gt;Many cool features for cdk-prowler are planned. The development of new features is done in cooperation with &lt;a href=&quot;https://twitter.com/ToniBlyx&quot;&gt;Tony De La Fluente&lt;/a&gt; the creator of Prowler.&lt;/p&gt;
&lt;p&gt;Planned is to make Prowler multiaccount ready. So you have a centralized place for Prowler to check all accounts. Multiaccount should work with and without AWS organization.&lt;/p&gt;
&lt;p&gt;In the future, Prowler will no longer be run with Codebuild but with Fargate. This allows a more flexible further development of Prowler to parallelize scans, for example. Parallelizing Prowler scans is an important and much needed feature because with over 180 Prowler tests running sequentially, execution can take a long time.&lt;/p&gt;
&lt;p&gt;Also, Tony and I are thinking about an improved UI analysis tool with QuickSight. The Prowler HTML report is very useful but it is hard to send complex queries to the report. With QuickSight you have the possibility to define filters, variables, etc.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Prowler is mega cool and I love that it gives me automated feedback on security, best practices, etc. AWS CDK makes it easy to install ProwlerAudit and nest it with other services. Test the ProwlerAudit Construct and give me suggestions to make it even cooler. Feel free to create PRs for it in Github.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/10670f5ae1005be2500d392ad825b89a/logo.png</featuredImage><media:content url="https://martinmueller.dev/static/10670f5ae1005be2500d392ad825b89a/logo.png" medium="image"/></item><item><title><![CDATA[Wordpress Posts automated with AWS CDK]]></title><description><![CDATA[Hi Folks! My last post was about how to make a wordpress deployment more DevOps friendly using Docker and some cool scripts. Today I want to…]]></description><link>https://martinmueller.dev/wp-post-automation-cdk-eng/</link><guid isPermaLink="false">https://martinmueller.dev/wp-post-automation-cdk-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[github]]></category><category><![CDATA[docker]]></category><category><![CDATA[wordpress]]></category><category><![CDATA[cdk]]></category><pubDate>Sun, 08 Aug 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/128a7b075dbd336762bdacec9cf22e07/wp-aws.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi Folks!&lt;/p&gt;
&lt;p&gt;My &lt;a href=&quot;https://martinmueller.dev/wordpress-with-docker-eng&quot;&gt;last post&lt;/a&gt; was about how to make a wordpress deployment more DevOps friendly using Docker and some cool scripts. Today I want to talk about another exciting task. The customer wants new wordpress posts to be created automatically using AWS and when a video gets uploaded to S3. That sounds exciting so lets go. In the next few sections, I&apos;ll describe my solution.&lt;/p&gt;
&lt;h1&gt;Wordpress AWS solution&lt;/h1&gt;
&lt;p&gt;As described above, I want a wordpress post to be created after the video upload to S3. As well the video should be embedded in that post. For this I mainly need the two AWS services S3 and Lambda. The Lambda then needs to be set to run Lambda logic when uploading to S3.&lt;/p&gt;
&lt;p&gt;The Lambda should then log into the wordpress environment via SSH and create a new post via &lt;a href=&quot;https://developer.wordpress.org/cli/commands/post/create/&quot;&gt;WP CLI&lt;/a&gt;. I think it&apos;s pretty cool that wordpress has its own CLI. I can then use this to easily create new posts, for example.&lt;/p&gt;
&lt;p&gt;The configuration of the AWS services I do with AWS CDK. You can find the complete code in my Github repo &lt;a href=&quot;https://github.com/hacking-akademie/video-up&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;AWS CDK&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt; is an open source framework for creating and managing AWS resources. By using languages familiar to the developer such as TypeScript or Python, the Infrastructure as Code is described. In doing so, CDK synthesizes the code into AWS Cloudformation Templates and can optionally deploy them right away.&lt;/p&gt;
&lt;p&gt;AWS CDK has been experiencing a steady growth of enthusiastic developers since 2019 and already has a strong and helpful community that is eg. very active on &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt;. There is of course much more to say about AWS CDK and I recommend you explore it. Drop me a line if you have any questions.&lt;/p&gt;
&lt;p&gt;The wordpress S3 Lambda stack now looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; S3EventSource &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-lambda-event-sources&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; lambdajs &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-lambda-nodejs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; s3 &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-s3&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cdk &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; statement &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdk-iam-floyd&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UploadBucketStackProps&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StackProps &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UploadBucketStack&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stack &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UploadBucketStackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bucket &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;s3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;my-videos&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      bucketName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;my-videos&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      removalPolicy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RemovalPolicy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DESTROY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      autoDeleteObjects&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lambda &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;lambdajs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NodejsFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;upload-trigger&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      bundling&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        externalModules&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&apos;ssh2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        nodeModules&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&apos;ssh2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToRolePolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;statement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Secretsmanager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toGetSecretValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventSource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;S3EventSource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bucket&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      events&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;s3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;EventType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;OBJECT_CREATED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For the Lambda I decided to use the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda-nodejs.NodejsFunction.html&quot;&gt;NodeJsFunction Construct&lt;/a&gt; because it comes with many advantages like esbuild as package manager and I don&apos;t have to create a separate package.json for the Lambda because esbuild picks the needed library code from the main package.json.&lt;/p&gt;
&lt;p&gt;The ssh2 module for the lambda has to be loaded as an external module though. This simply means that esbuild is not used as package manager for this and the module is loaded completely.&lt;/p&gt;
&lt;p&gt;The code for the lambda function is shown and explained in the next section.&lt;/p&gt;
&lt;h1&gt;Lambda&lt;/h1&gt;
&lt;p&gt;The Lambda has as event source the S3 bucket and is executed when objects are created in the S3 bucket. Then the Lambda connects to the wordpress hoster via SSH and creates a wordpress post using &lt;a href=&quot;https://developer.wordpress.org/cli/commands/post/create/&quot;&gt;WP CLI&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; lambda &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-sdk&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NodeSSH &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;node-ssh&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; secretsmanager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SecretsManager&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;S3CreateEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;event: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; record &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Records&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sshKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; secretsmanager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getSecretValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; SecretId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sshkey&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SecretString&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ssh &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodeSSH&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; ssh&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    host&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;mywordpresshoster.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    username&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;wp&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    privateKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sshKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; objectKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Records&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;s3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; videoLink &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;s3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bucket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.s3.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;awsRegion&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.amazonaws.com/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;objectKey&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// eg. 001_41_Das-ist-die-erste-Lektion.mp4&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Kategorien: 41 - Grundlagen&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fileName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; objectKey&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// eg. 001_kategorie1_Das-ist-die-erste-Lektion&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; videoFormat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; objectKey&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// eg. mp4&lt;/span&gt;
  videoFormat&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; splittedFilename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fileName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;_&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; lection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;splittedFilename&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// eg. 1&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; category &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;splittedFilename&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// eg. 41&lt;/span&gt;
  category&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; splittedFilename&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// eg. Das ist die erste Lektion&lt;/span&gt;


  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;video info: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;lection&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;category&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;videoFormat&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wpContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;[vc_row][vc_column][vc_column_text]

Lektion &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;lection&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;

[/vc_column_text][us_separator][vc_column_text]

Here will be some content ...

&amp;lt;video poster=&quot;PATH-TO-STILL-IMAGE&quot; controls=&quot;controls&quot; controlsList=”nodownload” width=&quot;640&quot; height=&quot;360&quot;&gt;
    &amp;lt;source src=&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;videoLink&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; type=&quot;video/mp4&quot;&gt;
&amp;lt;/video&gt;

&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wpCommand &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;wp post create --post_title=&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; --post_categories=&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;category&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; --post_content=&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;wpContent&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// category?&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; ssh&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wpCommand&lt;span class=&quot;token comment&quot;&gt;/*, { cwd:&apos;/var/www&apos; }*/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;STDOUT: &apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stdout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;STDERR: &apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stderr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see I use the NodeSSH class from the node-ssh package to connect to the wordpress hoster. Then I pare some information from the S3 object key like the title or the lesson. At the end I just create the wordpress posts with the WP CLI.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Automating the creation of wordpress posts using AWS services is just mega cool. I built a small AWS CDK stack for this purpose. I&apos;m already very excited about what else can possibly be automated in wordpress :). Do you have any ideas? Then write me!&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/128a7b075dbd336762bdacec9cf22e07/wp-aws.jpg</featuredImage><media:content url="https://martinmueller.dev/static/128a7b075dbd336762bdacec9cf22e07/wp-aws.jpg" medium="image"/></item><item><title><![CDATA[Wordpress with Docker]]></title><description><![CDATA[Hi guys! For my newest customer I built a great AWS backend with AWS AppSync and many other great AWS services. But now I'm faced with the…]]></description><link>https://martinmueller.dev/wordpress-with-docker-eng/</link><guid isPermaLink="false">https://martinmueller.dev/wordpress-with-docker-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[github]]></category><category><![CDATA[docker]]></category><category><![CDATA[wordpress]]></category><pubDate>Sat, 03 Jul 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/e3afee2a76af2d42b1418e7e519608c5/docker-wordpress.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi guys!&lt;/p&gt;
&lt;p&gt;For my newest customer I built a great AWS backend with AWS AppSync and many other great AWS services. But now I&apos;m faced with the exciting task of making the AppSync or GraphQL API callable in a Wordpress frontend. I have heard a lot about wordpress but never worked with it.&lt;/p&gt;
&lt;p&gt;Also, this wordpress is hosted on &lt;a href=&quot;https://raidbox.de&quot;&gt;Raidbox.de&lt;/a&gt; which makes it a bit difficult to manage the deployment directly. Coming from the DevOps world I want to configure the Wordpress deployment as comfortable and automated as possible.&lt;/p&gt;
&lt;p&gt;I wanted three requirements to be met by the Wordpress deployment. First, Wordpress should be executable locally with minimal effort. Second, the Wordpress should be versioned with GitHub. And third, there should be a synchronization between the local wordpress and the wordpress hosted on Raidbox.&lt;/p&gt;
&lt;h1&gt;Wordpress&lt;/h1&gt;
&lt;p&gt;Wordpress is a content management system (CMS). It was developed to create blogposts. But it has developed a lot and is not only used for blogposts anymore. About so-called plugins new features are added to Wordpress. Such features can be a payment function. We ourselves use &lt;a href=&quot;https://digimember.de&quot;&gt;Digimember&lt;/a&gt; to manage a subscription payment system.&lt;/p&gt;
&lt;h1&gt;Wordpress with Docker&lt;/h1&gt;
&lt;p&gt;To solve my first problem, i.e. getting Wordpress to work locally, I decided to use Docker. Fortunately I was not the first one who tried or succeeded to do this. There are many good tutorials on the internet on how to set up a wordpress deployment with Docker. To orchestrate the Docker containers I use Docker Compose and here is the code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;3.3&apos;&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;wordpress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; db
    &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wordpress&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;5.7.2
    &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./wordpress_files&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/var/www/html
    &lt;span class=&quot;token key atrule&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;8080:80&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; always
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;WORDPRESS_DB_HOST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; db
      &lt;span class=&quot;token key atrule&quot;&gt;WORDPRESS_DB_USER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wordpressuser
      &lt;span class=&quot;token key atrule&quot;&gt;WORDPRESS_DB_NAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wordpress
      &lt;span class=&quot;token key atrule&quot;&gt;WORDPRESS_DB_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; geheim
      &lt;span class=&quot;token key atrule&quot;&gt;WORDPRESS_HOME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http://localhost:8080&apos;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;WORDPRESS_SITEURL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http://localhost:8080&apos;&lt;/span&gt;

  &lt;span class=&quot;token key atrule&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mysql&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5.7&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; db
    &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./db_data&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/var/lib/mysql
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./wordpress_files/wp&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;content/mysql&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;dump/wordpress.sql&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/docker&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;entrypoint&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;initdb.d/1_wordpress.sql&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;ro
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./scripts/wordpress_replacing.sql&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/docker&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;entrypoint&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;initdb.d/2_wordpress_replacing.sql&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;ro
    &lt;span class=&quot;token key atrule&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; always
    &lt;span class=&quot;token key atrule&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 3306&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3306&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; geheim
      &lt;span class=&quot;token key atrule&quot;&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wordpress
      &lt;span class=&quot;token key atrule&quot;&gt;MYSQL_USER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; wordpressuser
      &lt;span class=&quot;token key atrule&quot;&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; geheim

  &lt;span class=&quot;token key atrule&quot;&gt;phpmyadmin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; phpmyadmin/phpmyadmin
    &lt;span class=&quot;token key atrule&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; phpmyadmin
    &lt;span class=&quot;token key atrule&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; always
    &lt;span class=&quot;token key atrule&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;8081:80&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;PMA_HOST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; db
      &lt;span class=&quot;token key atrule&quot;&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; geheim&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first Docker container &lt;strong&gt;wordpress&lt;/strong&gt; is of course for wordpress. With the volume wordpress_files I persist the wordpress files.&lt;/p&gt;
&lt;p&gt;After that comes the &lt;strong&gt;db&lt;/strong&gt; container which deploys a MySQL database. Wordpress uses MySQL as database to store information like blogposts, sites, users, pluginconfigs and much more. The volume db persists the database. The next two volumes store SQL scripts in the container at /docker-entrypoint-initdb.d :&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;- ./wordpress_files/wp-content/mysql-dump/wordpress.sql:/docker-entrypoint-initdb.d/1_wordpress.sql:ro
- ./scripts/wordpress_replacing.sql:/docker-entrypoint-initdb.d/2_wordpress_replacing.sql:ro&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will execute the SQL scripts on first startup. The first script wordpress.sql contains the complete Wordpress MySQL database which was previously exported as a dump. The second script does a text replacing from the domain to localhost:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; wp_options &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; option_value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;option_value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https://www.example.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http://localhost:8080&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; option_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;home&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; option_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;siteurl&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; wp_posts &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; post_content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;post_content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https://www.example.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http://localhost:8080&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; wp_postmeta &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; meta_value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;meta_value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;https://www.example.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;http://localhost:8080&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is necessary because I want to get the deployment working locally.&lt;/p&gt;
&lt;p&gt;The last container phpmyadmin is a graphical administration for the MySQL DB.&lt;/p&gt;
&lt;h1&gt;GitHub&lt;/h1&gt;
&lt;p&gt;Pushing the code, the Wordpress files and the Docker Compose file to a GitHub repository is easy. Just create a new GitHub repository and copy and push the files to it.&lt;/p&gt;
&lt;h1&gt;Sync to Raidbox.de&lt;/h1&gt;
&lt;p&gt;As mentioned before, Raidbox.de is our hoster for Wordpress. To update the MySQL database and the Wordpress files there I decided to use rsync in combination with ssh. For this I have developed a workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;./scripts/syncWithStaging.sh&lt;/code&gt; pushes your local wordpress_files/wp-content, then dumps the staging mydb and then pulls the wordpress/wp-content including the dump. If there are changes now that probably means someone changed something directly over raidbox. Inspect the changes! If they are ok git commit the current status!&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;docker-compose down &amp;#x26;&amp;#x26; sudo rm -rf db_data &amp;#x26;&amp;#x26; docker-compose up -d --build&lt;/code&gt; and make your changes&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;./scripts/createMySqlDumpExport.sh&lt;/code&gt; to export the local DB to mysql-dump-export&lt;/li&gt;
&lt;li&gt;apply the mysql-dump-export/wordpress.sql to the wordpress with using raidbox phpmyadmin&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;./scripts/syncWithStaging.sh&lt;/code&gt; for syncing / pushing the wp-content folder.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This sync workflow may be changed in the future and the number of steps reduced. As it is designed now, you can still add e.g. blogs via the normal wordpress editor accessible via Raidbox. These new blogposts will then not be lost in the next sync workflow. In the following I show the used scripts&lt;/p&gt;
&lt;h2 id=&quot;syncwithstagingsh&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#syncwithstagingsh&quot; aria-label=&quot;syncwithstagingsh permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;syncWithStaging.sh&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# push to remote&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;rsync&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-avzh&lt;/span&gt; --no-perms --no-owner --no-group &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ssh -i ~/.ssh/example&quot;&lt;/span&gt; ./wordpress_files/wp-content wp@b9emwoc.myraidbox.de:/home/wp/disk/wordpress

&lt;span class=&quot;token comment&quot;&gt;# create sql dump on raidbox.de&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; ~/.ssh/example wp@b9emwoc.myraidbox.de &lt;span class=&quot;token string&quot;&gt;&quot;mkdir -p /home/wp/disk/wordpress/wp-content/mysql-dump &amp;amp;&amp;amp; mysqldump -u wordpressuser --no-tablespaces --password=secret wordpress &gt; /home/wp/disk/wordpress/wp-content/mysql-dump/wordpress.sql&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# pull from remote&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;rsync&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-avzh&lt;/span&gt; --no-perms --no-owner --no-group &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ssh -i ~/.ssh/example&quot;&lt;/span&gt; wp@b9emwoc.myraidbox.de:/home/wp/disk/wordpress/wp-content ./wordpress_files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here you can see how with rsync, ssh and a private key (~/ssh/example) the wordpress files are first pushed and then pulled. Additionally the MySQL DB is dumped to Raidbox and pulled as well.&lt;/p&gt;
&lt;h2 id=&quot;createmysqldumpexportsh&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#createmysqldumpexportsh&quot; aria-label=&quot;createmysqldumpexportsh permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;createMySqlDumpExport.sh&lt;/h2&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# mysql export sql&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;CONTAINER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ps&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-aqf&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;name=db&quot;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$CONTAINER&lt;/span&gt; /usr/bin/mysqldump &lt;span class=&quot;token parameter variable&quot;&gt;-u&lt;/span&gt; wordpressuser --no-tablespaces &lt;span class=&quot;token parameter variable&quot;&gt;--password&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;secret wordpress_staging &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ./mysql-dump-export/wordpress.sql

&lt;span class=&quot;token comment&quot;&gt;# replacing http://localhost:8080 with https://www.example.com in the sql dump&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; s&lt;span class=&quot;token comment&quot;&gt;#http://localhost:8080#https://www.example.com#g ./mysql-dump-export/wordpress.sql&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This script searches for the MySQL Docker container and creates a DB dump. Afterwards the urls are rewritten to the original url names. This dump can now be imported with the wordpress on Raidbox. Usually this is done with PHP Admin in Raidbox.&lt;/p&gt;
&lt;h1&gt;HTML as code&lt;/h1&gt;
&lt;p&gt;One thing that bothers me a lot with Wordpress is the inline editor for HTML and JavaScript code. Compared to e.g. Visual Studio Code it offers zero functionality. What I would like is that the HTML and JavaScript code sections in Wordpress can be done via local files.&lt;/p&gt;
&lt;p&gt;I can then edit these local files as usual with my VS code editor and get great help like syntax correction, syntax highlighting and many more. I did this by converting the HTML and JavaScript into iFrames, which point to the files:&lt;/p&gt;
&lt;p&gt;``html&lt;/p&gt;
&lt;iframe src=&quot;/wp-content/themes/Impreza/get-vms.html&quot; /&gt;
```
&lt;p&gt;But the whole thing probably still has one problem. It is not scalable or responsive when the size of the screen changes because you visit the wordpress site with a cell phone for example.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Wordpress is an interesting new experience for me. I like the wordpress editor which allows a graphical building of the website. However, I missed many out of the box DevOps techniques. But that doesn&apos;t matter with the approaches described here, development with Wordpress is much more fun.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/e3afee2a76af2d42b1418e7e519608c5/docker-wordpress.png</featuredImage><media:content url="https://martinmueller.dev/static/e3afee2a76af2d42b1418e7e519608c5/docker-wordpress.png" medium="image"/></item><item><title><![CDATA[AWS Cloudformation deploying with Lambda]]></title><description><![CDATA[Hi Folks! I am currently working on an exciting project where it should be possible to create Ec2 instances flexibly via an API. These…]]></description><link>https://martinmueller.dev/aws-deploy-cfn-with-lambda-eng/</link><guid isPermaLink="false">https://martinmueller.dev/aws-deploy-cfn-with-lambda-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[projen]]></category><category><![CDATA[cdk]]></category><category><![CDATA[aws]]></category><pubDate>Mon, 07 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi Folks!&lt;/p&gt;
&lt;p&gt;I am currently working on an exciting project where it should be possible to create Ec2 instances flexibly via an API. These instances should then be made available to the customer for training purposes. The instances should be customized for the customer, so they should have a certain setting like the Ec2 type, some special tags and some more.&lt;/p&gt;
&lt;p&gt;The deployment of the Ec2 instances should be done as cheap as possible by lambdas. About a year ago I did a similar project where Ec2 instances are dynamically created for an Alfresco deployment. &lt;a href=&quot;https://martinmueller.dev/alf-provisioner-eng&quot;&gt;Alfresco Provisioner&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;How to deploy Ec2 instances as dynamically as possible and also extremely easy to maintain with AWS CDK via an API like Api Gateway or Appsync, I will explain in the next sections.&lt;/p&gt;
&lt;h1&gt;AWS CDK&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt; is an open source framework for creating and managing AWS resources. By using languages familiar to the developer such as TypeScript or Python, the Infrastructure as Code is described. In doing so, CDK synthesizes the code into AWS Cloudformation Templates and can optionally deploy them right away.&lt;/p&gt;
&lt;p&gt;AWS CDK has been experiencing a steady increase in enthusiastic developers since 2019 and already has a strong and helpful community that is very active on &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt;, for example. There is of course much more to say about AWS CDK and I recommend you explore it. Drop me a line if you have any questions.&lt;/p&gt;
&lt;p&gt;In the next section, I briefly summarize the requirements for dynamic Ec2 deploying via an API.&lt;/p&gt;
&lt;h1&gt;Requirements&lt;/h1&gt;
&lt;p&gt;The Ec2 instances should be dynamically deployable via an API like AWS ApiGateway, which implements a REST API or AWS AppSync, which implements a GraphQL. In doing so, certain tags such as UserId or VmType shall be attached to the Ec2 instance. This allows the Ec2 instances to be easily retrieved and displayed in a React frontend, for example.&lt;/p&gt;
&lt;p&gt;For the administration, i.e. creation, deletion and update of the resources belonging to the Ec2 instance, Cloudformation (short: CFN) should be used. Cloudformation is a handy AWS service for managing resources. Thus, the Ec2 stack can be easily created, modified or deleted. Another advantage for using CFN is that this part can be tested separately from the rest like the API for the Ec2 instance creation. I even created my own staging pipeline for this &lt;a href=&quot;https://martinmueller.dev/cdk-pipeline-lib&quot;&gt;Stating Lib&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the creation of the CFN templates I want to use AWS CDK, because using CDK makes the creation and maintenance of the Ec2 stack extremely easy.&lt;/p&gt;
&lt;p&gt;The Ec2 CFN template synthesized by CDK is to be deployed through a Lambda.&lt;/p&gt;
&lt;h1&gt;Problem&lt;/h1&gt;
&lt;p&gt;Unfortunately, AWS CDK alone is not made for this use case. The main problem is that the CFN parameters cannot be flexible and after the synth phase the parameters were fixed. This drawback could be worked around by always doing a complete deploy with context parameters e.g.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cdk deploy -c userId=Alice -c vmType=2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;does. But this is very impractical because it takes a lot of build time and every time a new CFN template is created.&lt;/p&gt;
&lt;p&gt;To solve this problem I decided to use Cloudformation directly. Because CFN has the nice feature of parameters. So with every CFN deployment you can specify parameters to e.g. change the name of the Ec2 instance. Exactly what I was looking for.&lt;/p&gt;
&lt;h1&gt;Solution&lt;/h1&gt;
&lt;p&gt;So I use CDK for the Ec2 stack and the Lambda which should deploy the Ec2 stack dynamically. Let&apos;s start with the Lambda:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cdkSchedulerLambda &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;lambdajs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NodejsFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;scheduler&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  entry&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/lambda/scheduler.ts&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  bundling&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    commandHooks&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;afterBundling&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;inputDir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputDir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;cp &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;inputDir&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/cfn/ec2-vm-stack.template.json &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;outputDir&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; 2&gt;/dev/null&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;beforeInstall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_inputDir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _outputDir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;beforeBundling&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_inputDir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _outputDir&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  logRetention&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; logs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RetentionDays&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ONE_DAY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  timeout&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;minutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I use the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/aws-lambda-nodejs-readme.html&quot;&gt;LambdaJS&lt;/a&gt; variant here. This has the advantage that I can define the Lambda &lt;strong&gt;scheduler.ts&lt;/strong&gt; directly in TypeScript and Construct will convert it to JS and upload it to AWS. That&apos;s as a great level of abstraction. And with the afterBundling webhook, I can upload the CFN template to Lambda already. So I don&apos;t have to do complicated work with another storage like S3 or EFS.&lt;/p&gt;
&lt;p&gt;Next let&apos;s have a look at the &lt;strong&gt;scheduler.ts&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// eslint-disable-next-line import/no-extraneous-dependencies&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; readFileSync &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;fs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; lambda &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-sdk&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Ec2 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./query-ec2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cfn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CloudFormation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DynamoDBStreamEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;event: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Records&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;event not valid! Exactly one record allowed!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;failed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; newImage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Ec2 &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Records&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dynamodb&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;NewImage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    newImage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DynamoDB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Converter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unmarshall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Records&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dynamodb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NewImage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Ec2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;no NewImage existing&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; oldImage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Ec2 &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Records&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dynamodb&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;OldImage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    oldImage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DynamoDB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Converter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unmarshall&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Records&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dynamodb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OldImage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Ec2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;no OldImage existing&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; templateBody &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./ec2-vm-stack.template.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;utf-8&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;templateBody: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;templateBody&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newImage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Having NewImage so creating or updating&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createStackParams&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CloudFormation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Types&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CreateStackInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      StackName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;stack-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;newImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;noUserId&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;newImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vmType &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-1&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      TemplateBody&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; templateBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      Capabilities&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;CAPABILITY_IAM&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;CAPABILITY_NAMED_IAM&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      Parameters&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ParameterKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;userIdParam&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        ParameterValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ParameterKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vmTypeParam&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        ParameterValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vmType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;createStackParams: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;createStackParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createStackResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; cfn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;createStackParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;createStackResult: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;createStackResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Creating failed with this error: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; updateStackResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; cfn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;updateStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;createStackParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;updateStackResult: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;updateStackResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;success&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;oldImage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Having no NewImage but OldImage so deleting!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deleteStackParams&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CloudFormation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Types&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DeleteStackInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        StackName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;stack-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;oldImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;noUserId&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;oldImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vmType &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;noVmType&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;deleteStackParams: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deleteStackParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deleteStackResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; cfn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;deleteStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deleteStackParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;deleteStackResult: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deleteStackResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;deleted&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;failed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By using a DynamoDBStreamEvent as input, it complicates the code a bit. In principle, however, these lines are important:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; templateBody &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./ec2-vm-stack.template.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;utf-8&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createStackParams&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CloudFormation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Types&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CreateStackInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      StackName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;stack-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;newImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;noUserId&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;newImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vmType &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-1&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      TemplateBody&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; templateBody&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      Capabilities&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;CAPABILITY_IAM&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;CAPABILITY_NAMED_IAM&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      Parameters&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ParameterKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;userIdParam&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        ParameterValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ParameterKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vmTypeParam&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        ParameterValue&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; newImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vmType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;createStackParams: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;createStackParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createStackResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; cfn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;createStackParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;createStackResult: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;createStackResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So here the CFN template is loaded from the ec2-vm-stack.template.json file and applied using AWS SDK &lt;strong&gt;createStack&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So all that remains is the ec2-vm-stack.template.json. How do I create this? Well it is as already said also a CDK stack. However, this one uses CFN parameters as input for &lt;strong&gt;userIdParam&lt;/strong&gt; and &lt;strong&gt;vmTypeParam&lt;/strong&gt;. And here is the code for the Ec2 stack:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ec2 &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-ec2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cdk &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; CustomStack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws-cdk-staging-pipeline/lib/custom-stack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; KeyPair &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdk-ec2-key-pair&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; statement &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdk-iam-floyd&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Ec2StackProps&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StackProps &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Ec2Stack&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomStack&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Ec2StackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; vpc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Vpc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromLookup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;VPC&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      isDefault&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; securityGroup &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ec2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SecurityGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sg&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      vpc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vpc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    securityGroup&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addIngressRule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Peer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;anyIpv4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Port&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tcp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    securityGroup&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addIngressRule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Peer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;anyIpv4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Port&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tcp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UserData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forLinux&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    userData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addCommands&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
#!/bin/bash
yum update -y
yum install -y httpd.x86_64
systemctl start httpd.service
systemctl enable httpd.service
echo “Hello World” &gt; /var/www/html/index.html
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userIdParam &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CfnParameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;userIdParam&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;noUserId&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; vmTypeParam &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CfnParameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vmTypeParam&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; identifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;userIdParam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;noUserId&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;vmTypeParam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-1&apos;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; instance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ec2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;instance&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      instanceName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;vm-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;identifier&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      instanceType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ec2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;InstanceType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;t2.micro&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      vpc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      securityGroup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      keyName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;mykey&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      machineImage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MachineImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;latestAmazonLinux&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        generation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ec2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AmazonLinuxGeneration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AMAZON_LINUX_2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      userData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Tags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Owner&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Hacklab&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Tags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;UserId&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userIdParam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Tags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;VmType&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vmTypeParam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    instance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToRolePolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;statement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Ec2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDescribeVolumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDetachVolume&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toAttachVolume&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toCreateTags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDescribeTags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toTerminateInstances&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDeleteSecurityGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toDescribeInstances&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toStopInstances&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Interestingly, I use the CFN parameters &lt;strong&gt;userIdParam&lt;/strong&gt; and &lt;strong&gt;vmTypeParam&lt;/strong&gt; for the dynamic part of the Ec2 stack. If the stack is now created as via the Lambda, for example, the Ec2 instance gets the two tags UserId and VmType with the values of the CFN parameters.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Creating Ec2 instances using CFN and Lambdas is a cool thing. With CDK everything i.e. the lambda, the API and the Ec2 stack can be formulated and extended very easily. Super cool is also that with CFN it is very easy to add other resources in the future. For example, in the future I may want to provide an S3 bucket for deployment as well. I hope you enjoyed this article and maybe it even helped you. Do you have any questions? Write me :) !&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[AWS CDK Custom Construct Versions Checker]]></title><description><![CDATA[Hi CDK Fans! With Custom Constructs it is possible to implement certain features as Level 2 AWS CDK Constructs. In fact, many of the AWS CDK…]]></description><link>https://martinmueller.dev/cdk-construct-checker-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-construct-checker-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[projen]]></category><category><![CDATA[cdk]]></category><category><![CDATA[aws]]></category><category><![CDATA[construct]]></category><pubDate>Tue, 18 May 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/86a229f5300d5bea6b6145f220c6e566/version-prs.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi CDK Fans!&lt;/p&gt;
&lt;p&gt;With Custom Constructs it is possible to implement certain features as Level 2 AWS CDK Constructs. In fact, many of the AWS CDK Constructs already in use are already Level 2 Constructs. I have already built some custom constructs. There is the &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-build-badge&quot;&gt;Build Badge&lt;/a&gt; and the &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-staging-pipeline&quot;&gt;Staging Pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As we all know AWS CDK iterates very fast and a new version is released basically weekly. With each release there is a risk that my custom constructs are not compatible with the released CDK version. Therefore, I have developed a GitHub workflow that automatically tests the compatibility of my custom constructs against the new version.&lt;/p&gt;
&lt;p&gt;In the next sections I will explain how the compatibility check works and how I implemented it.&lt;/p&gt;
&lt;h1&gt;AWS CDK&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt; is an open source framework for creating and managing AWS resources. Using languages familiar to the developer such as TypeScript or Python, the Infrastructure as Code is described. In doing so, CDK synthesizes the code into AWS Cloudformation Templates and can optionally deploy them right away.&lt;/p&gt;
&lt;p&gt;AWS CDK has been experiencing a steady increase in enthusiastic developers since 2019 and already has a strong and helpful community that is very active on &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt;, for example. There is of course much more to say about AWS CDK and I recommend you explore it. Drop me a line if you have any questions.&lt;/p&gt;
&lt;p&gt;In the next section I explain how the compatibility check works with the AWS CDK version.&lt;/p&gt;
&lt;h1&gt;Compatibility check&lt;/h1&gt;
&lt;p&gt;Once a day a GitHub workflow, here called version checker, curls to the page &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;https://github.com/aws/aws-cdk&lt;/a&gt; and extracts the latest released CDK version. Then the version checker creates a branch in the name pattern bump/1.X.X . So when version 1.103.0 was released recently, the version checker created the branch bump/1.103.0 . Then the version checker creates a pull request against master. The pull request now contains the new CDK version. This is achieved by the version checker making a string replace in the .projenrc.js file. For example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cdkVersion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1.97.0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;replaced with&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cdkVersion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1.103.0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now a normal build is performed but with a new CDK version. The build and unit tests checks the compatibility with the CDK dependencies automatically. The use of the version checker requires a good unit testing strategy. Lambda code testing could look like that e.g.:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../__mocks__/aws-sdk&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; handler &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../src/index.badge&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; codebuild &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CodeBuild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;test index.badge.ts lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;failure when&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;queryStringParameters.projectName is not existing&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      mockedApiEvent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryStringParameters&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;projectName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockedApiEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;reason: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;reason&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;projectName in query parameter is not existing or empty!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and the expected synthesized cloudformation templates tests can look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; SynthUtils &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/assert&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; core &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; BuildBadge &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../src&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/assert/jest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Get&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;BuildBadge&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stack &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Stack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;testing-stack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;successful&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;with not defined hideAccountID&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BuildBadge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;BuildBadge1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveResourceLike&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;AWS::ApiGateway::Method&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveResourceLike&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;AWS::Lambda::Function&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SynthUtils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toCloudFormation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;\&quot;ACCOUNT\&quot;:\&quot;123\&quot;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;with hideAccountID = &quot;no&quot;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BuildBadge&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;BuildBadge2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hideAccountID&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;no&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveResourceLike&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;AWS::ApiGateway::Method&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveResourceLike&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;AWS::Lambda::Function&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SynthUtils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toCloudFormation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&quot;ACCOUNT\&quot;:{\&quot;Ref\&quot;:\&quot;AWS::AccountId\&quot;}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These examples were copied from my &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-build-badge&quot;&gt;Build Badge&lt;/a&gt; Construct.&lt;/p&gt;
&lt;h1&gt;Versionschecker - GitHub Workflow&lt;/h1&gt;
&lt;p&gt;The version checker is a GitHub workflow and is run daily at 4 o&apos;clock.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cdkversioncheck
&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;cron&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&apos;0 4 * * *&apos;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# push:&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;#   branches:&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;#     - master&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;CI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;false&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Checkout
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v2
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;fetch-depth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;# - name: Set CDK version manually&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;#   run: |-&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;#     echo &quot;CDK_VERSION=1.99.0&quot; &gt;&gt; $GITHUB_ENV&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Fetch CDK version
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;
          echo &quot;CDK_VERSION=$(curl &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;silent &quot;https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//api.github.com/repos/aws/aws&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;cdk/releases/latest&quot; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;grep &apos;&quot;tag_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &quot;v1&apos; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
          sed &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;E &apos;s/.&lt;span class=&quot;token important&quot;&gt;*&quot;v(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;^&quot;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;+)&quot;.&lt;span class=&quot;token important&quot;&gt;*/\1/&apos;)&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; $GITHUB_ENV
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Synthesize project files
        &lt;span class=&quot;token key atrule&quot;&gt;continue-on-error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;
          yarn add projen
          echo &quot;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&quot;
          sed &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;i &quot;3s/.&lt;span class=&quot;token important&quot;&gt;*/const&lt;/span&gt; cdkVersion = &apos;$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&apos;;/&quot; .projenrc.js
          npx projen
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Set git identity
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;
          git config user.name &quot;Auto&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;bump&quot;
          git config user.email &quot;github&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;actions@github.com&quot;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Push branch
        &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 
          git checkout &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;b bump/$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          git diff &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;exit&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;code &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; ((git add package.json yarn.lock .projen/deps.json .projenrc.js) &lt;span class=&quot;token important&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (git commit &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;m &quot;Testing CDK version to $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&quot; &lt;span class=&quot;token important&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;u origin bump/$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;))
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pull&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;request
        &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; repo&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;sync/pull&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;request@v2
        &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;source_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bump/$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;pr_title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Testing CDK version to $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;pr_label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cdk-version-test&quot;&lt;/span&gt;  
          &lt;span class=&quot;token key atrule&quot;&gt;destination_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;master&quot;&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;github_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.PUSHABLE_GITHUB_TOKEN &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; jsii/superchain&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The curl for the version number only accepts v1.X tags. v2.X is by design not compatible with my CDK stacks. So the PR would always fail.&lt;/p&gt;
&lt;p&gt;It would also be possible to test manually against specific versions. For this some lines of code have to be commented out or in. E.g. for manual triggering the push master must be commented. Also the action to curl the CDK version must be commented out and the CDK version action above it must be commented in.&lt;/p&gt;
&lt;h1&gt;Tested Versions List&lt;/h1&gt;
&lt;p&gt;I had the cool idea to create a list of the already tested CDK versions. Simply the created pull requests are provided with the previously created label &lt;strong&gt;cdk-version-test&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pull&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;request
  &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; repo&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;sync/pull&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;request@v2
  &lt;span class=&quot;token key atrule&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;source_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bump/$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;pr_title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Testing CDK version to $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; env.CDK_VERSION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;pr_label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cdk-version-test&quot;&lt;/span&gt;  
    &lt;span class=&quot;token key atrule&quot;&gt;destination_branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;master&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;github_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.PUSHABLE_GITHUB_TOKEN &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then you can simply link to a filter with the label like &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-build-badge/pulls?q=is%3Apr+is%3Aopen+label%3Acdk-version-test&quot;&gt;https://github.com/mmuller88/aws-cdk-build-badge/pulls?q=is%3Apr+is%3Aopen+label%3Acdk-version-test&lt;/a&gt; . And voila all PRs for the version test are displayed.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 87.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAJHRFWHRDcmVhdGlvbgBNbyAxMCBNYWkgMjAyMSAwNjo0ODo0NiAtMDPxxwraAAAAGXRFWHRTb2Z0d2FyZQBnbm9tZS1zY3JlZW5zaG907wO/PgAAAgZJREFUeNqNVOl62jAQ5FFIArbxocP3HVJoSmib93+b6Y6wC+mXuPyYb2VpPZq9tPJUBT87Cg4XW/xAUJ7hFScE9W88xRXW2wgPXvIBj766rm/2VpudgR9noA1UCU/WfpTCFgPS6hkqbbANrfjk8CLxkzX95v+24svzIMllz2L1FGh36GwoVtZhZGF04aBVgZ180+cCKwSp8+P6un/hWFHmjKt8JWEmWHtTWDc+H/y3sQPXvIRKV49fOBO8kfjqLDS1oEJa79G+vKF5Pi0TEutJwWegIm/K4Rz2l4QMNbINquG7JLxwziwKC0HrCiQ5fJDU3GKRMGsPLhyGRdKdVHenS1flUOwmMFhv4vsIiVBXjiCW1olsPeWsdoTc96VV2E63+E/INYr+gHJ4hSlHaEL6k6lIsu5TLCr0dYtA544ka15gpdGNwDriUQhSjMcU3T6VnBr5xywTeqqBl6RI8g5GSKlA5b2gQ+TC1yg7I1N1ba27CHV5UciwCY5knLZygUY7WlFu3DDcReirFKroXbUZ+gwqDbWRZraoeo6jcqTLOVRSUZM7VbNC5pHgJZFNUbYZspr9aZdHj1VOpF2yXsbq2xnj6zu6w0/BL/Rim/0bqnHA6X3A8TzIJb2koF9WyIH/Ox0T5n7j/tZNSy4vj6yn80XCfx/VW3DGA3nalFSebyEniXP9BzugI9+PS4HtAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/324ec3b1f63d135910df77c77fafd467/f1512/versions.webp 200w,
/static/324ec3b1f63d135910df77c77fafd467/f59aa/versions.webp 400w,
/static/324ec3b1f63d135910df77c77fafd467/47a22/versions.webp 800w,
/static/324ec3b1f63d135910df77c77fafd467/8a3f5/versions.webp 819w&quot;
              sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/324ec3b1f63d135910df77c77fafd467/f8f3a/versions.png 200w,
/static/324ec3b1f63d135910df77c77fafd467/6a8a8/versions.png 400w,
/static/324ec3b1f63d135910df77c77fafd467/7842b/versions.png 800w,
/static/324ec3b1f63d135910df77c77fafd467/2f950/versions.png 819w&quot;
            sizes=&quot;(max-width: 800px) 100vw, 800px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/324ec3b1f63d135910df77c77fafd467/7842b/versions.png&quot;
            alt=&quot;pic&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;AWS CDK is still the perfect framework for Infrastructure as Code in AWS. With my Custom Constructs I hope to give back to the community. To ensure the best experience at all times, I have developed a workflow that checks CDK version compatibility. Creating the workflow was a lot of fun. But even more fun is to have a PR list where I can see if the version checks worked. I have more exciting CDK topics in my forum: &lt;a href=&quot;https://martinmueller.dev/tags/cdk&quot;&gt;https://martinmueller.dev/tags/cdk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/86a229f5300d5bea6b6145f220c6e566/version-prs.png</featuredImage><media:content url="https://martinmueller.dev/static/86a229f5300d5bea6b6145f220c6e566/version-prs.png" medium="image"/></item><item><title><![CDATA[AWS QuickSight DataSet and DataSource CDK Custom Constructs]]></title><description><![CDATA[Hi. In my previous blog posts I showed how to generate analytics from DynamoDB table using AWS QuickSight. Unfortunately, QuickSight is only…]]></description><link>https://martinmueller.dev/qs-constructs-eng/</link><guid isPermaLink="false">https://martinmueller.dev/qs-constructs-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[projen]]></category><category><![CDATA[cdk]]></category><category><![CDATA[aws]]></category><category><![CDATA[quicksight]]></category><pubDate>Thu, 06 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;In my previous blog posts I showed how to generate analytics from DynamoDB table using AWS QuickSight. Unfortunately, QuickSight is only minimally supported by Cloudformation and QuickSight&apos;s DataSource and DataSet are only on the roadmap so far &lt;a href=&quot;https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/274&quot;&gt;https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/274&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;Therefore, I have developed AWS CDK Custom Constructs for &lt;a href=&quot;https://github.com/mmuller88/cdk-quicksight-constructs&quot;&gt;DataSource and DataSet&lt;/a&gt;. In this post, I go into a little more detail about what QuickSight DataSources and DataSets are and how I deploy using AWS CDK Custom Construct.&lt;/p&gt;
&lt;h1&gt;AWS CDK&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt; is an open source framework for creating and managing AWS resources. Using languages familiar to the developer such as TypeScript or Python, it describes the infrastructure as code. In doing so, CDK synthesizes the code into AWS Cloudformation Templates and can optionally deploy them right away.&lt;/p&gt;
&lt;p&gt;AWS CDK has been experiencing a steady increase in enthusiastic developers since 2019 and already has a strong and helpful community that is very active on &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt;, for example. There is of course much more to say about AWS CDK and I recommend you explore it. Drop me a line if you have any questions.&lt;/p&gt;
&lt;h1&gt;DataSource&lt;/h1&gt;
&lt;p&gt;A QuickSight DataSource defines the source of data for analysis. You can see which data sources are possible in the &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/QuickSight.html#createDataSource-property&quot;&gt;SDK Documentation&lt;/a&gt;. The DataSource construct also uses the SDK parameter definition as typed input.&lt;/p&gt;
&lt;p&gt;The concrete interface can be found &lt;a href=&quot;https://github.com/mmuller88/cdk-quicksight-constructs/blob/main/src/datasource.ts&quot;&gt;here&lt;/a&gt;. For example if you want to define Athena as DataSource it looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; users&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;martin.mueller&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; datasource &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataSource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DataSource&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdkdatasource&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  dataSourceParameters&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    athenaParameters&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      workGroup&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ddbworkgroup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  users&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;dataSourceParameters&lt;/strong&gt; is the &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/QuickSight.html#createDataSource-property&quot;&gt;typed parameter from the SDK&lt;/a&gt;. I think it&apos;s pretty cool that we have type support here now and so we can also define other sources as DataSource like Aurora or RDS very easily &amp;#x3C;3 . The &lt;strong&gt;workGroup&lt;/strong&gt; in the example must be created before. You can do that manually with the AWS Console in Athena or even better with Athena. I already explained how exactly to do this in a previous &lt;a href=&quot;https://martinmueller.dev/cdk-ddb-quicksight&quot;&gt;blogpost&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;DataSet&lt;/h1&gt;
&lt;p&gt;A DataSet can then be used to refine and concretize the DataSources. For example joins or transforms can be defined. All possibilities you can find here in the &lt;a href=&quot;https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/QuickSight.html#createDataSet-property&quot;&gt;DataSet SDK Documentation&lt;/a&gt;. Very important to know, the permissions for DataSource and DataSet must always be set correctly. I have already built this into the constructs for example.&lt;/p&gt;
&lt;p&gt;The implementation of the DataSet is &lt;a href=&quot;https://github.com/mmuller88/cdk-quicksight-constructs/blob/main/src/dataset.ts&quot;&gt;here&lt;/a&gt;. In the following I describe a more complex example where logical tables are joined from the DataSource.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DataSetConstruct&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DataSetConstruct&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cdkdataset3&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  users&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; users&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  physicalTableMap&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    users&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      customSql&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        dataSourceArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; datasource&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataSourceArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;users&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        sqlQuery&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SELECT primarypractice, dateofbirth FROM &quot;ddbconnector&quot;.&quot;martin1&quot;.&quot;martin1&quot; WHERE groupid = \&apos;users\&apos; AND firstname is not null&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        columns&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;primarypractice&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;STRING&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dateofbirth&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;STRING&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    practices&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      customSql&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        dataSourceArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; datasource&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataSourceArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;practices&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        sqlQuery&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SELECT id, name FROM &quot;ddbconnector&quot;.&quot;martin1&quot;.&quot;martin1&quot; WHERE groupid = \&apos;medical-practices\&apos; AND name is not null&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        columns&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;STRING&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;STRING&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  logicalTableMap&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;users&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      alias&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;users&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      source&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        physicalTableId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;users&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;practices&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      alias&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;practices&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      source&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        physicalTableId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;practices&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;users-practices&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      alias&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;users-practices&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      source&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        joinInstruction&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          leftOperand&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;users&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          rightOperand&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;practices&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;INNER&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          onClause&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;primarypractice = id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      dataTransforms&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        createColumnsOperation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          columns&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            columnName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;age&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            columnId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;age&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            expression&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dateDiff(parseDate(dateofbirth, &quot;YYYY-MM-dd\&apos;T\&apos;HH:mm:ssZ&quot;),now(), &quot;YYYY&quot;)&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this example, the two tables &lt;strong&gt;users&lt;/strong&gt; and &lt;strong&gt;practices&lt;/strong&gt; are first created virtually and then joined together to find out to which practice the user is assigned.&lt;/p&gt;
&lt;p&gt;I also perform a data transformation here. I would like to know the &lt;strong&gt;age&lt;/strong&gt; of the user, but the data only contains the date of birth. So I perform a transformation where the age is calculated and defined as a new column named &lt;strong&gt;age&lt;/strong&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;QuickSight is a cool AWS tool for visualizing data insights. Since I am a huge fan of Infrastructure as Code I want to have all QuickSight resources in CDK. Unfortunately, the DataSource and DataSet are not yet supported by Cloudformation. As long as this is still the case, I and you are welcome to use my CDK Custom Construct as a replacement :).&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage></featuredImage></item><item><title><![CDATA[AWS DynamoDB Analysis with QuickSight and AWS CDK - Quite big Tables]]></title><description><![CDATA[Hi. In my last blogpost, I covered exciting work with AWS Athena and AWS QuickSight. If you want to do analytics from small AWS DynamoDB…]]></description><link>https://martinmueller.dev/cdk-ddb-quicksight-2-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-ddb-quicksight-2-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[projen]]></category><category><![CDATA[cdk]]></category><category><![CDATA[quicksight]]></category><category><![CDATA[aws]]></category><pubDate>Wed, 21 Apr 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/9518027c78885ed4c42f4bed0a621871/long-table.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&quot;https://martinmueller.dev/cdk-ddb-quicksight&quot;&gt;last blogpost&lt;/a&gt;, I covered exciting work with AWS Athena and AWS QuickSight. If you want to do analytics from small AWS DynamoDB tables, everything should work smoothly. By small I mean a relatively small number of columns in the table.&lt;/p&gt;
&lt;p&gt;It happened to me that when processing the &lt;a href=&quot;https://www.take2.co/&quot;&gt;TAKE2&lt;/a&gt; data, the required columns for QuickSight were not displayed at all. Now the number of columns in the TAKE2 data is anything but small with more than 700! How I solved the problem and even cast it into code using AWS CDK, you will learn in the next sections.&lt;/p&gt;
&lt;p&gt;Before that I would like to thank the sponsor &lt;a href=&quot;https://www.take2.co/&quot;&gt;TAKE2&lt;/a&gt; for this blogpost as well.&lt;/p&gt;
&lt;h1&gt;Solution&lt;/h1&gt;
&lt;p&gt;The problem is that the DynamoDB table is way too big and the Lambda &lt;a href=&quot;https://github.com/awslabs/aws-athena-query-federation/blob/master/athena-dynamodb&quot;&gt;AthenaDynamoDBConnector&lt;/a&gt; is no longer reasonably able to recognize all the columns. Fortunately, the programmers of the connector have considered this case and have built in a possibility to define specific columns with their names and types.&lt;/p&gt;
&lt;p&gt;The exact instructions are in this &lt;a href=&quot;https://github.com/awslabs/aws-athena-query-federation/tree/master/athena-dynamodb#setting-up-databases--tables-in-glue&quot;&gt;repo&lt;/a&gt;. In short, an AWS Glue Table must be created. The connector can then detect the desired columns based on the columns defined there.&lt;/p&gt;
&lt;p&gt;To visualize it using the AWS component diagram also used in the last post, all you need to do is add a Glue Table:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 491px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 116.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAYAAAALHW+jAAAACXBIWXMAAAsTAAALEwEAmpwYAAFiPnRFWHRteGZpbGUAJTNDbXhmaWxlJTIwaG9zdCUzRCUyMmFwcC5kaWFncmFtcy5uZXQlMjIlMjBtb2RpZmllZCUzRCUyMjIwMjEtMDQtMTBUMDUlM0E0NCUzQTA1Ljg5N1olMjIlMjBhZ2VudCUzRCUyMjUuMCUyMChYMTElM0IlMjBMaW51eCUyMHg4Nl82NCklMjBBcHBsZVdlYktpdCUyRjUzNy4zNiUyMChLSFRNTCUyQyUyMGxpa2UlMjBHZWNrbyklMjBDaHJvbWUlMkY4OS4wLjQzODkuMTE0JTIwU2FmYXJpJTJGNTM3LjM2JTIyJTIwZXRhZyUzRCUyMmp4WldLTVpBQWFlT0RadDE5OV9sJTIyJTIwdmVyc2lvbiUzRCUyMjE0LjUuNiUyMiUyMHR5cGUlM0QlMjJkZXZpY2UlMjIlMjBwYWdlcyUzRCUyMjIlMjIlM0UlM0NkaWFncmFtJTIwaWQlM0QlMjJWRWl4NEtUOUJLcms4OEp2cGpqYyUyMiUyMG5hbWUlM0QlMjJkZGItc2ltcGxlJTIyJTNFN0x6WHR1VElrU3o2Tlh3Y0xtanhDR1JDSnJRR1hzNkMxbHJqNnclMkJ3cTZyWjNkVkREdSUyRmhESG5YY0hlbFFFQkd1THU1bVVkayUyRndsJTJCdFFjM2hVTWg5MG5hJTJGQWtDa3VOUDhQdFBFQVJpQUhCJTJGUEMzbnR4WWNSNzQxNUZPWmZEJTJGb0x3MW1lYVhmRzclMkJmbDY5bGtzNiUyRk9YRHAlMkIyWXBoOTgyeG4zWHBmSHltN1p3bXZyOXQ0ZGxmZlBidXc1aG52N1VZTVpoODNPcld5Wkw4YjBWJTJGTkd2WndlZmxubnglMkZkWUUlMkJuMUhHJTJGNDQlMkJIdkRYSVJKdiUyRiUyQnFDV2IlMkJCTCUyQm12bCUyQiUyQmZXdVBWOW84ZyUyRmRqWEw2ZHglMkY0bmUzOTVzQ250bHYlMkZLQ1pydkxIU25mMW85bXdjcjFRWlR0ZjhEaEw4JTJGM0hMJTJCNkhHYTNBUHdmYk9mbHFMUCUyQnk1c21MJTJCMDBsTyUyRmRrbjZYQmE0dCUyRjV5ak5UM3c5MEkzbzFWdWl6bmQydUc2OUxmVGNYU050JTJGMzNrODhuZDV6JTJGcCUyRlJINXYlMkI5OHQ5YmJ5UDMyeWR2OTdTMHFsczB5V2R2amYlMkJQQTQlMkYlMkZDU2M4blQ1SzUxSHZ4MzNkUGhYSjM0ZlBTN3Q3N3RNNTMzQWxEYmhVbTYlMkY5WWp3dTJQbHZ4ejN5NmxhWDk2UEFnSGZnd0RDeVclMkJuZkE4QjVJZnYlMkZMakUzSzlUbkg0JTJGNnk4V3ZMJTJGODZqSCUyQjB2UmwxNyUyRkR4dEMzdTIxaHMzN3ZBclVVYVJmZWJXNCUyRjFmbHR6dUZQaiUyRk5nWVh2YmolMkY3MmZtODI5JTJCRFIwWFIlMkZ5NTl2NzNBSlglMkZlcjZmT2ZuR1o0SHY2ck95aDklMkY3c3Y5dnIyUXUlMkI5cjZmbHp4RDZCNDElMkYxSWIlMkYzQWolMkJmTmo5QWY3UkhYN2YlMkJFZHQlMkJNJTJCTjRNJTJCSFBWcyUyRm52cTNqWCUyRlVocU0lMkZQJTJGSHZ6d2IlMkY0R3p3ZDJmZiUyRiUyQjZZV3BlbTdOTFhMNkQyT0hyV2Q4dXJiJTJGcnBhOGpoJTJCeiUyRjI4UUk2bjhLa1RIJTJCemowVFFOd3Y5YXQlMkI3bk80TGxYMTM3JTJCJTJCZWlIMnVWemJOcjg1QktSaWduM0NjbDZtdjAxJTJGdHliNyUyQjdqMUpPQmUlMkZ4UDJXVGt0NUE2VVVSbW1qOVhQNSUyRmZKUnZ5eDklMkI2c0RxS2JNbngxTCUyRiUyQlZkMzdmaSUyQjZtZUdQNDFManc5JTJGQTRhSVBSaiUyQjd1VFBiY001JTJCSGJjR1RsOFR3SGZXUHE4T3hzaiUyRnhKUDM4Tzl4bjU4NVIlMkJDeWdoZnA2SHZqZSUyRmZmdnRVZUczR1BnciUyQlBFOGYzcjhWV1Q0RWVFSThKc0loNGp2MiUyRnRmVWdaT2ZHc3FmcFVzZnJUOUVaYjhCZ1glMkIzcENIZndwNWM3aXRIYTF4blM3JTJGRHQ1JTJGN2VERkFBcUc4Yjh2ZUc5ZUJZTFklMkY1cmduZUYlMkZUT0FTdjQxYkJQa254eTM1VDJGalI3bDRQeGpXJTJGZDMlMkZDekc3dCUyRjVDeFo2TjgxY2J2eWRpdjdDNlh5amVyNjcwRDJOMTM5empiOU9kdjhuJTJCa0g4MCUyQiUyRnQlMkZzandJJTJGbE5NJTJGNjlCeE9IJTJGR1NJT2d2OWtJZzc5VThQN2w1RCUyQnhjSiUyRlYzaiUyRmY0JTJGSWYzaWslMkZkZk0lMkJ3c3IlMkIzR0piMzc0MzJaZTVEJTJGUldlJTJCekM5diUyQlRYJTJGVFdMOFRWZDlad3AydCUyRjgzSyUyRnFWWkdZc1RESUQ4ZmF6c0RhQXZFUDlmdzhxYXNJMlNmNUNrSXY3RkZCWDZVM0RyYXpxZCUyRjJHazg5bzhJRVQlMkZXMXY5JTJGeUNLJTJGNjJ0JTJGc2UwMWUlMkJMSXY5MGNRWCUyQmMlMkJqWHY0WXFJdjZMVkJ6NmwxSkZ4TSUyQlU2aDc3OHg3cSUyRjBLOSUyQnBjRHVtZ2V2dXJYY3hIMTRaVE1QJTJGbkJIOExLZjNkUSUyRjBHTXduOGUxekt1NTIlMkZSOEhzZ0FnQWFaMzlOUVg3czYlMkZvdSUyRmNjRTdTJTJCUzZKZThpJTJGd2N0TUFmQkMzdzMlMkJRQnYzVGhMeTd3ayUyRlclMkJ6MkQ4Vnp2JTJGeTJSaEdQMjRBdkJYQndYNzdaajhNdmUzJTJGM3BDRVB0NVVFQUElMkJlJTJCQ012SnZqOHElMkZtY2UlMkZGUE5BM3ZpOTglMkI5akh2Y2ZRcFAlMkZhNWhIOGlXVWslMkJnUG9leXZvOFBmQnJoJTJGR3V2NE9ZZjlPMVQlMkZIYXIlMkZEdFclMkZ5VVYlMkJWODc3c1ZUbG54YkklMkY0N2pmOGZ4diUyQlA0NzQ5am1QaXRwTUQlMkJ4JTJCTDRLb0Y2R1lKUnYxQjVUTmxNbE1qakQlMkJMNFZ3VjY2OUVFUCUyQnZEdTZmTDc4VGJiOXpqdXdEN3RTOTliJTJGckowTCUyRjNoN1pNa3E5S3cxNlVTMm9PNFplTTMyOFQlMkZWUjklMkJBZm9PJTJGSjN0Z0IlMkZsakklMkZ5alMlMkZOc2FQTll6JTJGTDhZSXl1YiUyRnRMNkdkdWRIJTJCejljUUMlMkJLRHZ6QlFwWCUyRmNYVUglMkYxYmRvWDh3SXVRZkRBbUslMkZuZU55YzhPbWlUUmYlMkZ5cU1BQUJsR3ZlNzYlMkYzNTM0M2x6Q3VmeHExdjNnTyUyQkolMkY0MXElMkJjJTJCUmRFQSUyRiUyRllpWnZmZ2R0UHp2eWZvdCUyRmZkUDl2Y1BpemVmJTJCcXQlMkZ4dGQlMkYlMkZoMyUyRkNmTVFLNXZSeUZNQmhFY1JMOTJiZ0UlMkJXZnlWMzhFJTJGQWUyaHJBJTJGUDZjVEpJTEQ5d1glMkZBYkwlMkJEJTJGc0glMkZlMW8lMkJJSDFaZnUxY1BsdlclMkJETGR2VHRJdm1YUyUyRnhSUXZ0UFV0VHYwOHpYTGFrZnJjQ1BsdnQ3RWk3aG4yRHEyeWJFRGwxJTJCNSUyRkhTb1ZWakJ6NWMzbFAzbjJMYUJXUG45emRadnQ5byUyRlVYNTklMkJlcnJtS1d2NyUyRmtGTk13dW1NZ1ZIcVNnV2NrQmg1dEtYNG5DMVo2aGpVbVNRVEpvcEZuRUhsdTVqMCUyRmNVbkFaZU1BMWdZQUJsQVZTWURPaWVPNDZHcTBxVmpXSnpYaEJLTmxCYm1CZ2pDQURQJTJCS0VoeE1JYzJGNmkxTnlteElSUEhDNTVaTW9OVU9OMjVjM09sUEVDMlM3cnhtMk1KTTkyUFA3JTJCSmpJbFJnbUVNbEVsR2pxWGhKYmdlZWJUSWVGVVoxNko0NXRZcEpMSXJIWWJwamRpYWwzcyUyRkxuZElnNVluYVFKaGJKOFhNcThkbHhsV3lkaUplN29LZGlGZTQlMkJVdUdzd3lTU2hBU3I2SkY4bmlBODN1aUpscDdQd2Y2ZU5QOVFjNGRMczliQlY1V05tUUpoRVBBcWw3RkFwT0VGbzg0ckViQ2lxSmRkTG5lOW96JTJGWlRZZ202Q3FXYWpDJTJGU2kwNWZUVyUyRmRGSjcyMnYlMkZVSzhacVBMcHFnajRqZlRWJTJGdDVPeXRkSEJZdVlmdDBrYUJjOE0wNEdOWm44aWpjTVRMRWtxYUo2cVBZS0JwJTJGZnEzN3FrUHppJTJCOCUyQmpnWFdXTlhFQ09kVCUyQmw3RUx3MG83SGlCbWhOWnhaZyUyQk5EMVNENExIWWcza3RVeXVicWRqM3hxTU91ZkxrZzhZMWJwVWl2ZU9TS0dYclJ5cVo2QURDMm44bVUzZW11S2RGMVJlTWphZWN1c0F1b3F6U0ZJUzVIR0hVZVB2RDFWeTZYaVV1YklwMGRDUkd5emJXRnk3RVpIRjRFOUpEb2pra3VXVksxR0pNUVJJYzYwa2xSNVdnOHFWb2h1UWphMVM2ZU9CdlZqd0VGVE1PdDY1dHloanRSWGlwamdyNnNPc2p2V1UwOU5WVDlnek1DNzZHdk1yRFpEJTJCZlF1NGlNNVF1cCUyQkxwTXVOM3p5NGZXNU1IbFZodGNnUzZ4ZmVxbXVMTzJoQ2dBeEp5YjZMWDlwOWVJaFdsd3FuUzVhQWdkWWQzWDFTZGpjZnp5ZFpMeUVyTVhvWDglMkI3QXl4S21CYVBNaUx2ZUFpWG45aVFYdkxHWXVXJTJGS3BqM1NzRXMlMkI4dXliQnBCVXlid2w4cHA4UVpodzZjMlBoSlp2djdZTWJSRFZNV1NrWEU5eFc0bW1GRnZaS3p1REZudm53d1JWRmRRTFhZd1ZnYnBZSXhLeHRsRFRNN21yRmVESjhWSzhFRTA4TWxDVGxQc0pYWXJua1AyJTJCOTUwb3pEV3A3cENrWVdoTHdydUp5YVJOdVhCUmdWUVFYSGtHODZiTnVkSzNFNERGMHpGeFM4aE1XdWVWM0Ruc2tpSXgyZVNRMk1BdFM2T0RXS0VESTV0dUk2VUpjeVBEakhYbjl0ZkNFRWNDSzYyNWJ0OTZ4bTU2dmJkUHo1Y1ElMkJNZ0RhTXBQWURCZ3IydDdKV1hBSkdIZFpIbkxHcENmaWZwUXprakY2YXB5NHhGRGc1alBMR2lDdFhNRkI4a3dWb0V0a1pyUXVZQ3BiUTRvaXJVRjd1S3AlMkJ6dzRsZU5DOFNnbHglMkJxQUJ1b2JYTE16JTJGUnI1a0FGY0lxSXcwQ2EyR2Z3RTU0dEFZcUtrazZlSHclMkZ0eGJkS3BDdFZCYnB2U2lobU5SdSUyQk1WcjJSakdSTkNUQ2UzUGJFSjRHZm1vSm5rdEpwd2FSNklUcUo4STFLVmtyT1c1WjBlWm9KOXJDQUV6Y2FxVG9sQXAzTDhyQXhvNGhVQ0VFZmRkeG9KRlFaWDhqQUVnOUN3R2Rpb3VGd2ZoejVrMUE4OWM2eUpWYWdjdVJLeUc1dWUyZmNxUFNvbmNBdkFKNnhJNmhTdm0ydU9mSk1BMTdwMWtLM1VoZXlNcGEyTWhTMzBoYWhKSDhzSFo3aGV0aU5sZWkyUzFiQnRwVE5xSDFLeHh4bVdYRnVrc3hXcVplT3NjeXNzVnlxQiUyRnpZaDM3ZW8lMkZzMXA3ZSUyRnM4aHRsVEd4UnFBNiUyQllMMDBtTlhVMCUyRjdobXZyYzZSRFA0WmNsa3RLdnpwRFRGbUNCdmUzbSUyQmF3ZUhEZDc5T3kzRm1BSGw2MnJiSEI4am4zV1Exb0UwVEFsJTJGSHVycmMlMkZLc0tuUElxc3l6WFFkeEFPWHhYR0g5RUo2MFk1TSUyRnFUazdiSTVrbm13a2hndHlFSnFUJTJGVG5hSFlEMlp0d2dSZEJUU2gzdXptQ1I4T2V6enh6alV6N05HenJlRTg3bzJnQXlhUlNSYWFJV25oJTJGSm03MHZOWUNyZG9EaW9HcVBuQnZZQzN4cW93MGZPRjd6RiUyRlFEV3lTTkZuYXN0MmpoNSUyRkFGWUVtcVNDNnZSbzdWOEZGcDNlRGpEM25xMFZqZ3Jzb1NVaE5ncFhPbUo2RUJ4Q3E4S09UbGklMkI0MW9OUU5SYllGelN3a2l1RHV2Z1FYSlFiYUpDb3o0VlRpRWhSWFZybFNGSk52YnBWUzglMkJzSFE5bVlBR1M3SjFyU0VyYldiQkIzdUZ3UG9LSWVEaTZCRWZyVlBVU3MlMkZjalZrR3lqcDF4bWtxYmc3RDJoblZuZnhxMyUyQmZUb3k1JTJGekJjWGhYSFVGazZNd2JRSnBKOTglMkZZUVdyQzBMTHlZbUZIY0hWMjA4dHV4eDVPaHh5TkkxJTJCQm9oZUhJdnRCV3NjUjgyR2M0Mk5Zd1dsV0hEeHBXc1JzZGZhSGVKa0paQ3hQd0pKVFhhcHZPTjNoa0xIMUhndm9ZZFI2d2ZoeDE5alRMTzlja0F2ZSUyRlFqNlhYMnFabmFKUUl0SFRjQnRxZnhFdjRkcmFoT2t1d1ZPRmElMkZCVzhlSWVUdnp0WUozZGJtdk5rWWFOdjRIRThVQllQSFZSWGRPUHVROXBBN2F4THlqT1FQMk5nUU9hcDRaREFNaEElMkJ3Y1luTHk0MTQ3bEJCRWRYcWJJeXBFaUo1WUNjTnN5OEQ4SlFBMk9aRzdiVkZFTFhpaSUyQjN6OUs0RFRqM1I1UzNqNCUyQmJLWkp0dG91SFVLS3E0SXZhd3dQaFAwVkoxR2kyam84YmVUSHFJUm90MHhvemlIcW5iQnNKQTRiM1JQZzFJMzFrcVlPdHdHeXdjeGRPRmhBWkRZSkxDQnBycFZmcDB1ZURSUEtMR1dYMzg5enZTaW1seGJZSG5XazdSejJDQnVBYWpFelRKaFhSR2wwTFp3Ylc2b0Z5QU5GalVmQTdrZlg4d3hIUXdQWFdvbG85dEVITGUzdENkQmpZRkZRTElVRWhGVlUlMkJ0ZXJOdGs3NVlOJTJGcUhpMG1DN2Zxb0FsVUZqdVJGQWhaWU9pSFBFWDdYSDZEQURwYiUyQmlNVmJtRG50anhpYXp0aVoyOWlaOXYzbnBTM0xQaVRNeWVFS1J3TzdoemVzT3lFZjVYWCUyRkdHVkt0Yll0NEZHZEdDTTFqSHJ6S3hUOTBsNjZqOUdMVWRHUkluMXVqSGxlSzJ4ajlkWlZpQmgzMDdYcXpjbk10WVBFTyUyRm9QQlV1QWJXdVlJRlJYcXcxJTJCaDVVbXRMbHZzOHlYWnBBYk01eTRzM05UNCUyRm9DeHFoejduMDdsSGhvSXVKbkxXJTJCVzlpWWt0Ynh1MFo4UnZUOEZFZDk1SVFrVG90NnFhQkk0TzFOZWklMkIwQk1wVXZzbG5qY1dESW9zdnM4WmZOSEhVem9OYiUyQnNOZUZnMnhxUHBOYzlVQU0lMkJYdGRKcU9kbklrTGF0cUI0UERxVThhdWZtY2RHc0V1cmZYOUQxSVBGTzglMkZJYzAxT2tPUlhwJTJCOXJmSjQ3ZGNZeE9RY0tIUVglMkI4dDI4eE5mRkc2OXZnTEVwbksyYnpvcWFsdEVWMWpsQTNnZURUUCUyRkpSQnAwZGc5VjNZSU5FVmRKbnhYR0h3aGc2TlRub1NrY3Nua0o0UUx2OEtIdGhOYmRsU3lmYlREcWw5cUJmRWY3cnV2QU9yS2NMV1olMkJkTFZHZnNsb3daeU5HSTdBM0hDd3ZlTW0xZVViRmNKWnUlMkZYSkZrSWJBYjNxeXBIJTJCSHN0NklINmNmRGxtWVpPd21nemlMSzlNYTMzMzQ1V3ZlYWtMYThrUGExbEx1c1NmUTVMQ3p0NDQ4UEF5VzZYWktPcjFESTA0Rk9oN3JDTkVLODglMkJSRnk4djFZZ3lrdHpvS2Z5dHBSQmR2MVBPbTRmRzhKeDMzbzlyRDRZcERwQkRrWSUyRlJwNiUyQlJwUmh3UGV5TndDUm5QVWVaeVJSJTJCNE9oYWpaZDQ5MWdRRVJXbVBFZURjOHZHTjVtSGw5bXAyWmVMM09MekF4Sm9VRU1NemEzSlNYWG9DaFZTbjV2Rjd2SjJTb3liOFFpOXlKTEhpekZaYk9Mb3B4YVpsbXg0cGd2OHRaOE4yT2o4eWxLN3VWNUtsdlZMWW9lWSUyRnFGJTJGdXp1TUc4OWtIa3BtU0dQUHFFMm1GeWFjN05OYXVCSzJUMlFUdUclMkJmbGhPOUpSVnkwbTRMdzEwbmV3Y0U2Zk5IZFBkQzVYcSUyQk9jdGYxTiUyRmhTZUJlNzlVRVhCMm9DVEw1cllqViUyQmZxb1o4UlpQbkowZVA0NHA1cm5GNWpuVXhibkZpVDZQbzglMkZhUUdqbUxFV1Z0cDJNVjVLTnQ2ZE5mMHdRclBsT0VIS1JBalVYalNjN2V3R2JHblNCeDElMkZ5VHJ5RFZ4RGFiZzBtbFo5SzY5UGZlalpmN0JNOWRVSTU3bDZrMjhCVFlsd3pVZzBVdmxZJTJGckU1TUZxR3JBanIzWjVpbzlDRnVHUWw0dU9aOVdteSUyQnBYZUJGYkU1VGFIbHJ1OW10VjBETGpWdVdldVg0WkNnbUVhUU1zJTJCOSUyQnhuSGNFMjhFWkRwbmtUZWlmTnhnUVdNSW41QXZSQkhCYyUyQllHUUIzZW5PZ1ZzSGQlMkZjZ1BJM2NJUVpqSXFxVUt1R1Ayd09ReFBjY21QUVpkSGglMkZoTGpaTFJmSFFJUiUyQndzdDNxdHZuOVRrR1ZxVzZTUXU4UWlkR2JOTHFYTmlRTU43M3ZGTzMyZElaeDlJdk9rYzVmRGN1VFVHZlFPV1BqYkElMkZPWUl4WVE1bTJER2h2eWR2NlQwcEtYeDhCelBnSWt3eTZJSjE5V0dJQVpDWFBFZVJJdlFKdmdMQ01rdW1CZEFUNm14UEYxSlBwMlZmeGtjVUNsZWpQMFMyM0RvTkJneWl5alNHY3FNdWRNU3Y5U1ZWcTBsbFk1WmpFN1U2JTJGTjg0NlBlcEJWMzV6UXZycEZoQTlPY0NEeVdNVTdzM0c1TzMxdXI1VWR4OG9zbVZ1clhUTlV2cDJsJTJGYlJIdXNuVlIlMkJRQ0dQd3c0VmRCMGtyM2tndGJrMDBySURzeGV5THp3UWhaV2xXaVphV1l4dGg1OE5nZ3ZhaUczMjRYYlVIJTJCc0g5MEZEZW4wclhOJTJCJTJCeHRGRDJBUE1sTkdRYyUyRnlna08lMkZyNW5WWEt3NXV3U0s2NWgxR2lwVzZwRnZSbWJ2MkdlUGFkQm5mVWZUeVZEMnV3bkpXbGJPVlN0azF3bkVMVFMwQXg2MnplY0o3ZWd4dXd2aEJnRFY1SCUyQndrYmxibiUyRiUyRkh5cGZVJTJCV3p0cWtZOTFpdzFJTXNaNTdCcllJeEdLVnQ2T3FoUGpyemdCaVdLNGowNSUyRnV3eDFxUkNIUkZBRHU5TUtRWkl3JTJGRzByVGIlMkJFSjUxMXk4Y1V3czdVdk5JQ2lTdVBwbTQzQjdwTGt2c0lESFFBeEhmRjROUkNRMU5VYkVDb1dnViUyQk9GNDdWMjVNTkgwemElMkJRNUQxVDVzTENJV25vWjUlMkZNNzNRJTJGN3hsMnV3d21Gc0o5c051QUpCT3NTcDZZbEsxRlolMkZPNHlVZlZsUmo0WTNYMzlqMnV5ZEVHVHFTR2RpclpzU01TZ3FOeHhtNVYzYTZLQkRieFlqT1BISjJVa091WTZ6eHhjNjdnMzhnYUl1Mk41OEtTTkxJdExFYkhQYVhPTG50Sk9CZlNWMSUyRlBTdGl6MEd0M0I2MG5UclV0QXJueXJ5aUU1d1FpbVk3SXZFWnF5NEttJTJGUjVNQXZuQWE2TmdDaFlxMkRBRzNOYkJnR3preUQxbk5mRiUyQk43VDdZa0lBWSUyRmlMZUZTOHpqNFVIclN4clJtb3ZZMjdQNzVTbEVEZ05lMUlvSTdZbjA2MGpNaHdLZGkyN09waXpDaCUyQnUlMkZuQmFwUXFZJTJCaFV6ekdHbkkzN0dXd1hFdWZmVEVUN1RkTEI4dSUyRjFrc25qdU1HJTJGZE1ubVp5RUYlMkJOZ0JpMlJGU3M4TWtnVDZYQkNGVFFTODRsY1FzdlprR2tzUGJ0cFJyTlUyV2dTV203MHM4UjgxdWFLRFBCTUJ4R1YyT2VIRVY1c3pub0FEaFRDbU42U0VZemhqNUFNcnowVG00emxkZHdBbXZJZ0VoUkhtcndIaSUyQld6eVZWM2NxJTJGU2VyV1UlMkI1OTdUeGphMjFER0NhJTJCek1jTVNBOSUyQjB0eFdmVTJTNmVpSlRzeDVrczRXekJ1TTZka2c0Y29aeWR0V2gzQ1g4N1BxblV3eXJjcWxBVHhtTGZ2ckRaSlVVZSUyQnljUE1tTkRvdUt3MWc2VTRtcVAwYVFTJTJGOFZJUVhqWGFCUTAzRFhnMUtiazhXR0VmY3pRN0NQNVRTb1lDYnd1ODBwVTVEdU4lMkI1N1FnYTdITTZOMnM3VVlpSUN2cUludWlONUlpVlV6YSUyQnpYVnZQUm5mYVNQM3cyZkpJckxvaUVvd01SS1g4bW05andJMzhxTWhSMDFsV1hLdWtVdko3QnFBUTA4MjE2Vmx1NXQ5WE5LcGNzdEY3eTElMkJOZyUyRmRYRkFUYlVPWDZJSlE5VFR6c0gza1FpMzU5c29nOXJFaERGTyUyRmNiQjJzJTJGZm9UbnJtWEoxM3F0ZzhCRmRHelVLbSUyQnhJc25YSFBSeiUyQlglMkJvc3RveDZaWnFUckthZlVuNkZ1a0Fma3hzTEFwSWZOQ3pnMkxTU0wyVGRhbVFFak1rUHd4T0w3MllkNk4lMkZPSkthRFNiaUppWTV2bGlnWjVlN3pIMWUyaWdDYTIlMkJkQkh5OXpQZHI5eTJGNnJKb0JxTm5PTWpnV2ZzWEZBdHNRZ2JnJTJCUjdiV2dBU0VRaFJSTGNiemhJTU1KYmlVaWVUR1RUbCUyRk5Nc0hrQnpya3M3VEZpcFFDc3VlTXZBSmxPT1BzTmt1V1BoRmJUUFdNT1l2Uno2VXBXeE83S0k3QlJ5QzROb1R6R1hLbSUyQmxOTlRlZFBWbEFBcm9waVZEd2prZXRTdE1LZjFYdmlXZVdKQmVmRDY0bCUyQjBucU94d3llT1RWZWl6ZDQ5V0lZbG13RXB4RWtEdExEZWs2bk5PeGgwRnUycXU4S0lwNTBYc0c0ZUtMcE9xNUtGbTN2eXA1ak1ScEFwVGhDdDJoSDRpUWtLaWNmaVlCb2xLM2VnbCUyRnQ3UFFLRVpDek91Zk8wWVhqTFNocjNLTzFORUtZdVh2Q1lFZktjRG04Zmc0bzhpZ2tnVUw0ZHJ3Q20xNGpjb1FBTVFEa1IycWpFNjglMkZ6U0RHMTBlZDNYZ3pQUG1zTHJhUkRGTmNDWEolMkYlMkJEZzVvS1hqeGxkY1VXSWJwTDdWb0x3R2Z2WnlXQWxqRjRxd2tWTWJaS1RVZW0lMkYwZzBsdGw1b2JxVWlhZWFKdEZ2dmpUQ09qQXBJUUl5MG90UXZUNCUyRmtQdmNWcm40YnR2UWkzSHROWnZ3bURtOHNzUGtTUmVEUXhVekV5RnlZeGF3c0tRa3V4emdhb1BpOFpOeEVUT3JOcEJFZ3dxQ1p1aEtlWXRDa2U4c1I1JTJCNXI1R0NhY3k2UWUlMkZSeDdINlRhbUVkQWtibUJhR1hQdU1jR3NNTWpab3ViY014VjQwVExMYVBtR2VRTlgwM01IZ0Z4Wnl4Z3J2aVVKNGtBbVloeEpOWk95bjd1NTV0NXZTWlp3Rnc0WG9lNVMzUCUyRklwTEhxdkZtJTJCUzkzR0ZXc0hhTTJrOEQ4ZklZQzBVMiUyQmN1blBsVXdMWXdWYiUyQjVTQnRpJTJCTmNyQkVkMEVPdURmQkQ5bVRUNm9RV2luMG1XbSUyQmF0OWlKWmh0OUFCRDU4cG9PVHdhUGFpWWglMkJnTHdYayUyQmM1RjBXMEx1NHo5czNEekZVWVJMNVhhTHJTZjVRWFBHbHQ4U0dxZnhuN1E0cXJSOXE1TU8zbkh2ZWRSMTF2TXR2Vm5aYnJKcEE0aXpmQ1B6dnQwUVpNN05tJTJCeUg5YkZUU2FaaHJONEtDQ08lMkZ5TjREb3pKMXF5QVVlaWV0TWJpb2M3VDRncHpJOHBFVWpWVVprOVNEc3JIa2VnM2FodWVVVnpNTTlpRkpwcjFhU1NTbDdyTFJMdGsyRlVNcVBvR0dVU2ViOCUyQllwTXdkYzlLY05BbnNYempYRGd2WkdLbUFNNURGbGdDdEprV2xvWFUlMkJHVUppdkI1aFglMkJhZllWSU9ReDkwS0lycThPN2tKb2p0aGFmNXdwaGNtaWpBOUNCTXVnYXNLJTJCOFZLTnMlMkI4eVB2aG9VMWJhUFRiYWZmV0VLNFJEYmJEeFgxUkE3bWdlZmoxeVNselJMREU2Tk9DRTU0YWZkNGU2QWFIZkw0JTJCaDV6NEJpa2pZVEZoZUptUWl6cEg4eE1ucWJpUjAyc3FSMiUyQnBWSFVwcDJWZndBdzNYOTFaQjRkanB1Z0NqWWlya0ElMkJjMGtDUlIxdHp1S3R6cHVWbnl2RkRLUGxBSEc5UXJLTWRsejFpYmVQJTJCVVVUQXJtJTJGOHpmMHZSdVZmbCUyQjBiUFl4TFFibzUwQUJqS1l4WHZuRTdpMGJWWFBtSW9nVEsyc3dpUHFRT3VEUUZZN2N4WGtnZWFINTNNT0RqZUFORVp1JTJCQ21MQ2liJTJCdWMxZTJZWkNaM3NZbzYwRE1WQ2JNTmZuRVdmbklwNmk1RmtkZENLSjRtOVhaVTRVRng1SUc5ZGNGSkVtSHBmSUdaeiUyQmVtUU9ZYjF2VXNjSXhRZFpSWlpzUEN1UFd1cSUyQjVkRjNZNSUyRkZEJTJGVVhvUHVLTSUyQlhocmp0VlFDJTJGUmgwVGZkWjVNTVV4OVNUWCUyQjVsMGJIMTV2a2hzQTlOZ2hTdVhhemJrUURFZEE2T2M4bU9mVk9iNUdlRGl0OGF5bW5MM1pMQkViMkdGQ0IyTVZJcGhkU3VOaENOVTdNQXFvMW1WVFpQMkZzRVZUb2ZDRUJEdkZFSWZFZXRtOVJGVHpidDMwJTJCWG1pQlpSWXdxekphWmx1TURDT1BUMHhlZW1HbzU0bG1sV3RoYlF3cWRleGxWZTR0MXVQWHBmTjRaN3EwWGxlZFR4c3J2bFI3UGNDaVQ5dnhCNEpDamJrVUd0Q1pyVG9iMVNabHYyWjA5MHRWZjMlMkJHN2lPUDFTUUxvUnlXWFI5Z2JBS1lqNlVLJTJCc2hyZ1JaMElRMTRQTDluZEdlRTh6SklaNzVqd3pVdjB4WjR0OVVGUWNTYzlQMnlGTFU4RkV0bndEU1dDT0NpeFlvNlhkMUhRV29QQzNmRiUyQkV0SVJmSWo4UVJkTVJ1U1hRWTBRNGRMWGZqNnF2VVdNR0tnNWhLU2E5bjVUU2M4VXlZMXNTUXNpdEJmZHlLNXM5TkZ5cnVDSTAwTWZRRXA3UGNnNVhtJTJGSU1XRVhkNTcwJTJGJTJCUyUyRkc3OVlOMHBwYjdNVk5FcDdRbkxhZXJJUncwbkVsWXY1JTJCNnpIQkc4NEo5Njd6Z2pPelMlMkZEOXlhT25XRUNueTF3VlNCSFBFTEJhU2NOVmp5MVIydTViZWtZUjMlMkZaRE5sekpUTXZRVGR4cjFRNFQ3UjAzVGl3cDFNMGRiOUlxWk1qSzdFWjZQSmRBalZ4YWlGa3ElMkJsTnpaaGJ4UFBCeUVSYXN5cUdPYXpJNkd2VDJoTlh1Z1VwbkdEcEtaU3JvOFEzY1h5dmFJWGZPUjRyQnEyJTJCRk5nclk3QSUyQlZwQ0dPMEMyWTIyQnNqTWx2dFhpJTJCMHVnNDIzUW9Iam9zOGVSUlA3eHBPQ0xCTGZ6aTJLTmJWaXZNZ0FvNTNYS3QzcW5oV0Z1MnNtY1JoY04wWko2aVYlMkZKMVZkZU9jZEo5ZVl4bUNHVjFjT2xEMnQyRm81YTlreHpaZDV5eEFGVnRibVNjeWg3Q2lGanFHeGN4QkpXUDlHQm8wQ2xoNWRLTjJDNlhjaUNPaDlDcU9jeG9QWm5LWFZkWHlMdkpuUVl0TCUyRlBaSjRDQVo2c0dTVFVtOXhKcjZjM2VxUUtwM0NLUEZOMVdQZ3RYeVMzOHU2aUFkcjZtZTRLJTJGTWtTR3pTcjJ4TzhyOFpGQ0Fvc2d4VXN4UGZPVThSMFBFeXdwJTJGZ25qNzI3N1U0RHhtNUwlMkZrMmRZJTJCRmRBTlFqVFJENlRSTVhxejZEbFFCWjZjR1E0ZDE0Z0phcHJ0JTJGbzVEbiUyQiUyQnlwRFhhUXZVY0NIRFBHeTl4NiUyQjMlMkJMb2dNMk11cXVtZXlNUHN0QU1nakI2QlFkdUFmM3FkMTM3Q3FOVmFnTVV5b3R1R09KTCUyQkx3Y2RSZHA0NnpNVFZnWGM1am5BN3Rwc3ZWV0pNNVNyMDlYVE1IZVdBbWE5SlI4eUNyaDJaSHR5YkREdjRoTmY0RUZydmwyZGxBJTJCbHBscGRvY3dCTnglMkJ6OEViRmZCZTBnTGVkQmptMVhWalNDSnRNejdaRmhPdlpaNWl4VyUyQkFqYzVsS04waXpwcm14NXolMkJJMVRCUyUyQndlR0pROU9IVnROeFBEV2ZTa1hOMFFSeXo0YTMlMkY3M0xSMEslMkJWJTJGQ21FWWgxdWdDd2sxaEF0NE9qdVVqWHpQRmkzVjZpUmxDc01pR1lMWTBRVlRJUkpZY09kSFlPRVl3a3pZM05NUGxhQ09DV2s1d3dpZW9zZjJKZmolMkJuZXBNTzF5bDlHVVNWSDZza0cweW5lWERyaDVmYXJqRm1lbyUyRmolMkZhWk5HMzdNbmFYOXc4UlJ1SjBwZzljZUxoYXN2RWUlMkZHNmdBbjd6JTJCaFJ2ejJGUDdBdWVSSG8lMkJhb3pJTm9SWVVkbVBYSGNKT01MUHMxaTBhOTR2SCUyQkdOSGUxbU9LYjk1Wm0xV2gwdlRTZTBnYXYxY0ZLaHZWeU50eFlyOW9laWQyejh3dlNVTTFkajUlMkJLa3k5NVNNZXNhMWN2TXJOZiUyQldjd0olMkYwR2hXS0xUT1dWSGhwUXZzOHVuSmFDQ2xGanZqT0klMkJkYUtnVFI4bU80a1g4MFhOeTF2bk5GZ3B4cVo4c1dKUzRxYmZsUmdseDVOTTBscGZsMUglMkI0VFQxdmxDTGowQWUxWEZSa3Nvalc4MVhWU3ZXJTJCVUpQSkFrNCUyRkthZnR2TFV4WE1rWnNmdzRWZnFvSFgyUThycW5rTzBLcUd0Y2M4ckd3cTV2cXplc1hncVIzY01iNE5rJTJGZmFoaWtTemhKT01GM2lrTzdCTHFpaFdGUW82QTJhekhzckRUazYlMkJPelFvcWg2a1BVRnBkODJvWWlpQkdSOEY4RXp1OHhzbGZDajlrN0c5JTJCMlNXdk9MYVdWNTNuY3ZlbDRlM0l0NDljeFElMkI1NjJTajRrdUh0R21qWUdVZnFjdE8lMkJkSHl5WlRIYTdEY2JyMTh5b0g4dXdYMVB2ZDh0R1EzTGtqcWFiU2NIU25JcmlwY2dnUG9rSHVJd1VkMlc3ZXV0aHQxTHpmeDl1Wk1PJTJCNlZGR1ZQUnZqdXlYSnpiS05MbGNVUGs0Y3JleEcyWHE2MGgwRklrJTJCbTZ5a09JTzd4bWJ6WXFMMTE5NXd1Qlo5YTBmMEszaCUyQmhiWklZVjlsclFOZ1g2UyUyRnJZdFh3YnBPS3hvaUpjeFlyVGt3MlUydk9zQTY2M29CaCUyQmZMSTFpZ2JNeGhOTHhHOUFaN240SWdQUVlLaVVQbWF5VEpOc0NWbk5IWmFyN1VkJTJGZzVrOWFMOURLUWFHMVk2NllMNWElMkIyZXBLUkElMkZkaGhuMUxRQTBnMEJ1aXpzM1phclV1dHFxamxoJTJGbUZSUG10UmpUVkNJWFZVSnNxNGhJTzhDb3NkTEVuRHU3WUhhRGd5Y1JrTUxyamhjS1Nsb21haDRteDZOMmdvRldxMUhCN2hUeFRqWTVCdlhmR0VHNTBPVGNYd1dmZ0syMmdyMHgzd1hSTHBNd01Od1RSVEt3SE9BcUIxTGxjd3lRMDlWQ3NhUDBJZCUyQnNkTElsbENnamhsViUyQkxJUlpmczJ6c1VoQTFaMGJBdmRLMHhsdmRjc0NnZmluU0lyRVl5MFBtZyUyRlZ6b2lrZGFEOFRkZSUyQm5tT2thNFI0JTJCcXlhbk9BcmNtUVAxbDlwQ0ZGcGdQVnFOVDhxZ2UlMkZ4Q3BGM0VjMSUyQjVrNUxKVDklMkJZVEpxQ21iM0E0TmVNbFBaVzdKU0htNkFMZ01veHhOZVVGTWdTMklPNnIzN2RoYSUyRldXelRaMHpZekRPcEd6VThsQWhsemR3MTZGRmJMU1BTQnZuWFV3VkNsYk9vSU1nWk4wOVlZMmcxQmZDbFBYRjZqUW14cVREMENaTmlBYnU4NDBFVmZvSXZUbTVNTDZjU0ZaRDRlTGJPVmdKbFV6UDJhUlZRcEl1OUl1RDQlMkJoZUxPbFo3QlVTanI0M2owTWxVQVpZR21kb3J4VHNYcjFuZWdJS09qN0d0MjRreHpwQ2NJR29GU1RUNFQ2d0pPMFhxZDRxUUNVNmU0SDNaWVolMkI4bEJ4Y0ZOMDJKSHElMkZJeEhGd0tUNTRXSDdOYUQ3VE5NJTJCcUJySko1JTJGTVpyNGslMkJaazFaSm5GMDIlMkZLMFpVTHZzUnVoZVglMkYyMDU2MGozZE5VTTE3UEN1JTJCeXhRMkxaRm5lc0xuJTJGUSUyRkJoUmZzUTV1TzZtdnNsa2NWJTJCWklka3FrbVJTT2t2Y3dTV3lmNFFXZlJYdUp1NVljZFhxOGkzTUgwMVV1cUk0TjklMkJsUWRXMThOSG9CS0w5bEpBTHc4c3JNYnlRYmRZVjJKUnRSSGlQSklYVzF1JTJGUEExVFE2NG9kbURNS2pEZWRRMDRYZHlESzB3aDR3aUhZZkhiUTZOdVUyekt5RWtqRTdiZUs0VE9tTUhpVUx6SVZrd0wlMkJXNTk1MmhsUjMxTEc5SUhaRWRKa0UwajVkZ3VFbVJmMEFabmpTSzVjYW5rNWxyRDFzQTIxZ0FuN2lJZ3kxSU4zNUd6Wlppcnk5eGdyMTFOZ28zRDFkcTYlMkZGQ3pnTDM5SHJwYndyOEVHaTVYMkdaVmladDg5JTJGVmpSS1B5JTJCNkxJUVZmZkxjaUtkaFpYMnNWUm1TaFdTc1BqeEY0SWcyaEl1d3pBV2dHTUZQZXZMM08xaGJmRFNyWHRUeVZLWE5sTkhzb3dqZDc2dnBzelN3dnlsNUpLOGkweXRyQnptNWhGQ3VxNkFCUXd2QnN1eVJRaW9nJTJCNFBUU3dLVjI4RXE5dmoyRnNxWVlUMmkwQWhVYzdNUXZyRXQ3RjBselhOJTJCUkNGR3NPNEY5UUpQbFRUaiUyQjVNdU80SlFnRkdGTzJ1VXM4cG8xUHlpV29EaWUlMkJKTXglMkJ2RmdSTHVhckJRNWs5S0s0JTJGVWN4aHVtcUptUGpPNThKcyUyQjBHeW5zUWFJaEVRWXd3ZUh0VHRoQjUlMkZyT05CTFBRMTYxcHBBUkhYMWFHdlFPem1COHVVTDFFbEp2dDB6akxjb2tVTE5TR1JsbFpLbENXZW5UTThDN3dkcjFXN0RsMHFydldHNDh1UVc3NXRIUlBLaXdzdVpCQVJma1dCYnc2UHNCUUtpQ2xkNTUxbWNCSUFLVktnJTJCUUlMSEpBTDdsRWg0MEcxTHRHTzA1cXpJTzdTY2NVQzU4NWglMkY1eFo4bTZQV05XNyUyQmtjVGZXZnFqYXZxamRIaHZkUHR5WHZSUHdkNXdLb05xanl0NUZ4TWNaend3Z0hjaVFWakMxZHBoS015WjdxMUJIakZ5RWVCOFJPU3FmYWt4ZDMxeU00UEZ1WjExaHR0eWd1WExvRk1zV0FtcHdTJTJCNWhlTXMwVWZBenBDaDB4UWkwJTJGVnJXTnJoMW12eHhUQTV5ZDlyWUljQlRhVHJMaDI1ck9ya0tUMmNSdnlhV1hqQUw4SDdvU1JubDZPdElPJTJGcWR4VVpGNXVjQU1meTNqZ1g3WiUyQmhvY1I2RGdsMmpuc1JPNlFVWm8zbVZPcDJJTnJUMnhnQjBkdVRodDglMkZEZlNlNFBmY2t4ZExhWU40Y1RLOE9IdGpidyUyRmp4QjR0RTZZYlpOM0NqZGw4VXpXSmhLQzA4TTRZN2traTY0dXVFS0owclRySm9pMHIyWm04WCUyQjRiSFl1T05nQTNlQ3NjQ3pXJTJCSWZ4UG9qRjRlaWVJTkdlNFh0TjclMkJ5TXRiNUtXcUxjSVlPNExpYk9XbUFCVVNWeThYMGhVaEEwUm1VOUJzU3ZTQzJpVTN3NjVoMXZNT0NyU3VwSHR2eGdJR3VUU2Q5SWlkRDlObDVpd1BlTGlvWnVqRzRMMHM0a2NnY1FqUktzUFhBV3E3aUtqMnliRmp0cDVWVUJpYWpNOHNRdlJXeUlXJTJGVHB2dmtFa3BSVGFuUDRqM3V2VVpWemJucTBMWTdlb2VXTlhJdkpuajhQRGZVTzJvaVRrcmNzM3p0Q0RxZFUlMkZUREdidGdhbWNqaTlkTjMwaVpiJTJCODlhQXhLb0lHMGxNa1ljNGhac0ZxaFdkd1BHekpDV0FoUyUyRlhoS1pLODBWSE5OZUNsY2hpRklHeEJNTVBlN1NGMWEzSU85TUZiSndNZjJhZlpzTXhwdlhJUnFWZEJqbld6cXBvdWJRU0NDWHlCaEZtbkVaOXpTZVpJa2xSbk1TOUZlbU9SWWF6NlNUJTJGQzUlMkZVT244VVpwdkpRa1BJVjFKZEpQbW1qRmZQYXQlMkJZeXBuYkNYOXA2NXpoWlRIc2RBWERLMmloJTJCbjg1THdqU3Ixc3cwNlBqR3JJQ0g0cllkSjVETEZvRHFtVnJzWXJJeXpzanYwWHFvZlNQelBYREpSZ0RycFFXQkxnZGt0S01Hc1lCTUxZb1ZNU3E1SU91c0Qyak9YYjlYT0Zoak01SGxGNzJLNmpXJTJGRWdMWkhZN3hQeDNoNDczWVE3ZDZ0QjBDSzRoeDFLJTJCTDNNME1rWUFua2czR1B2T0VBb2VWQ3R6ckJiZWdWTm9XNWVjMGZWdnBLWDhMSnBQaWhCNzVOTDNWdVFVN1VXS2dGNWVTOFF6dkNkV0lpTFh6UjBpNnU4SlRMJTJGVUNDTk82Y3cwb0ladjd6TGlxNkZPaTIlMkIzR0llVEJuWllYTnp4MVBjUUw5MzA5R2g1UzE4bTJ3SUI2VDZtbnB3bW44N3hQbnpha3NWSXRWdU9tWjdrZm1nMERRbUdPcjFBOXBDS0JoNDc2ME5UTWt6em1LWXlVNVNvaU9KTjFQalpDdXZWVVFxJTJCSDdJZG40NGkzRlQ3JTJCd3A1dVQxRXZpakp0ZzNaa3luaWppc0RsNnVyRkZwQVI3eDI0eFZheDZUZDB3cCUyQlRTOXF3NHJLaCUyQktxcDJvaEJnbG9IaU5RdGFQQ2FzY3oyVUQ2MlJnOFMwaGJ4SzFUMjR4NSUyRnN5OWJ4ZUs0OVZqVDNXTld5bkhSSm9yaUJ1ZnJTblpNbVFxNjB5anMzUzVzNUg1bGhUNDZ4TkNyM1lNVkpxR0tybU00T09TVnhUZmFWbTZRcWJ5WFowSCUyRlhxZGpTMUl1dXlvSVlmVWQwWE1lTW5LU3hVVnJvZXBObldMVkp4ZWNlZyUyQmtvR2lKRkV5ZkdrOW9ZWjgxQ2hOV2wlMkZnbVRiRzVTbm5WdVROcWQ1VXhOc09HdzJGaW4wNlRiRmxQb2R1Q1ZRUlZET05aWHBlJTJGaWpRbjFyU0sxeXpYdGgxck5xTUxrOTdWQ1pWRGtndlBYaFQ0U3ZqWUdpWnFTUFZidml3YmxVNnVOTDNzZkFQbWNSb3BHMzZpSmglMkJEQyUyRm4wakhNcWE0SmxVTms1Q0NpaDJZZENnUm5mSGdMMUppTzV2clFQSjdwQmlWMUFwJTJGcU5Nd25pMGZKaE5FVG5BRCUyRmFLVEViNjBOVmF2QnhxMURwM1dlWnlZZmNLZ05TVW1XUHdOdmhNTWFsOXdGSWpLM3RLV3c1QnVlV3JZJTJGMnJaZFE4VDcyYllsVXpvTTdKUmZ4cW4lMkI0T3F4aWw3Vlc3ajFjSGFZZEIzV01ZNldnNkt3NDlPdDQyTDZlJTJCeFlud0dWQ01JWFVyUGlXcnBVSGNZJTJCSGVmeFhTUXNocE5QUVZjOSUyRjZhNXVscXBjcTBDV05JazBwWWdtSkVGWTRTdjQ3alFpSUFuZUdSY0U3N3k1RiUyRkRTVndkTGFDcGxBbmU0M0tNODE4RGVPSEJpTFdCdE9UbnEyenpqYTFUT3k2QkdjTWRxZFh3S05JcmZ2TVBiRmRndExjSmI4M2dZdlE2QWFLbFJ0ZVhZNUpIUU9Ha1B2MnJJNmtSRXozamoxQ2dHcUE5MGZrUkxKNHlMMmJjRXppRmNVYkJ0VU1TSCUyRk1UU2l4QXElMkZLTXhWd1ZiMGpxOHNGenc2aGM0NnNieVNSaGdldFoxMHUxMmh2UXVJdkJyNDVCbGd1MTh4b2pQWVBZSDNXV29YTUxLaEslMkZranZid3k3YjJUd2d3OHpLZGhxb3BwYTNieDZxcFpheG1QREE4YTkwVkFXb0FyRnpPVlFySWk4aGpqbnNaNU1QbVE0b1ElMkJtQjdPb3dTV3RGbm56ck9CcCUyRk1UV2hBZHBNNVgwUnY3Y2FiTVd4eUczSEdGT2R3ZnglMkJDZlRPMk44aExwdE8zYUFNTSUyQkRPcllzTTR1N3hjSllBZ1VDTDFoJTJGd0RiRGc5aVB2VWhEeFBBcm1JYk9Md1BXT0Y2QklPMktqVDdNQSUyQlhVSmRuOHFZeXVoc1dERnlMTTNzWUlHT3ZBbTNZdmhRTmlXWmh4UHFOYzFxamtqd0Q1OGklMkJEY3RQa3NsQzJXaEoyWUxtT05GcjJFN0hONnhZT2NiVkloTFpCUUxhR1NFT1Q5MzNnOG1XOG10STZUU0hKaXAyc3E1TzhVQmxiRnh2VGslMkJ4VWZGbVk4aHdqZjJkbVBHUGlCcUxlM1lxV3pHcmV4bmd2ZUJXOG94aWp2bnN3aFhyNTNkck04U2RUcDdaaHA4TXk5YzZaR1ZxJTJCenZxNUl6N011SERteXJ2cGFvT0pXSVBKNDJpcmxJNzQ3WUFRSmg3d0ppcmFKV3Jqdmt5ZVZGRTlidTclMkI5bk11NzVEUWlkd2lFVkklMkIxTXA0TU9yb1FWRHVlczlsZ0Y5VmglMkIyTGlCOW1vJTJCTENKQm42JTJGZ2duY1RISjZxNjRGTkRJTU1uQ1VEZ2lieHBRamY0enJtaWQzVU5WMndSN3BIdzF4M2dZVENENEk1YTBPTWdvWkhKdVdMc0xCSnFnd0JwS2lGVnJZVlhRZmI4UGxGdjVZcFdtNmxlQnhBbGx2TFVMd3d0V0R5T2NROHhoZGE3UWg2WFlkZ2sxYk1JQW1yVVhMS3N3Tzg1bmo0ZzNCVDFaUzVwV3c1dXdtRDFPT3RiQk1lNGE2UU1wWWlWZnFQdUh5aTlHdHVyOWxBMVdZa3BWQVJTeGFPclFIT20zaEV3TXBIRk1ldkFJblYlMkZHMkhjQmVBJTJGWklCeGE5SFVUdzhaSUp3dXJRQldkRDdJajBhV3VaRzloMW94MmVtdVpuY0Z4bTQ1akdybE9xcTZMRVhZZDdOQjhWOGV5M0JPbnZjdiUyQkRJS1J0RjB3TkJmNzgyWDIzdCUyQmtJcXBENGpnZWZUanJMMUFJeW8zazUyaGpZJTJGayUyRmJDSSUyQiUyRnN6VTNpQ1kxYzJrZmxpU2Y2aGo5alZ6THpoczR5bVdJdDdoSHZoWHpYcWN4WXBWZk5zUVB2ek5YcmhpcCUyQnl2bVY4Y2dqNWxpdXprcVQ2NjJ1RGhQTE5wd281a3g1Ynh5bVYzR0JQcnlvS0VlUmp1QlpyOTY1akVSNXVGRTF0U3REb3Zaak12R0Q5dEJKRVg0Vnh1Y3Bpd2xISWNkaVllNHZDOE94NFNsTzBpVlQxUHVMaFNSdllzUFdFVWJZeUl2d29lM1RxWW9Ua0FwY2ZWcnglMkZIbzNhWVhWQVRKenVrampsbjZLdHVoeWxCbWlKbmRxR1pLejUlMkJPaWolMkJ6UlhpbCUyQnk3WmJxVHBMQlpSOWNZdURHNGlIcWpiN3N5NFpRMGlRcWRUT2ZXeHFVM3NXUSUyQlVNOSUyRlg3bTBNSHNVbU9ndmU1eW91VGIwM2RQNVBCTm14OEFJY0k1NHFXVXBPQThpWEM1QkNycjlFSHZNVE1PZlNhRG43MmNvdldjNE1ibmRPY3FQSlpQVldxV1gyenZRYVJqR2RhbVE2VUhYMkdsdmRNWXdVNXJvZVpLb1lzRGh1bDY2YTlwJTJCRnFRZ3QwNGtrdm51UDZENmJndTV4VVJsJTJCM2xzSEljMTczSDNzd3VWZmF6ZXZ1RjNMeGdleXolMkZqQmxac1I2b0swYWpTanlZbVg5bGIlMkZlQmVnTnN2NDJ3Tk9ocnIxeUFSamRLJTJGMTE0N0NIVlMlMkZzOVNxYWhaMCUyRlFMOVdqRzdNcXBlc0J4YVM1bFBLRlZ6a3liTVJ6b2hkcllNZmUlMkJPNFVFTFlteEYycEhueGE3UkVUWkowaSUyQmxkV0JwdDBwR0lWU2JXTCUyQkpDMlVaRzRSWWhIbEVFWGZoVEpHMCUyQnVDaDFYMnR4TDlrbmptUmVNZEo2ZnNOVjRkcTUxZFJwa3JaNEQlMkJKQSUyQmI3NHhvb21RTDBlU0lFZ2ZGbksxNHdITGFJVlB2S0hjV291NEpKbWJjV2ZWRDRrQkhLTGJGb0wxbWY2eUtxTlVoVWRwallpblM0YVpiSVRONXElMkZhRkdKTFR0OVo5OVlQRm5FekklMkIyc24yJTJGWTdJcTRkbW1nb3hsa0s4eHhJUDlVck9zbmpRNm5YVlpNSkRYa3pDRkc4cW9SeEtKZFZxQ0FrR2RzJTJCYjJsMFpoTXI4VDNDdmU5U2k1aEQ3VThVblloSUl6RkxqRXglMkZwSzdqenVZR0xPRHUlMkJTc0Q5ejl1R0ZBdktjUTNDTFdwS0dNNXlQbVpLbGtsaVRnOVZXb1NSTmZibmhSS05ZZlpXTVRhNkolMkZhMTlic200UFdXazF0ZUh4VXB2T0hsV0dtM3BRVzVhQXJsQlFNSzdyejRscE8zV1BkJTJGbWlBSnhDZmlGN0tiODVoNThoTjUwcHJ1MVBrM24zTXVrSEV0dFMxRzRveENXVUg3b0JWZjJGRTk0cXFXclpsOXYyTHZXUUlZS3JiVm42V2J5eDJENyUyQlRVZjdKRDJ4dGtlMER0aSUyRkh1ZzE1TUxvYTNzN0UlMkZpOWxnUCUyQmZFVGhYeWRGSW9TbFolMkZQd2RaUmRmVWQzNVdjS2V3ZE9OT2ZJV2MlMkYlMkJEeGcxUjI2dHlmQnp4b05lY01pUnhpNlpBVUdCYVJhbDROVndhNzRXcElyWlgxaCUyRkJadG9DdHJaeVZsYlBWMnkwSnUySHlnUzBybXV2UnJtcGclMkJhMDBrM0JKT3o4SjI4ZlBFNWM4QzRKVXc5NGtadUZZa3BiSnQ5d2ZlZmw2bW96ZEZ2UzZTTEJRJTJCVmVPb1clMkZDbmJLUVBiV2hIQXpZRDZNbWp5WW0yTHI3Sk5PYzBRcUJrVHpuM0ZiSVlnMjN3dHBKUk5wejlRNkxuY0c0QXlxJTJGNzEzTUJsWGdzQVpKYjE2bkxMa25STXlIQjBrYlJZdTlhSzRhJTJCcHQ1VVUlMkJnMHMxZjV6USUyRmlTOEJWWmlIbHIlMkZtTUhhenhNVEx3TmxLRHJaMWlNcmVRanBzciUyRjVYQ1p5MU5JV08lMkJSN09IR3EyYU9WTVZCY3dPRkRVTFBkcVhINW11JTJCZGpMZHNxUFB6RzJzV3B5QmZDTnNUNXJVOVRpZ2hHWDQ0YXpnWVVWYkdhb3VQZmZWQVVHVlJ4NDFtUTh4Q2lOa2FqU092VUd3UXZ6Sm9JOXMybzljOUY3ZnJCR3A4VDUxQUM2eU1NZSUyQlVUb1VoS3h5WDRnT2xIZFE3bEVyVzBHeXFzSFByRndIUDV6UmIlMkZsOHJOMENueDhXWVMlMkI2Q1BoaU9pYjE3UWkxWGZDakZHTnVZVzdLM0ltViUyRnZsWE9vJTJCQVpYUG5CeVQ2elFkNmRoTlNrZzhMVjRWSUtZMyUyQmVVbUU5WXlCNjBhODJ1eUd5Mkt4JTJGekx3WjJwZjlsb3hiZktKb2N3NlhQRWhYMFZlSmVIdlJ4T1RvaSUyQkFBMXU2TVNScktXMllISTNRMkRuRXpDemliNnBYUXkyWG1OUGp4SGRjOFhSaWRQOGhqZjdpJTJCNHE0WE1yTjJHSEFxSDY2SXZzVCUyQjdCNVZoZEI4YURhd2dLZm1vUTZsOFFHdDE2NUJFcHhxdE9Tc212YU5kNFNTcElsalZtTVQwMThBQjgxTlJtczNGazJYekx2NURDQTl5Z0VNN2I0JTJGTWhuWWVIczUxV2RxZUpoQ2slMkZRYkRJa3Rpa0wlMkJ1TklOU082NFdsYjBldjJEWFd2eGJPakl1a2IyTEZRNkNiOHJ4ZnRQRFJlelpsNmpEUUJOdERlN21xMUFsUlU3aVBPZjZqbzBMcXVQYlhFdmJRTkJEMkRRaW45czRwZkxSUExPNW1FdVY4bHVSTGV1aEJURTVoSlhIZXFhRzlQc1l0amo4QkxZMXZER0NwUjhEQ01xaWRMV0VzZkxsTlZJOXVGSExETlB2TVF0OVpqM2FFUlhiaTFtWmZRaUd1eE9yUHolMkZSNG03SlFwYlRSZGpLRmYyb0x1WlBuQjVaWEJmM1N4QUJjMG5SdkhlVEhWV2t4aWd0VGJaaGk1cURQSWNxWnpoaWtrcVNTTlFvRDRpZ09GTDNyRFptUllFaHVzQWp5THIlMkZ4alJWR29QMzY5UTViNjJIOFZTNVlNejFwdjM2TmdNUnVReHcxZ2tNYUp0VjdIbjVZbWFpSkl2Zzg2emZwaGFUMmoxZ2ZYS1RiMTdNOHc3QSUyQlBzTG5RbGtRTjRYVmZVMiUyQkhBWTNua29RUDZkaEdiZjVrUWFDVFQyWVhDeEF4UFFpNXJ5NmM1Y0YyMVdKc2o1TkFKZXZUU2VnOTBIbDUxaW1KSTZzcGFtWUI2VDZYJTJCdDlzeE9VYSUyQm9lS0ZMa1JmWU1CaTJ4bnVWeVI5MHBCTEdyVWE4dmhXbjF4S05oM0N4S3hWbGZRTlM1dGtjRFhPSTJiZFFZekJsOFpsNFZSJTJGMXptUGh4WWFXQmFNb0kwNmV5YzlVdjhpYmFGTkg2aU1OWnc2aTdpZSUyQmdYMnZSMnVyT0ltcjRsUEdYaDV5OVBrQmF6QWNOcWtHbkl0amFReGZuZk0xbHBjTnJHRFFLUG5hb2xkNkVHcklDYzZtRzZPbTVCY281RFN0NTgyUVJIVkp4T3RsNWhBRHlUVGtMcVBYR1Vka2wza1VackY2eW9jVVlWRGs4Rm1MSHVxV3JVYTV4ZTZ1bHZSYmZMSVFaWmN3VFBOSHRBYVYlMkZMdDlhMjg5MTlYMXhUTTR6U2FlUTdoTWpSeTVMTFF6S0lVN0Nwcll6Rk5JZkZYY01PNTglMkZWWDFhMHBBRWoyMW9Ccm91TDhvRENGM29UTGRQcHdNclZvJTJCSjgxbEpXeGdTU2hSMnUlMkJtMldVTFFlSGc3MDFUckpBZk5EaGxPQnVXOG4xOVFQZ052MlhVakpmempxRVdNekhhRHclMkJDdERlMzV5QUFKMGFjcTFTQmlUMmxpTWlZZWZaWmJYRE9vdmc5dGllS0FETDdtQUs2Tzh1VURlb3FLb1VobGU4Vk1Fa3BERmFlaVZwdk5YMHlSYnZGcll0UnJQbDJweDZzbm8wTUJMa0hwVGNta3d6bkd0SjRUOHFZUFhCWHIyUXElMkJRUmJXQUI4Y1JpcWRHQ2Z4Qkh2c21FQ0NGczJPNklKT0VrSGdCcVVNR1NJMlhlOFUxYXRUUm5xMEo3N2VCQWwlMkZmbyUyQnVKc3pqN3JLWXl1S2tJbTJpUDBVMVViOVM4djFvcHJRSHB5JTJGR1ZwNE5RZUE0S0huekxaZ3FPJTJGbHNEOTk0RjBRRUVldm1UMzRSYjg4anYySWpNNU1abGZTdnBVVmRCVmtOQU10T1FFbTZzVjFBS3hnMW9EeGMlMkJUbGZlZ3E3ekpmalZ1b3oya0FzcjBPM2FvSmFXbkolMkZya0FqV0hXbHkwZlp3bUdaWGp1THBBMDExbm9lS2kyR0pGSDZRZUM2TTVVV3FNSHVjcDdmNTlOUUVBZjh0c3JTeWgzTVVaT0ViYmNYaUZOckQwZlE0MG1XQWFLRGVuUEtGY0s0cUZkNGZiR2NaUkF6VzM3c3QlMkJOTnpjZEFoY0I1R3NiWlpWcGtxc3Zob1ZjZmpaMzR6cVJadkxwWktjSGxqNWplaVJRbFh3WiUyRjIlMkZUNiUyQnA5bXpFVTR3VWFKTmwyQXNqc1FQOURPRWZ6UzE0bkNsJTJGaXRuTVV5M2NvM2pMODdEUWx2b2xPMXByVmtjYTVHTlF2enBCNUVoak9WbXdBJTJCdVk2MUNUTkR6Mng3T0cwQXVBTVVqMVgxJTJGQ3ppZm5MU3NsVyUyQndya3RWM25WczVDUGFuY1d5SG93JTJCWGFvVlQ2TE5zMUhCTVQycU9MZnFDeHpadXJQMDhxNDJUeW1MNVdzWHcxZW9tMWMyMW5zTmZXS0NMRHR2VzUyejBVcVhueGMlMkZJMCUyRnVtYTQzdndiTSUyRmJRblZhc0pWYWtjNkd1Q3NQbiUyQldxeTl1UGsyeSUyRlIxSlFOWU00NVF2b1RoUGdsWTdtVUFSVFpDdTNvJTJCdVhvOVNFMjY1YUg2UzdBRDZRSWhvJTJGN3hSMyUyQkRuRXpoWkJ6dkVZSkk5NVdQQ1NLJTJGdEJ3Ulg4czZnY29lYk1JMXRPTXhsRjNlSnFDcEY4MVFPdHVLUkJhZ0dlbVBGTyUyQk1aeW80JTJCbVRKanAweXpBbk1UJTJGZGRhWVB3Skg1czRwcUNxYTNSOFl6T2hYbmhUVXc5aFFWWkpjdWhBMlhGSkxGVVM4aUdtanZidElJNVJYcFc4JTJGQ21jWTdibEVONmV1T0VQU3phQTlSJTJCeVBGMVpudk9aMElYdG4lMkZaZWs2bGlWRll1QXY0YzBSNzczbmhuZU45M3o5d3BzOVRNeEVURGZRVlpJeVUxSUpIaTlVTVcxS0thSm4yYjVMbnRuSjhnQlQlMkZjdUJXOWhyZXdlTlNSOUhScW1ocE1xNzl4OFNvNlBRTmlBTE1TMlZMZlJQQVRNc3hOUWJ0OFJzYmRJVVh2c1BUaGFNZkw2N3hvNGYlMkJYOEUwaGdOTVk4NUROTDA2cmlXRG80dTJpQ3RZWERTa3lJdFFrWDg0bCUyRkc3MHU1VFFlbkE4d25RQnYlMkZxJTJCZlFHSTJrVXdHN3NPaFZmOGR3Nkh3JTJGT2sxUzZZUCUyQmtKQWc2QThLZWxjUjkyZ0wxaERIMDc5anZyaWJFSlByaUh0JTJCamlLUHN5WDRSWXJ3ZnJUendROFlBOW1PUVBMTk5JSDhJNlFJUjBEcGx4TjJKeGZxNzV5QXloaWNCM1JQZ3lqT2xhWHNTRzJYT3NDUmtNcGg4aEFVblElMkY2RUdwajZDNTFGajhidjNObUFQR1JPUEdCdnc0Ymt0bW1tNkNsRUJoTk1Md0lSS1lGd3ZtZ3RBbVhpVXBaVkFWdTdJYktPJTJCaFFWNE9sZUIlMkZzN01DS01rNkJqTXltNDFzQkc1dWl1OSUyRlJZeXhEUVpuRyUyRmVCRUZ3cnlhYllibnZSUGI2bFdlJTJCZmViZkU5elpxQXBHRkhXTlFMWHRBbjR5TGxqSENkN2YlMkJwSnRJWExlTE1OJTJCRFM4OERVTTE4VFRwdVRLZll2clprelJZdCUyRjBWOVB4bG53UTFoSnBwdUpVeldGdm1JaVRTMUJScEN0JTJCV2xpZXF2MmE1T0pzdDVod05JZCUyRnN4Yms5VmtLTExiamIlMkZseVdRTlpWOWtHWlMlMkZyMzdkeWdrJTJCa0tLMWpzVERGdUY2JTJCT0lYaSUyRkRES1l4QVpTM3JreWpjOU5mZnRzTlpXNUF3ME5mZmR5V1FOSCUyQmNQUk02VnRMdUtWRE1XZFNmeVBuc2huZnhkWTNpWVVnRlYlMkJiRTBRa055eHNZbTBDWjd6R1BJQyUyQkg2bFRPT3dPbzdWJTJGV3VpdXQySmlpb2ZhcXYlMkY0VlRoWTc4UUM0bXJBYTg4THRYVTl4WWl6TlNRQmFEYWhxbkk3S1MlMkZ5ekVraHM1NTd4UTYwR0U3VUIlMkZYJTJCcmlzaTdPWXNBVzhIRG5kQTFTZDM2Slh4SkcwVjhzS3VrdTRqOXYzS1NxQ2QlMkI2YlNsazFLNUEwJTJCdFklMkZWcVdhYkltZVlvaUFCRE41cThLMSUyRmRvVDFqNEl0amxoU0xXcUF5MlJjTzhxWGxPWmNGQ2poZmJCem9kOHd6MWR6b0E4N0F2NEZ2ZEhkalROWXc5WGZPdTlXWUE2VnJZNEg3cVlId1hHd2t4WFk4ZjRJNDdibUk3RkpGc2tEJTJGJTJCdDlyOE1GeGhFUU9Ub1ljWkJsMnNUWjY3dm5YY1dtcSUyRlVZUG52NThQZHV3UUkzeEx4YTRVSmhvN3pKVVNKM2hTZGM2cE1QbTdEc2lsSXF2UGNJSkgwTkd1JTJCJTJGQVlCMiUyRmVGSnglMkJHOVVpeERPeW9SOXBiZmgxTnFpZUZWR0IxRkh5VHY2SGRva2JXdDJDNk11dmNabjZSWWhNZzdmWjBJT1lzM2pqZFhQWUpOeW9vJTJCNGdMUmtOWU1Oc3k4ckM0M2Z3THd5VklwcXRYeXclMkZKSkNNQkhLazFJQ1cwc0VyVmVYSE9LOG0lMkZLTHd0Wm9NeTBQdVFqcnp2ZlAyTFhqUWhzYW9aOSUyQmQxMWNoV1l3cCUyRjBtczUwZGxHaUg0JTJCZmh2MiUyRm52WDJlajRMYVY0QjFMbDhsYTZMT0RTNnN0Y3VjdnBMbmpidXpkb0pmZ1lvcU9kZkdLSDB2V0JLJTJCVm0yZDd4UHk3RnpickhIMXdWOWVtZ0VjdVpBSUlQQyUyRjBNTmUlMkZjUWs5VUN3bE40WXlHdHZsaTRnMiUyQkZRTGsxQmtvelJPWSUyQlRsQlNHRDk0MjlLczQ3WCUyRjI1THoyNnVyYTE2anlHVXZCMm1JRmNNaDJ1YWp3WTJGNGdDJTJGODJtc21KdzlMT2VsNlFiOHZTbzV4cXJsSm15aDVIcHpLSktYWmllSzclMkZ6QyUyRkFJUjNSQ2JMeFBGU0k1R3RNd3dqZHR5THBON2RmQVFJcDAxekZVSHNXMlRUUm8zTzRZSEZXVExxSjRMd2I0RHRKVnZzQ0ZaeEFHcUR6M3UlMkZvNTNzeENHJTJGZndUcXF2V2JFMGxwYUc3JTJGb1ZKOWg2M2JXaldnTGQ1ZCUyQlFRQU5EUEIxbXdTbERwcXBYNEhJbW5KMGdCUXVSNlN0VCUyRmRjMzdLOTlETTY3Vno2dU5qVFpjRTdXN1ZHdDRFYkhERXlieGU5UXI3ZnR6aUolMkJsMGtIMCUyRjh3Tll1d3p4UlVYTVAlMkIyUkxYS21VJTJGMXI3Z00wZEhXJTJGMEVBNnhhMlYzd1g5YlJaWHh6T3pBanNpRHpTOUVFdFBvTjBUUlJHdUlWcUV2RjJqUm5CZ285Vm9TSXNYSTBONVlKQU9vV2l4NEdsMU8lMkZnNmxEbUVQV0ZoQ0RjU3E4UVZGRUFSTTNjNVVmWVVFWVhvc1RNb2dyQzExc0dQSkh4cjA4OUZqWDlIM2FRZHVZbWt2ZGVpY2RlZ2VUcW5mcnFpZGo5UXBmSmc1TnBXczJmdXNHZFdhejNEc3cxdDdLN3NjWTNhRU9jSk01TmpUT2VtS3o2JTJCNENOQlBYNVpHN09tJTJCT0dibzhPUG43QnVRSFU4WUVtc3ZQVjN4cFY5bTBVYkpxdTVFNUxLQmk4clVvUEpKZmFrNEh3JTJCSHA3THR5V3lRTXA1MGlTU3F2TEZUeEtZJTJCNnMyT3BTSzJkQ3Y0ZDFRZmkySU95eEp3RWdKVjZpbkJBUk8lMkJqYnh0QTJwTGs1UGt6QjIxJTJCQ1JKejkxd1olMkJDQU9SNUI0NUk3JTJCZEU4VGZJaDdJMFdhSExtaEoyUktReE1ocTRpU0QlMkJ5dlloTm1ibXlkbyUyRnhaTEpVN1dHTHF4SFJNbzBpZWNrVGVqY2NlUnFqTGFBSnRMb3N6aXllSzY0U3hhbHIwamllQVBwNnRFU294MWRTY0lEMVhJUCUyQnBQR25ySEdONndWVVlQOUltT01Wc0tKUlp1QmV5SEUwRFoxUGoyRVNwcUlkenhxblpxQSUyRk15TWJuUHFqRnlqdDE1JTJGVVVRa3olMkJCcXd1anFxazVWU2hxaU5iRVRYZTUzMnglMkZXU3g4T0FnUXYxanFEeERSZjY3VWNRYjV6ayUyRklmaWVCeEhlWlYlMkZjWUdVQSUyQmZRVHdndnN5Q2tyZ2ZmeXN1RVI3ejNJMXprSVpod014TG13U0xzOSUyRlhqNGpXaHFuamcxQVVOdnBGRWpGT25jYXR6UU5oY0tUM01oa2s2VER1NlgwaEpMQ3M5bGR1JTJGYkFKJTJCVTZKJTJGZlkzOUpIMUhhS3VDMjZyV1ZyWDV3T2ZhTFJKSTBEZkJ3SkdTcjFCOXRWc3FsOUtmeWZScWolMkZyRkp3MSUyRm9vU1l0R1B6ak5vYnNMczZobW1mZUk4UHc0VWh4Q1E4OElDd2ZKSzVzenRaeXVWcjRmTDgySTBEUUFqN1clMkZqS2FGTnM3JTJCVGl5V0psViUyRnVFUVVPYkxrWSUyRkYxVkVwMkpQaGFDMTIlMkZ4cTN0SkxEbldjWSUyQnpaekJraUJ6dU9SWFpZT01mSjN1aG1vdiUyRmcyR1NYcFB2REFGVEplSXNzQXclMkZldlJIdHNvb242U2pYRFRrJTJGQmhEWlk2aWUzT2ppTmZ2TjdJbll1bzFzZ3hSRWREeHIyaDNlZ1dTZHg4STcwTUlveGxUUnlDazlDRWJvc2tuZktlaGZLMEhlQmhUeE5tb3BUZVlBUDR5Z2VtayUyRnRaWlA1ZE1ZZXdORDk4WUJVeXE5eVBoWnpzbGppYyUyRlAlMkJBV1NhWXczN2o5eXAzUTFiRk92TWF0RmhIWnNla1A0MnNpc3RsT3NhMHBGVmFnaDlxJTJGMUljYzRidmxhUUR4VXZnYTNqdUFaZjVPQmpwblhtNzdVMEpnVjV6eE9JbVEwJTJGNCUyQm0ycEhkNEQzV0labjlYQWREdUc0SzZlSTZIV1BpbFUlMkI2QWlZODRNTmhKeGNzQkZMRSUyRlRLZjVpQ3hhaWxhYU9VJTJGZTU0a29oVjF4U25BTmJ0QVlBcE9nekFraiUyQm1VVTRNZkh3RSUyRkwwUHhwRmxmZWRNb0U5dVBabmZpY0owU0xpRFZFNHNqdUh0VVlyRk1MQUtKMkFMNDJGJTJGa3ZmRnNIN3UxeldoT3hQOHMzNGc4VEd6VWpiWVVRbm5QNEg5ZE5pNjVzMkRITFE2Q2ZPWDJORnQ0ek1VbTJPSkFpTFNDMlFTYlh6ZSUyRjAxRyUyQkFCYWNKdnlsemFSJTJGQkFTWWg0UTZOeEhLTGFqR2FoNjA4d3M4cFJhRnBoYVhsNlFXOGdYUGVDbkZ6MUR2NFhrRTFKY2Mzd0RiVjNDZzhNb3gxMCUyQnFCJTJCUzNVUjhYRXFJcWJHQ1BhaVE2MUx2JTJCdVVwUlM1Tkk4bXk1ZlhXYVZIVDdRWlFuTnpmakNyTEhMVm1GbEwzNjliVTBSTCUyQkF6SE5OU2E3T0NNZGVlM2pzSUJFaTRzZUgxQVpsZVNkR0g5R3RzT09PaiUyRlpZb1R3cmh6ZGIzcnFVJTJGMWtGaGpBNVkxdjM3SWpxQiUyQkdXREh1dENNQ042VjVLUmtlWmZaSm9JWm5OOHV5SXJ4JTJGRnpCcFNpUVhDQ1dENDBHc0FscU1DNmVVbm1hdEo1enh6S2k0b1RCRDZwUDR0JTJCZVRWQ09wQ0JEN3BtWXFlVDc1YTlrMEtDOHZmJTJGeHd3d3QlMkZ6cGFWNFBZSkpQWlRPQ09lMnJmeFpmQjQlMkZwY050JTJGUnVuWUc4a3Y0VmZ5SldMakFmMXJTdnV0OTBnRkZZZ3pCVkt6QVJBZ3NJVVNQN3FtNWd3TWFmSWlQdkpTOHFlNWtkdHR4cmJWTGN4UHhyNHFTcFc1YiUyQkNGSW02Q0ZzVUVQSFZGaDRNYW44czE1d0JybmIxWUFWblNHTm1tQklkckJIMVByVDlEU25tZ04lMkZGZTFRQ3J6dzJZUyUyRjQxQWNpQUdwM2JtMThJRHBBck9OczQzUWEwRWw3OG1BZFpjZ2lMZzJTVnpPSExQTGZBMTd0YzM2YkJJeVJJVGhxOWp2Um9NSllwdXV5NUJJODVSaGttZSUyQlpYJTJCalBoSTlxJTJCMzR4MlhvYnY0cTFkOVhCUXZwZnVJQldZdm5IN1FOZDF0aDNwMDZRM3ZUOVdoTFFodHp3Q0szMUlpMkhrZ1BQcUtUSmpiTmZMSE1QZGpldzVyWU9pSkFMeVVIZnNnOVRBRkZwR1hmcnJZdFJNMnVqSWxaQ2ZhOGwxazgxSThraCUyRkZGRWVhUkVueCUyRmNSJTJCWDJGN2FlMyUyRjVyWHZ0Vm5HTlBhSjBuRWxDd3ZQMkElMkY2RzJic2dXUThKZ1clMkJwSFEwbWEzTVYyT2l1Y3FMJTJCS0p1NWFsRWgzaXclMkJnS09PUkg4YkFoeENiM3hWQSUyQkJqRTlHODdTOU9LTzMwc3pUMTRjaVAlMkJ3S2E2NkIlMkZYZEVubnBWVkNUUU1QVVlXd1ZDQ1poVmN1WGJwampwR0N6JTJGRmFGbXlmMlZKM2J1ZGNRUTZuajVBa3YlMkJkREliY3luS0JKcU9HUW00aDh3aDNBUkNwNmxOb1NQbHA3U3BCTlFoclV5VUNacVhzaWRPa3VaT1IlMkYlMkJrN0NiZWVVU3hHekp4WTNhNmdOTzlySFBwcTc5SjBzRThPSyUyRklQUnhCd2U2SElEMmM0VER3S2tRR01zaGg3OEV4RThaYWtTeGhUa3ZWNUl4Qnc3SlcyJTJCMmtSc1JZJTJCRHJobndLSXNscWd2UFRoaW1Ua3FWNTZhc296SE51Mnpnd0VGU1ZIUiUyQnllWEpKblVlb3ZsNSUyRm43UmZJT1lOTElnQ2d0SjU2aVBETGdWbkNieEMlMkZOdGYwJTJGZFYwciUyQndZbSUyQmlhUThROHVaQXJ1TXNTTllNcjc4cG9WcmRNdnYyJTJGTzRCUHFmRFNvUHp1bkV4NjRsUWY2RyUyQkpYSyUyQkQ0Q29UbFJXOWJwMlRWYXh4bzRwdVZDSXhUUm5CaGRUSG1kN1MwemxqYUJDOWtSajc1Ymp2SnE5WWRmWUtGUTNoajUxYzFDeVd5aE02NldxOWNqSml1bkx0Z2d6M0hOY2E2d3BqWGhuTkRVNCUyQjJ2aXVOUmolMkYxU01mZFhMbTFGWkFiRXBRcFIlMkJQR3pLaFAzSk80MFpWUFNoSGVMbUo0c0dCc0haT205V0hzc1VxWGhJY0t0MUZIJTJCQjNybk9kbEs1WHZZQkxQSllUc2Z4eEZ5VU9lZXA2emJwOHRVSGNRMkVQdlNtOVQxJTJGUzF1ckclMkZZWHZBdlVRbFZrZGpaWHpoTm5OR3NFZHclMkZuQmhrbnR3eExKUTE2SXJUbWUwMFFGUUdWR2dkc3VmVDRrQTRnWmlOYTFHTDlGSkVSZGtYeTFraiUyRmhlUXZSQUZrV2dHNGJGOXVXWWlDME5HQnhET0pZaWhBUFFjQlFsQzVUNkcxNzFucG9PWlJYb2xEMHptSnRETHBKNHB6JTJCQUZuMFBzJTJGTExYNW5KM0FXRXpJYjI1Y1RWciUyRjhpV3IlMkZxTkcxUzJZeThlZ1pzendFTk5QbXAydVJ5NE0yJTJCN0Q3RW9QTjhQbnoxMVZmMmFsRHNzMGdhUERxZDdDTXJUZDJlZUY4cmRhdDRXNUE0M0F0aiUyQm1sJTJGJTJCb2taZHVhaUI5NmJWbVJZRXJMRGVQSUw4ZUV2SmZWRW83cmFFJTJGSmFOakJHNFozaTRjJTJCMGRiZUJaYVpEVm5ER1lVNmVlem5mUWRqSkxqY0ptZWxUJTJCT1ZNSmZJSVdjeHI1TW5SYTFhRzVCRm5PbFl6c01ocGNxZmdBRm1DV2kwQUNsMElHcWRKM3hDR0pDUXVYdnNuVEUzZ3BSaDJFNzJDaTZxd1IwQ0lyblQ3VXN0U3QlMkZ6bWVSVUx4VVhxc0RRNlVsZ2pyUkNPU3JMVVFuN2R0QUZyRWh6TFNXUFVyTkszckdlZmZzMDZFSlc0ckcyWEwyem1UZ1k5ViUyRmRxWFB6VFhZc0hsVzc2TTVMVHNCSGtaU3E5cU9qMVE4WWFjYkJMa1RocGg0UUNsVllmY2VTJTJGWHNaZ08zNUtsVkZvUlVRWGt1dXI1aXVkJTJGYXMlMkZ6U0VWYW56SkwlMkJZRzU3S2JVTnRNTHFtUDZYRklyJTJCcjVmTE8lMkIyTzFMOTBsbmxRbGNhQ0thd0YzUjB5S0QxMlo0UTNtM296MUs1YWFvb3FYbEs0MlNsQVo0RSUyRmp5ejd6MlIxQiUyRlNmYVhlM1h3TDFIbW5NWVBUSiUyRjk4RFE1b1k4ZkZlZjRpOFRRRDVId0w4RFZZV1k4MzhCQVhzU09icHdlU3FMTzl0NTBPUWpLRlQxakdxM2E3SEhnYnBuQkMlMkI5dTV6ZkplRFdnS1l2ekFNcnpKMjZCWnAzTjQ0dDRqS09OQyUyRlJqQlVCR29FYUR1TzRacld2WEV4Mm9kVGlsdWphSmtMS0NRMU1nR2F6Q2t2c0RmWjhUWmE5czA2MnFHZVNlZk8wbDVNd2NxNUIweGhITWhCNHNEbDlDTDl0bjU3MUhiRXFXNGJoU1h4a3JZejBOUkFaaXhJMmxQYkJOTWkxT1BDdHhQaHRmamdoaGtkMmlHOVlnZDlkcjR2SnNPeTZuRkNIZ0x6UjZ2QWo2RklpNFFtbkp2WlMlMkJuVXRUcXdTbWkyUG4yUEdudTlQUHZ5anFkT1JTOW1HJTJGS0tDMSUyRjU0RXNWMkRvUlFLWUlZSHRjMnZlTVBiOUg1WXR5eGt1emluQ1FqZEtzJTJCb25GeVZrTzRiRlBVdUt5M2JITyUyRlJ3N2N0MFBFMXk2czEzSlVVcFR4ZTEzTlVXU1BuclRZTVJPMW10WEtWWW5iN0psbW11ZHk3RmF6TXBhak90MUZXJTJGR242WXRTRWRuUG05bldIc0JFYnZCaE1iTFgxMExMbTFJNiUyQndzSHhqY3NiNXZFM2RFUzV1cHlHbzQwcDZBNU5BVU94YVNZQ3pUY1R4Z1BPMEVEa2ZuS0VrdHhuTXREbVElMkIxTlRNYmJuejNyWDdMbHU5Unp4OGtIMThOY0M4RVU0dXlhV3FRZHZYUkFYSXBwS3pUenIlMkZOTkwyYUllZ2tWc2dIN0t3emZiMGJlUiUyQlNEYVdCUyUyRmF2ZUR2RXA4djZOVzExYU9OTnIyeGgzT3l5ZFhjRUkyYmM3UUJOVFpZd3JJSzklMkJXYTVOZ2ZMV2hSYTlxUEJnVCUyQjQ5Ym00VUdpMmM5byUyRjFhbjlISjJtaiUyRjlTc29Hc2djWWZqdzZsZFI2Vk4yVDRIU2syWURGeGFYamxYbzVzaGw0RkhjeFZiMzhkRW81ODBVbHElMkIyUVRHZUw5S2ZsSG1CVkRKOXJsMmFoU1VZYkR5UmgwSEtoQnFXWnJRVkc3SnFFWUtDSDNkRmlMdUk4RGJqWVBKWWNHWTQlMkZXOGFvZlNWY2NjMmtHQ0ltUnBmT1laUm9xVmVudVhlQ1k1ZSUyQnVreVo1VjRPdXpDeVJKcEptMkNiN2M4amo1U1h3VmpMYjBaYTdvT1FwaXZwcXFvcXFxZXhtNyUyQjFja2tGNlclMkIyMlNRbjVCdEsxMWdNSGpOU0N4UER1Z3loQXE3NDYxTHpjaEduVjdtWHNDdGtyZkdVdXh5Tnp1dmolMkJ5R0NqZWpSdThCbkVZUSUyRkpQTCUyRmNUOXMzR283dFltSEhSU0VlUkZkUUNPUW9zcFJQVVcxWTlQRm8zRmtlT1hmbFElMkJDaSUyQjNRaEFCODlDUVZsNmZEeSUyQiUyRngzb205ZUs3TGclMkZVVHFEQ2Z3SjNoJTJCUHFWelE5UjhpajYyOGNocHNGdDQyciUyQmtCVCUyQnJDJTJGeTRqdW05OTVnNWZWRFg0cjZrRSUyQjFXZDJiU3pQYUNYNEFYQ3BtRUFzSUQ4VXclMkY0UGZYNGlESk9nNWFYdkpEaURDN2pRdjJ1dW41NjJkQmF1b0IlMkJWTHMydVlDQUgycUhFU01HbTRqazdSTkQ3ZmRieCUyRlRlOEdCdzFBWjR1TzZrYUlGVzZtYTNISDd1bnUlMkYyazh6WkNCdzElMkJQN0FpVCUyRmdySWFCRVN4eUxlbE5zZU9LWGFQVDREY0JvQlpZN2NFY2RIUXZYeWlOejEwaUlEVCUyQkVtJTJCJTJGOFdSJTJCVzYycVNaT29DeVdacGNvN1haZTlzUUdJdVNFeW0weTNTZ2pvUyUyQmo3dkIzJTJGT3BacUtwZDRURVlkSU5ONkVsdjhEQ1J5VUU1bGFBVHZ1ZnhydFJBRXFid3B4cW41RU1EN1Zadk1qbWNMR1hGYkx2Z2J4RG5ueGt0RUhWU1ZYTTZsaFdpRGlQUGxrZmJhYVZZYm1WUTU2MUJTN0E0V0VoZGNyY0lXazJNTXdxYmFLSXc0RzA3S2VZcDB4eHNNWUNCY1ByREVQOVVJSHElMkZCUlVObHdnc2toJTJCbWFQZmU0YU9LbUswNVVpc040dWFRSkpseEhWY25sMzA0bkMzYkZmdFcxTW9XZmVPJTJGWGNuZjhnY3pLakRvTDd1TjQlMkI1UURGV0tXa0lqUWEyWjM5Q2g4WnhmJTJCbXVHUGJQJTJGRSUyQmZBcWhTJTJGZ2xQellZakwxaXBoakRBN1lQUXQya2tNemdxZWU4clhIZlNnd3pHanIyYTljaHV2MHEwOXl6clpySlpER1NTTkszdE01OGN2Nm1JS1F6NFZWeXNDWGhXVUFGQkNkNVUwaDhqYUF6UmxKZFUlMkJOJTJGdHBaeEZKb0p1M3BhOWEwbGNsanF5eUhPQVJmSlNta3dxOWZkUmolMkZHSExiZk5rdEpvSXZEbVpXQWZHMnpMWWhwUlF1ZzVhRnFDT2l4anYyOWNhVTMlMkZoS0U2SFV2bGFjU0lQJTJGYk9TY3VMSjV0c09YQzEyU0I1alViZ1FoQldRRnl2cXBmMlpNSU0lMkJtdzVnQkVvWFRtQWp1RVZLd0JBazhIdzNoOXlpVEU3NVc2MFpYTFFTcE45MEZiNnJSRFpqenJtdDVnRUc1QWEwbGZwUldVTlVHamprYiUyQm4yVko2c1V0WkMlMkY4UkpZaTFqODhsazIlMkZsNDBDTGJNRjZ1Q1lhenlVYXZvWXFyQ2w5RGklMkZ5eDdSJTJCcDBMUURNQ2pCJTJGM0dRTmwyNVB2eXlWcE1SYWllVEdmUDJZTkRzeEFBSkN2TmxyTUVaSEQlMkIlMkZ2VU5oQ3RPTXh1c0s2Z3FTcjFIYlV5RDVQaVo4WHk1UW11RCUyRkNkSmR2d2NCYnQ5NEowaGlCWWhpN3Z6Rm5GWktQQlVFQjhUS0hiRlVISmRjT3ZmRlh5QVdjRldEJTJGSDBMT1pSJTJGcEcwWHNielp3cEV2dUt5a056JTJGOXFCRDU1JTJCZUVxWnRkZ0htSmJHdlJBYzlxVkZSMyUyRlJoZFBjJTJGdmxwJTJGVk80ZTVrcSUyRmQ0Z3phNGhwU044cGVTTWsxa2VwSkRqTHd1YTI3ZFRpVnJIRXpPTGdhTXFUVE9OayUyRjBvM3lVbllDRTM4RGxObUQ2NjVsNTExRG5JMTRDQlpGaWNZbiUyQnlWU3pXdHMlMkZ3S3B1aSUyRmFvZjAlMkZkem1ERldZQWM0YUo0UVEwbDVGZ252T0pLODhlR3Nkb2NBMUtyYjVsaUhxOVglMkJHTzhNaEJ4REdMQWRXSXlhQ1hQVVBlaGhGQ1d4bFZPVmI1RWpNTTZ0RXlHVWtRNyUyRlJTUGtudW9lUW1CY1BJNSUyRlBKZkxiOSUyRjV1MFNPYXVvVDdydCUyRnYxbE1ncFMxM2J3bTFkR2QxazlmcEc4cUtMOE96ZkgwQiUyRlc5TTBXNGxPbEJjazYwQXZWNlNtRXVDbWhNcHhVRUgzUnlXNFN0Q2E5dmd1UHRNUEpaOTlwYTg2bE5ISDQ5cEFydiUyRmczYzUzU0RNZzJ5MU5IWElMeFE3UyUyRmVVYkExN25pSElBaUlqZFhuNWhJYnhqU0ppaXRBYjJ5aGVsUTlZYnljYXUlMkZBYjZpQ2Z6YlV2N284MCUyRjM1VGpEbFozcnhFUXRSYWliYXFSYVNMZWxoVmRYJTJGMUFSSEZsV01JJTJGZ28weHIwNW9LMkV2MTdMR0VzSCUyRjZmZmdjOGdkUkJKJTJCVTVUSjFtb3BIZjVMZyUyRnBudW5iNkJNbElTTGxIc1huc09rS0xDMENXVnoyWE9Ia3clMkJqZDNJUWNmOGVsZiUyQlhiTmVnRUQzclBhNHlMalQyN2FlUVJMM0c0QWplVmp2ZDhOTUhwNE92aHZOQ1dUeDk0c2dWUm9vNzg5azE1OXFIZU9hYU5lRVA5UyUyQjdFYjlvRGRVZWNIOU5RVngzZll5bzFqMnAlMkZOTHdYeUoxWkQ4UnZYVFh1eiUyRk8yam80emglMkI0RjFtVyUyRlVvdnlMeTExRU0xa2dqdjJOdkFKcjN2UXpEME80NjN2TTVib3FDV2UyV1EzZjRMZW1rMDJMcXFRTWVSWmIxSWtabHpjakw3endialE4RE4xRHJIdUx3QmgydWlBd29jY2Q5a1JGb2loWDc4OERsUjF5YUFXNmdLOUthSUdSZFY3UzN2ZDUzaWRncHZEWXRaaUtGU3Z4RmRYNXdFY0ZrakV5aTVxZzBzJTJGYkdyJTJCQ2hTSDREJTJCaDBWQ2dMJTJCV0FMclBoTHpRY0Zhb2ZhZFgwcCUyQmw4SnlWSUtXZmNuQ002JTJCJTJCNElsRFdaVXMwNGZYcSUyRkdOMktPRjFrdTUydWp2dTc2TUJsUTFWcnFsWGxLNHZTenFOZUYxWk9yUVclMkYwMmJTQnVRRGE5S3YlMkZuaGlodG5WMkxyaThCZkt3b0VDakUxZXFYRHF6MHkxJTJGUlhnUjJ0b3NzOTI4c1VZTmlGbnJSdkJlZDdDdHhlOXBabmYyN0R0Y0g2SHBoY3Y0RlJ4T0pPVGN1dUMzZnBud1g0ZFVWYVZvTlVrZWtQT0h3MUk3bGlPOXo1eVRVSEVsZmtzWFowbVhhbEpQVFdxbGZjelVXdTJqd3FuYUR6OTFNNjhrdnZnNFlVUyUyRjFFZklFYmp3cG9iZTJZQTZUUGcyVHIwdnZuZkhKdiUyQmFlWUpaUTZEbnA0aXZkVlJiNEM0R3J1SmVROTZLdzRYcE8lMkIwTUlqN0hyd3RRVVVpQXU1Q04wTkhxSTRxbWIwcUppMHBPZVVLSTNLR2VmOFRQZEdQVmRXczlvTnJyUDU1VUtsbzE4TWxPMTl4c3NUdjN2YlJGQ1g2RVhrNmpOelg3Wnl1OGNUS0lPSG9kV1ZFcEh6RyUyQm91TWQzS2lNJTJCVFB1aFlhcWNibkhNZ3c0UjZJTjJnSFRwdnJwRWZMUyUyRlNOcTFYTmFVU3pPJTJGN0hjVVklMkZxZkxEbU5OTWJvalFBVWhHMHlla2lLR2dvSlVZMyUyQlNvJTJGQXlhbXMlMkZqZXh2bmtlV3YlMkYxalJSUldXWUJGZjZrSlA5RnVxOEJnVGJEelBNS2NyV2t1eHYlMkJHdTk2SVN6dmpqczFrMzRSaE0wZ3cwNDFuaHJmNTlVZkR0RlJjR1p1QVI3dGNTOHVwRzRsejJZcEg5aEI5cSUyQng2alBXaTRsNk9kSWJKSFZmJTJCT2RRQVdRc2JDQkNHZXNuRFJiUEdqS0s0Qml4UXB6QzMlMkJrVnNIZnhJY21MZmFwa3hmU0ZXdjljNjd2MTlJc2V4eW5aQmZWYjRVTWglMkJZUFNaTDdxYVlDeGdGb2JmeTNQSE1wcWdvZCUyQkdwYW16R2tkZEo1ZkRuOVklMkZDa0RRSCUyQnVodW1iWGs0RThjcHdBYUtHYXhjRk11UURtNEVrOXZ4cVFrVnhnUUJyWjFiTGtSejZUV2FLJTJGUkVxbElRT0lkMWVTNFBYSVRhVTRtcFU4UlBWJTJGJTJCcDR2SzkzZ05nUzVqRENXcXRrbmxSNXB1ZmJpYTZTckc0U3glMkZoN05tWTl1Nm42OWdGbkllY0xWOXEyZ2lVUEolMkIyUUdTJTJCQ0MxJTJCMiUyRnFvWFRhVk41aVFqVFY1azVEaUpsdDlMQWFjJTJGT2I0OVJCblhHb2lUWnIxRGQzMk1OJTJGaEt4aSUyQkt2N2YlMkJLSm8wMk50a0lLY0lnNlU4VmhKQ3ZwYjBsVFpTbEdEd0lzS2k0RFRGc0xLd2RsYURyYnJ5Tnc1STZjcDY2bTBId2FRdzBpcU5BSllkJTJCSTBDYUlzd3l5c1ozd3VvRVpqb2o0UUtra3dJdCUyRkh2SFMxMEFGbTFZa3pkWjRzWW15TTVRQXE1WnUyNlVCWmY1OElialVaV1MlMkZzZWtLczlIJTJCNEQwVjJPUXlONVpzdER5eEQzZnFFRUdmRklJR3pWSGVCeGdLQWxSSkR0akcwVnBXSE0yWVF2MjN4VHFIamdRQW9RTzJFZnd4bU9rJTJCcWZHZnd5TVJPV3pKa1YlMkZSbzZxaXVHN2ZIdXZ5TzNjRkM3SG1rNnZlSlNOczJBV1ZiYnlsanYwJTJCdlNZWVlPeGdxblp4YUNpZFJuZ2clMkYySTEzanNvM3VMREN6MVJxWTBSMjBEWTZhZmM0ZmJidFhoRDJaSW5zR1ZtUVZOTVpWS2pyeWk5UjczdDA4TFNVaW51YTlVUTRZSEFGb0ZPN1lsRTVrUVNXaG9uVDVlYmgyd05tVnNGQnpkRnBsYzFqVVBNTHJHMVVoZnBtMzJ4c3pvTjhlSGppeno2VkxhSG1mbzNHWG1pNllpNXlkYXZZY1V1STRIODFORzdBNTByaE1WcG9MaHVQb1dPMFl0eUhIYWlyTUdRVkp0bVdqc2JhY0FjSTVVVWlOM2E2cU95R3RnaXV1OFdOWVkwbDV1cnZ6RDVPbEZOS01oS09iRjNCJTJCYjBia080ckx0c0l3T0RZaHNpMHlVeDhIMXNEQjE4TFlKVG9rMEhqTiUyRjk3aG9sZktRZ2dwaUdBdlAzNW1Jc3d4JTJGWGZMaUlUelNDUHglMkJ0MHYzRWFDTkFISkdIdDh0dHRKSW44cU9YMkoyQmNlSmtJZkMydjRaMGF1NmFieHlwdkxSTGt0UkFVQWptdTJTdzh2SGdZR3lTJTJCaGRXOXBkV0N1MEklMkZCVjAybGpobnU2S3AzYXRUSERjdUNIOFElMkJvUE42aFR2S1hBakNnY0tMcVhwWjVFS2pUeGdmRDZQZE81TUZhTFdVeHlpbVZveG45Nk5QTlZJUkdPQUJORGJ1SGtXend4R3pCVVYySVFtZ0MyWlpvRWlMWlpUVyUyQlBDdDk2ckZNa1poak9VVSUyQkJmbnNHVWVRakZGWHNYRjVkOFJYV0V4b3VwUmtCMHFhSXNsMzNBQjVpTlBSWFFrTTQ2Vm5Ka3o0dzYlMkJmZEJEcTBRaEpBTGhDc2J3Y1hSVkclMkJtJTJGRTRkbWlMRE8zTXpYRkczcCUyQmhNbEY0WEVTa09SZXB4ZDVGbCUyRiUyQjZFcnZSJTJGNXdzdG0zWFRrV2RhcDJUYmhmV3g2YWVwVSUyRk53dEQ3NzVoandDeXVFJTJCQ1c3QmZNMGVMZFdVN2RUSVRGcGZoeWNWTHBmR0VGWnlzdWJGUE0wZ0l4MUIlMkZxJTJGWGhnR3ZYYlFDeVZPczZjTTFXTWNRQlpZUU42QjBZMGNyanF1THExTVhuNnFLWnRVNDQyYmkyJTJCOG5HZVh2b3dJJTJGTFZDTHdFTWY2JTJGN2k5MDFlOUk0azF3RG1DaFAlMkZ0bjY4djJGMXdJNFRiQW9yN0ZsUjNZRiUyRmtwNTJ6dktOYjB2TndHMUxjQUdSJTJGZWl0MEREOUQ2dmpIdkZERWdYWllkUVdRUGlORUN1WmVINE00NzJ6UVNrMlNONmRmSXJxJTJCVTFMUVlpSzBuSyUyRk5tVThaWnN3TklyUjRJQlFlSnJDUUZ6Z2pwaG1Ra3IxV0lQRVJZVjBWJTJGc2JMc0lJOWRQTWl5OUVmJTJCT0w0OUljNUVTZkNjcEU4cjhoWEhuUnZHWiUyQkQ3c0ZpdG9PQmREJTJCTVRNZ1htJTJGJTJCZFpjMllYR01TOTFBSTFuTnZaWEk5TEliejM1TWVHQjVOJTJGZXA4TzZuQUJLR201eXFKbndKWmw2QlF4TW9oVHMySWpMRHd0NWtpMkIxVmxpaXJ0dGQ3ZDlpcVJFJTJCZ0hnMGI0SzZaOWVUYUc0NUpzaUwwN1k4JTJGNFE1VDNmbmgzRk1IT1pRVlNZVVJtZFNUak9UVEd0VzNIZnk2UVV2ZU1BWGdOUUhrWWtOV2duc2lscmwlMkI4UTg4bElaeU1oOGZSZzMyMVlEVHhIczVVZThZc09xQzhYaXJGR3I2cSUyQms4U1ZNJTJCZlJSTnZzNGRjMm9ta0NwdTliNTVUNDdKbXJSaUNwQlphN0dvQ0YxQ0M0VyUyRmhKMFJpTFVvSXdYTXJhNVdFTXdEcHFJS21ET2RMSHBxMnVYb0E5SWdaRlhPZGx5dElCZWFYS3d0NW1XJTJGSSUyQlk5aWF3V3YzQmRRdjNrMXZBOXpFWDNGVzNFYXkwOEglMkIxUjlHbFU4RTZOY3ljM1ZmTXJZWHp1cHczcmI1U1clMkJNYzJ1TG13M05QN2glMkZmMnFyMU5UVUV1RnhLeURCZCUyQlBRUkVFVXdPMVclMkY2SWxoREg3YW1PWUxxTXRQM2hCQUN3aWNyNm54Z011c25sMU4lMkJ0VTVtRFQ0U250dkdManA2QldLczJFVURMNkdVVSUyRmpVaVclMkZydlJxY3RpVnU3M01GODNwRVZVY0tnMGpNZlhMdFRlSThEMEk0SzNZU3BxblJIVzB2QTVvaDlTQWVmT1lxaFlVbm9OTTZnUmwwZHpsNll2WFR4JTJGdm9ZclVmQzNzbzRTdWt0N2ZSZmtiNUdoV04xb05EUXprd2FYYk8lMkJ6WjMzc2Q2SU5pSjlOU2o3TVZyczEyV0F1JTJGZSUyQnVHQTk0Mk9LUThkSVkwdm9lb3pHUzlRUDVqQzgxTDFrYThUYnJQYiUyRlhhUVlsaXNqOHVtSHdDNGhvdkolMkY0YmxyekJZTU5ERjVOeVpUbjJzb0xIVmJLUHU4dDlFQyUyRjBaaEZLJTJCUnM2cGk2dktVM283bDNjQnFINUtldVlxJTJGTkdXMHcxOERWTHBXYXlWMVZhdGV3SnlVd0RvVTN6VjBtak1iMlpHdjNiRnQ3TzFHVFZGa3RRbFZwMmhsJTJGSE9LRTZqdDc0RTVLbTlyJTJCUDk3b0hmYUtYdFNiYzFXempiZ09IWlUyQUMlMkJBZXVKZDclMkJzNnBCSm9zZU8lMkZpZXdRbHJvYW9HWWROZUZYeWs0aUxscjdPdkE0SFJHUVJhN1hpUU4wTkhKajZoaDNUVU0wOEpUOHB6YVRVZnczdndoWG4xRzcya1ZoSHNYbVNZU2xPNWFjTVlMeE9ZUVllSzhBJTJCdGVRRWZ4TTJjMFQ5MG1iUkFka095VnZaaFZxVmtsN0NrUlR0azcwTXJaZzh0UUttMEt2JTJGcFk5WTkyWHZaMHBuJTJCckpkMkMlMkJvWmk0dklVbjdZRnJMUmRkdU1ZZGJmaldHVlhMMnVRMUN3ZTBWdHRYek42cER1NXo2QTJObGh3VWc3SXklMkYlMkJRcnRuQ25LRDJYcm1jQ1RKdFZKUEJPdXNocGpuU1FxVGR3cWlFZFJ2U2xVSFZwQTFCd1cyTFNFTGJFTHJOa3dNUjVJalJ0SVdlN2glMkZSUU1UQ0RFMVM2cUwxOXhPa242cVlWNkxrOTNVNzNNOG5KVFNhZmszbWczcTc4cTkyWiUyRjZyZzBaeDBuZEg1OHIlMkZ6OTBHc0JQaTNDU3ZRWlhSeHJYRkxGSHEyNlZPWlI4UUR1aFdYdGZIVUptS05lQ2VpUlZTaHI5TklqUm5Cd0Z0RFhTWXRHSlF6OFNSWFJodlhDcVklMkZjWVFhTE1HcTJncjV0ZTl3MUxlVXFmZlZsZWdIYnFja2dESW5LV2tGU0tXcGdkR0FFJTJCM2ZxRlpMbWFDUHp0dlhERFh2VktxcHVtQzBKZlJ1WmdsdGhackJ5NE12d3Y4Y1dwOU5xQ3dFdjNEamtmOENJRUVZTUdKZ2Z2bEhMNTVkV3g1T3RLS2lmM3BVQVMxUEI4MjlQWmFFUlhGTHlIYlpMUyUyQmwxWWFObk03TkdOYzFxUzZxS3dtRWhWY0JZbmRnMUhaOVZwTm1uTHRSYW5XSFltWk5ld0I1d3pocndOUUFtdWticXIxN3Zjdm5rSUpMbEo5VlFDd0FZSlRNeXFGY3JrOWlzd0ZBa0tiQ25CWDVmTkRaZmN6ajl1MEQwc2dWTElIWiUyRlNzRHdCTjVvRGlTOFlHc3h2UnRSMTNSYnE3MnhwdnhxWnJUWFlCdXVpTVQwSVo4WHJUQTI5OTJrTXlIUlRYV0hVJTJGcjJ3amUxMjVFZSUyQkVDU1R3bUVFSyUyQjQzb2F5ZHpmOEdPYWJNY2dlSnRoNUhLYjFjMDIxc1dSREFDNGdlUlo3ZVcwWnJUNXRkV3c3UTAxV0E5MUVNR2JnYSUyQjVmRHVmZVp5UzNReE1LTnZjVmt2QXZ1RkFXejVEQmk4MkxFMmJvRmNVbTVoYzB2T3FqNHQ4R2Vlam15QnlQT2JpZGFja3d1ZXVqdmdEUzN3dm5mRUFmalJFdlglMkZLaWhJeFRIR2d2NEhma2t1UzRqZ3FETVROJTJCUnFicjg0UWNsQlpjRmtYN0VyOXpBOSUyQjdpZ0FaaVVCTVglMkZwMXhpUW0xcEM2VWZBakl1cEIySGljaUlBQTR0UUtveTBtN2VYREpTVmNGWENHZUtRYUV4V1c5cUxzWUdwalBCTmQ0WXRjV0w4aFk1VTBtbE4xc3RzJTJGNE9JWEEyYm1NRFBqdElKRW93M1dJNyUyQnB2eUViUFVMaVgxUDBKY0FsdmZhSHFoVjMzUDF1WVhJSFJpekJhT3Z4UlQlMkI1cXdhOExSTWx4M1V3U1JlUTFxVVFZWmt2NmVaZThJOHhlZSUyQmlDVUl6MmF1Y3czRWZIRm5MdHVyeTBrdlpWamdLcVR5UlZ3V29MS0YlMkY2RTdUVW1veFlrU2U5MTYyU09OYk5zRlVLWllhMDkxVmdud09Db05VOVZMN0tJU0xoeFNvY1JZVllzdkZTTHFFeWVGNGhYbGhKRjhUaDRDMUMxZWM5emNBMEdPTlUlMkZNNVBva3c3NzU0b05DSHFIczgzbmlRNHVzOWVsVVM5RGZuYW4xS3VNNWhiWm1PJTJCZjB4ZyUyQnAxRDJ1djFBOUJrdURGT0dIYjZoQWk1NTQzdyUyRm52dFRCbnh1UmZFeVYlMkZVUzliM3oxcWdQb2dNM1lNQTZOeUhxT1p1UHhBTERZJTJCM3hhVGJUTiUyQlpleGZpMlRKam9zdmx6QlNwcDR1NWN2bjdqTGR6d0R2aEZVWUJPdHlCUm55VzdRZGlPSmlvcFQlMkY4MkNVd01kT2dJUSUyRmlFbkdMSCUyQjZWVVMwRm1VVlQ0UVJkOEhOdyUyRm9tM3NETHFJaVJ0d0IlMkJBYkUxOEJYRDhsNEtHNk0lMkJEQU9aVDV5WSUyQkpTQkVTciUyQlN3SGRISGljMXFMbXhhbnRoR0t1M1g0ZHk4UGpvbHJXb2VnQVU2MmtFTmZWVzZEemoybjVwbDF1N2xCSzJEM2VtMTJFNDdiSnFZdXhYeWR1N2FWdUF0TWxqSndDQ25LQXZxYzA0c3pjVXA1TlcxdCUyQmhCUW8lMkZRV24zNjlRMjVmSVJUOSUyRlYlMkZ3eW1pY2VQQ1hkeDhTZyUyRnpxMyUyQkJhb24zazl5RVJSWSUyRjlMU0Npb2ZKNjlXVmZhdXhOSmtCdXYzWHhwMXNqZkZPYjRza0RvSVFraG9yRHNTTVBXTEp6Wkx5RTAlMkZyVGJPVkZEJTJCSmRhWjZrQkltUDBmVHVoZ1VnZXM4MzUybFYyWTNPMEpHS3ZsdlpiUjQxbkZ1WUROVUo3ZXZwOFpXMk9TTHVwSVZoNktYWjZhb3lQdkdhRU9LJTJCVSUyQiUyQnZkQldYVFJKeDdlYzNqTjN2eFl5d0x0cFpHV21GMHFFVDZabWpISTdCZjV5TmROeHJQZmhsT1pjU0t1NzZJYmNmR3I2VFdQT1ZsbllyaEllTEN1MXpOQmJ5VDdiQyUyQlFYZ3R3bGxDbWxER0tBdm9WOFI2NGxhQ3VHN05UempyMXV4Z0dTSU5nS3hqaXE2VzRqZFpWQkJtTmdaN2tURHZSQ1gyVnpHRG40ejJmcFhCMTlkNGs5NlZPRFpqZEJwUGJxUmhtRGNpWGlvbkZLbiUyQmhqMXk1N1NZc0F3MlhKTXlyMzFzVmNJNkw2JTJCMTlPYlhKY0pWbDdOMjhpRVpsUlFNWnpOMHRlN3M4UjJjOWFVVmRDc1BYRkZ6eGNpVzlXUGJiOHJ5REhBR1F5b01HcSUyQjVubzh4R1FKYUxIbkZZeFpyMkYwNmhuZVJkMFBVVUFIVWZkYjkxM0F1Qm9XZCUyRk9WMldHZlQyY2FPTVpUdk1zaUlGeHNwdyUyRm1oNmF1WU8xNk82dHRXM3h0RkE5JTJGRUlZSiUyRnVRUHVpQksxbDNEZzVMViUyRnh3eHBXc2hKSnIlMkYzYUdubXBoSTJLb2NONUdySFI4dDlFQWd5QlllWUF4MVZJZzlqYWZoNmZLYmElMkZwdGt1cCUyRnk5NWUlMkJtWmV3cUFyV0JmTml4OG9tY2oza3ZjOTFUJTJGUzhBTXE5V09QeTJMNjBnWEh6Uzd4TUpOZnNEYkxKR3pJMm9VTnhQYjRtSUdSZWw4N1glMkZHUyUyQlV2RDJXaFRqdk40eER0JTJGN0oxdVZ3eFFGRUtwUmF2MU1OcVBDYklCbEd5OTFtZ0Z5VUZFWlFmdWY5WXJybUNCeFN2TiUyQjdNR2ZZQ0QwN0hQTEE1d2olMkZvcyUyQmxzWWpQMUg4UzRsUmtkaDU1eUh0SHpmcldXbWQ1MHFqcXJGYXhZRUNzT3p1ek5WV0VQclIzSmROZDVHRmZCOWtRcTNMZXBDN09Hc3Rla3N1cXNJVGtNcUdOZlB2amNIQ0VCS3BoQW1kNDJyV3VKRjhPOTB5NUxXWFVLJTJGJTJCeCUyRjh4aEJ6aiUyQkF3aTgzd1dMNVFnM0lEdHlyNmlBQ3QwbmslMkIlMkZhWEJaUGZBdTJ1c0FLRnFhOEhoZnlQaFFNOFhWOEhoOXZRZUwyUnNhJTJGSlJZOE9wSGdnNWV6aW91Wk1Nc0wycXU4aGV3NzUzanNSV0pTYlVtb1o5WXZnUmFtOHdWT1d6JTJGRSUyRnl5cjJxNlg5ZnZOdkNXcFFkUXYzSThUU1l6TG1yQjZIbkpQVGhMWGx6M01PWllIanNUdnlpZGdPeWYwSmhYYnJqdDBocEthTnl1ZWIzcEZROTBnMWYzUzhCVE9ublVSJTJGdkdNOUYlMkJZU1hOVCUyQnkyZ0pibDFWWGNlM1YzanBqVGVKYnBQTE5nbGZZVE4xSW1lcDJKU0NsT0tPQ2Y1anBVaW5rJTJGNDVUeVZEWkRHUHM0OVVJQmhiJTJCa29FRk1QeGhFRzBDeUdxVGh5T2NEQTd3ajFQTWVQa0JKbUpMeHpsZzBFSXplTlZMejVBdWR1NVR6b1VRTXU4Vk45RjVJMmt1ckhaZjNwV2NtdVg3cG5EbnRYdElTRjdVRGhyRFpDa2oyVmRmb0NoVDd2N25USXlQQVNzU3NYNU1FclFTdk5oTHJ5dk9YdG5hWXhwejlaOG1GeVpJJTJGcU1MdVZ5ek9zQUJHeGJ6dWdMV092OTZldGxCcVFzMFdwNTFxOUFvVmFBUVNvalV3ejVlY3BhdG04c2JVSFJjZkMzeHZzaERLajF2Zk8zWnlZcVR4S0hwbUtDYXVRMGJsa1ZrektEJTJGJTJGbW5zJTJGR21PQzZRdXBYVFYxd2M4V3FSNFZYV2FCS3dZQmhrVzdOWFA5OTAwWGhyJTJGT2pyUW0zQzlCaTNndlc1TUVwMDB6MEVlbnBmNSUyRjdsRFB5b0p1JTJGUG9MbFQ5aGlXVzBwckhtbWdsUEZuNWREQjVINzhJRlBOUmMwaGRVcG5yWTFlbTVFekhkdFZnUmUycG5LOG5VZUtiMjQlMkJ3dkNvWDVsVFY3T09iQ2x6a2RNOWQ0cWRwbmRsTFVVZFV5ajZTWXpRQURZSG1Ed0RsaFpvQVVFSHVGZDJDWSUyRmIzWDNlZjFxc0RkekpqNENoaGdlb0dNRUk2eXhYT1RjOGtjTnNGWDdhVk9rTzNxdml5NVpweklzdlpBMm15bnpjYjJDNWd4Y3NiOWVtYzVrNW5oWnljV0pxWUlFQkg0eTc5ZlRwSTRFUGNiNHlvUGduNCUyRllUNWFRaWFWJTJGUkgwNWxPZiUyQkRHemttWCUyQkdoSjUzWiUyRjBmbiUyRkRkMUxaZHJwRjlCbDRuQTR2cEZWYmhEcWpyJTJGVjY4WHhVcGp6OXBBNEZzd29zYktiZmVoMVZ6NlNVYTdlZExkV2R6M1hoWGhsbXhSUGF6cXUlMkJoWTBFYXFEJTJGNiUyQlpPaURZYmxsJTJCdmpKTWJaYndYcUwxRDJLUm4wS3N0OVF6c0ppQ3AwT2NQJTJCeU9MNHBDalhYNkVvUWNkNGxnRGd4ZkN2ekdTcUc1RGY0ZWEzMyUyRm1ueERiT0dJMG9vYWRGYUtuYjgyd3YlMkZJd1c1MllKRlpORlliZlVwdnNHNDh4cSUyQmFiZHB4enhSQkNZQko3YVdqcmtxSTUwT3hFcmhwZngwQjhFNFJDeXNzMUR4cFNYWHFsNXZJcTJxMHMydEdrNXVQQWU0cVZIamVnQTd0U1JQUW9BZDFlVDZXVkRYJTJCcHA3UHhMTXpFYVpOYmo2JTJGYTQ5VkdlM3B0YmRQWmtQVFd1ajJKNTVISGRnUENlUnpGOVdWa0JCY3h0TmpzcFg1cFFzN1dITmx1OHhmMHJGcjdqWm40bTYlMkZBSWJuallMMEJ4U3FBY3A4dlliSiUyRlUwM1VSclJjRExCYWNmM3lKdEcxNWkzNSUyQlBqMDllNG5NdUNRaE5vR3phUUhaUVM1bkcwSzA5aDBVR3FjYXl0aFJmUEtyYXl6RFQ3YmZIOUc4M0luekc0aSUyQkpOdnRBUFlCb1JLaGxSa1dQWnVZWG9ReVBXRHhUQjR6akV6UXdvM3BXckR1ckwlMkZPbTNvbUkxNFd6eWI3V21MV2ZqTEtQakZiT1kxc1ZyRGtvcHZKSUt6NWlrY3o4M2tzSGMybXZvbFhJRDhPdWZ5SGZkbERsMUJlbEx1TSUyQmQ4TU5tOHNuZjVCVTNmdTl0ZlRQR09vdlByQkRUZ3o1cWI1Zkg5S0UwV3hzWmlaV0VqdkJOaVNOcDhwN2tzMWJiSDRWZDdXTTN1WGFEdDUlMkYxTEROJTJGeTRFNlk4U3F3bjlxaWR0aERLbTZ3ZjQ2YVdUV0ZkVkI4VnB6MlE3c0dNR1MlMkJtMSUyQiUyRnk5UWpKSUVmUm90ZjFkUDdLJTJCcURhc3Nab3JMWW1UTFpGcFNvOWFFQm12cjFUdEl6VnklMkZnd0Y1JTJCVkRyYlJDb3Y0bm1HeGhkdCUyQjJDamxWT2RUaGxwU0RxY2RkdSUyRmpXTXJMT3NYY2JQOTdQbzZnREN5b1QlMkY4b3k1Qkk2QXdPT1FhYWFVJTJCYm90S2Jod3BBSVJ1VTRWeCUyRm1zdHhFV0UyQXFiJTJCN014cERCJTJGTjBvM20yT3VmbHFDbUJ5REpFSWh4RkhZSXF6Q1NBSkFaVkYlMkZFb0pvSHo1YURZcmUxQlJTR29SQkpNMFhnY0dwM2hDMTI0cDRhblo3MXZBYkVoMXRqNDZ6SnN2aVNuVTFmS253OCUyQlU3bGZmYUJJTVE2M3QzODJ2dDRaaTRDWXNHZmRYJTJCUTJGUk5UZFlVSVZmQThZZWNoTTNLaHQzOHpUJTJGMERpZXJMJTJCTm11MDNzTyUyRlFLRHhDVWNYOGpsSW5KJTJCSWRhOXZrWGU5Q095NThDNktvQlRlV296UGdRSXR6JTJCRGRhJTJCNnNzNnZGJTJCeTVTbjl5ODRmZzM5TlBZREdtdVFlQU9LbmJGcEd3Qks4Nzg4RkN5aSUyRnVXSlglMkJjdyUyRlV2MDYwdjB2enBoQTI1ZFBjR0VLeGRQcENEYjVNZzBvbDlUeFR1OXROcmdnc1ZIemMzcGVtaVlnWnpzUlNJNWs5bEIwZkhyS3ZEWG1kb0s1SE8lMkZicFc2dUtUbUclMkZiRE1sMFgwUWN2T3JuVUd6MnZlOVdXQ1FwJTJGMkl1YVV0aTY4cklnWDlsazN5UGFqSFU4T1VxNTRMSW5yWEJucWZNa3pDdmFvSHZ1NkFZdENjWENFYXM2THd3eDB2SkV5d0hJYXdQMFl2TzYlMkZ2enFsd0JLOGpLTGllOXlhZCUyQlAxWSUyQmF4NSUyRmxXRmxaNVg0NnUzcHR1Vm41OXUlMkZseFluMkN0c0t5WllDRmYxWjYlMkZsWmZsSjd2dnZXeVZENENDbFJTZyUyQldna2xOM2NsWkdTMUMwNWN6aGlPVkxYZWhXeUczRTl0ZDRtemJnUkRMSnlpS01pRHZ4MW0lMkJBJTJGcW5GTTRCY2kwblFsUGp3T05neHRxOVZQY3FucFp2UEpUdXFDbU55Mk9DcEQ1T1BIJTJGdlBTWWpGTXVKa01pYzIzOWFjUUZ2a1l2NE5ySWxRaHR1NEVzOUtMMmtwSHNPMHJxQnVad2ZvWUxOdFJQRUNLNDVqSW54bUtmellzWSUyRlR0OUpGb1Z5cjM1ZlZqS2Y0ZzZaemViNWV5SHFOUCUyQjkwN3I3OVlEQUdOSWU2MUZySmNSZDI4ZGNtbHllZlMwOWZLZjklMkZLN1hrUmVXNEdFNEFoY29wcCUyRlRiUVBOUkRZdDdjODlNM1p6WE4zRFJCY1F3VEVsM1J4MU9WWnJFS21sN2t1WWsyUU53elplZlc4a1NvdVBWJTJCQjBpZW1QeUFjMzA1bCUyQlM0N25uOHVTVEJsb3k4eGRqeW0yVWdKVVpLQml5V2hZeW5aeFZHd0lBQ0FtWDF6N2UzQWFaeHRVcjMyUHRUZ2glMkZhYUFkbDM3aSUyRlFZSE1GQmFOMU11WEl4SzFOcWJYZTJZUjR3TXR1bHc5Yzh0WnV2NzlIdmw2JTJGblliU1glMkJTYzJ4ejNqN010NHB4OVpiMUU4RXhiMXJ0Vk1DMWZUelRCR3BVRXlEZktleUlzbzM2UlM0bWZIRDFrd2FuNCUyQmw2TWkzcVcxQ2NvJTJCbW5uajJxJTJGSVV6YlFyJTJGZVprSlJxWmVlTG1WJTJGZDh1dGxWT1pMVWFvZzd6WjhDZktxZWlKczVyQlpONGNNJTJGamhUVHhQWnclMkJJeXhYNmpMc1Vnd2h1ckU2NWF0enRqMmNtR0RKZiUyQnBWOTYxamRmdVdGR0xNOFFPRmtpemIlMkZkam03MkJGRjd6dDFYaktydFgxOGt2cTVuTHRwb2lFQmN1YVZpcyUyRnNRZVhiVjM2bkZvcmwlMkZzTXpObm9DYm9tWXJHcEdTWCUyQkkxcVlSaDZiV3AwWGV3QlNJZCUyRllaQUdlZkRESGZNM1VSMWlZMGRvSTMwUWxOb0JHZGpmcFdPcmlmRG1aWG9XcWdsNE91b2l2RWQlMkJmR3VJRHZ1YUNqZlkwZFBKTml5ZEY1JTJCUjQxY3JJdE4lMkYyaDRGNDFYR1hIZkwwamxXOGt2WEM2NXlVVU84ZUxCbzRwc3hyRWlmNTFKUWl6aGY0bTVYVVpTd3JvMGtmbm9qUSUyRnBRMk1HbWhIWGtZdE04a0M3MGRkZVptbmwyb01MR1lHUThBYUhnOU15MTl3dnFUM3ZnUEpFQm94YXVpOE5FelFhaHpNYmROWjBrb3psWG9tOTZPJTJCRmx1ZEZEMFREaU55MVo0Q0xOcFZ2dWJ0R1ZxTlRaWmFBd0M4UGhuZVV6UmN0ak5FRHkxU1ZyMEZ0SzkxMlN6cmg0NU1EaEQ4U1ZyV05LJTJCOENkU002Ukh4RWhEWmtSWGt3TEpBR2o4SDhLRXAySzRnSGJoQ3d3NDVua20yNjREa3FJdm1VOHl1bkp3dVp3SGJzQU9oU3J6aFM5RmN4Q1U5SGs1RTNpeTcxQ2R6bGQ1dTVQMllBVmo5UThCTjJqNEQ5RjZNT2ExbmlKaUxYemE5JTJGeXhvTkh5b3MxNVg2VUtyQUVES3RnbmxpRUMwS21JVFVEJTJCeHhXVktXamNHRER0YmFIUmhVeU45YnBzUzB5MHBuR0FYUENNSHg0YWdzazl1U1pLdUl1ZGM3cDAlMkZrTHpodG5Ea0dsNTE4MjUzV0FveENBTEZHJTJGcEY4NXlZYTBYVWV4UlowOGhvdTBhaWFPTlVLaklnZlFhaXpRTHFDWUowRUlaYiUyQmElMkJvNm1oN2trZlN2bWVOT2tjTVJrekhaNU1zVU9XY1RmJTJGMGl2MSUyRk5yZyUyQnVzbEVoa0ZyZFQyZkxPb2FlJTJGTFNCOCUyQnVVNUUzZGJFJTJCU1ZFaE0wOTNabHEzbWZjeE9XU0ttTkY3NGw0WWxlaVIyUVVZR2NxVHlFRzRKYk5NQmx4TnpwblJtYnRQNyUyQmxxRmlJYkdwYllsaVBMcWJubWdoU0s3NkJWYjRzMlNLT3BRRCUyRjdrN2RiV0xmUGo5a1VGSk9KZHNGSThoR0RMdk1adTBNaUZsd0FmM0RQZGVlY0R1OXBYd2RCdTc4MVpPJTJCNEVZSnFNQXRuSmNaZkxuekpNNWltMWhMTGZjRk9RN3RtdW5xT1lSaktkc3FlJTJCMGlBaDVjSGFGVFZlSlA5cVNlbWppdzJsU3dONktBNU92eCUyQmtCMkxJNjhBNDlGNW5KJTJCSmMyTGMyREJ0d0hRVTNjTDNMOWp5YXhlUjZFZTlTNHNiTnpJWERMMUZBYU1Jb0p6QUJucFMwb1I5ayUyQlpHMXdzWTMxdEQ3SHZNdnNocU1UQndKN0VXeXcxYWx5VUk2RlElMkJ2TkR6Vjh5cUhmQXdMZm44NjFhTm50SDQlMkJXNUVJTTQ4T0x5akMlMkJtMTd5SmowY2hiOHRKU055Nk4yVUhWWWFJZ0NFenVtbnQxWG5ObktvNVNGU1MwdzhjSzlTWTJUOEhLaVFoQmV3Z3BuTm9NT2ZnSmJVcm9oWVFRU2N3OHF6dm5Xdzd0Sm1OR2dGZHJrZVd0UjJqNWtEa3NmZ3MlMkZ3R2FCckVGOWdrMjVZUGlmNEdnaWU0VnBHQkZvQ1hwRUtKNXN0dzdnVXd4VzRKcEFmeEI4dktHOWZsdnRQJTJCMFdqRVhJcVRpZUxzUVdPbnFJY3JTWkM1bU9LOWNRREJCRUsxSlRVQ2taWlI1MUlNJTJCQUNZdE1aS285cUg0NG5sSXBvV0tic3BZb29TcEczSWVnNXRqaW5hMGJZaTBNcTJTT2huQjV3JTJGdVdIJTJCQ1VUZUliTDRIandoU2R5MGF6S3NkNSUyRjZnVk50UnBZWDRRZzlMUkROV1hqN2VzaHdnSXJEMnh2T2l1JTJGeGFRZnhydHFBejdVVUlMWXhORmhWQUc5ZWJYJTJCRlpBckg5Z1pZTmpDMVI2WnhYajY1ZnVsWXBjQjRnOUlFVXY1RndHQjBJOHFCRXluciUyRlhEUDJKOXZLTHFtZkRSYk9yMDNRbG9JNkw1dnEwazViUnY1MU8zUmp0NERqSzJGY3pSd0lub2NzVU5IJTJCNnF0R0tndm0zbkZvdjlEdW9Ia1R4SW94Nzdkdzh3ZnlWM3lkZUR3OHdUS3llSUJPZEhDaWtUdU1jN3JWUHZtMXZiUVdHWlVnZU93UFFGUjBkNnhZanhaeDhaOHk0Z3J4MzF6VXJncGczMTJUZ2tkbGtoWE9DaXhBeWJtV2hOSkVTenkxQnRiQzBpb1VTR3ZuSFRtTGFQU1NBbk1kcTJyeWpxdTBWTWVEMjMlMkZYdXpremN1cktzdlJPSkt0ek1DZjFRdmtDblkxJTJCUG1RQ1luVlJHMnRucGk2eTZOSHVpNGZjOVdBQnVpT2lNb3RzMWo4SUlQenRDVUFackU3ZU1haG5FMXNLRm5HcHJtNXNDRWVtVkJzYnFzc0NlVjBLT0tZc3k0alBuNUVNTWRHM0JnOXNSc0FiZWFJSyUyQjJjSkFZd3ppY2ZpWnlYQTl0VjF5ckQ2eEtuZzZ0UllDcTV0a0t0c1B5UHR1SXZnenBCVVh2SWpmeUx4cTNjU2pxaHdyZEM2ViUyQnYwNndqZHpZcXRJVVdSOG1VZHBYSFk0VFBrenpXcGdJbEQ4QW1YcjlLcmRUemVlZjJuRm1nbjJkUHE3dWRINGc2SHA2JTJCZEg5VkJLR1Z5VzBmSmdRSFpkbFhoU3ZSMU5SZWJjJTJCY1ZMYTB6OFJ5eDU1c1N1Q0tpeVUlMkZzSXgzTXhDMnFqdURSQzNqYU1neWlTOHhsJTJCUHZ2aFptJTJGSkNVTEZEWlI0QkZSNWVzbzlOSG9xd1BLNDBOUG5hRWM5aVhsR24lMkJpYWhHN1RPT0NDJTJCRmlTWlBpcSUyQkFPNUY1ZHlOSWpsOUFzY2dvbUVEOHZXZ3d4RVVSWVNmTjJsVjV1TURGSUpxQjBsVyUyQkxORlBiWWR1TmtGYThHOUpwTERydGdEZ2tydXU5eDBsQ21wVU1qV0FZR2F6RzFJTFFGeTlGTW83cyUyRndoV2h4MjByMkR5RWpic3pvb0x5dDRIWml4RVJ1MHdORmNLbEE5SXF3Y28lMkZPZTljMUcyR2VFZEpKZSUyRk05M2dlamlPYzl3Y1FzOWFmeGk4MjNYSDZxemhaRyUyQlNBbFpLcE95a0YyZnBTb3dGSGlmNXlxMW5SeHgyTWk5ZjEyaUI1TyUyQk9YZTVaRGd2QlVmJTJGdXVVcDFiTiUyQjNpb0JXUGFhc1Vvd2xjTnlrMEhNckl2aTEzbWFJdlNUVGlhZWVSV1Y3d0pobTFFOEVKZDRqTGFNYkh3YUw5bFhaa1lxRGpCNFQ0SEpmSXRPbSUyQkhKeXA3bjU5eFJjUUl5VnBnQUN6WjJRUXR5QVU0d1BBVTQzZ1RxdWo1a1JjWk1DMmxtJTJCVUNYa20lMkZrcTduS2NoaEEyb2J0SDdMMSUyQnlqTGNoeDlzJTJCSlJUQjRYMUVUeVh6eCUyRldQcU50V1VIcnhzb1NYYzNGdXpzVzBzSTMwMTdadWFOODlIa2xzN2lEZ1lhQ2hWJTJGTlNubkNuMlo5RmRUWXVnQkVTRUtQZ2V3SDFXQU9ZVnEzQ3V4c2hreExISyUyQlkwT3pYdVpJOExRZW1oRmgzNkRaTyUyRmpEMGVmNm9GM1ZCY1hpZVBSTEJLeFp3M3E1VW1XWHlDM1QlMkZtS1BwU2ZXa2FtY3ZSbVF2VlgzTCUyQlRxWWFqdlpXZG4zT3hyaTFHTlJadnZlaEQlMkZ6SVExekNhTzVuRTlUWDdEMmx5VllKZ3lKMDVFQWJUcktteWVPaDZ0MTBHNG1HT1RTWWthSmlyank1d0puNU5YRVc3VVZibGxOTnlxdW9LYmFjMnAlMkI3RFZ6eEVZbkhXbzRNOFlFY3RMQjNQdUpQc09kVkNBcCUyQk1tS1hCZEg0cFE2SEdJeGNTRzAlMkJKZ2kyaFRaZEtZS2liTEFVWVdIeXY4SkdEZmUyR3FJOEJWQkE3RFZLJTJCQldKQnR4MDZ4Tkh1ZWMxUUhubFRPUWNDJTJCem5rTUpCNE9ZYkhTUVdJRVElMkJFN0cyaEZ2TEJ5MHFWNkZrWE9aQURMS0clMkZMJTJCRHlsbmlKQzBnVUVQNmd2YlY4UFA2azVrWUJBJTJGakdFTDNmdmZ2YlB6czBLZG5WN1pqNGptTHFFeTR5RE96ZTNRNUpuakU5JTJGTXl3Z3QxUVhyYlIzdU42YWNhJTJCMjNIYVlJYlY2JTJCbVN2UFJzWkMwRmxpeWtsemdxMEtWdms2SnB0UkdhRW5sbmZ2bGxkTmlUYzhvOEFjZXVtbFlucUt6OVV1TmFwQiUyQk9uNzhkcXk3OFlMNDVEODZUOWIzOWJLSnJVbkNOTDJtZktab21va2dyeUwyY0clMkZUWUZXd1o1UVc5UzlINmU5R2JMaU9sS204bWZiNUd3WE1HZVUxdmclMkJFbFhzSFowRHMlMkZ2WkkwdkQ2d3NZZ0FNeXFFSUR1MUcwZGUwWEpmS0hkRGtLQjJ2R0J1MzYweFNHdkZEZ2V3VEd0QWFtWVNBZjBDVzB4TCUyRiUyRnJpQUFnQjdGZUhVeUluN09oY2lkUjB3bnlBQXVaOTFUa3A3RmhQSmptTGRZTlJRUnptYzM3YzZSSnJUYTQ2NGxjc1FYSmFIb21aRFRCSHZqcTNXeVczRUk0UU81N3Vpa3NKYWYlMkJNVkRITllRNTlZR01qcCUyQlBjVUNBQ1FxeE1xOHBBWWx3YjVEeGg3aWJFdGFKU0t0cjRNbzhNYlZ6NTJqSGVjbkdROFNDb2l3RkxJN21LOEhmQVhmcHdiQVF3YWVoMXNMJTJGT0h6cHVhdldYWlZUZmlzWmV1JTJCNUVlM1N0NnR0d1NJbDFxdkNyb1g5UWdnJTJGMTh1bVFma2I2VkJicERFUHYxTUI5eDdtRlhsMjhvZWtPOUxPTVRLcjlUOXBFaWI2YmtxTyUyQlVxZkVpZGRKelJWWm96eTBqSkx5bWtTY0VpbWtldzJTVldLbVpoR3VyYk5oR0ZMaHNYVWd6QXk5SjRYSUlaZG5zRmVKOGRQMU1MOEtnTUxEWEZxeGp1eDMlMkZ0YUslMkJZVXh5MjZQcSUyRm9jWiUyQiUyRmtkSWpBdDRGN28lMkJIdUxKWU9UTUxDWFJqNkdsdEN2QURYVlo2OGNLNmhWN1dtdHhmckFvMWczdm54cGF4VnFLeDdyeDNYUnhqelhRNG5wMllObVRDbHhuTFVaMkglMkJKREN1VXlycllwY3BFdCUyQk9hazRUcEFjSk1OajZmMGlqeXQ5S3FPc0hCN0xVaEUlMkJaekpnSEdnMSUyQmIxZDd3SDF0UWQzbkpkc3Ywb3BjanBQZWpOYiUyQmVvVjNDN0NGdGxSTGxobzBPMTNGeVYlMkZoNDdPVjdLaCUyQjlPMGRkb0V5Vnl3WG51YlNKQzI2YjVUajZrVGF6S2ZlSnlGREwlMkZpbE00RWVkUGZDem9BdmppJTJCQWtXZTFkdGl6cVp1VDBiYllLSTVjUkdQcEZDRkl4Yno1cyUyQnZzR3dtTTl1JTJGaHI5VG1OaVBuZkNhaGZiWGdjNHRqY3FRJTJGUDBFRFVJUzVRaEJpbnpzSVVNVFhjeEFwd0NSJTJCYlkzQTlvJTJCd2pjN29BTjVtQVN0Q2pUUzM1QlQzZnJjRXF6aUtCUXRmcHJwNjU1TCUyRkt2TVozUWQxeDVkVmJKJTJCWk4lMkZIQWclMkJKSWpvNFFyQ21hOWlGWEpwcWZQWks1NEtrcFA0elE1TCUyQndwZmFpckN2TzhzbU9yem16UFlMUjZqZEhNSHlQeTYzZVpIeGtnYW5OYXZOaXBCbDVaalJFVHJUREN0T0ttcldDJTJCMHdmJTJGZVRmdGh5aCUyRnFHeEdiVVFjaExQZ0ROVHdTOTVFeTd5eUp2ayUyRmlURUpMZXViMG5LN3V5RTJsN1FLb3pJREclMkJMUWJpUnBrVFM3Z25BOFkzRUtIQm45OFViZXhpYW11YzlJSWZsS3QlMkZLN0ZaclJwTTFZczlMTlVhaGtzeEdNN1Q4YlNxYVc0MWpZSlVaMWU4U3NXWGpHNDdNaTh2ZzZpMkhZNGRyWFpwaHVTSnM3NUI0NU4lMkY3bDJJbmVGNUlKUTdoeFFWbDlXN1FJb3JsUm9vcSUyRjNTYiUyQkxxMW1ITDQ0ZXFiZ1d4azV3QnNJREh5YmNVY291U2E0JTJCSjElMkZUc3QzMThtZENGRSUyRnBnS2IwcUZBYm15Nlkyc0tCclpLbEVYbTRnMkVrYUNTZEVGS20yWXdkaFF4NmFrdzFrNGFZdGl0MVJackJERlJ1bG5tc29nRzNheGxKRUJINzRUblBheldUM0wlMkZndDlHTUx6Y05BVUwlMkZudyUyRlJlQW1raFVkJTJGJTJGcFF4TWZycmY1SHpGNmZYVUwlMkJoJTJGMGI5eWVMOSUyRjglMkZCc0hnNzlRJTJGbDhvMjU5aVB2YjVkM2tPTGZUUFZRTCUyQjk3UDclMkYlMkZlaCUyRm01dzFObTMlMkJodEJJZiUyRkdZUnlGVUF5QkNReWpzTDhSVlY2WDFUJTJCUGdxTCUyRnBuQUloa2tDeGFHSGpJaSUyRklmSDZkN244NzZ4Z2dmJTJCZUJmaFdUemJ2dXYlMkYlMkJYTWJ4JTJCJTJGJTJCdWlVczhWZHFZNVdERSUyRndJJTNEJTNDJTJGZGlhZ3JhbSUzRSUzQ2RpYWdyYW0lMjBuYW1lJTNEJTIyZGRiLWNvbXBsZXglMjIlMjBpZCUzRCUyMks5V2piVVFjV0JZMVVFQWxRcm1fJTIyJTNFN0x6WDJ1UkdjaTM2TkhPcCUyQmVETkpWQ0ZnaW5ZZ3NjZHZQY2VUNyUyQlJmM2R6U0RaMXBOa1N6MmglMkY0czh1ZzRUTmpJZ1ZhMFZtOFclMkZvb3ozNEtSd0twVSUyRlM1bThJbEJ4JTJGUTU5JTJGUXhDWWdLRDdBN1NjMzFwSUV2dldrRTlsOHYyZ2Z6U1k1WlYlMkJiJTJGeCUyQlhyNldTVHIlMkY1c0NsNzV1bEhIN2JHUGRkbDhiTGI5ckNhZXIzM3g2VzljMXY3enFFZWZwVGd4bUh6YyUyQnRicGtzeGZkVyUyQkVlJTJGd0E0aExmUGklMkI2MHAlMkZQdU9Odnh4OFBlR3VRaVRmdjlWRThyOURYMU1mYjk4JTJCOVllajdRQmclMkZkalhHeHZEWSUyQmFLVmdidHQzMXZmbDgxdnpidDR1OSUyRnBsVGZ1bkNsSGJMZiUyRk9scVclMkZYM3NKbSUyRlQ1Z1NSTDkyN2lXY1QxJTJGRFFvQ01hNTV2eiUyQmU3JTJGdmRYTUs0JTJGajRjeSUyRmxqaktkJTJCN1pJVTNBZiUyQkc4cnVSYm1rNWhER1lPOSUyQmU5WGRWaXh0ODMxM0VzN0ZMOGRtWmRNOCUyQnFhZjd1MnU3JTJCNHoyQ2FNMGtidjUzSXAlMkIlMkI1dWp1OU9wJTJGZCUyQmRrdW5wYndOSyUyRiUyRnVnS2hmbHI2OUR3aWJNdiUyRkRNNWp2TzVZZVBNdjNIdCUyRjcwdU4zUHZJZkRERDhpOVh2Y0VuN05sMm04ejd2JTJCMVhRNzM3eUkxRFF2eE1VZHNjQmpoQW9qSDhmNlAwZlBvaFI5TiUyRnBYJTJGMVI2TGREaWw5NTQzM3UzJTJCJTJCVFNZckdTUFMlMkIzUGZZQzc4SFJmN0xRJTJGekQ4UGVYNzdiJTJGSiUyRndBJTJCY21tYVhLSDBmZk5mbHFLUHUlMkI3c09IJTJCMGNyJTJCdyUyQnJRdmZXUFklMkJRZURQT1hlYXQwV2M3dm1CQ3VTJTJGOWJUN2dIZXpvOWNQN2Y4UiUyQmIlMkZ2ZkxmVzA4ajk5c25iJTJGZTB0T3B2UHNPN1B6ViUyQkswRDRLbiUyRkwyeDZZMUk0NWVuJTJGMTNIMEg5dCUyQlNwdHdLYmZmM3ZTUHpQUDlWTDB2dSUyQlVmUG9PUTlHJTJCY0J2c0JTejh1TWZmckZLZmZ6JTJGcWRrWDk1alA5N3U2TSUyRmhUJTJCekZHa1gzbTF1UDlYNWJlUGhid0R0aUxBRnNmUHQlMkZkNXM3ckZpbyUyQm4lMkJsb052ejNBSkglMkZlcjZmT2ZQR2tBRCUyRiUyRlZIWnk5JTJGOTBYZTN4NzRmZmVCMmo1TzRMJTJGUWVNZnRaRSUyRk44SSUyRkgzWiUyRndIOTBoOTgzJTJGbEViJTJCWE1qJTJGUE5oWU92SFUlMkYlMkIyOFklMkZhU1B6bkolMkY3OTJmQWZuQTMlMkY3dXo3M3gxbzY5S1VYZnI0SlY4Qzc4JTJGNmJ2bUJvMzlEMFB1JTJGRiUyRkFDTnAlMkZDcEV4JTJGczQlMkZHOE9jTCUyQmRXJTJCWnpuZEYlMkZxR3BSMEk0OSUyRmg4bjBPenFBUUMySjBYcWElMkJUbiUyQjFKJTJGdjYlMkJ6V3NRJTJGOFpxUDVqWlA0SndIOEZGcUNIMzVFRVJuNXNmM2N5Y010d0hyNE5SMVllNERuWU8xMFBZR2Q3NUlEWiUyRkQzY1olMkJ6dlUlMkZvdG9NUVlQQTk3YjM3Nzl0dWp3bTh4OE9lbGlqdk9meFAyQ0FYOWxCNUk2dWQwOEtQdHZ4MyUyRnNaOXd3Qnh1RjRqV3VFNlh2eUw2ZjNaRUV4Q0RvdVElMkZGOUUzajRkaDRuOU5STSUyRm9ueGpOMUclMkJER2NQJTJCeGNHTSUyRjB2STNGRXUzZyUyQkNkbiUyRjMlMkY4SHI3cTElMkZNRG13Y2Y1cTQlMkZjODdoZFMlMkJBdEQlMkZOV1YlMkZuOG1oZDg4NnolMkJtVCUyRjhoZWFUJTJCaSUyQlR4diUyQlFPeEYlMkZjJTJGajh3RCUyRmFuY0hzWSUyRnRkeWUlMkZKZkNnTyUyRmhQNHZWdiUyQm5ZT0RQanR6JTJGYWtUJTJCNTB6JTJCQzglMkY3Y1lsdnJ2aW5tZnpuYXM0M09mYzh1N0R0biUyQnczS2ZjNzdmYWRkOXo1JTJGeSUyQmU5eiUyQmE1NzFJaW9Pd2Y0N25QU0g4QVpQJTJGYTNoZUU3WlI4bWNxTiUyQnAlMkZtSENqZjRwNFkwMm44OTglMkI2YncyQUpuWXZ5VGMlMkZ3T2glMkZaZUUlMkI5ZEt1TjhYWlA3bEd1N0g5Tm0lMkZpTFglMkZ2eUMlMkI0UDhzdlVmJTJGbGVycngxUCUyQm1wUGRKamx2QyUyRnduNnVxJTJGSE5CRjglMkZCVlo1JTJCTHFBJTJCblpQN0pQZjRRZ3Y1c0FQaURlRWIlMkYlMkZxdlp3NTlBQzRKWTh2VnJEdk83MmI4JTJGSzhCJTJGRVYlMkIlMkZKRzdzNXdDSCUyRmlEQW9UJTJGTEw1Q2YlMkZPSW5rMzZmZnZsM1J1VDdqSGtZJTJGVGdjJTJCbThaS2VLM0ElMkZYTFJQbiUyQjY5bHo0dWVSZ3FFJTJGYTNJUyUyRm5tVzZpOCUyQjh6JTJCYnoyQlA4dDc1eiUyRkdaJTJCdzlqNmY4MWZDYjUwdVJKOUY4RFBlU1BZJTJGbGZSbHQlMkJua2o2SzFUJTJGQ3RXJTJGUXZYZkQ5VWZsJTJGbHQ1ZkJIenZ1WEJUTCUyQlZ5RCUyRkZjaCUyRkJmSSUyRkg4Z285VnVoUWZ5TEE1bjRLWkIlMkZOUnRnQWZYd3M1YTh4MlQ1bmREN2pYOThGMnQlMkZzSHJ6UDF5RDJaWko4bFdzJTJCS05sb3I4dFlQeFpXcEQlMkJuWVhnbnhYT2olMkZMUHIwMzBRMSUyRjk5NXZvNXlMdVR4YjU0ZlJsJTJCN1hlJTJCVDhPeEs5bHRHd1lmNjNoNjVJJTJGaXV4JTJGSjFaJTJGSDI5ZnQyUiUyQnRFSSUyRld1N3ZTYmlFZjBPWmI1dklhJTJCanlHOUJLaDlVJTJCTyUyRlRtODU2NSUyRjFUVExqZzd2NzhweXYzR0dnJTJGR3Z6OGZkUlclMkZoUHRMem5BTlp6Z2ZqRWxQT3ZBJTJCeVllTXRwUzh2ZllsZzNHTmFSckRzbWdVT0V5Wm0zblBUMUlXU2VWelFHc0RRUU9zU1RURTV0UnhYR3cxMmt5c0dKT1c4T0tuZllsS2d3UmhnSHo4SzBwSU9FVjBGNm0zTkNteklaR2tpNXhiT2tGV085ejRjWEdudnlHc1JMdnptaEVMTjkyUFBUJTJCTHQ0a3h3Y2NjS29tS0dsMGpTM283eUd4VHlLajRWSWZobVZPcm10U2llanhoT0dabk10cjl2UHdwRDNLZWFBMUN1SFZTeklKMlhHWmNKV3Nua2VVdTJvbDBoWnUlMkZaT1NMdzFJWndlSlZzbWlCREVoaFQ3UkViJTJCJTJGbndJRTczUiUyRjAzSkhLdkZYd1pXVkRsaUFrQXEzYVZTd29UZW54U0tKYUpLNDQza1dYNjIxZyUyRkMlMkJ6Z1Y4SnJwbUZKdDZQd2xwT2I5MGZuZnpjOXRvdnBHdiUyQmROa1VkVlQ4NVBwcVAyOXZaWXZESW1WaW55NGFWZ3FoR1llUDlaNDhoblElMkJHV2JKMDhUMFVmd3BHbjklMkJyUHRxSVBORDZONk9CZGRFMWNRWTd6UEdYc1FQSFNyc2VFR2FFMXVsbUQxMEk5SU9TaUJpSFJiMFRLbHVwM3M5ZFJSM3pvZWxIQ2l1ZDZrYzd4MlZJZzliUFRUdmd3OHZSQmZPYlBMV2xPeThvUEtTc2ZIVU95ellLczRpV1UwdzRBNmpMdHdmbXV5eThhandaVlBpb2FNMFJMYTlTUDE5N3lIUWQwa1BtT3pTNVpXclVVbHdGTXp5clN5WEhsSEQ2cFhpRzVTTnJWb1o0MEU4WHZBaGFvUjFQSE52VWNkcUs2Uk5kVmJjUjE4RzBUTk96MVk5WmMlMkZRdUJockxLd3NSUHYzTGRBaU9rUDVmaTZhTFRkaDg5QVczSmclMkJxc0pxc1NVMkxyTFYxcFowOElTQ09acFJmSmU4OVB2d0VLOHVEVTJYTElFRHZUdTYlMkI2VHNiajdBSjEwdjRVdm1qQzRXM0VGUVpFSVBSb1dUZHFPRlN0N3RhVDU0RWpGMzMlMkZTVjlsanpXdkpSZUQxWkNFdlZ6RnNpcjhrWGpBdVgzbnpMZVBuMGElMkJ1akQ1STJocHljR3lscHE5R1VFdXZyeXM2Z0paNzVNQ0ZWaGZSaUZ4TkZvQzNXaUVVdlc2elptZDYxQ3ZLVWVDa2VtQzRkR2F6TDZ2MkVMaVB3Mkg3ZiUyQiUyQllBNXBwVWQwaXlLTElsNGQzRVpmS21YcVNrSWhvTXJ3SkhlTlBtWE9uVENlQUNkRXphRWpxVDEzbWxkNTY0NUVoS05pV2tObmpMMHVpZ1Z1UWc2S2JiYUhraTNPaGp4b1p6JTJCMnZ4a1VhS0tLMjVicDlHOXRxTWVtOUJ6NWNRZWlzRGJDb2dNRGk0TiUyRlM5a2pOb2tvbHVzcnhsRGVqM3hMd1paMlRpZE5YNDhZaVJRY3JuRjJ6Q3RYTUZCODF4VmtFc2taYXd1VWhvYlE2cHFyVUY3dUpwJTJCenc0bGVNaThTZ254JTJCckFIOXolMkY4TTNPOVd2a0l4JTJGb2tqQ1ZRemFwelZBUW5BOEtpNm1TVFVBUGh5ZHdiZHFwQ3MzQmJwdXlxaG1Objk0WnJYcWpPZG1hRW1nOCUyQlEzRUowV2V1a3Btc3RycHdhUjVJVDVKNkkxS1ZrclBXNVowZVpxSjlyREFFejklMkJVbTFLUkRaWGxHSGpSZ21yTUlvOTZyalJhYVQ2ZkNIRGl3SUlnWjZKaVlmRCUyQlhhVWQ4SUl6RFBMbGxoRnlwRXZFYnU1N1ozeG85cmpkb0klMkJJSFFtanFCS2hiYTU1c2d6UCUyQmpLdGhhJTJCbFlhWWxiRzhsYUcwbGJhRUpEbXdkSGlHNjJFM1ZtTFlMbDBGMjFJMm8lMkY0dUhYT1lGZFc1eWNLclNyMTBqQlZ1alpWU08xQmdIeGE4UiUyRmRyVG05JTJGZjJHM1ZjYkVHcUhxRkFyYVM0OWRTejM5RzY2dDRFaUhCWVpjbGt0T3Z6cERUVm1DQiUyRmUzNVg2UndYVyUyRlQ4dHlad0YyZU5pMiUyRmdxVzk3blBXc0NhTUFZJTJGUHMlMkZ1ZXZxaktyN0xvOGk2WElkOUIlMkJQSlZlWDhFWiUyQklibFN5VDMlMkZ5OGhiWkFzMWRCQTN0TmlKajlYdTZNOVRyVFZpYk9DRlhnVXk0Tjd0NUlvVERIayUyQkNjODNjNiUyQmhmN2NjQjdvM2hBeUhUU1JhYUlXMlJ3cG03TW5nc2xWOTBCNWNDM0h5VFhpQllZMVdZJTJCUGtnOTFnNGtCcGI1T2c5dFdVN1I4QWZvQlZESnJsZ09pTmElMkIwZEJSS2UzUTl5OVoydkZvNEo3WkVtb2pTSFZqcG9BZ2lONFZkalJpU3AzWEdzQmpIc0xTc3A2R0NuVllSMENUQSUyQmFUVlY0MUtmaUtTYTBwRzJ0T2lUSjlnSzk2aVVBU3hmSUJDeGMwcTFyRFZscGN3czUyQ3NDMTFlSVFCZlBqdVJvblpKZWV1YiUyQm1SV29yRk5ubktiaUpqRXZPMk82VTFqdCUyQjN4Mk5KUzMlMkJlQ2pNSTdhd29rSmxEV2g5SjJ2NzlCQzlXVVJwTVJFNHU3Z3EwMGdsajJPSENNT1gyd05QMFlFbmR3TGIwVnIzSWROUWJOTkM2TkY0MTVoNDhwV1k1QVB2THNrUkU4UmFuNkhzaFp0MCUyRm5FNzR4RmpqaDBYOE9PbzVjZmh4MTdqUXJKOThtQVBPJTJGUWolMkJYSDJxWm4lMkJDa3haT240RGJiZmlaY0k3V3dqZFpZUXFjcTM1Q040Q0E2dmZIZXdUdW0yTkJmb3dzYWZFSEE4V0pFT0E5WldmT1B2UTlwQTY2eEx6ak5ZT0dOb3dPYXA0YkhBJTJCbUJDUW93Z0x5NDE1N2xCaEVaWHFiMFVSSlVUeTRGNWZaZ0ZIMGFSQmlVeU4yeXJLVVN1bFZ4dW4yVkpHM0x1anlodmdZJTJCYktaWnR0a3VHU0tKcDhJUFp3d01UM2tWSjFYaTJqc0NOdkJqM01KMVZXSjBiSktOVHQ0MUdvWThISXZ5YXNUNnl0TUZXMFZldzh4ZEpGd2dkRGFKTGlmckxTcSUyRlNaVSUyQkFSTXFER3hYM0RlNTNwWXphRWh0QVo5Yk9jWTlpSWJTR0k5TzBhVld5UnRjaXVlRmw5VkE1d1BpeHFPU2R5SG9CY0FROGNMMjFxRllQYiUyRkR5M3A0d0E0VTJGZGREUkZScFZWTk92WHElMkJXcWNFMkxlNlIwc29ZbjElMkZwWEJGNmlSYXBCU1JZd0Y1aXZhNSUyRkFZQmJMYjBSeXJld001dmVmU3E3ZWcxZTlOcnRuMFBwTHhsSVVIT25EQ3VjSGkwYzRTUFpTZkNvN3ptOTB1dFl2MzElMkZPQVJHM3hHNjVnTmJqYVklMkJ5UWo5WUZSeTVHVGNHcTlia3c1SG12c2szV1dGVmpZdDlQMTZNMkpqbzBESmpzMlQ4Vkx4SzByV0ZCY2tHcWR2UWVWWlF5bDc3UE1rQ2VZbUxPY2V2SXo2QkY3SVNQeVBwZmVQU29TZGdtSnQ5Wm5pMzZtcEhYOHJwSEFpSjd2NHFpUG5KS2xhZEV1RFpZb3NyMUo3NFdYVUprcU4lMkZtc2lYaFFGZWxoMXVTRHBZN2FBYmhsQVBheTZKakYxRSUyQldyd2FVSzIlMkJuMHcyOFV5SjVXVFU3R0J4ZUEybms1blB5TFJMWTNsN1Q1eUFMWFBId0FXbW8weDJKalB6c2I1UEhUNlVtSmlqaFE3RyUyRm5sdTJtWnYwWUF3ZCUyQkFzV21lclpQTmlwcVcwSlgyUDhGYUR4YUo3NXFjQk9qNkhhczdCaHFpdllNaFA0NGlOOERHUjAwcE9LWENGQmpJUnloVWNBWURlMUZVdWoyM2M3cFBhaFhZanc3cnJ6RHF5bUNGdiUyRk5WJTJCU05oTkpPR2N3ejJLS054d1BJbmdxckhsRnhYS1ZyJTJGemhTdlFMZ2J2aCUyQlRLTkk1ejlWdklRNHdCc2FWYUlrNExxTEdKTWIzejY3WmVqZFk4SmE4c0xheDlMdVN1NnpKN0Q4bUo5RXZnd1ZPTGJKUnZraW9RQ0d4aHNhS2hjSThhN1FGJTJCc3Nsd1A3b1AxVnNlUVR6V04yT0tKZTk0MEFNOEQ2YmdmdFI0TlZ4S2h4U0FmbzNkYko2QVpjenppaWFFbDhnRkhtY3NWdmRIcVdENHQ5JTJCeUpKcUFZUmdkR1FIUExKemRXUU5YYnExOHJGeiUyRkg0UUVuMXFUQ0JKbFprNU1hTWdnVVdwc2E0UGRrT3lWSFRmbUZVZVJZWXNXWnJiVm9kRk9LVGM4MkkxSkYlMkYxdk9SdTEwcG5IZ0UlMkZjcnlkSmVMZXhROXdIcWw3c0QzR0ElMkIlMkIwQTJVNXJnSG4waXJ5Z051c01TN1VxeEJwMU44TDd4WGs3NW5sekVSYnVwbUhDZDlCMGNMMGNvdXJzSEJ0OGIxVkh1aHZHRUg2cmdFcmMlMkI2T0pBUzZESmQwMmlKczkzTldQZTRrbXowNVBITWNVQ3Y5Z0NqN3NrdnpqUkd6ajZyQSUyQlViczV5Vk9uYnlYa2wzWGg3MnZUSGhLQzY3d1FoSDZsSWM3Rmtzcjh1YU5PQ0x2Q0VTOW1wWiUyRkFJUXR1dDRhVHlVM2tGJTJGYTFuOCUyRkVDMFZNbmpPUHVSYm9OQWlQRk5TZlhVT0hyTldCMVVyS0lYUld3dVQlMkJqVkdVTWNjdkpFT0NhOTJteCUyQlpTZkJWSEU1alNGbHJzJTJCbTlWMlAyaXA4OHRhUHo0T0RVdHBoS2p6M0x2dmNRelh4QnNoaGUxcDdKazRieGRhNENnU0J0d0xTVnowUGpNSGtVNXZEc3dxdXJzZiUyQldIa0RpR01VbG0xVkFGJTJGekI2Y0FOUHpyNlFua01zVEl0SWxacmtvQUIzeUlTdmJyVzZibjg4VTFyanFKaW5zanRBRXU4bWplJTJCbER3dkhUODA3UmJzOW1CTTglMkIyQnpyJTJGUFZqZVRMdURBYiUyRjJYamJRek9Vb05aUVlhMFBzcmYwYlgyUWt0TEhXNFF6SVNMa0QxdlF6ajRzTVFTJTJGWk04UmxVaTdBbTlBaUl4UjJJRjJSUGFiRThVTXlQU3ZSJTJGRldwQUtYMmZmUkxiY09RJTJCRVBWV1FiUnpsUmx6dGpWdnFUcHRhMHM3elVZNUsyTyUyRjNlT092MHVJZGMlMkJjMEpXZEF0S0FJNXdFUHBZeFR2emNZVTdQVzZ2bFIzSDZpS1pXNnRmTTF5JTJCblNYRm1pUDlaMXFBQ1RDR0g3ellkY2g4a28yY2t0YUU0dXE4T3ZpOXNYbmdwQ3hkS3ZFUzh1eFAySG5vM0NDOTVJYnZmbGRzd2NXNEg3NFVaJTJGdnlqQTJEMWhhTEh1SSUyQnhJYUNrbSUyQlZmbzElMkJ2bWRWY3JEbTRoSXFYbkFLUEhTc0RRTGVYSzNmc004JTJCMDZETyUyQjRDVHhYQ0dpNW5kU2xicFZSc0V4Nm4wUFFTV01vNlclMkZnNG9QZndCcTBQREZxRHg5RyUyQncwYmo3ajglMkZYMnJmVSUyQlN6TnRuWXNGNWhLWVZFejRPQkxRS3BXSlh0cUNveCUyRnJvemhIMHMxMUhZZCUyRmZtRHkxaXNHZ0tJSGQ2RUZneXh1OE5aOW1uQ01KNWwxMXklMkJaaloyaGM2eEREbEIlMkZUTkpsQjNTWEpmRmFBT1FyaU9BbDROQlRSejlSOEVsNHJBTDhlTEpPb05aRU9BU2J2UUVialdoNDFGeFNKb21NZnZmRDhVZ0w5Y2d4VU9ZenZaYnNBWEdOWmhUczFPVEtLMXh0UGg1T3pMaWtZMFBJWDZHOU4lMkIzUWxCWVk1MHB0YTZLYkVQdyUyQlFmaDFzRmwlMkYxMHlHRTB5eWM0eWNuWmFSNjdqck1uRnpidVB5U0FvaTdZbmtLcFlFc2lzZFJzOCUyRnBja3VlMDA0RjlKWFVNJTJCdGJGSGtkYUpEdnBobldwJTJCSlZQRlgxRUp6emhERXIzUldKelZseVZ0Mmh5MEFmSlFsMGJ3RWl4MWtHQXQyWTJEQU52cGtIcnVZJTJCTDh6MlFMU21FSXclMkZxYVpFeUJ6dzhhSDFacDFwemtYcDdkcjg4aGNwUnlJdGFDV005aVgwY2lRa28wTGtZNW13cUVucTQlMkZzTnBzU3JrNmxQTWRJJTJCVGglMkZ3WjZ4a2E1JTJGTGJTUHhFMzgwU2NQbjNZZ244OGJseHp4UllMb2ZKOVJOUXc1WklxaFdDREFJcURaOUFnNzNrWEJLMzhPSVhqQlhXdmoyMFR3T3FEQ3d0YjFmNlBtSmhTeE4xcGppT0o5aHF6Sk9qS0c4Mmh4d1FiOHBoekE3SmFNYklHMHFHaDlFcGJhWUpPa2tSRFIxUUtTNGdEZG1UeGZLJTJCNUtwYmhTZk4zSHJLdmElMkJkWjY5YTN6Q09peThUbUFIcjRYZWEyNXF2eXdvYmdlZ2tISkIwdG1EZVVNTElCcGxVejBqWnRqcEV1MXlZTmUlMkZra21sVkx4MFNDR3ZaSDAlMkJZWm9wNlY4U2JOJTJCSFJjVmxwZ01wM01zSHR4d2g3NGJ1aXZHaTBDeEpwbXRmVjRQUUdzc0E0a201MlVQNmhsZzREM1JSJTJCWnhsdEdzTDl6bTFIMEJEdjA3bFoyNGtqVkZTd1J3U2lOMUtpbDVLJTJCNHR0Yzl4YkklMkJFNGJ1VzhoU3hicGhZJTJCNGpGSWpkYW52MW51cmFLTUFEVG5xMnV0Rnp6VjJxWmxkUTJqb0tlYTZ0SyUyRnVaaCUyQlhmR3I4Y3JGN1M1NE5vSnNMYnVKdDZGSmRFR3FlYmg2MmoxMjRwZHhlR2NRJTJCTVlSaDZqY08wVzcySHQxSno1eXI4MDRWbTRlUjZxaGIySFJmNHNWbVBQam81OUo0dk1xb3g2WVo2M3JHS1EwdzFBMEdRRzRzUG9RTTJMeElFdE5DdndqN1Jpc3o0Q1J1Q0VBc1BzRSUyQjNMdVpUOHhBbFg0VEVadllMRmY2MExmSGUzemRMaXBzRXB1UHZQWE1mVyUyRjNLMGZ0dFdvQ3BINWx6cWQ3d1dCc0hQaFZFZ2klMkZoOWoyV1BDQUVxbENqdVU0M2tpWTQwVzNrckM4bUdtbnIyYUY0dklESCUyRkpaM21KVlRpSEZjMFpCUlRLU2MzYjdSWmMlMkJGVnRjQmNiOFJiRGcwb3l0UzEwVXh6QVFDSzZOa0VLR25ha0JxcW5wJTJGTTRLQmlJMVNZb0tNQks1SVVjciUyQmw0OUVNJTJCYVFDMmtFRjRnJTJCbWtMSEU5OEJPN1VCVDNlME5XTFVWUzJNWkxGc0RoSUR3dWN6dWdFWU5CYnRtclBDcUZBT3E5UVVqcnhkQjFYTll1MloyWFBzUlFOc0ZvY29WdTBJM1ZTTXBQVFFDSmdPbU5ydCUyQkRYT2p1OVFnem1yYzY1YzNUaGVBdiUyQiUyQnR5anRUUmltTGw3d2hGSHl2RTV1cjRQSlBJWUxFRkM5SGE4Z3BnZUkzYUVFRFZBOUZ0dW81T3MzODBneGRkYm05MTQlMkIzaktXVjJ2UnY2WTBrclJPJTJCRGo5SUNYamh0ZmNjVkliWkQ2Vm9NTE92emV5MkdsUHJ0WWhJMlMyakFucDlaell3RW10VjFxYnJRcTYlMkJhSnQxbnNqek9MalNwTUk1eTg0TXd1VHNEekFiMGxhNTlGN2IwSXQ1NHdYbjRUQmplWFdYeUVvY2xvNHFaaTVDNUM1dFlXRnNXV2VUa2JwUG1DJTJGTG1KbU5pWlRTTWk0b2RwNGtZRXhhUk45VEFRNSUyQjFqRm1LVWNpNlRBZm81OXQ1WXRYRkFRTkg1QjlQTG5uT1BEWG9OUU13V04lMkJHWXE4YUpsbHRHelRNc2ZId3RNWHNNSnAyeFFQbmlYWjQwQm1VU3dkTkVPNm43dVo5UDd2R1lGSkZ3MFhnZDVpN04lMkZZdEtnRlhqemZJZjdqQnFSRHRHYlNiRCUyQlFtR0FqTk1vWExaOTVWTUMyY0ZXd3ZLUU51WFJqbGVWSGNoRHJ3M3dRJTJGWmswJTJCYUdGb3A4cDVab1dxZlVpV2FiUVNBb1hNVnZCeUFSZzhxRGhCOU1UaFBNUDNDdGlYaUF2OTV4UTBvam1KOHFyUmJiSUhraDh6WnElMkZ5VzBIaGRlS2ZGVWFYdFU1c00lMkJJNTd6Mk91czU1djZmMVM3Q2FiTm9nNnl5YzI3OXNOUWViY1BPbCUyQldJR2RTam9OWSUyQjFXUUFUOVJmWUFqQ3JNcllKdzVKbTBuOEhGbmFNbEYlMkJ6RWxyZXM2aSUyQk5NMmtqS0J0THFkZWdiUVJlZlRURFlCJTJCeWJOcXJsVVJ5Nmk0YjY5SnRVM0cwNmxONEdIV0tPVyUyQmVPdlBReGI3YklMQjM4Vnd6SW1odnBJTEdRQmxURHJxU0ZKdUcxdlVVQkVlRmVrQUZUUURGcGhwR1BQNVdFTkhsM2NsTmxOeUpTSFBBbVI2RUpLSHNJRTZrREs4YTZoY3IzWUI1a1NmZ29VMWI2T3pUYWZmMkkxNGpIbXlIUyUyRnFTRHZOQkElMkZqMXlhdHpSTDJvMFdkRkp6eDE5cnc5MEEwTzVYeThEeVh4UDdTQ2hjVkVrR1ZDTDlvY3pTQk9VbW1qcDhkVWp0NVNhZHBTVHN1JTJCd0JscFBycXpEZzdIVFBFRkdURlhwUUdjc2xDUlIxdHp1S3R6cHVWN3lzbERMSVZBR205UXJLT2RWRHhxYmVNZUtDSm9OemJoNXY0WHB3bVB5JTJGWSUyRlBVcktRYm81eUlBU0tVcFclMkZ1ZDJGcDJwJTJCUktJb2dUSjJzeWkzclFCdVN5REVyY3hIbGdlNkg1M2NEQnd2QUdoczJkQlRVVFJ0M1glMkJNdXlZNWlaM3NZbzZNRElOQzdNTmZmQVdlZklwN2k1RmtkZGlLSjBtODNRMEVhQTRCbUJ2WFVpYXhsNXN2cURjJTJCMzFUSVBPSkdrWVdPSjlRYzlSWmVZWEY1OWE3cnJaM1hkamxLS0QlMkJvJTJGd2NTRWNEWGhxVHRWeEMlMkZSaDBUZmRlbE1PVXh0UlRIdTVsc2JIMUZJUWhzQTlkUmxTJTJCWGF6YmtTRE1kQTZlZCUyQm51OVdRMjJjOEdqYncxbE5PV3U2WEFJMzROS1VUdFVxUXhLcTFmYlNCOVR0MkNtRGFhTmNVOFVXOFJOZmtFRUlDSFpLTlM1STViTjZtTFFEYnRuNkJMVFpDc0VzRVVac3ROeSUyRkdHeEJIMDlFRW1wbGFPWkZacEZ2SFVzY0xnSDUlMkJxdmNVNjJ2cHNQdThjJTJGelNLeXZPWnp5cnNsUkhQYUtqUTl2ekcwSkJuYmtVR3RlYkxuRDdXTyUyQlclMkJaZmZYa2E3JTJCJTJCZ3lmUlJ5dklBbmdiNDFlZ0xEJTJGUUlTQnBRdjl5R3BJa0F3cURBVWp2QlIzNThUek1FdHV2R1BDTnklMkZKbCUyRnBYYVF5aVJqcnAlMkJYNVZ4QUlxa05oR2JqZ1Z4RUZKRkhPOFBJdUMxUnNjN1k0blNFaEg4S1p5Z0M2RWdpbVBEek1pbE10ZSUyQndsVWU0dDlZcWptTVpwcDJ2dE5vejFUb2plNnBTMkUwaDlzbzdqS3A0JTJCV2M0VkhraDM2QUZIYkN5RG5lRDBSeDBSZDBnSHBIJTJCUyUyRkc3OWVicFN5M21hcmVKVDJsT3kwOVdSakh5ZVJWajRXN3JPQUNaNW9UajEzZ3hPZG0xJTJCR3owMGF1NDhKdmJmQTFhQWM4eWlWWkowMFdNblVIcTNsdHFYek9mckw1dWllTDdsNUNicUpmNlRpZWVLbDY4YUJQWjJTYWZoRnlwdzhYVW5Od0piUEVxcXBVdzhSVzB0dmFzYmRJbDRJUmk3U20xWDltTU9LamI0JTJCclQxMXBWdVFvZ21Sbm1LNU9tcDhFOGZuaWxma25lT0pZdERyUzBXOU1vYnJZNFZadElNVU85WVhKRHRUNmxzdHZyOUVOdDRHSFltSFBnT09KQW5BazRJdkV0ek9EJTJCYjEyWWIxS2dPSWNSNm5jcXQzVmh6bXBwM01hWFR4RUMlMkJaaCUyRlNWWEgzMWtmTzhYRzhlUjN6a3NnSmMlMkJyQm1aJTJCR1paYzkwVnhFc1J4cHdUWjhySlVjeVVBZ1pRM1hqb3hkbDlSTWJPQ3BTZW1TcGRnTmgySVVpYXZNaGhrWWVRMXAlMkZsbkxYOVNYMmJFS0h3JTJGdjdUQTRVQ01oa3pSQ3gzcFJPZm9EZUdKRW1udUlwQ1Z6VkVlRzNmSkhjeXJ1TEJtVHJaN1lyU0pBbE5tVFdOaEM4ajhiRktBWXVneFV1cE9jdU1OUjBBQ2JZTXdMSVk4OXV1OVBBWjdkbCUyRjZiT3NmZ3NJQVpJRTR4OXN0VDEwc0JnSlZCV2Vpank4VzQ4d012VU1HNTA4aHolMkZlWldoSWJHWEpKSkRobm5aY3clMkJmVDJsMDRHYkczVlUzdkZHQVg4Z013eWglMkJCUWRwUWYzcWQxMzdDS05WYmdNY3lZdHVHT0pMZkQ4Y2JaZll6MW1abTdndTVqRFBCM0hUWk91cHlyeWxYZSUyQnVtSUs5c1JJODZSbmxVRFRLc3lQYlUxQkhlRkNiOFlBTFV2ZnQ3R0I4SWpQVDdBNWhCTHI5bmtjM0poQzhwSVc4NmZpWVY5ZU5JWTIxelFpeUxTRmR5enpGcXQ5QUc1c3JTTHBGdkRYTndKdyUyQkVLcndKWFVBQmhVUFRWM2J6YVJ3bGp3NTF6Yk1rUXJoMnA4JTJCUHkzZHl2anZRaHpHNFJib1lzSU00UUtmem81a285QyUyRmlwWnBEWm94eFdHUlA2TFVzUVZYWVRKYzhPZGJmS0V4UXBpb3VhZHZKc0VkRTlGempoTTkxWWp0UyUyRlQ5TzlXWmRyaks2Y09rbVB4WUVkdmtPc3RIWFNPJTJCdEhDTE04MEhqJTJGYWVkSDM3TW5hWDk0QUlZM0U2c3djcEFxNldiSUtIUGh1a1FKJTJCQ01jVWJPQXpFdnVqSnRPZmpueEhiaHBBb0todklkWmRDSSUyRkk4aTBXJTJGNXYzeU1lR3o0OTJNeHF5JTJGZ0ZtcjFmSFNkTUlidEZvUEp4WGJ5OVVGYTdGaWZ5aDZ4eVl2d2toNWMlMkYzc2ZKeDAyVk11WmtObmVvV2JqZG8lMkZpemtSM2pnU3kydzZwNiUyQlJvNVhMN1BKcENaZ2dwZFk3bzdpZ1RoUzBLV0N5azNSeFg5Uzh2SFZPUTVSU2JDclhTMHBLMHZTN2ttQ1VlRkpvVnUlMkZyTXNyZnZLN2RGMnJKRWNxak9pNUtXZ1d5MVh4VXRXcWREJTJGekVrb0FuYiUyRnBwcTZBdW5tUHhhd3dCdjlJR3ZiTUJLYXQ3SHRPcmhMWEdQYTlzSk9UN3NuckcwcWtlM1RFOFAlMkZUTGJ3RlZwSm9sbkJTeUlDUERRVjFhdzRtcVVQRVpNcHYxVUFFN09ZWHUwSkdvQWtoN3d2THVtbEhGTVNJM0FnVUFKdmVGalJIZmpQSE9YcjBMTWt0ZThlMnNyTHZCWjglMkZMSTF1SjdNQWNoYzk3cSUyQndUa2t0R3JHa1RNR1BjYWN2T2hkR3k2ZFJBNjNDY2J2MjhLb0V5JTJCd1h6ZkxaQ05DUjM3a2lxcWZ3NGhsTlIlMkZGUTVsSWV3TVAlMkJXZzQ1dU4yOWQ3RFpxbnMlMkZqNlV5RWQxMmFwQ21lVFFqZGt1Um0yVWFYSzRsdko0N1cxOGJZUnJxeUhRUFdOck40eiUyRkFRZFklMkZQNU1XZjJsdDN6JTJCbFNHTlNLN2xmd2ZJdHRrOFNrOXJvRzdQV2clMkZXVmRyQnJkYlZyVk9TbHh6bUlscWNubWF0MFoxc0V3R2pnc0h4N2Rmc3JHREViVFN5UnZRT2M1T09KRGxKRW9WTDltc2t3VGJ1a1pqNTNXYTIxSHVBTlp1MWclMkZnNW5HUnRWT3ZsRGhXanVRbEZTa0h6dmlYWXBHZ0VpZkFYbnZMenV0MXFYV05Oenl3JTJGekNvdnhXSTdyMkNjWDFvelZWeENjODVGVkU2QklnRHU3WUhaQUFaR0k2R04zeHdsRlp6eVRkSTZSWThtNVEwQ3ROYnZpOXdzQlVvJTJGTmhuanYzRVc5ME9UY1hJMmZvSzIzZ2o4eHc0WFJMNU13TU53elRUYUtIZUFaRHRMbGN3eVEwalZDcVdPTUlkJTJCc1pMSWxsaWhqbGxWJTJCTElSWmZ0MnppVWpFdDUwYkl2ZEswSmx2RGN1Q2dmcWp5SXIlMkJJbDRDWUFPdm5SRmM3MkFZVGRVOVF6SFElMkY0UjZDMVdOVEhBWHV6TVBHUTJzUkJpJTJCSUhxOUdrRExZbnJ3d2VaZkkzRmZ2cEdRSzB6Y21rNlp3Wmk4byUyRkRVanBUOVZPeFhRSnVnQ3FISSUyQjBtTktDbXdKN0VIYlY3JTJGdXdrZnJMYnJpNlpzWkJuV2o1YWNhd1p5NXV4OTJGRmZya3hnRGUlMkJ1b2cyTkt4VFF3YkF5YXBxMEp2QnVDJTJCRkpCWEY2alNtMWF6QUFCTW14UXQzYzg3T0lQMkNYWnpjbkZkT0pET2glMkJQbHR0S3lFd3E3bjdORXE0V2tYY2tmQiUyQmZZbkhuU3UlMkZETSUyRmpMSjhub1lXb1ElMkZvS2EyaW5HT3hXdlc5JTJGQm9vS1BpcSUyRmJpVFBOa1pGZ2VBVExOUTBtMWtXU1lZMDZKV2tWWlU1cFAlMkJ5d3pwNUxEaThxYVpveU8xNlJTWkx3VXJ6SnNQeWEwUVRUTkdCVkE5Mms4d25HYTJLUFdWZVhTUnJkdGp4dGhUSjY0a1pvd1olMkY5dEtmdDQxbFRUUE1jejByb012V1ZsaGlZbnZBRiUyRjAzeDRZWDZ5R2JneGhxNzVWRkZ2bXlIZEtyTDBZam9EN01rMWdrRjZDelpTOXl0d3JDajYxV0VPNXclMkJlbGx6RkxoUFFkV3g5YlVBQUZSNktVNENrZVdSbmQxSU4lMkZpT0dtbzA0ajVHbFVmcTZuUGpoNDlwY3VBTnp3REM0QTd2TWRORTNza3h0TUljJTJCUlRwT0FDM09YVHVOczJ1aG9nNE9tM2p1VTdvakIwaWljMmJmc0Y1cWN5OTd3eXQ0bWhuZVVQcWlPMG9EZU41dkFURFRZcjhBOG5JcEZFdE56NmR6Rng3MUlKZWpRVUppWXM1eElKMTQzdlViVG4yJTJCcEtrWHJmT3h0RUdjS1cySGklMkZzTEVqUHFKZiUyQnBzQ0FRQ3Y5aWlxc091bWIlMkY2eHVsQUF1dXk4Zk9maml1eFhOb003NldLc3dvZ3ZkV2dWMGpPQVRheWdOZTRFSlFETkF1ZkxtN1hXMnR1VCUyQllYSkR6MU9GTVZkT3Q0Y2lmTDVPdzVpdCUyQlNWSWlsZXlLamF0aW42OFpyZjRGQ3V1R2hCVW91aHN1elJVU3BneGtPelNvS1YlMkJDR3E5UGoyVnNhYVlURmk4Z2xVUzdxUXZyRXQ3RjB0ejB0aXhDRk90TzRHOVlmTWxtR2o4enBjZEl4bFJMTUtjdHN0WkVuUnJCaWlXNENTWiUyQk5ObjlPUGhFJTJCMWFzakwwVE1zclNkWnpHRyUyQkVxbVUlMkJOcnJ6bVlCcE4xcmNnMFRISWdMaWdzUGJuYkJEenZXWjZUU1poNEptVFNFbk9jYTBOUGdkbk1INGNNWHFJYWJlYnBtZnA2VFFVUDJTeSUyQmhUUnBZbWxwVXhnUUhlUHklMkI3Zm9xMlVscjFIY3VOcDdSdzF3QWRMY0RxUzlFOUpPQ0RuTWdDQVg4Q0FFUXFWTzBkc0Q0TGdqR2sxQVNJaHFsTmdjZ3RsOG1nMmJCcUoxalBXZFZ4YU4lMkZoZ1BNaG1IOFVGbiUyQmFrTWMzYnYyUXglMkYyejlrUFY5a1h0OXNUbzl1RyUyQjdKMUlQdU5VaExVZVYlMkZjdW90N09lR1lRN1NBZmVZVlRhMGVaTk9PeXA0WjAxTWhIbVBlV3NLUHltY1kwak0wbEtJSHM5cGNyenBZYk5GZU9uRkxaSWxBTmI4azlERSUyQkZwUXBoUmxTVnJUaVJ0UiUyRkwyZ2EzVGxQZWpza2o3czUlMkJkZ1R5TkpiTjhxSGJtazZwd3ROWnBLJTJCSnBRZjZnZ1ElMkY5T1NNY1l4MVpCM2p6bUtqcWdoemdIMzhwMEVFJTJCM3ZvV0drZWclMkJLMVJqMU5uUElEJTJCWXptVlJwc0l0bkkybjhHcUxNamo3eDlIdTA3MGUxNWtCUkxhME1GY3pDOU9nQ3d0NGN4OEFlTHh0bUcyemQ0WTNaZmtzeGk0Umc5UERPT1A1Skl2dUxyUkJpREwwNjZhSXRLOFdadmwlMkZwR0lPTFBFNE1ic2hXUEJabWZpUENrOEJtJTJGUEJvbkd6cmNMMlM5JTJGVkZRdHNoTE5WdENpZGNJUzdPVm15SlN5SHk5WEZoWGhCd1VtVTNCdmxLcUY3VXV1UmwyamI0ODcyQmc2MHE2NSUyRlpaNENDWHA1TWRpUk13WFc3TzhrQkFpMnBHYmd6ZXl5SUdBb25IcUZZZHZnN1Eya1hDOVhkT0hMTUZWa0VSZURLQ1dZVG9xZEtMY0oyMjBHR1RXa3F2bkgxajN1UFdaM3pabkk4S2UyMVhCMkJWcCUyRk5tanNQRGZ5SzFveVhtckNxMUlMQ2laTlE5eTNLRXRRZW1lanElMkJmTjMwaVZiODh0YURuMUVWZFppZElwbHdEaWtMVmlzOGd3T3dKU2RBeFN3MUJsQWtlZUtqbHV2UVElMkJNSkJzTmVCY1VOZTdlSHpLM0plZGlIYjUwTXZSV2ZmWVZsemhxVmk4bTlCdk12TjZ1cTZkSkhLSmpnQjB5WmRSb0pPWjlraml6TGRSWUxjbVEwRmgzR21wJTJGMEkzcGV6eEFzempCVlFFSEtSMUJmSmczU1Jpdmx0VyUyRk5aY3pzbEwlMkIwOWM3emlwVDJCZ2FSakxVeHdqNmRsMHpvVnEyYmFkQUpqVmxCZ09LMkhTJTJGU3l4YkEycGxhcjhWOEtTU25QRWNMVVB0R0VYcm9VajRCYXBRV0FyczhsTEdPRnNRaU5yVTRVY1M0N01Jdlp3V2dPWGY5WHBGd1RjeFVsbCUyRnNLbW5YJTJGRWdvYkhkNHpuOTNsRSUyRjJVbyUyRmM2dEYyS0tLZ3h0RzRMbm8zTTB5R1FDUiUyRk9Qdk1Fd1llVmlad3J3ZmF3bkpwVzR5ZnMlMkJ4dEpWRCUyQkZrMHVKU2tqOGxsMnEzTUxkYUxrZzE5OFNzY3p1aWRNSTJIV0xod2g3ZTZxd0R5MEM2Sk02ODQxc0l4dExwaHgxWEJRb3R2dHhxR1V3WjJXQnolMkJBdWg3bWhmdSUyQkhvMkFhT3RrVzNEQVBLZlVNOUtFTndUQlowOGIwVjl5TFZYalptUzVINW9OQnlOaFRxNUlQYVFTUllhT0JtaHE1c2tlQndvalpibEtHTWxsblUlMkJNaUdHQlN1Z0Z5SDU0Tm81MFclMkJIdEw2JTJGVDdSbm13VENtJTJGV0VkaGZrOGNWWGtjMjMxWWd2S3FPY08zV0tyMkl3Yk90SDN5U2R0V1BIWlVIelZWRzNzUThONkIwbk1MV2pJbXJQTTlsRGZ0czRPTXRZVzhTTlU5JTJCTWVmN012VzlYaSUyQmZWWTA5M2pWc1p4OFNhSzRvWVU2a3B4VElVSnV2TlQyTHRkMk5qOXlncGpkS2loMXpxQUZTYWxTYTd6Y1VqRUs0dHZ0SzNjRUZOOUxtREolMkZsNm5ZMHN6N210Vk1jcnFPNnJuUFd6a1pZdVAxa0l6bWpvbHFuY3VPdlVleUVIUlVpbWNnaHBQYUJIdk5RcVRseUVMVFpvU2M1VUttbk5uMU80cVkySkdQdzVQU0gwNlRZcGxnVUszaFdvWXJuNCUyQllIbGQlMkZpalNuRnJUS2w2elhOOTJvdGslMkJYWmowcmtGcFBKWmNaUFpnNEVjaXhOWXdNVU5xM1BKbDJaaDBjdVhwWWVjYk5JJTJGVHlOZ29pSnA4REM3czNYUE9xYTRKa1NGbDUyQ3dqR2R2Qm9kbWNnTUU2a2xIU24zcGIxNXlnNUs0b0U3ekcyY1NwYU1Wd21pSXpnRUYyaWt4RyUyQnZOVkZyd2RxdFE3VjJ3ek9STmI5VUhVVk4xaiUyQkRiNFFqT1pmY0JTajViMnpQRWNnek9MVnVCOXEyWFVQWGU5bTJKVk1tRE95VVg4V3E4JTJCVHFzWXZkbHJmeHp1RHBDUHc3bUdNZEt4ZkZaZGRqSEFkaSUyQmtmc1dMNkpsUW5HRjNLemtscTZWaCUyRkRBd3p6aHE2U0ZVZkw1TVRUUGZ4aXVZWmFhVW10UWxqU0pQS1dZTGlaQldKRXIlMkZPeDBLcUFwd1JrWGpPeTh1UmZKMHRjR1Myd3FkWUozdE55alBOZmglMkZuT1ExRnFnJTJCbkx5ekxkNXhzZW9udGVIR2VHZHFMVVJGR2hVdjNtR3R5dTh0clFJYjgzakVldzZRSktsUmRXV0U1TkhJJTJCT2tBMzdWME5XSlNkN25TVEtqRk9BJTJCMVBrUks1OG9LV1hmRWppUDhVWHhhb01pUGhRUVN3OUtyTWkzemwwVmFzbnI4Q0J5MGFzZjhHaDhsbmZDUVJOWTE4bTIyeG15dTRTaGo0M0hsZ20xODVtZzNvUFpIMnlYNFVxSnFoTzUwanZlb3clMkZiMnQ4aHhNM0xkSDQwWFMxdHd6NVdYU3RqTFJPZ0FheDFWMFdrZ1loeU9WYzVvQzhxajNuJTJCOGFFQm13OFpTdXlERFhRWXAlMkZTaXo5NTFuQTAlMkJuWnZJZ08wbWR6Nm8zdG8lMkZUJTJCNWowOXRJY3FZMGglMkZ2ekVPMmJzVDFoUVRhZHZzVWJhQ0RCcklxTmtxJTJGbDRhb0Jnc0F5YlFEeUQ3M0NDU0F1cUFsNW5nenpFZDNFNFhNbUNzbWxITGpScHRsQmZiWkV1ajVWQ0kwelhtSEZLYkU4dndZTGRwUk52QlhEbTdFWjJUeWMwS2pabCUyQjVJbEFENEZDVThXUWtzbFN6VWhaMjRMZUNPQjd1RzdYQjR4MEtjVDFpbExvbFRMYWhSTU81ODMzayUyRm1HdzF0NDZRU1hOb1ptb3I1JTJCOFVCMVdmamUlMkZORVJRZlZXYyUyQmhvamNYcmNiYyUyRmFCTUd0cHgwNWxjMjVsZ3dsZUFMZU04eW51blAlMkZDJTJCSHJ0N0dZRlM5VFpETXcwJTJCR1pldURLUWxhdmk3NnVhYzYlMkJIanh6RVZuMHRVWEVxQ1FPZU5rcTV4TzZPMUVFaVplOGlacTJTWHE0NzRpbmx4VkxXN3U5UE1Ca0hmZ1BDcG1qSXhGZzdzJTJCbGd3Q3RsaGNNNWF6MVJJVDJSSHpiNXdYc3RIeGFKWXM5SGNLRzdDUSUyQmc2bm9RRThkaEEyOHBrS2pMUWltaDk3aU9lV0kzZGMwV3J5UGRvMkd1dTBER1VZQmd6dHBRbzZpVGtjbjRFaXB1c3FZZ0VDM3BvWlZ0UmRlaE5ucCUyQjBhOWxpcFpiS1I0SGxPWFdNaFFQUWl1NGZBNEpqJTJGUEZWaiUyQkMzakFRMUdSVk0wakNhcFNkOHV3Z3J6a0FmeEJ2cXBweXQ1UXRaemZoc0hxOGxXMGlZUHdWTXAlMkJsU05YJTJCTFMzdktQMmEyMnMyV0xNNVdTMDB6RkxFWTJ1Zzh5WWVFYlFLRWNNTEswUVR0WERiSWR4RmFMOFVTUFhyVVpJT0Q1c1FraTF0U0JHTnZraVBobFg0OGZVTTlPTTlzJTJGeE03NHNDWGZPWVZXcDFWZXpZUzZqZzVvTnFQcjJXZWpsNzNEJTJGUXlDa2JWVGNDMFhnJTJCTmw5cjdmckNLcXclMkJJMUVRMG82eGpRQ09tTjVPZG80MTM1UCUyQklDUHY3TTFORmlpZFhscWc4cVFUZjZMdnNTdTVlY05uaFU2Smx2U281MEklMkY2MVRock5LcjV0aEJkJTJCN3FqWThtdmN2NWtRa1lFSE12dnM1S2slMkIlMkJ0cmc0VHklMkY0NFVjeWJ5dDQ0WEslMkJSSW50NFVWR09FaHVoczFFOWN3V0w4bkJqYW1aWGgwVHJ4MlFTQmgzUVNRbDlGSjgzS0l1SlI2SEVVbUh1RDRzZ2lRRVVKOW1TSyUyQnI5OFVKa2IzcUZyU09PNkNjdlFrRGJwMU9USmlnViUyQmZxMDR2bnhiTktLcUFOczVnMkpKUzNqbEd6SjVSa3p4RTMlMkIxRE1zZjUzQVJZSHMwUjhwZWN1Mlc2azZTd1dWZlhHTGd4dUloNm8yJTJCN011dVklMkJZWUZPcG4lMkZ2WTFLWU9Ga1BsSFAlMkYxJTJCNXZEZ0lsSmlZTG51U3FMazI5TjNZUEpZQnY5dkNHSEN1ZUtsVk9UUXZJbElwU1FxSyUyRlJoN3pFekhuOG1nNWg5bktMTmZJUFB6cW5PVEVsV0QxVmFsbDlzNzBHa3o5Z1dwa04xQjBIUXl0NDVtZUZlYjVIdVNwR0xKNFk1ZXVtdmVmSDFjVVc2cVNUWFR6SDlRR21rTHVTVkolMkIlMkJicTBQcDh4NTNiJTJGdHdlUWZhVGV2dTE4b3hSdXh6JTJGck5sZGtuTmdKOTFWbE1WUllyNjYlMkY4OFN4Z2IxQ001d2MlMkJIZWJhS3hkQzhiMHlIamNPZTBUMUlCNlBvbGxlOHh2cTE0b3pQclBtSmV0QmhMUUpTcm1paTRFOEc1R2MxTlVHJTJGTFkzbmc5bDdIVXp3bzQyTDJHTmxxaEprbTR4dll0SW8wMCUyQkVxbktwUHBCWGZpclVYQzB4U2dnaXBDTEJFWFM1azFLY3ZlMUZ2ZFNmT3BJNXBXZ0xmQWJyb3JVejYxbVRwTzJwWHNRQjhiM3BTZFJOQUh1OVZBS0JlSERVcjltUEZnSnI4aFJPRDZuN2tJdWJkWlclMkZFNlZROFlRdDhpbXRYajVYQjlaOWFmVUpJZXJQNUhCRm8wNjJZa2J6ViUyQjBxQ1NXbmIyemJ5eWRMOHpNajdheWZiJTJGanNpb1JYazJGZkpaQnVjYVFEUFpMeTdKNjB0bDBOaFR4Z3oxQXdoUnZLR09BSkpMcXRJUkZpamxuM2Uwdm5TRVVZYWY0Ujd3YlVYS0pmV2lRazdpSkJmOVIwWkljNnl1NTg3aERTUGxyZUphVSUyRlo2enR5QVdpT2Njb2x2VXNqeWM0WHpNakNLWDFKb2NMMzBWUzlvMGxodE9kT1psclBKblUycHFmJTJCcnZXekp1b0l6VSUyQnNhd1dPa05KMkNsMFpZZTlLWW5pQnNFTkxyN0dpZ2hiYmZ1JTJCVFpIRkVoTElDeDBOJTJCVTM5eEFpJTJGS1l6M2EzMVdUYm5IeWJqV0ZwYlN1SWRoYWlNQzBNdnVvcW5laUtvbHE2NmZUMVI3MW9EQlNuMDFwN2xtOGtmZyUyQjNuMTN5OGhyVCUyRm5PMkJQQ1BPdndkNlBma1EyY3JPZmlkdVQlMkZTSUg0TW9GT3FrVU5Xb2ZMJTJCUFZ4MVZWOThKWGNtYjR0N0JNJTJGc2U4dGVibkFlaXVrUDM5aVFVck5GUU5pSnl4S0ZMVm1oUVlhWjFlVlFUN1Vxb1phVlMxd2NoYk5FR3U0cCUyQlZuTDJxcDV1V1NqTkt4JTJGWWtsSDRMdjJhSm1iUFdwY290MFRUczdCZDhqeEo1YjFBWkNYT2ZXSUdyaFhKcVdMYiUyRlVHMjc0ZnBHRTFScjR1c2lJWFAxQ1R1RnNLcGZGSkFHOXJ4ZzVvQkF2Sm9jdUt0UzI0S3l6dU5HS2daS09jJTJCd2hmQkVSdTZyWFNVRFdjUFNQUWN6ZzNFJTJCSFglMkZBQmZRS0dBSm1ONjZUbHQyV1k3QWhNU0wlMkZSUXQ4YXoxWXVocjVzazBoY0Z5ZTVYZiUyRkNDJTJCUkZMakZscjVtcyUyRlk0Wm9jb3clMkZaUmxxd3RWTk01eGJXOFhQbFAxTDByT1VwNU16bmFQWklvMWN6YjJxU1NOaUJxbVdoeCUyRm9La09tNlR6eHNwM3o3RTJkJTJGVmwycElLSDVyR0J0aWxaY0tPYnklMkZIQTJxTGpDell3VTklMkY2YnFxQ3dSa0pnVFFZZ1JtbU1SWlhlYVRjSVhvUTNVYTh6cTlZemx6endnelUycFU1UUElMkJnaWp3RHlpVExrSkhvbCUyQjRFWlZIVVA1UksxdGhtb2p4NTZ4JTJCSnglMkJPQ0tmc3ZuWiUyQmtVNVBpd0tHTXhSc3FSOEtlZzYwVnE3SlFaNHpwM0MzZFg0azIlMkI5c3U1Tkh3S0tjR2NISmNiTEJzWnhFMUthREl0SGhVa3BUZjU1U2NUMVRNSHJ4cnphN0liTHdwZyUyRnVYZ3o5UyUyRmJMd1NXblZUUXBUMmVlb2l2Z3E4QzJBdmg1TlRraThpZ3hzNmNhVG9xUzJhJTJGTTBRWHZNSm1kbkUzdFF1aGx1dnNTZGdSUGRjU1h6aWRiOFJ6UDVpdTBwODM4cE4zSkZBck43R292aVRlJTJGQTVVZGZCQiUyQkFhaHNQdkdrYjZCNEpIdHg0Qkl1WHpxSk5TOWl2VyUyRlR4a0RhYkxtckM0bmhrRUNEMXFack5mY1dUWlFpczhzTUtEM0tBUXo5dmo4eUdkQjhEWlRpdTcwMFRDbGU4Z1dCUlphdEtIOWNRd1ppZU53aksybzFmdG11Z2ZDMiUyRkdSZEkzc2VwaHlFMTVuZzlXZkJ2OUslMkJYcU1OQkYyOE43cGFxMENkTlN0STk1NFczZ1l1cTQ5dGNTOXREOFlLOG5KSjc2TTJmSTBUNkp1SnRwblBkZnRGQ3lRdzhUU29xcWlmTk1QJTJGcmolMkZibkY4VHRnNWZGSlFDOEdDRmhVZ2ZXenBUNkxVRzRUMCUyQk1iZzkwdyUyRlFLejBIZldZeDF4VVp5NHRWOFBzWkJXYXZWbk1EM2VwaSUyQmtVdHRvTzduQ1AlMkZXRjN1bnpqU3FyaW45cFlnZ3RXYmEzRHZydGFxd1V4WVdwTlZ3eDg4ajdrSlRNNEQ2MG1xU3lOWW9ENXFnT0VqM3JEWnV4WUVodXNBanlMciUyRng3U1dPVVB2MTY1MVhiWVR4VjdsZ3pZeWslMkZmbzFBaGE3RFhYVUdJbm9oRnp2ZWZoJTJCS1ZSTkZjRWJyTjlrRjVyWjMxSjk4SkZoWDJCNXhzZDYlMkI1aVFpMlZCM1JUVzhIWGxjamp5QXlwQndweUdaZHptUnhxSU5nTXd1VmlnaU9zbHdubDA1NjZJdHF0UlpYMmFFS2xjbTBFaHo0UEp6N0ZNYVJKYlMxTTFEMFR6djliN1ppZXMxTXc5VUxRa1NLOHpHUFRFQXN2bGpycFRLV3JYb3Q1WUN0UHFLYUJoM0N4S3BkbFlZTnk1TnFBQkxtbWJObVlNNWd3OU02JTJCS294NGNKcjFkVkcwUWx2bUVLYWpzWFBXRHZvazJRN1UlMkI1dkRXTUJwdTRqdjQxMXEwdHJxemlCYUNNdjRDeU5uakRhWEZmTEN3Rm5RYVJxdzljdkhPMTF4V09qeUdRV2ZRWTBkYSUyQlVscDRVdmtMdTBqZVVadXdVck9vbXJlZ0N4aUlCckpKcnVBVVZDJTJCcVdlQnRONDRxcnNzdURoSDFFczJ0QVNIcTRmM1FsNWozYkxWcU5Ta3ZkWHlYa3ZQRjBKOHlsaWdCS3JiQThaNFg3NjF0dSUyRnI2dnZpbUJ3d1NhZlNMb2lSSTFma0ZvV1ZrS1JSVTk4NUJ1dVBpaiUyQkdYY2hCVlolMkJWZFN3aFl4dVpvYTdMaSUyRktBUWhjNTAlMkIzZEdkQksxR1BpdkZmYUZvZUVrY1RkYnJwdGxqRThIcDdPTk5VR3pTT3pRNGZUaDNHZTRCZVVZT0F0dTI3a1JBQ09Xc1RZYkRja0N0JTJGYTBKNlBESkl4WTZwU0hhSDJsS1dtenlUZ1lMbkZOY1BhODlDWEtBN280R3NPNE9vWVh6a1FVRlFNSlNiYksyNlNjUmFwZUEyMzJteiUyQllvcHNTMTRUcDEzejZjbzlXWUdNamdTa2pLUTNKWk1QNXhqVGVrN29tejd3Vld4a0slMkZ5RVg2Z08lMkJmQXdNdW5FT1lrbjJtUEhCVEt5NkhiRUZteVNpQ0klMkZxR1hJVWJIcGVxZWtYWjA2c3FNOUNmVW15aVQ0UGJxV2NNRGRGU2xWcEVuRDJzUUFSVFhKdUZMNkNUUlQyc1BURjJNcno0YWlTQktXdmZrV1RKV2R2RGZBTjU0RkZTSFV1dm1UWDhRYmVPUkglMkZNbk1aTVpsNDJ0cFVWY2hWZ09oaWhNd3N2SFpMcWdWUHpXa0FxNE16cGRCWVpmN2N0eEtBNk1OeGNvNmRLc3VhcVdsOU9jS05hSlZWNFp5bEMwYWx1bTF2N0MwWWNiYXlFTzFKYkFrU3Q4WVduZW0ya0kxM0YwTyUyQkgwJTJCaXdSeElHeXJJcSUyRjh3UjAxVGRsMmU4RWtzJTJGWm9oQUJQc2o0d1BtZzNwMXdSZ285NlZUQVd5MWtHS2JNVllMJTJCZGJHb2hoaW9NemRNd3ppN1RvbE5EQ1ElMkJqZXV1dlNlaE05a1ZXTnl1bCUyQkJ5STZaMUtjZnJ4RVc2YlhsJTJGJTJGMTR5NUNDZjBVJTJCSk5GJTJCQ3ZIWW9CdFBPVXNQUjFvZ29sZVN0bnFVeTM4b21TejA3SHdwdm9WSzFwTFZtY2ExSDlRZ1hhQ0tLUE01V2JDSU5jOTdJcE04UFBiQU9jTm9EY0FZbkhxZ0klMkZpN2lmbkxac1RhaElmc3MxUWZNczdLM1puUVclMkZQSlIlMkJPc3lxbkVXYjVpTUdFM3RVQ1U5Y1VYZ3o5ZWRwNWR4c0h0T0hSdGVQaGl6eE5xN3RMUGFhZXNWRTFQWWVON3ZuSTQwczNpNzVKSUd1R2E2bjhDUSUyQmUlMkJoT0s5RlNLOWE1U0ZlRklYaSUyQm1xNzlPUG4yU3pRdGZRVW83eHdoJTJCdzVDOGxLSVhNNGdobTdGZG5UOWN2VDZrSmdOeXlNTUZ4SUdXb0pENEg1eFJ6NUQwa3dSN0J5dlVTYW9weFVQaVdvQUdxNGF3S0olMkJnTk0zaTNoNSUyQnFkeHRCMmRwaURwVngzU3Uxc0toQmJrbWFuQWxVJTJCQ3BPcDRlcWVKZ2R3eXpFbk1kM2VkS1FBNE9nZXJxS1pnZW5wMFBPTlRjVjVFZ3hLZ3FLQzRiQ0Z1cEt6U0x4TDNJcXBCOXU0bWpVaGUwYjRGRnM0MDNuR0xhc1JZZDR4aXdhSTlUT3VQbE5SbW9lY05LbmhrTHpLVmhhak1SSjhkcGMlMkJadlI0cm5XMXdwSUlhdUVIY3ZyZXhoQWc0TXM1MEdaT2RyWFBSQlB0JTJGV0xxS1pjbVJHUGhMWmppYW1kazNNN1daJTJGZlZydjluRHhFekVOTGlySkdXbXBGSkZvVzFBRm1KYUtsdm9ud0ptV0lpcE4yNkoyZHFrS2J6Mkg1d3NHUGw4ZDQwZFAlMkZMJTJGQ0tReEdtSWVjeGlrNmRWeExSMGNYYlJCV3NQZ3BDZEZXb1NLJTJCTVclMkZqTiUyQlhjcHNPVGdlWVQ0QTIlMkZsZlBvVEVhU2FjQ2RtSFJxJTJGNk80ZEQ1Zm5TYXBOSUglMkZTRWhRZEFmRlBTdUl1N1JGcXdoanFkJTJGeDN4eE55RW0xeEgzJTJGQnhGSG1kTDhJc1U0ZjFvNTRNZk1BYXlIWUhrbTJrQyUyQlVkSUVZNkEwaThuN0U0dTFOODVBWlV4T0ElMkZvbmdaUm5DdEwyWkhhTG5XQUl5R1Z3JTJCUWhLRG9mOUNIVXh0QmQ2aXglMkJObjduekFEaUkzSGlBMzhkTmlTelRUZEJTeUV3bW1CNEVZaE1DNFR6UVdrVExoT1ZzcWdLM05nTmxYZlFvYTRHUyUyRkUlMkIyTm1CRldXY0FobVpUY2UzQWpZMlJYZSUyRm84ZFlob0l5amZ2QmlTNFU1Tk5zTnp6cG45NVNyZmJPdmR2aWU1bzFBVW5EanJDb0Y3eWdUOFpGeWhuaE90diUyRlUwMmtMMXJFbVclMkZBcGVlQnFXZSUyQkpwdzJKMVBzWDFvelo0b1clMkY2SyUyRm5veXo0SWV3a2t3M0U2ZHFDbjNGUkpwYWdvd2dXJTJGUFR4UFJXN2RjbUUyVzl3NENsTyUyRnladHlhcnlWQmt0eHQlMkZ5NVBKR3NxJTJCeURJb2YyJTJGOXVwVVRmQ0JGYXgySmh5M0M5ZkRGTHhiaGgxTVlnY3BhMWlkUnVPbXZ2MjJIczdZZ1lhQ3Z2JTJGZEtJR24lMkJPSHNtZEt5azNWT2dtTE9vUDVIejJRM3Y0dXNheGNPUUNxN01pYU1UR3BZM01EYUJNdDlqSGtGZUR0V3BuSGNHVU51JTJGckhWWFdyRXhSVVB0VlglMkY5SzV3c2R1SUJjRFZoTmVhRjI3dWU0c1JZbXBNQXRCcFExVGdkbFpmNFp5V1EyTTQ5NDRkYURTWnFBJTJGciUyRlZoV1JkM01XQWJhQ2h6dWhhNUs2OVV2NGtqYUslMkJHQlhTWGNSJTJCMyUyRmxKRkZQJTJGTkpwU3llbGNnZWVXc2ZxMWJKTWtUUE5VUkFCaG00MGVWZSUyQnVrTjd4c0FYeHl3cEZyVkFaYkl2SE9STHkzTXVDeFJ3dnRnNDBPJTJCWVo2cTUwUWVjZ1glMkJUciUyQmp1eHBpc1llcnZuSGVyTVFkSzE4WUM5MU1ENGJuWVNJcnRlUDRFY2RwekVkbWxpbVNCJTJGdlclMkYxJTJCQ0Q0d2lKSEp3TU9jZ3k3R0p0OU56enIlMkJQU1ZQdU5Iano5JTJCWHEyWVlFYTQxOHNjS0V3MGQ1bHFKQTZ3NU91ZFVpSHpkbDNSQ2dWWDN1RUV6NkdqSGJmZ2NFNmZ2R2s0dkRmcUJZaG5KVUolMkIwcHZ3Nm0xUmZHcWpBNmlqcEozOUR1MFNkclc3QlpHWFhxTno5SXRRbVFjdnRlRUhNU2F4eHVybjhFbTVVUWZjUUZweVdvR0cyWmZWaFlhMyUyQmV6eWxBcHF0WHl3ZkpMQ3NGRUtFOUtDV3d0RWJSZVhYS0k4MjdLTHdwYm84MjBQT1FpckR2ZlAyUFhqZ3R0YUlSJTJCJTJCdDExY1JXYXdaejJtOHgyZGxDaUhZNmZoJTJGJTJCJTJCbmZmMmVUNEthbDhCMXJsOGxheUpPamU0c05ZdWMlMkZwS25qZnV6dG9KZmdVcXF1UmNHNlAwdldCSiUyQkZxMWRiNVB5TE56YmJQRzFRZCUyRmVXa0djT1JDSW9EQSUyRjBJUGUlMkZVVGs5UUR3Vko2WXlDdnZWbTZnR3lIUTdrMEJVa3lSdWM4VGxKU0dENTQyOUN2NHJUJTJGMlpQejJxdXJhMSUyQmp5bWNzQld1TEZjQWgyJTJCV2l3byUyQkY0UUclMkI4R3V2bVp3OExPV2s2d1g5M2lnNXhxbm1KbTJpNUhsd0twT1VaaWVLNyUyRjdEJTJGQUlRM2hHWkxCUEhTNDFFdHM0d2pOaHhMNUo2ZCUyRk1SSUp3MnpWVUVzVyUyQlJUUnMxT29jSEZtZkpxSjhJd3I4QnRwZHNzU05ZeFFHb0RUN3YlMkZZNTJzaE9IJTJGUDRScUt2V2IwNGtwYUc1JTJGWWRLOVIyMmJtdlZnTFo0ZCUyQlVUQU5ETUJGdXpTVkRxcUpYNkhZaWtKVXNEUU9WNlNOYiUyQmRNJTJGNUtkOURNNiUyRlh6cW1QanpWZEVyUzdWV3Q0RTdEQkVTZnpldFVyN1B0eGk1JTJCazAwSDIlMkZjd1BZTzB5eEJjVk1mJTJCMFI3YkltVTcxcjdrUDBORFYlMkZVSUQ2UlMzVm40ZjZHJTJCenVEcWVtUlhZRVhtZzZZVlllZ0x0bmlpS2NBM1JJdVR0R2pXQ0F4dXRSa05hdkJnWnlnT0RkQWhGaXdWUHE5dkIxNkhNSWV3SkMwTzRrVmdscnFBQWlwaTV5NG15cDRnb1JJJTJCZFFSR0VyYlVPZmlUaFc1dCUyQkxtcjhPJTJCb203Y2hOSk8yOUZvMjdCczNUT2ZYVEZiWDdnU3FWQnlQWHRwbzljNGM5czFyckdaNXRhR04zWlk5cjFJWTRUNWlaSEdNNk4xM3g4UVVmQ2VyeHk5cVlOY1VQM3h3ZGZ2eUVkUU9xNHdGTFl1V3R2ek91N05zczJqQlp6WjJRVkRaNFdaRWFUQzZ4SndYbjglMkZId1hMNHRrUVZTenBNbWtWU1ZMMzZTd054ZnRkR2hWTXlHZmczdmh2SnJRZHhoU1FKR1NyaENQU1VnY05LM2lhZHRTSFZ4ZXBxRXNic0dqeno1cVF2JTJCRkFRZ3p6dHdSSG8lMkZKNHElMkZRVDZVcGNrS1hkYVVzQ01palpIUndFMEU4VmUyRDdFeE0wJTJGVyUyRmltV1RKNnFOWFJoUFNKU3BrazhKMmxDNTQ0alYyTzBCVFNSUnAlMkZGa2NWenhWMnlLSDFGRXNjYlNGZVBsaGp0NkVvU0hxaVdlOUNmTlBhTU5iNWhyWWdhN0JjWlk3UVNUaXphRE53TElZYTJxZlBwSVZUU1JMempVZXZVQk9SblpuU2JVMmZrR3IzMSUyQm9zaUlua0dWeE5HVjFkMXFsTFNFSzJKbmVoeXY5diUyQnNGNzZjQkFnZUxIV0dTU20lMkJWcXY1UWp5blp1VSUyRjBnRWolMkJzd3IlMkJvM05vQjYlMkJBemlBZkZsRnBURSUyRmZoYmNZbndtT2R1bklNMERBTm1YdG9rV0p6OXZuNUV0RFpNSFIlMkJFb3JEUkw1S0ljZW8wYm0wZUNJTWp2WmZKSUVtSGNVJTJGdkN5R0JaYlclMkZjdXVIVGNoM1N1eTN2NkdQck84UWRWMXdXODNTdWo0ZiUyQkVTalRSb0IlMkJqNFFNRkxxRGJLdlpsUDlVdm83aVZiOVdhZmdyUEZYbEJDTGZuU2VRWE1UWmxmUE1PMFQ1JTJGbHhvRGlFZ0p3WEZnaVdWekpuYmo5YnFYdzlYSjRYbzJrQUdHbCUyRkcwOEpiWnI5blZ3c1NhejhjbzhvY0dETHhlRHZxcExvVFBTeEVMeCUyQmkxJTJGZFMyTEpzWTU3bkQyRElVUGtjTSUyQnB5QVliJTJGempaQzlWYyUyRkI4TWslMkZTYWZHY0ltQ29SWjRGbCUyQk5HalA3SlZSdmtrSGVXaUllZkhHQ3B6Rk4yYkcwVzhmdCUyQlJQUkZUcjVGbGlJcUFqbjlGdTlNcmtMejdRSGdmUWhqTm1Eb0NJYVVQMlJCTlB1RTdEZVZyUGNERG1DTE9SaTI5d1FUd2x3bE1KJTJGVzN6dnE1WkFwamIzajR4aWhnVXIwZkNUJTJGYktYRTglMkJma0J0MGd5aGZuRzdWZnVoSzZPZGVJMWJyV0l5STVOZnhoZkU1SE5kb3B0VGFtd0FqM1UlMkZxVSUyQjVBamZMVThEaUpmQzElMkZEZUFTenpkekxRT2ZOeTI1OFNBcnZpak1kSmhKejI5OWxVTzdvRHZNY3lQS3VINjNBSXgxMDVSVVN2ZTFTczhrRkh3SndmYkNEazVJS05XSnFnViUyRjdERkN4R0xVMGJwZXgzeDVORXJMcW1PQVd3Ymc4QVRORmhBSmI4TVkxeVl1RGpJJTJCRHY5MkFjV2RaM3pnVDY1TmFUJTJCWjBvVEllRU8wamx4T0lZM2g2bFdBd0RxM0FDdGpBZTlpZDVYd3pyNTM1ZEU3b3p3VCUyRnJCeElmTXl0bGd4MlZjUDRUMkUlMkJIcld2ZVBNaEJxNU13ZjRrZDNUWSUyQlE3RTVsaWdnSXIxQUp0SEc1JTJGM2ZaSVFQb0FXM0tYOXBFOGtQSVNIbUFZSE9mWVJpTzVxQnFqZk56Q0pQcVdXQnFlWGxCYm1GZk5FRGZuclJNJTJGUmJTRDRoeFRYSE45RFdKVHc0akhMYzVZUDZJZGxOeE1lbGhKZ2FLOWlEQ3JrdTlhNWZubExrMGpTU0xGdGViNTBXTmQxdUFNWEolMkZjMm9zc3hSYTJZaGRiOXVUUjB0NFQ4UTAxeGpzb3N6MHBIWFBnNExTTFM0NlBFQmxWRkozb254WjJRNzdLanpreTFHQ08lMkZLMGYybXB6N1ZUMmFCQVZ6ZSUyQlBZdE80TDZZWWdWNDA0N0luQlRtcGVTNFZGbW53UnFlSGF6TEN2QyUyQjNjQms2WkVjb0ZRTWpnZXhDcWd4Ymh3U3VscDFuckNHYyUyQk1paHNLTTZRJTJCaVg5N1BrazFrb29Bc1c5cXBwTG5rNyUyQldUWVB5OHZMSER6ZTg4T2RzV1FsdW4wQmlQNFV6NHFsOUcxOEdqJTJCZCUyRjJYQkw3OVlaeUN2cFglMkZFbll1VUM4MkZOJTJCNnI3VFFjWWhUVUlVN1VDRXlHd2dCQTFzcSUyRnFCZ1pzJTJGQ2t5OGw3eW9yS1gyV0hMdmRZbXhVM012eVpPbXJwbDZZOGdaWUlld2dZMWRFeUZoUmVUeWolMkZyQldlUXUxME5XTkVaMHFnSmhtUUhlMFN0UDAxUGM2bzU4RmZSRHFYQUM1OU4lMkJEc094WUVZa05xZFd3c1BtQzR3MnpqYkNMMFdWUEtlREZoM0NZS0lhNVBFNWN3eHU4elhzRmZick04bUlVTkVHTDZLJTJGVzQwbUNDMjZib01pVFJQR1NaNTVsdjJOJTJCb2owYlBham45Y2h1N21yMUw5ZlZXd2tPNG5IcEMxZVA1QjIzQzNGZWJkcVRPME4xMlB0aVMwTVFjc2NrdU5hT3VCOU9Bak9tbGkwOHdYeTl5RDdUMnNpYTBqQXZSU2N1Q0gzTU1VVUVSYTl1MXEyMExVN01xWW1KVmd6M3VaeFVQOVNISVlYeFJoSGluQjl4ZjNjWW50cGIzM2w5JTJCNjEyNFYxOWdqU3NlWkpDUThieiUyRmdiNWk5QzVMMWtCRDRsdHJSWUxJMlY0R043aW9uNm8lMkJ5bWFzV0ZlTE40Z000NmtqMHR5SEFJZlRHVnpVQVBqWVJ6ZHYlMkI0b1RTVGo5TFV4JTJCTyUyRkxndm9Ma08lMkJ0Y1ZmZUpaV1pWQXc5QmpaQkVNSldoV3daVnJsJTJCNm9ZN1R3VTR5V0pmdFhsdFM5MnhsSG9PUHBBeVQ1MzhsZ3lLMHNGMmd5YWlqa0ZqS1BjQmNBa2FvJTJCaFlhVW45YXVFbFNEc0RaVkltQld5cDQ0VFpvN0dmbWZ2cE53NnhuRllzVE1pZFh0Q2tyenZzYWhyJTJGWXVUUWY3NUxBaSUyRjNBRUFiY1hpdnh3aHNQRW94QVp3Q2lMc1FmUFJCUnZTYnFFTVNWWm56Y0NBY2RlYWJ1ZkZoRnI0ZU9BZXdZc3ltS0olMkJ0S0RJNWFabzNMbHFTbkxlR3pUUGpzWVVKQVVGYjElMkZja21TU2EyM1dINmV2MThrN3dBbWpReUkwbkxpS2NvakEyNEZ0MG44MGx6YiUyRjFQWHRiSnZZS0p2QWhuJTJGNEVLbTRDNUQzQWltdkMlMkJ2V2RFNiUyRmZMNzVndyUyQm9jNUhnJTJGcXpjenJoZ1Z0NW9MOGhmclVDanE5QVdGNzB0blZLVnIzR2dTYSUyQldZbkFPR1VFRjFZWFkzNUhTJTJCdU1wVTN3UW1ia2slMkIlMkIyazd4cTNkRW5XRGlFTjNaJTJCVmJOUUlrdm9yS3YxeXNXSTZjcTVDemJZYzF4anJDdU1lVzA0TnpUMWFPdTcwbWowVTQ5MDNNMlZXMXNCdVNGQm1YSTBic3lNJTJCc1E5aVJ0ZCUyQmFRVTRlMGloZ2NMeHRZeGFWb2Z4aDZyZEVsNHFIQWJkWVRmc2M1NVhyWlMlMkJRNG04VnhDeVA3SFVaUTg1S25uT2V2MjJRSjFCNEU5OUs3ME5uVk5YNnNiJTJCeHUyQjl4TFZHSjFORmJHRjI0elp3UjdCT2NQRnlhNUIwY3NDM1V0dXVKMFJoc2RBSlVSQldxMyUyRlBtVUNDQnVJRmJUYXZRU25SUnhRZmJWUXZhSTd5VkVEMlJSQkxwaFdHeGZqb25ZMG9EQk1ZUmpLVUk0QUExSFViSkFxYiUyRmhWZSUyQnA2VkJXZ1U3Wk00TzVPZVFpaVhmNkEyalI5ekFydiUyRnlWbWN4ZFFNaHNhRjlPWFAzNkw2TDFxMDdUSnBYTnlLdG53UFljMEVDVG42cE5MZ2ZlN012dVF3dzZ6JTJCZkRWMTk5WmE4R3hUNkxwTUdqMDhrJTJCc3RMVTdZbjN0VkszaXJjRmljTzlNS2FmOXFlZm1HRm5MbnJndldsRmhpVWhPNHdudnhBZiUyRmxKU1R6U3FxejBocjJVRFl4VGVLUjclMkJURnQzRzFobU9tUUZaeHptNUxtWDh4MkVuZXh5azVDWlBvVmZ6bFFpajVERnZFYWVITDFtWlVnZWNhWmpOUU9MbkNaM0NnNlFKYWpWQXFEUWhhQnhtdlFOWVVoQzR1SzFmOExVQkY2S1lUZlJLN2lvQ25zRWhPaEt0eSUyQjFMSFhMYjU1WHNWQmNwQTVMb3lPRk5kSUs0YWdrU3kzazEwMGJzQ2JCc1p3MFJzMHFmY3Q2OXVuWHJBTlJpY3ZhZHZuQ1p1NWswSE4xcjhiRlA5MjFlRkRwcGo4ak9RMGJRVjZtMG91S1hqOWtyQkVIdXhTSmszWklLRkJwOVJGSCUyRnV0bERMYmpwMVFaaFZaRWRDRzV2bXElMkIwdG0lMkYlMkJ0TWNVcUhHbCUyRnhpYm5BdXV3bTF6ZVNTJTJCcGdlaCUyRlNxbnM4MzY0dmR2blNmZEZhWndJVW1vZ25jRlQwdE1uaHRoamVVZHp2YW8xUnVpaXBhV3I3U0tFbHBnRGVCTCUyRiUyRk1hMzhFOVpka2Y3bFhCJTJGOFNaYzVwJTJGTUQwMlE5UGt4UDYlMkJGRnhqcjlJRFAwUUNmOENYQjFteHZNTkRPUkY3T2pHNmFFazZtenZUWmVEb0Z6Uk02YlJxczBlQiUyQjZXR2J6dzduWiUyQms0eFhBNXF5T0ElMkJnUEglMkZpRm1qVzJUeSUyQmlNYzQycmhBUDFZQVpBUnFOSWpybnRHNmRqM1JnVnFIVTZwcmt3Z3BLemcwQlpMQktpeTVQOUQzT1ZIMnlqYmRxcHBCN3NuWFhrTE96TEVLU1djY3dVem93ZUx3SmZTeWZYYmU3NGhOeVRJY1YlMkJvclkyV3NwNEhJUUl5NHNiUUh0a21teFlsbkpjNW40OHNSSVN5eVczVERHdVR1ZWsxY25tM0g1WlFpQlB5RlJvOFhRWjhDRVZjb0xibVgwcmR6YVdxVndIUng3Qnc3JTJGblIzJTJCdmtYUloyT1hNbyUyQjdCY0Z0UGJma3lDMmF6Q1VRZ0hNOEtDMiUyQlJWdmVKdmVEJTJCdVdoV3dYNXpRQm9WdmxHWldUcXhMU2ZZT2kzbVdsWlp2alBYcjR0Z1U2dm1aNXRZYTdrcUtVeCUyQnQ2amlwcjVMelZob0dvM2F4V3JsTE1idDhreXpTWGU3ZUNsYmtVMWZrMnlvbyUyRlRWJTJCTW10QnV6dHklMkI3aEEyWW9NWGc0bXR0aDVhMXB6YTBWYzRPTDV4ZWNNOCUyRm9hT0tGZVgwM0MwTVFYZG9TbGdLRGJOUktENVpzSjR3QmthaU54UGpsQ1MlMkIwd0cybnlvdlluSmVQdXpaJTJGMUx0bndmOWR4eDhzSDFNTmRDTUlVNHU2WVdhVWN2SFJDWFl0b0t6ZnpyZk5PTEdhSmVRb1Zzd1A0S3clMkZlZGtmY1IlMkJXQWFtRlQlMkZxcmREZklxOGYlMkJOV2x4Yk85Tm8yeHQwT1MyZFhNRUwyN1E3UXhGUVo0d3JJcTElMkJXYTFPZ3ZIV2hSUzhxUE5pVGU0JTJCYkc0VkdDNmY5WTczYTM5RkoydWclMkZOU3ZvR2tqYzRmaHdhdGRSYVZPMno0RlNFeVlEbDVaWHp0WG9ac2hsNE5GY3hkYjNNZEhvSjQyVWxtODJnVEhlcjVKZmxIa0JWTEo5cnAwYUJXVVlyTHhSeDRFS2hGcVdKalNWV3pLcWtRSkNYN2VGaVBzSThIYmpZSEpZTU9aNFBhJTJGYW9YVFZNWWQya0tBSVdScWZlWWFSWXFYZTNpV2VTYzdlT21teVp4WDQlMkJ1d0NTUkpwcG0yQ0w3YzhUbjRTWHdXakxYMlpLM3FPZ3BpdnBxcW9xdXBleHU3JTJCRlFta2wlMkJWJTJCbTZTUVh4QnRheDFnOEhnTlNDelBEcWd5aE1xN1klMkIzTFRZaEczVjdtbm9DdDBuZkdVaXd5dDd2dmp5d0dpbmZqQnE5QkhNYVElMkZOUEwlMkZZUjlzJTJGSG9MaFptWERUU1VXUUZ0VUNPQWt2cEJQV1dWUSUyQlAxbzNGa1dOWFBoUSUyQmltODNBdERCczFCUWxoNGZqJTJCOSUyRkIlMkZybXRTSTc3ayUyQlV6bUFDZjRMM3gyTXFGM1Q5aDhoaks2JTJCY0JwdUZ0ODFyZXNDVHV2QyUyRnk0anVXNSUyQjV3eGRWRGY1cktzRiUyQlZXYzI3V3dQNkNWNGdiQnBHQUFzSVAlMkZVQTM1UFBUNmlqTk9nNVNVdnBEaUR5N2hRdjZ1dW4xNDJ0Sll1b0IlMkZWcmswdUlPQ0gybUhFaU1FbUlubjd4RkQ3JTJGZFl4dlRjOEdCeTFBUjZ1T3lsYW9KVzYyUzJIbjd2biUyQiUyRnBKNW13RWpocDhmJTJCREVIM0JXdzhBSUZybVc5S2JZY2NXdTBXbndtd0JRQzZ6MllBNDZ1cGN2bE1ibkxoRVFHbiUyQkp0OTk0TXIlMkJ0VnRXa1NkU0Zrc3hTNVoydXk5N1lBTVRjRUpsTnBsc2xCUFFsOUwzZWpuOGRTeldWU3p3bW93NlFhVDJKTFg0R0Vqa29wekkwZ3ZkYyUyRnJWYUNJSlUzaFRqMUh3STRQMnFUV2JIczRXTXVDMFglMkZBM2luSFBqSmFJT3Frb3U1OUpDdEVIRSUyQmZKSWUlMkIwMHE0MU1xcHgxS0NsMkJ3dUpDNjVXWVl2Sk1RWmhVMjBVUnB3TkolMkJVOFJicmpEUVl3RUM0ZldPS2ZhZ1NQMSUyQkNpb1RMaEJaTERkTTJlZTF3MGNkTVZKeXJGWWJ4YzBnUVRycU9xNVBKdnA1TUZ1MkslMkY2bHFad2slMkI4OTJ1NU8lMkY1QVptVkduUVgzY2J4OXlvRUtNVXRJUk9nMXN6dDZGTDZ6QzMlMkZOOEVlMmYlMkJKOGVKWENGM0JLZm13eG1YcEZ6REVHQiUyQnllQlR2Sm9SbkJVMCUyRjUydU0lMkJGQmhtdFBYc1Z5N0RkZnJWSnpsbjI3VVNTT09rRVNYdjZaejRaWDFNUWNqbndpcGw0TXZDTWdBS2lNN3lwaEI1RzhEbWpLUzZwMFolMkY3U3hpS1RTVDl2UTFhOXJLNUxGVmxrTWNncSUyQlNGRkxoMTY4NmpIOE11VzIlMkI3QllUd1JjSE02dUFlRnRtMjVCU0NwZEJ5MExVRVZIakhmdDZZOHB2ZktXSlVHcGZLMDZrd1g4MmNrNWMyVHpiNGN1Rkxza0RUR28zZ3BBQ3NnSmwlMkZkUSUyRk15YVFaOU5oekFDSndtbE1CUGNJS1ZpQ0JKNlBodkI3bE1rSlg2dDFvNnNXZ3RTYjdvSTMxZWdHekhuWHRUekFvTnlBMWhJJTJGU2l1b2FnUEhuQTM5dnNxVFZZcGF5Tjk0Q2F4RkxINzVMQnQlMkZQelFJdHN3WHE0SmhyUEpScSUyQmhpcXNLWDBPTCUyRkxIdEg2blF0QU13S01IJTJGY1pBMlhiayUyQiUyRkxKV2t4RnFKNU1aOCUyRlpnME96RUFBa0s4Mldzd1JrY1A3JTJCOVEyRUswNHpHNndycUNwS3ZVZHRUSVBrJTJCSm54ZkxsQ2E0UDhKMGwyJTJGQndGdTMzZ25TR0lGaUdMdSUyRk1XY1ZrbzhGUVFIeE1vZHNWUWNsMXc2OThWZklCWndWWVA4ZlFzNWxIJTJCa2JSZXh2Tm5Da1MlMkI0cktRM1AlMkYyb0VQbm41NFNwbTEyQWVZbHNhOUVCejJwVVZIZjlHRjA5eiUyQiUyQlduOVU3aDdtU3I5M2lETnJpR2xJM3lsNUl5VFdSNmtrT012QzVyYnQxT0pXc2NUTTR1Qm95cE5NNDJUJTJGU2pmSlNkZ0lUZndPVTJZUHJybVhuWFVPY2pYZ0lGa1dKeGlmN0pWTE5hMnolMkZBcW02TDlxaCUyRlQ5M09ZTVZaZ0J6aG9uaEJEU1hrV0NlODRrcnp4NGF4Mmh3RFVxdHZtV0llcjFmNFk3d3lFSEVNWXNCMVlqSm9KYzlROTZHRVVKYkdWVTVWdmtTTXd6cTBUSVpTUkR2OUZJJTJCU2U2aDVDWUZ3OGpuODhsOHR2MyUyRm03Ukk1cTZoUHV1MyUyQiUyRldVeUNsTFhkdkNiVjBaM1dUMSUyQmtieW9vdnc3TjhmUUg5YjB6UmJpVTZVRnlUclFDOVhwS1lTNEthRXluRlFRZmRISmJoSzBKcjIlMkJDNCUyQjB3OGxuMzJscnpxVTBjZmoya0N1JTJGJTJCRGR6bmRJTXlEYkxVMGRjZ3ZGRHRMOTVSc0RYdWVJY2dDSWlOMWVmbUVodkdOSW1LSzBCdmJLRjZWRDFodkp4cTc4QnZxSUolMkZOdFMlMkZ1anpUJTJGZmxPTU9WbmV2RVJDMUZxSnRxcEZwSXQ2V0ZWMWYlMkZVQkVjV1ZZd2olMkJDalRHdlRtZ3JZUyUyRlhzc1lTd2YlMkZwOSUyQkJ6eUIxRUVuNVRsTW5XYWlrZCUyRmt1RCUyQm1lNmR2b0V5VWhJdVVleGVldzZRb3NMUUpaWFBaYzRlVEQ2TjNjaEJ4JTJGeDZWJTJGNWRzMTZBUVBlczlyakl1TlBidHA1QkV2Y2JnQ041V085M3cwd2VuZzYlMkJHODBKWlBIM2l5QlZHaWp2ejJUWG4yb2Q0NXBvMTRRJTJGMUw3c1J2MmdOMVI1d2YwMUJYSGQ5aktqV1BhbjgwdkJmSW5Wa1B4RzlkTmU3UDg3YU9qak9IN2dYV1piOVNpJTJGSXZMWFVReldTQ08lMkZZMjhBbXZlOURNUFE3anJlOHpsdWlvSlo3WlpEZCUyRmd0NmFUVFl1cXBBeDVGbHZVaVJtWE55TXZ2UEJ1TkR3TTNVT3NlNHZBR0hhNklEQ2h4eDMyUkVXaUtGZnZ6d09WSFhKb0JicUFyMHBvZ1pGMVh0TGU5M25lSjJDbThOaTFtSW9WSyUyRkVWMWZuQVJ3V1NNVEtMbXFEU3o5c2F2NEtGSWZnUDZIUlVLQXY1WUF1cyUyQkV2TkJ3VnFoOXAxZlNuNlh3bkpVZ3BaOXljSXpyNzdnaVVOWmxTelRoOWVyOFkzWW80WFdTN25hNk8lMkI3dm93R1ZEVld1cVZlVXJpOUxPbzE0WFZrNnRCYiUyRlRadElHNUFOcjBxJTJGJTJCZUdLRzJkWFl1dUx3RjhyQ2dRS01UVjZwY09yUFRMWDlGZUJIYTJpeXozYnl4UmcySVdldEc4RjUzc0szRjcybG1kJTJGZnNjcmclMkZROWNMayUyRkF1T0poSnpibHh3Vzc1TiUyQlM3Q3F5dlN0QnFramtoNXd1R3BIY3NSMyUyQnZPU2FnNWtyNGtpN09seTdRcEo2ZTFVciUyRm1haXgyMGVCVjdRYWZ1NW5XazE5OEhUQ2lYdW9qNUFuY2VGSkNiMjNCSENaOUdpWmZsOTQ3NDVOJTJGelQzQkxLSFFjOUxGVjdxckxQQVhBbGR4THlIdlJXSEQ5WnoyaHhBZVk5ZUZxU21rUUZ6SVIlMkJobzlCREZVemVsUmNXa0p6MmhSRzlRemo3alo3b3g2dnRvUGFQWjZENmZWeXBZTnZMSlROWGViN0E0OWIlMkZiSW9TJTJCUWk4bVVadWIlMkZiS1Yzem1ZUkIwOERxMm9sSTZZMzFCeGolMkI5VVJueVk5a1BEVkRuZDRwZ0hIU0xRQiUyQjBBNmRKOWRZbjRhSCUyQlJ0R3U1ckNtWFpuN1o3eWpHOUQ5WmNocHBqTkViQVNnSTIyVDBrQlExRkJLaUd2MlZIb0dUVTFuOWIySjk4enkwJTJGdXNiS2FLeXpBSXElMkZFbEolMkZvdDBYd01DYllhWjV4WGtha2wzTiUyRncxM3ZWQ1dONGRkMm9tJTJGU0lJbTBHR25XbzhOYjdQcXo4Y29xUGd6TndDUE5yalhseEkzVXFlelZJJTJCc0lQc1gyUFZaNndYRSUyRlZ5cERkSTZyN3d6NkVDeUZqWVFJUXkxazhhTEo0MVpCVEJNV0tGT0lXJTJGMHl0ZzclMkJKRGtoZjdWTW1LNlF1MSUyRnJuV2QlMkJ2cEZ6Mk9VN0lMNnJmQ2gwTHlCNlhKZk5YVEFHTUJ0VGIlMkJXcDQ1bE5VRUQlMkYwMExFMlowenJvUEw4YyUyRnJENFV3YUElMkZsd04wemU5bkFqaWxlRUNSQTNYTGdwa3lBYzJBMG5zJTJCZFdFaXVJQ0FkYk9ySllqT2ZTYnpCVDdJMVFvQ1IxQ3VyMldCcTlEYkNqRjFhamlKNnIlMkYxZkY0WCUyQjhBc1NYTVlZUzFWc2s4cWZKTXo3Y1RYU1ZaM1NTTzhmZHN6SHAyVSUyRlh0QTg1Q3poZXV0RzBGU3g1TzJpRXpYZ1FYdm16OVZTJTJCYVNwdk1TVWFhdk1qSWNSSXR2NWNDVG45eWZIdUlNcTQxRUNmTmVvZnUlMkJoaHY4SldNWHhSJTJGdiUyRnFqYU5KZ2I1T0JuQ0lNbHZKWVNRajVXdEpYMmtoUmdzR0xDSXVDMHhURHlzTGFXUTIyNnNyZk9DQ2xLJTJCdXB0eDBFazhKSXF6UUNXSGJnTndxZ0xjSXNyMlI4UDBDTndFUiUyRkpGU1FaRUs0alg5M3ROQUJaTldLTVhXZkxXSnNqdVFBS2VTYXRldENXWHlkQzI4MEdsa3Q3WHRBcnZaOHVBOUVkemtPamVTWkxROHRROXo3aFJKa3hDT0JzRlYzZ01jQmdwWVFRYll6dGxXVWhqRm5FNzVzODAyaDRvRURLVURzaEgwTVp6aE9xbjltOE12RVRGZ3laMWIwYSUyQmlvcmhpMng3diUyRmp0ekNRZTE2cE9uMGlrdlpOQU5tV1cwclk3MVByMHVIR1RvWUs1eWVXUWdtVXA4SlB0aVBkSTNMTnJxendNeFdhMkJHZDlBMk9HcjJPWCUyQjA3VjRSOW1TSzdCbFlrVlhRR0ZlcDZNZ3ZVdTk1ZCUyRk8wbEloNG12ZEdPV0J3QktCUnVHTlRPcEVGbFlTSzB1WG40ZG9CWjFmQ1FzM1JhWlhOWVZIekNLOXZWSVg0WmQ1dWI4eUFmbnQ0NE13JTJCbHk2aDVYMk94bDFxdW1BdWNuYXEyWE5JaWVOOE5EZHR3T1pJNHpKWmFTNFlqcU5qdFdQY2hoeXJxVEJuRkNUWmxvM0cybklHQ09kRUlUVjJ1NnJ1aExRS3JyakdqMkdOSmVYcDdzNCUyRlRKWlNTRE1Tam01ZXdQbGRCc2QzRkpkdGhXRndiRUprVzJTbVBnNnNnWU92aGJGTGRFaWc4WnIlMkYzZUdpVjhwQ0NDbUlZQzglMkZmbVlpekRIOWQ4dUloUE5JSSUyRkg2M1MlMkZjUm9JMEFja1llM3kyMjBraWZ5bzVmWW5ZRng0bVFoOExhJTJGaG5ScTdwcHZIS204dEV1UzFFQlFDT2E3WkxEeThlQmdiSkw2RjFiMmwxWUs3UWo4RlhUYVdPR2U3b3FuZHExTWNOeTRJZnhENmc4M3FGTzhwY0NNS0J3b3VwZWxua1FxTlBHQjhQbzkwN2t3Vm90WlRIS0taV2pHZjNvMDgxVWhFWTRBRTBOdTRlUmJQREViTUZSWFloQ2FBTFpsbWdTSXRsbE5iNDhLMzNxc1V5Um1HTTVSVDRGJTJCZXdaUjVDTVVWZXhjWGwzeEZkWVRHaTZsR1FIU3BvaXlYZmNBSG1JMDlGZENRempwV2NtVFBqRHI1OTBFT3JSQ0VrQXVFS3h2QnhkRlViNmI4VGgyYUlzTTdjek5jVWJlbjZFeVVYaGNSS1E1RjZuRjNrV1glMkY3b1N1OUglMkZuQ3kyYmRkT1JaMXFuWk51RjliSHBwNmxUODNDMFB2dm1HUEFMSzRUNEpic0Y4elI0dDFaVHQxTWhNV2wlMkJISnhVdWw4WVFWbkt5NXNVOHpTQWpIVUglMkJyOWVHQWE5ZHRBTEpVNnpwd3pWWXh4QUZsaEEzb0hSalJ5dU9xNHVyVXhlZnFvcG0xVGpqWnVMYjd5Y1o1ZSUyQmpBajh0VUl2QVF4JTJGciUyRnVMM1RWNzBqaVRYQU9ZS0UlMkYlMkIyZnJ5JTJGWVhYQWpoTnNDaXZzV1ZIZGdYJTJCU25uYk84bzF2UzgzQWJVdHdBWkg5NkszUU1QMFBxJTJCTWU4VU1TQmRsaDFCWkElMkJJMFFLNWw0Zmd6anZiTkJLVFpJM3AxOGl1cjVUVXRCaUlyU2NyODJaVHhsbXpBMGl0SGdnRkI0bXNKQVhPQ09tR1pDU3ZWWWc4UkZoWFJYJTJCeHN1d2dqMTA4eUxMMFIlMkY0NHZqMGh6a1JKOEp5a1R5dnlGY2VkRzhabjRQdXdXSzJnNEYwUDR4TXlCZWIlMkY1MWx6WmhjWXhMM1VBaldjMjlsY2owc2h2UGZreDRZSGszOTZudzdxY0FFb2FibktvbWZBbG1Yb0ZERXlpRk96WWlNc1BDM21TTFlIVldXS0t1MjEzdDMyS3BFVDZBZURSdmdycG4xNU5vYmprbXlJdlR0anolMkZoRGxQZCUyQmVIY1V3YzVsQlZKaFJHWjFKT001Tk1hMWJjZCUyRkxwQlM5NHdCZUExQWVSaVExYUNleUtXdVg3eER6eVVobkl5SHg5R0RmYlZnTlBFZXpsUjd4aXc2b0x4ZUtzVWF2cXI2VHhKVXo1OUZFMiUyQnpoMXphaWFRS203MXZubFBqc21hdEdJS2tGbHJzYWdJWFVJTGhiJTJCRW5SR0l0U2dqQmN5dHJsWVF6QU9tb2dxWU01MHNlbXJhNWVnRDBpQmtWYzUyWEswZ0Y1cGNyQzNtWmI4ajVqMkpyQmElMkZjRjFDJTJGZVRXOEQzTVJmY1ZiY1JyTFR3ZjdWSDBhVlR3VG8xekp6ZFY4eXRoZk82bkRldHZsSmI0eHphNHViRGMwJTJGdUg5JTJGYXF2VTFOUVM0WEVySU1GMzQ5QkVRUlRBN1ZiJTJGb2lXRU1mdHFZNWd1b3kwJTJGZUVFQUxDSnl2cWZHQXk2eWVYVTM2MVRtWU5QaEtlMjhZdU9ub0ZZcXpZUlFNdm9aUlQlMkJOU0piJTJCdTlHcHkySlc3dmN3WHpla1JWUndxRFNNeDljdTFONGp3UFFqZ3JkaEttcWRFZGJTOERtaUgxSUI1ODVpcUZoU2VnMHpxQkdYUjNPWHBpOWRQSCUyQiUyQmhpdFI4TGV5amhLNlMzdDlGJTJCUnZrYUZZM1dnME5ET1RCcGRzNzdObmZ2UTcwUWJHVGFhbkgyUXJYWmp1c2hkJTJCOWRjTUJieHNjVWg0NlF4cmZRMVJtc2w0ZyUyRjdHRjVpVnJJOTRtM2VlM2V1MmdSREhaSHhkTVBnRnhqWmNUJTJGdzFMM21DdzRhR0xTYm15SEh0WndlTXEyY2ZkNVQ2SUYzcXpDS1g4RFIxVGw5ZVVKblQzTG02RDBQeVVkY3pWZWFNdHBocjRtcVZTTTltcktxMWE5b1JrcG9IUXB2bXJwTkdZM2t5TiUyRm0wTGIyZHFzbXFMSmFoS0xUdkRyMk9jVUIxSGIlMkZ3SlNWUDczOHQ3M1lNJTJCMGN0YUUlMkI1cXRuRzNnY095SnNBRmNBJTJGY3l6MTk1MVFDVFJhOGQlMkZFOWdoSlhROVNNd3lhOEt2bEp4RVZMWDJkZWh3TWlzb2kxV25HZzdnWU9USDNEam1tb1pwNlNuNVJtVXVxJTJGaG5maGluTnFOJTJGdElyS1BZUE1td0ZLZnlVd1l3WHFjd0E0OFZZSjlhY29LJTJGQ1pzNW9uNXBzJTJCaUFiSWZrcmV4Q3JVcEpMJTJCRklpdmJKWG9aV1RKNWFBVlBvMWYlMkZTUjZ6N3N2Y3pwVE45MlM3c0YxUXpsNWVRcEgwd3JlV2lhN2VZd3kyJTJGR3NNcU9mdmNCcUhnOWdyYjZ2a2IxYUZkVHYyQnNiTERBaEIyeHQ5OGhYYk9GT1dIc3ZWTTRFbVQ2aVNlQ1ZkWmpiRk9FcFVtYmhYRW82amVGS29PTFNCcURndHNXc0tXMkFYV2JKZ1lENlRHRGFRczklMkZCJTJCQ2dZbUVPSnFGOVdYcnppZEpQM1VRajJYcDd1cFhtWjV1YW1rVTNKdnRKdlZYNVY3c3o5MVhKcXpqaE02UDc2ZiUyRlAzUWF3RSUyQkxjSks5QmxkSEd0Y1VzVWVyYnBVNWxIeEFPNkZaZTE4ZFFtWW8xNEo2SkZWS0d2MDBpTkdjSEFXME5kSmkwWWxEUHhKRmRHRzljS3BqOXhoQm9zd2FyYUN2bTE3M0RVdDVTcDk5V1Y2QWR1cHlTQU1pY3BhUVZJcGFtQjBZQVQ3ZCUyQm9Wa3Vab0klMkZPMjljTU5lOVVxcW02WUxRbDlHNW1DVzJGbXNITGd5JTJGQyUyRnh4YW4wMm9MQVMlMkZjT09SJTJGd0lnUVJnd1ltQiUyQiUyQlVjdm5sMWJIazYwb3FKJTJGZWxRQkxVOEh6YjA5bG9SRmNVdklkdGt0TDZYVmhvMmN6czBZMXpXcExxb3JDWVNGVndGaWQyRFVkbjFXazJhY3UxRnFkWWRpWmsxN0FIbkRPR3ZBMUFDYTZSdXF2WHU5eSUyQmVRZ2t1VW4xVkFMQUJnbE16S29WeXVUMkt6QVVDUXBzS2NGZmw4ME5sOXpPUDI3UVBTeUJVc2dkbjlLd1BBRTNtZ09KTHhnYXpHOUcxSFhkRnVydmJHbSUyRkdwbXROZGdHNjZJeFBRaG54ZXRNRGIzM2FReklkRk5kWWRUJTJCdmJDTjdYYmtSNzRRSkpQQ1lRUXI3amVockozTiUyRndZNXBzeHlCNG0ySGtjcHZWelRiV3haRU1BTGlCNUZudDViUm10UG0xMWJEdERUVllEM1VRd1p1QnI3bDhPNTk1bkpMZERFd28yOXhXUzhDJTJCNFVCYlBrTUdMellzVFp1Z1Z4U2JtRnpTODZxUGkzd1o1Nk9iSUhJODV1SjFweVRDNTY2TyUyQkFOTGZoWE0lMkJvSSUyRkdpSmN2ZVZGQ3hpa090QmZ3TzNKSmNseEhoY0dZR1Q4ajAlMkZWNVFnNUtDeTZMb24ySjM3bUI3N2VLQUJtSlFFeGYlMkJuWEdKQ2JXa0xwUjhDTWk2a0hZZUp5SWdBRGkxQXFqTFNidDVjTWxKVndWY0laNHBCb1RGWmIyb3V4Z2FtTThFMTNoaTF4WXZ5RmpsVFNhVTNXeTJ6JTJGZzRoY0RadVl3TSUyQk8wZ2tTakRkWWp2Nm0lMkZJUnM5UXVKZlUlMkZRbHdDVzk5b2VxRlhmYyUyRlc1aGNnZEdMTUZvNiUyRkZGUDdtckJyd3RFeVhIZFRCSkY1RFdwUkJobVMlMkZwNWw3d2p6RjU3NklKUWpQWnE1ekRjUjhjV2N1MjZ2TFNTOWxXT0FxcFBKRlhCYWdzb1glMkZvVHROU2FqRmlSSjczWHJaSTQxczJ3VlFwbGhyVDNWV0NmQTRLZzFUMVV2c29oSXVIRktoeEZoVml5OFZJdW9USjRYaUZlV0VrWHhPSGdMVUxWNXozTndEUVk0MVQ4emslMkJpVER2dm5pZzBJZW9lenplZUpEaTZ6MTZWUkwwTiUyQmRxZlVxNHptRnRtWTc1JTJGVEdENm5VUGE2JTJGVUQwR1M0TVU0WWR2cUVDTG5uamZEJTJCZTlhbUROajhxJTJCSmtyJTJCb2w2M3ZIalZBZlpBWk80YUJVVG1QMFV4Y2ZpQVdHNTl2aThtMkdiOHk5cTlGc21USHhaZExHQ2xUVDVmeTVYTjNtZTVuZ0hmQ0tneUNkYm1DRFBrdDJnNUVjVEZSeXY5NU1FcmdZeWRBd2glMkZFSkdPV1A5MHFJbHFMc29vbndvaTc0T1poZlJOdjRHVlV4TWhiQUwlMkJBMkJyNGltRjVMNFdOVVIlMkJHZ2N3blRreDh5c0FJRmYlMkJsZ0c0T1BFNXJVZlBpMUhaQ01kZHV2NDdsNFhGUkxldFFkSUNwVmxLSTYlMkJvdDBQbkh0SHpUTGpkM0tDWHNIdSUyRk5Mc0p4MiUyQlRVeGRpdkU3ZjJVamVCNlJKR1RnRUZPVURmVXhweFptNHB6NmF0TFQ5Q0NwVCUyQmd0UHZWNmp0UyUyQlNpbjc4cmZobk5FdyUyQmVrdTVqWXRCJTJGblZ0OEM5VFB2QjVrb3FpeCUyRnlVa0ZGUSUyQno5NnNLJTJCM2RpU1RJamRkdXZqUnI1RzhLYzN4WklQU1FoQkJSV0hha1lXc1d6dXlYRUJwJTJGMnUyY3FDSDhTNjJ6MUFDUk1mcSUyQm5kQkFKSSUyRlo1bnp0S3J1eE9Wb1NzVmRMJTJCNjJqeGpNTDg0RWFvVDA5ZmI2eU5rZWszZFFRTEwwVU96MDF4a2RlTTBLY1Y4cjk5ZTZDc21raXpyMjg1dkdidmZneGxnVmJTeU90TURwVUluMHp0T01SMkslMkZ6a2E0YmpXZSUyRkRLY3lZc1ZkWDhTMlklMkJOWFVtdWU4ckpPeGZBUWNlRmRydVlDM3NsMldOOGd2QmJoTENGTktHT1VCZlFyWWoxeEswRmN0JTJCWW5uSFZyZHJBTWtRWkExakZGVjB2eG15d3FDRE1iZzcxSW1IZWlFdnVybU1GUFJudSUyRnl1RHJhN3hKNzBvY216RTZqU2MzMGpETUd4RXZsUk9LVkglMkZESHJseldreFlCaHV1U1puWFByWXFZWjJYMTFwNjglMkJzUzRhckxXVHY1a0l4S0NvYXpHYnBhZCUyRmI0RHM3NjBncTZsUWV1cUxsaVpNdjZzZTAzWlhrR09JTWhGUWFOMTF6UHg1Z01BUzJXdk9JeGl6WHNMaDNEdThpN0lXcW9BT28lMkI2JTJGNXJPQmVEd2s3JTJCY2p1c3MlMkJsc1k4Y1l5bmNaWk1TTGpaVGglMkZORDBWY3dkTDBmMWJhdnZGMFVEMzhRaGduJTJCNUElMkI2SUVyV1hjT0RrdFglMkZIREdsYXlFa212JTJGZG9hZWFtRWpZcWh3M2thc2RIeTMwUUNESUZoNWdESFZVaUQyTnAlMkJIcDhwdHIlMkJtMlM2biUyRkwzbDc2Wmw3Q29DdFlGODJMSHlpWnlQZVM5ejNWUDlMd0F5cjFZNCUyRkxZdnJTQmNmTkx2RXdrMSUyQndOc3NrYk1qYWhRM0U5dmlZZ1pGNlh6dGY4Wkw1UzhQWmFGT084M2pFTzMlMkYyVHJjcGhpZ0lJMVNpMWZpYWJVV0Uyd0xLTmx6ck5BRG1vcUl5ZyUyRmM5NnhYVk1rRGlsZVQlMkYyNEU4d0VIcjJ1ZVVCemhIJTJGUlI5TDQ1R2ZLUDZseEtoSTdMenprUGFQbSUyRldzdE01enBWSFZXSzNpUUFGWWRuZm1haXNJJTJGV2p1eTZhN3lFSyUyQkZ6S2gxbVU5eUYyY3RSYTlKUmRWNFFsSVpjT2ElMkJYZGpzRENFUkNwaFF1ZTRtalZ1Sk45T3R3eDU3U1hVcSUyRiUyRnhmd3doeHpnJTJCZzhnOG44VUxKUWczWUx1eXJ5akFDcDNuMDI4YVhGWVB2SXYyT2dDS2xpWTgzaGN5UHRSTWNUVThYbCUyRnZ3V0wyaGdZJTJGSlJhOCUyQnBHZ2c1ZXppZ3ZaTU11TG1xdjhCZXg3NTNoc1JXSlNyVW5vSjVZdmdkWW1jMFVPMiUyRjhFdiUyQnlybXU3WDlic052R1hwQWRTdkhFJTJCVHlZeUxXakI2WG5JUHpwSVgxejJNT1piSHpzUXZTaWNnJTJCeWMwNXBVYmJydTBoaElhdDJ0ZWIzckZBOTNnMWYwUzhKUk9IdlhSdnZGTXRGOVlTZk1UdXkyZ1pYbDFGZmRlM1owajVqU2VaVHJQTEZpbCUyRmNTTmxJbGVaeUpTaWhNSyUyQktlNURwVmkzdGM0cFR5VnpSREdQazY5VUVEaEx5bG9FTk1QQnRFR2tLd0dhVGp5JTJCY0FBN3dqMXZJY1BVQkttWkx3ekZnMEVvM2VOMUR6NVF1Y3U1WHdvRWNOdWNSTzlGNUwyMG1ySDVYM3BtVW11WHpwblRydVh0TVJGN1lBaGJMWUNrbjNWTmJvQ3hmNXY3dlRJQ0xBU01ldlhKRUVyd2F1TnhMcnklMkZLV3RIYVl4WiUyRjlaY21HeTVBJTJCcXNQc1Zpek1zZ0ZFeHJ6dGdyZU92dDZjdGxKcFFzOFZwcHhxOVFnVWFnWVJvRGN6ekpXZnBxcG04TVhYSHhjY0MzNXNzaFBMajF2ZU9uWndZYVR5S25obUtpZXVRVVhsazFnekt6NyUyRm0zbyUyRkdtR0Q2UW1wWFRWM3dzMFdxUjBXWFdlQ0tRWUJoMFc3TlhQOTkwNFhocjdNanJRbjNTOUFpM3N2V0pNRnAwd3owMFdtcCUyRjU4NzFMT3lvQnUlMkYlMkZrTGxUMWhpR2ExcHJMbG13cE9GWHhlRHg5RzdjQUVQTlpmMEJaV3BIbloxZXU1RVRIY3RWc1NlMnRsS01qV2VxZjA0JTJCNHRDWVg1bHpSNk91ZkJsVHNmTU5WNnE5cG1kRkhWVXRjd2pLV1l6d0FCWTNpQndUcGdaSUFYRVh1RWRHR1olMkY5N3I3dkY0VnVKc1pFMThCQTB3dmtCSENVYlo0Ym5JdW1jTW0lMkJLcTkxQW15WGQyWEpkZU1FMW5XSGtpYjdiVFoySDRCTTBiT3VGJTJGdkxHY3lNJTJGenN4TUxFRkFFaUFuJTJGNTk4dEpFZ2ZpZm1OYzVVSFE3eWZNUjB2SXBMSSUyRmd0NTg2aE0lMkZabGF5ekY5RElxJTJGN2s5N3ZiJTJGaE9LdHRPdDRnJTJCQTQlMkZUNFlXMGFvdFFaJTJGUzFYaSUyQmVqOHFVcDUlMkZVb1dCV2dZWE45RnV2byUyQnFabEhMdHRyT2x1dk81THR3cnc2eDRRdHQ1MWJld2tVQU45SCUyRmQzQW5SWnNQeTY1VnhjcU9NOXdLMWR3aWI5QXg2dGFXZWdkMEVKQlg2JTJGR0YlMkZaRkVjY3JUTGp6RDBvRU1jYTJEd1F2ZzNSaExWYmVqdlVQUDd6JTJGd1RZaHRIakViVXNMTkM5UFN0R2ZaWEhtYXJFNVBFcXFuQzhGdHFrMzNqTVdiVmZOT09jNjRZUWdoTVlpOE5iVjFTTkFlYW5jaFY0JTJCc1lpRyUyQkNVRWg1dWVaQlE2cExyOVJjWGtXN2xVVTdtdFI4SEhoUHNkTGpCblJnVjRxSUhpV2cyJTJCdXB0TExoTCUyRlYwTnA2Rm1UaHRjdXZ4Vlh1ODJtaFByNjF0T2h1UzNscTNKJTJGRTg4dGh1UURpUG83aSUyQmpJemdJb1lXbTczVUwwM0kyWm9qMjIzJTJCZ3A1VmE3OHhFMyUyRnpGVGdrZHh5c042QllCVkR1OHlWTTltJTJCcWlkcUlsb3NCVml1dVg5NGt1dGE4SlI4Zm43N2UlMkZVUUdISkpRMjZDWjlLQ01JSmV6VFdFYW13NUtqWE50SmF4b1hybVZkYmJCWjV2dnoyaGU3b1RaVFFSJTJGOG8xMkFOdUFVTW1RaWd6TDNpMU1Ed0s1ZnJBWUJzODVabVpJNGFaVWJWaFg5bCUyQm5EUjJ6RVclMkJMWjdNOWJURUxmeGtGdjVqTnZDWldhMWhTOFkxRWNOWThoZU81bVJ6MnprWlR2NFFMa0YlMkZuWEw3anZzeWhLMGhQeW4zbW5BOG1tMWYyTHIlMkJnNlh0MyUyQjRzcDNsRjBmcDJBQnZ4WmM3TTh2aCUyQmx5Y0xZV0t3c2JJUjNRZ3hKbSUyQjgwbDZYYTlqajhhZyUyQnIyYjBMdFAyOGY0bmhXeDdjQ1ROZUJmWlRXOVFPZTBqRkRmYlBVVE9ycHJBT2lzJTJCSzAzNW8xd0NHekhmejYzZVplb1FrOE1ObzhhdDZlbjlGZlZCdE9VTlVGanRUSnR1Q0VyVSUyQk5FQlR2OTVKZXVicUJSell5NDlLWjV0STVVVTh6OUQ0b20wZmJMUnlxdE1wSXcxSmg3TnUlMkI3ZHhiSVZsJTJGU0p1dHA5ZFh3Y1FSamIwaDMlMkZVSldnRUZBYUhYQ090MU1kdFVjbU5Jd1dBMEcycU1NNSUyRnJZVzRpQkJiWVhOJTJGTm9ZVTV1OUc2V1p6ek5WUFN4Q1RZNUJFS0lRNENsdUVWUmhKQUtnczZrOUNFTzNEUjZ0QjBadWFRa3FETUlpayUyQlNJd09OVWJvblpiRVUlMkZOYnM4YWZrT2lvJTJCM1JjZFprV1Z5cHJvWXZGWDYlMkJmS2Z5ZmpiQklNVDZmcnY1dGZad1ROeUVSWU8lMkJhdiUyQmhzS2lhR3l5b3dxOEJZdyUyQjVpUnVWamJ0NW1uOW9IRSUyRlczMGJOOWh2WWQyZ1VIcUdvWW41SHFaTVQ4WTYxYmZLdWQ2RWRGNzRGVWRTQ0c4dlJHWENneFRuOEc2MzlWUmIxZUw5bHl0UDdGeHklMkZobjRhJTJCd0dOTlVpOEFjWE8yTFFOQUtYNVh4NEtGbEglMkY4c1N2YzVqJTJCSmZyMUpmcGZuYkFCdDY2ZVlNS1ZpeWRTa0cxeVpCclJyNm5pblY1YWJYREI0cVBtNW5ROU5NeEFUdllpa1p6SjdLRG8lMkJIVVYlMkJPdE1iUVh5dVYlMkIzU2wxY1V2TU4lMkIyR1pyb3ZvZ3hlZFhPcU5udGU5YXNzRWhUJTJGc1JVMHBiRjE1V1pDdmJMTHZFVzNHT3A0Y3BWeHcyWk5XdUxQVWVSTG1GVzNRUFhkMGc1YUVZdUdJVlowWGhoaHBlYUxsQU9TMUFYcXhlVjElMkZmdlZMQUNWNW1jWEVkN20wNzhmcVI4M2p6M0tzckt4eVA1MWR2YmJjckh6N2QzbHhvcjNDdGtLeXBVQkZmOVo2ZnBhZjFKN3Z2blV5RkQ1Q1NwVFNnNlZnVWxOM2NsWkdpOUQwNVl6aFNHWExYZWhXeU8zRWRwYzQyM1lneFBJSmlxSU15UHR4bHUlMkJBJTJGaW1GYzRCY3k0blExRGp3T0ppeGRpJTJGVnZZcW41UnNQcFR0cVN1UHltQ0NwanhQUDMlMkI4ZWt4R0s1VVJJWk03dFA2MjRnTGZJUlh3YjJSS2hEVGZ3cFI2VVhsTFNQUWRwM2NCY3pvOVF3ZWJhQ1dJRTF4ekd4SGpNMDNreDR4JTJCbjd5U0xRcmxYdnk4cm1VOXhoOHhtOCUyRnhkaURyTmYzZGFkNzhlRUJoRDJtTTlhcTJFdUd2N21FdVR5N092cFlmdnRKJTJGZjlUcnl3aEk4REVmZ0FzWDBjN3B0b0puSXBxWDl1V2ZHYm82cmU1am9BaUk0cHFTYm95N0hhZzBpdGRSOUNYT1NyR0hZeHF2dlJxSzAlMkJIZ0ZUcGVZJTJGb2g4Y0RPZDZiZmtlUDY1TE1tVWdiYk0zUFdZWWlzbFFFVUdLcGFNaHFWc0YwZkZoZ0FBWXZMRnRiOEhwM0cyUWZYYTkxaUxFOUp2Q21qWHRiOUlqOEVSSElUV3paUXJGN015cGRaMlp4dm1BU096WFRwOHpWTzclMkJmb2UlMkZYNzVlaDVHZTVsJTJGWW5QY004NiUyQmpIZjZrZlVXeFROaFVlOWF6YlJ3TmQwTVkxUWFKTk1nNzRtOGlQSk5LaVYlMkJkdnlRQmFQbTUzTTVLdUpkV3B1ZzdLT1pONjc5aWp4bEElMkYxNm53bEpxVloydnBqNTFTMiUyRlhrWmx2aFNsQ3ZKdXc1Y2dyNm9ud21ZT20zVnp5T0NQTSUyRlUwa1Qwc0xsUHNOJTJCcFNEQ0s4c1RyaHFuVzdNNWFkYk1odzZWJTJGNnBXZDk4NVViWnNUeURJR1RKZEw4MiUyQjNvWms4UXRlZmNmY1dvMnY3MVJlTHJldWFpallZSXhKVmJLamE3RDVGblYlMkYyZFdpeWElMkJ3ZkwzT3dKdUNscXRxSVJLZmtsWHBOS0dKWmVteHA5QjFzZzB0RnZDSlJ4UHN4d3g5eE5WSmZZMkFIYVNDODBoVVp3TnVaWDZlaDZNcHhaaWE2RldnSyUyQmpxb1kzNUVmN3dxeTQ0Nkc4ajEyOUVTQ0xVdm41WGZVeU1XNjJQU1BobmZSZUpVUjklMkYyQ1ZMNlYlMkZNTGxrcHRjNUJBdkhqeXF5R1ljSyUyRkxYbVNURUV2NlhtTnRsSkNXc1N4T1pqOTc0a0Q0MFpxQVpjUjI1eUNRUHRCdDk3V1dXVnE0OXVKQVJDQWx2Y0RnNExYUE4lMkZaTGE4dzRvVDJUQXFLWDcwakJCbzNFNHMwRm5UU2ZKV082VjJJdiUyQkxyUThMM29nR2tia3JqMERYTFNwZk12ZE5iSWFuU3F6QkFSJTJCZVRDOG8yeSUyQmFHR01IbGltcW53TmFsdnB0bHZTQ1IlMkJmSENEOGtiQ3FiVng1RjZnYjBTSGlJeUswSVN2S2cyR0JOSGdNNWtkUnNsdEJQSENEZ0IxMlBKTnMwd1hQVVJISnA1eGZPVDFaeUFTMll3ZEFsM3JGa2FLJTJGaWtsNE9wcU12RmwwcVUlMkZnTHIlMkZielAweEE3RDZnWUtmc0hzRTdMOFlkVmpMRWpjUnVXNSUyQiUyRlZ2V2FQaFFZYm11MUlkU0JZYVFhUlhNRTROb1VjQWtwSDVnajh1U3Ntd01IblN3MXU3QW9FTCUyQmJwa1MweTRybldFVVBDTUV4NGVqc2t4dVM1S3RJdVplNzV3JTJCa2IlMkZndEhIbUdGeDI4bTEzV2dzd0NnSEVHdmxIOHAyYmFFVFhlUlJiME1scnVFU2phdUpVS3pBaWZnU2h6Z0xwQ29KMUVvUllzcXh6NkhHbkM5MiUyRm01TDg2VGZia3lpV0l0WCUyQm5uelBWJTJGTTVaN2VxSUZNY2IzUWpRZkclMkYycDVqeTFFbDJhJTJCNXklMkJtRE4wdThRSGdCRXV6dzNsdnA2NGVVcXVkMjMlMkJvemkzZmVVS29xRVpsa0Joa21JeUlkM1JPYktDTWQyVk9wRDljRXR1cEF5MGtwa3pzanYlMkJwdCUyQlp6RmdJYjZxYlF2RU9XVnpYU2FGb3Jzb3MlMkZRa2w0Y2lhSU9kZHFmZ2wzYnVtWGUzRFlyUUklMkY0eXJoTDJQbUFaRjVsVjJqZ3d0TUQ3OXdqM2dUbkJydmFvbUJvczdYbXFPMnZDTmcwQ1FWV0o0ZE5LdDl5UHhxSDJCTHpkc1ZOOGZJYTdlSVV4VGlRNlpnNzlKa0dDMUpPVzd1ZyUyQmljcHNEVjV1ZWxTUmVtWER0MFZCNmV2cDZVSDVwQ1hEMlBYVzUwYmlHUGlybHJYcldEbzZQRUNRJTJCJTJCeVBmWm1OcmhlSUxpVXRQSWo4OFJoVmhJUm1qRHlBVlNBUnpsdDZEdVozMlF0cyUyRkdWTSUyRlMyeGU1UHN1aU1ST29KakNXNWJpM2lhQ0tkUW9CbkdoN0tjWlo5SVlURmUzczR4ZWxuMVBkMHRBSUpaazRmWGxURWVhbGJ5QmowZkJUdmNTNGJUNCUyRmF3SzdEWWtWa21OUXc1ZWl5WVdJcnAxUG1SNlhJaEJOJTJGSlRYJTJCZ3VjRDVZUHBKWng0SkNNNHdVJTJGa2NrbzNMaGlCaFB4cEZhZEM3ZUhOSUk3b294YnI2SHhyNmJMZXlCUyUyQjNBZ2h3VWRnWFlQNUJUYnAlMkJ2a3B3YyUyQk9FQmklMkJaaVRnSmVBRnFmQ3lXVE9NU3pGOGhtc2llVVB1JTJGUk5LYTlaeXY0NWZOQ294cGNKNHNCaGI1T2toU05GaUlHUWhwRGhQMnNFa1FwRWFvbExCS0dzdm84c0l0SUJVTllZcW9OcU5Gd2lsSUNxT3lkdExRV1M1Sk5nUWRJb3R6dXVhNGJkU0YxJTJGc25sQU9Ed3olMkJwYnUwa0JFOHd2bGpQJTJCMExUJTJCS0RVWlZEdmIyVkV4cHJKWWklMkJpQSUyRmYwM2JWbEkzclhmY1JEa1I1WUh2Vk9ma3FSVzNYdjRyNklmZ2FTaENyMUR1TUtxSXZRUzNmRzhqbHA5bjV3TENKTHoweUNmRjRFZHFwNEtZT0VuWklrWEw1UFFNQ29VOVhDSVJPMmZrbW5OMTYlMkZ3eUtzOExUc3luamF5T2lsWVNtMnpxVGxGTmZuVnRaRzNYbk9VaGZGekJQZzBGRWw4OWU4TzdPU2kwOTFLdnR2S1JzZXozSzB5STVMWTJ5YjY4dHNQa0x1WWtXRCUyRllUVHlxY1J5QTZiMWFJbVllN1glMkJNeTlwYlVXbmNLUzVUeTRZaE1tJTJGRjBvQmVNRk42Mm5qRmZHZVRWdmI1YUVWelZ2ajRhJTJCNFdiWmdnWCUyQlNBeSUyRldva2FoUHgwZVJwcURZMlo0R1lJMTFidVhGSTIlMkZzZ2tvTVVyT3NpU2ZwbUVRTmVqblY3WGUzb2lvdnpmQmNEYWFickVZRnZxdmVRS2ZpdWg5V09ERTZzSWx4cHRjVGFQRFc2bzhQNk9sb1AySkRVRVVHeGRld2ZMTHp6aHFaMDBDQ3ROOWN3akdjRkczcWlvWEZxZG95dkZ4WVVxdE1NZTVjY09sMVJqT21uUGoxT1puaUZCdnd3VzJLMHdMQ2FLTSUyQjJ1Sk1Zd3ppOGZrUnlXSFoxa3ozbk80Z3FlVG8wWnc5VU5ZOWF0QjFPdUhPVmRKY2hQYVBvVGVKN2dhVnhHNGVDdGl2UUxWUEtLM3NBTXZKOXJWNkd3TG94a1ZLenBkOFBlRGVNYzJZaVVIb2F5QlQ3M3JtZHFtNWZlOGVaRWJZNGJWaTg0dkUwUWVmRFMlMkZmbTdaSXdnbnBCODFNSjBXR2VwMW5HbnA2S0tyamxnWk9YTGY1MHNkeWVacHNpcXVKRTZTeU80V2JpMDBieFdnRnoyemdLWnBuNHolMkY1OVJsOTR0azMlMkJSRkNwUVdVQkFUczhzUElkR3p3VTRRUmNxV2lTM1JEUFl0aWdVZThtb1J1MHpqaGdmaTFZWkhxNiUyQkNJb2kwcjVGNHFrOUFFR0JoRU42NURGZzNaSFZCUUpQdCUyQmtWcG5iSFZnaHFMYVRaSUdmSkdxeGRjZk41akZuUER1UVBQWU1QZEJSeVcyVG1vNHlSQVVLMlRwZ1VKTjVHWmVhQUd2MFl5aHNENTlGdExDdUwlMkZiYlFrYmNrTkhCOXJhaTIwZ0JFN2hWQ3h6QnFRQ3pWOFNaUDMzZVYxbHlBZVlaUGgzVkw2SEYyMGN2NFdsTE1DRkhmVHglMkJxVnJ5NmUzcXJINlFkcGVJak5WQjJjbm1Ia1FxR0NpNTM1eWkxSFJwdzBNaXZ0JTJGckxqZzE0Y0pmOHk3Q0JTdmM3JTJCd2hEN1dhdG1GWGlzYXdsb3FSJTJCV3dKdHB0JTJCeU1nMlRYYWVvalZLVjM1dnBvRmJQTU5WTkd3amdDZnFLVTI5SFJLVGdMWnIwdVNSZ1VvRDdHJTJGakkwZVdyUEUyZUtDUzYzSHJaMFFLa0tRR0FjQ2NHMDF3QkxrSVB6QTh4bmpCaEFwNlBQdUxCSVNXNHRWeWdhNmsyYWhwQlFweXVBZTFkbHE3cG5OeTB5WmtQOXBUWWhFTTNtYlVSSks3ZEgwcmRadXFjZyUyQmVWdDhTWCUyRnhWczdHMXp3TjlOdTBYTmE3ZUhZbGUyazZFajQ2R1l1VWUzeWxuQ08lMkJqNU02bVJWQWlJa0VVJTJGT3BBT1RNdzVoVXJjNTZWa2NpSVklMkJYakZlMnE2elFHaEtHMTBJeDI3UXJKM3UzZTdXMnNQN3k5ZVBLQjFPJTJGVmRDRzJwRUs5TkVyU0oxamJweXpTSFVvUExTRmpPYmd5dnZyZTNMJTJCUnFZcW52WmtiVDdtWTV4cWpLa3V3V0hyWEZ3YmlLMFp6QjVONExtWjdJMDIlMkJpQkFNZVNVT2hNRTBaNm9jN3J2ZXk4NGYwbTcyVlNKR3FKJTJCcXB5OXdSUGVTZUdiMVNsbUZrdyUyRlRvYW96dEI3YUdMdW5YdkdRQzRkekh2MUlIMXl2JTJCYm5qR2E4b09hVmFqT0NEa1pMNE1Sd0xaU2hVdjZkaVpPTXhrWEU1dE9xWEhBVHFCa3NCQVphN2w5MlJuV00zUTlMN0I1UVJHdzJXZkl2RWhLNGJ0RXU5M1FxYW9aejlUZUhzQ0h4UElZZUJwS2RqZVB3bEEzUEVIMkp5dFZBTHVlRjVvVjdvVVpkNHNBYjRncjclMkZnQ0h2aTNEaEh5UUtHTCUyRlRybHJhNzU5ZWM2VkFBSHhsaVBiZVhOdlglMkZXalFLT2RtdDJIQ1Z4QlNOMyUyQlNZUkQzYmpibzRobkRxYzhNNjdFWkNtc2I5YXVmbjVxeGJYWVlWNWhodFhvOFJheWU5Snlsd0JjTGFTODg5ZEF2U3hXamNiRVNtaEo0UiUyRnE4NThGdUQ4NGhDd1FjdW1wY0hHQm5iVllOUzRrJTJCTlg1NmRhd3l1eiUyRkdGJTJCJTJGQmFUUmYxM2RNZEk0eXZycGZ0TnNRREFPUnhRWGtQcDBYT0dOWHRHVlVFUFVtUnN2bFNhJTJCNmpPU3F2SnIwd2ZhaTUzVHlITDhNUnJnSUNzNzUzbkZybGFnUzlJNExKUVNFVVNFRTJhak4yTk9DbHR0TWVWVUVDZmFPRjgxMVdTdUR0R1pzZDRES3REcWtaQVlKOEMlMkJJeGRUMCUyQjF3Y1lFS0ElMkJOWHU1TWdCT3pxZkl5VWRNVGZnZ0htTE9rYVpIZXJSSUNlaGJqQXFtSWQ1eW84N1BLVlNrNHVHZUclMkJXY0hGcUFRbVpGU2hIb1RqV2wwcXVQaHdnZGppOENqNG1MdHV0cDdKaDlGUG9CaHNyT2V6SGlvSXV3TWZ5dUNnTUpNUzFUazRqNWxYNXVKWVZTa0ViQzNQMm9aVXJQemRNc0Z3Y3JIZ1ExY21BTHowNVMlMkZEUzRTNjlPellDbERURTd0ejc1QThkTjdWeTRSajFiZ1Y5cXoxZmtYYjZXc1ZTOFVpT05hcjQza04lMkZwOFE3MU1xSFE5NFQ4azRsZ2M0dzlFWjElMkZOS1BOY1EyNFlyR0clMkZEUEVqSXF0azl2RTBUNlpsNGNsWTJkSENmWWd4b0xza1FGYU9vdkNqdElPQ1ZSU01OMkZ5dkhUTTBpWEZ2bmZOJTJCbiUyRkgxdHdEUXo5RFVvUkFxNUFvT3hPU1lNejFQNUZjQW8zTTJwbHNyQXZxWlhMUnRaakprMnU1JTJGVlU1eTlnOWNoQWw4NyUyRm9yNm16TlpPZ2dKaTYlMkZNME9mUUVzTUpERjJsRVl2ekZUMnJKYjJ5bkFzOGduRVRlbGFaQzElMkJadDFiYm56ZXhUemZaSDV5U00yVEN2RlNXbzU0TjglMkJtQmNaMVNPUmQ3bWhLeE5GUjFtR0I1a0FnRDBuJTJCeFJwRmVGViUyRlhkeDZzVWhOdmVUUmlIamhvY0htNTJtbmNseGJVM0ZqWlpra3JjSG4lMkJjbVcwJTJCbjFXZURPQldHaE4xV1N1UWFQVEZMeThpTGM3VjhpT2VnJTJCVzF1RW1LSEdsZkJKb1BvN2lyRm1DRkZjSDBtWnU1VGFJQ2ZxRVdaMTU2SSUyRm1OWEVqMElzOUMyemtVUzBkN3FqSzZtQzBOVFN5UFpYUThISklFS1JpM25qYmRPNktQSXo2ZyUyRnd6dHZuVlNQazdFOUYzTlJOU2kyZFNwRDF1andwWUVlWU1RWWg5YkdDQ0lqNGZuVVFCSmZFJTJCMWdpUXY0ZHRkRVE3OERZVGFCR3FwJTJGa3BwZmpydFNZNHhWRXNXRnlZNHRrNlQlMkZtek01JTJGUjNGQzNaNjFzdlkyQ2lUODhLQXprWVBkQm02Sng2JTJGTjVwTjJUczJmT0JHcElkOE0zaFFXMjFGYVNkY1daYnNtJTJCbUNQWEloaXRMaW1DNFZ1WXIlMkJVcTR6MEhRbTFXbldZOXpjZ2pveUZ5cE8yV0h4ZlVxR1g4YmJqcGgzQzE1UUM5N3hxWFVCTWhSJTJCRUlORFAxZUMlMkZlaExNMDhBYTVQUWdwU3EzbmtwT3lPenElMkJ0bVcwQ2lNeUk5alN3MTlKODBMUzdnR000eGNTb21BNHU4MnUyS25RMURSdEFUdE16JTJGeXFqRzR4SnpSWkl2WTRGWDNnSzlGb1ZGMHR2RXhGYzR1JTJCZjFoNVFyWGJoVmlUJTJGZ29INXBOUDRPSXElMkIzMkRhMDJjWUtraXJsZWZPUHUlMkY2M3VKbmVoNVBoVTVoQmRtbE5XNmp4cFJMRGRRVlBudDI0VFBseFpTanRBOTI2b2pLOW5aZ1JxSWpIU2RNWWZJJTJCV3AlMkZDcnElMkJETlB5WGdtZGljRzlqOFVycGNLQVhibjRoY3dvR3RncVVXYXJoRllYakFTVm9oT1UyekNEY2I2T0RWR0RjM0JVWjlsbXFiSlVJSXFOMG1jMWhVRlczR1FwUFFNdW9SR2QlMkJyWmFMY2Y5aFo0SzRVUU8ydEpwU1klMkIlMkZnS21Kd0IlMkZRRUU1cHQzeEE3bU1OajVvcFdCZDI3JTJCdDE4NldzJTJCZGM3SHlyOGhYTHRJYVY5bXk3VEtiVFFWeWswJTJGT09rJTJGdDhYJTJCU24xJTJCVW5Gb2MlMkZ0WGlaTDhRRlJ5QThjeGxFSXhSQ1l3REFLJTJCJTJCUW8wakl2dnRCQTBSOFVEc0V3U2FBNGRISVY4Y2tTenAlMkZrJTJGRDlJZ1BiJTJCb0FhR1dnOHViWnFmbUw2JTJGSTFDWiUyRkpjM1E3NncyOEptVFQlMkY1SlBBTmdad3dhdEpQNHJ3OG02JTJGRW9TJTJCNzVZMEV6cDZmODJudTg0dWZxUnlBJTJGRUR3UHdEJTJGQkNPJTJGQSUyQkh2MmM1JTJGOEo5cSUyQkNmd1R6RHlPeEQlMkJuZzNjJTJGY1Q2ZCUyQkNmWUNUJTJCSGVOJTJGUGczJTJGNFduNEgwJTJCZkg1VHQxNlVwdTVUcnV5Nk5BZW1oRTVqMTNjTDFUVCUyQjlteHc5ZjBSQVVUYWZ3cVJNZjB1ak1ad1hrViUyRlMlMkJISTZDeXI3N2t6diUyQmdsd0hKdVZUZlBMTXppRFFpeCUyQnd1ZGw2dXYwbDVUc2ZaMHBTVGdYYWZLRkRoQ1lNZzRiTll6U3h1em44cXY0cUYlMkJXdnYwbEE5T1VPVWhZJTJCdUdFaGw5MzhZbFZlbGJBRmt0N3NpWVBmNzNoclh3Qm5vS1JuJTJGZGZUQWFxRE9maDB4eFplUUE4MkxrSUI1RFlIdWVMRHNXUGNKJTJCeEgxTTZnNFBRVXprRyUyQkxEbjdlZmI3N255TjJQJTJGejRRZndhRGZ4QjFHdnNzN1NYMFg4SiUyQnclMkYzJTJCSlJyNUo5RGNwVHJ1RW1hYlREaiUyRkowNFR6WE1hJTJGMCUyQmZ6UUpyazZmJTJCaHFSQm9DYWM4JTJGVyUyRjVQbTMwdlUxJTJGYWJPZmF2UFhOdnNKbTlJbVhNcnRkJTJCVCUyQjFKQmZOWmhBYWYxTk1oaW5maU1aUWtHJTJGRiUyRkZocTYlMkJuJTJGaWJIdDRJUTZCOEZvZjhvNk5NUTN3cDYwJTJGVSUyRnIlMkYwblVvTnV1JTJCJTJCWFg3TURqdGI2SkFVNSUyRmcwJTNEJTNDJTJGZGlhZ3JhbSUzRSUzQyUyRm14ZmlsZSUzRWUKKQMAAAPKSURBVHjajZX7axxVFMf3X/Bf8CfBX/yt6C+iRQV/MVR8tBQVTFOlEEqK9ZGSxKqkEJu2tLGikhKs0NWEtkuxGnGNlDYJSR+7fcRNZvOanZ3ZnWZ3dt5z5/H13pmdSbMmqQcOO/fOdz9z7jn33JsKggDMFsscrlxLY+pmDhy3BDbveS5c14NL1t3zNnff90NOig1E2UFRMHFvUYFUrcPQFSoIQlEQMGHk7JnNtTpjOI4T/qbYw+CIio4vVOzt1tA9ZGJFiqJmpso+lm67WM65kDgvmlx/vcEYKwQOnBXR3l1G10AN7b0P0dlfg6pFS7gxpmKoQ8LwoSp+/Kwa8fzNgbZtI+W6BL1fFvD6u3fRe1zAp8d47D+8hFrdDUXZCxUcacuj/537OHNwPpxj6XjU4joYhhEBhbKFI30P8P6HOew7cAdv7J1FvU5C0Xi6iJ490+jfN4vveu4/HsiWzKxUEnH58iSyf93D4qIOpjFNA7K8BqEkg5vn0WgYTQC2A5JQwKoliqs0sXbykvl2FrQATQYkxEkESqMBj2Zc0wzourFB3PrMjNCh4QVw/EciJHTjwjVgXf0AxsXdMH7aCSLMNL8eYH7aRmZQxa+nNUyc15PQbAq5VvMwR3fDZN2DQStvmyYF0i8EloLq4DNY++Y5VHuegDw7CoMW2Q8MXL8kY/iTEs73lTHStwzT1kAsG7JmISsTZB+6+HjOhkgX6lkx0FQgfP0K+KPPgv98B5T8OKIae8imBfTtvo0zXXMYPlqg/ULbkbiwCMHOGbqRfyd4csKGShfqMKBL28XUNRR/GwE3dgLcpSHUea6ZJR93pktIn72Ln7/NY+JKEZ7vJtUYW5BxcrKADCeHU82iECryISkaOEEGLyuwHNLsiACq3oBQ5bEqLtOeL4fRxVaXylgtPMBauRRVOcwhIYmATcSnxoZq0g84tvN/tw2hyfexIOdxfe4P5Pgb0J1G8qeaWcFM8W9MLWSxUi80QUECYh4HEUbouz4FqOjNtOPw2B4cTO9CrjSVAP/85yI6L7yGj0bfwsB4VxPkb90pvseAGjrOteHlgafx3vev4tbyZCK+mh/Fi8eeQtvJHfgqc+jxQI9GaDg69v/wNt489RJ2nXgBt5amE3Hm5i9oO/586N3pzqj22wHjosi1NazwAsRqJfkDO/5LooiyVIEgSlgtCzBMa8vetixr/bSJE9zar9E1EGz5/j8ntuu6CCsd3w/++qXTCovHm90rjMM8FUfBoDGcARWFXliSFLpIl828UqmEY1VVQ00MYc7G7Nb7F2G2pj6bl6K8AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;picture&gt;
          &lt;source
              srcset=&quot;/static/68eb0cb61658a011efbc03602625284a/f1512/ddb-qs-complex.webp 200w,
/static/68eb0cb61658a011efbc03602625284a/f59aa/ddb-qs-complex.webp 400w,
/static/68eb0cb61658a011efbc03602625284a/ed157/ddb-qs-complex.webp 491w&quot;
              sizes=&quot;(max-width: 491px) 100vw, 491px&quot;
              type=&quot;image/webp&quot;
            /&gt;
          &lt;source
            srcset=&quot;/static/68eb0cb61658a011efbc03602625284a/f8f3a/ddb-qs-complex.png 200w,
/static/68eb0cb61658a011efbc03602625284a/6a8a8/ddb-qs-complex.png 400w,
/static/68eb0cb61658a011efbc03602625284a/5c810/ddb-qs-complex.png 491w&quot;
            sizes=&quot;(max-width: 491px) 100vw, 491px&quot;
            type=&quot;image/png&quot;
          /&gt;
          &lt;img
            class=&quot;gatsby-resp-image-image&quot;
            src=&quot;/static/68eb0cb61658a011efbc03602625284a/5c810/ddb-qs-complex.png&quot;
            alt=&quot;pic&quot;
            title=&quot;&quot;
            loading=&quot;lazy&quot;
            decoding=&quot;async&quot;
            style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
          /&gt;
        &lt;/picture&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;AWS CDK Code&lt;/h1&gt;
&lt;p&gt;I packed the CDK Glue Table extension into its own &lt;a href=&quot;https://github.com/mmuller88/ddb-quicksight/blob/main/src/glue-stack.ts&quot;&gt;CDK Stack&lt;/a&gt;. Here is the code snipped:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; glue &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-glue&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cdk &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GlueStackProps&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StackProps &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; ddbTableName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GlueStack&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stack &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; GlueStackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; database &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;glue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Database&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Database&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      databaseName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ddbTableName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      locationUri&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dynamo-db-flag&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; gluetable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;glue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Table&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GlueTable&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      tableName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ddbTableName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      database&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; database&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      columns&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;userid&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; glue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;BIG_INT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;firstname&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; glue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;STRING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      dataFormat&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; glue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataFormat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cfngluetable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; gluetable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;defaultChild &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; glue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CfnTable&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cfngluetable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPropertyOverride&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;TableInput.Parameters.classification&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dynamodb&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cfngluetable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPropertyOverride&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;TableInput.Parameters.columnMapping&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;userid=userId,firstname=firstName,...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The DynamoDB columns you would like to be parsed you simply need to define as columns in the glue table. Watch out here! Glue Table does not support certain characters like capslock and special characters. Therefore you may have to do a columnMapping!&lt;/p&gt;
&lt;p&gt;After deployment the columns defined in &lt;strong&gt;columns&lt;/strong&gt; can be used in Athena and QuickSight.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Analyzing large DynamoDB tables is not that easy. However, with the use of AWS Glue Tables, the Lambda AthenaDynamoDBConnector can still reliably detect the desired columns.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/9518027c78885ed4c42f4bed0a621871/long-table.jpg</featuredImage><media:content url="https://martinmueller.dev/static/9518027c78885ed4c42f4bed0a621871/long-table.jpg" medium="image"/></item><item><title><![CDATA[AWS DynamoDB Analysis with QuickSight and AWS CDK]]></title><description><![CDATA[Hi. AWS DynamoDB is an extremely performant and scalable NoSQL database. Due to the lack of a schema, data, called items in DynamoDb, can be…]]></description><link>https://martinmueller.dev/cdk-ddb-quicksight-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-ddb-quicksight-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[projen]]></category><category><![CDATA[cdk]]></category><category><![CDATA[quicksight]]></category><category><![CDATA[aws]]></category><pubDate>Thu, 08 Apr 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/a4e6419a5e300000378c2c3add7afcda/ddb-quicksight.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;AWS DynamoDB is an extremely performant and scalable NoSQL database. Due to the lack of a schema, data, called items in DynamoDb, can be extremely flexible. This also allows a kind of evolutionary development of the items by simply creating new columns.&lt;/p&gt;
&lt;p&gt;But there is a catch. Because we are no longer in the world of relational data, we can no longer perform relational operations such as joins or the usual relational operations like COUNT, ORDER BY, GROUP by and many more. Now you ask yourself why should I be able to perform joins for example, they already bugged us with relational databases? We can use joins for example in analysis. I&apos;ll try to explain it with a store:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Top X products sold in the period from t1 to t2 grouped by gender.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our example the users and the sold products are each in their own DynamoDB table and are indirectly connected via a userId. However, it is also conceivable that both are in the same table, but in different data sets or rows. DynamoDB does not allow joins and so we cannot relate products sold to gender.&lt;/p&gt;
&lt;p&gt;The solution to the problem is AWS Athena, QuickSight, Lambda and S3. Using a Lambda, we store the DynamoDB items as a flat JSON file in an S3. Then we let Athena access it. QuickSight then uses Athena as a data engine to create joins, analytics, and dashboards. How you automate this with AWS CDK and a description of the AWS services used will follow in the next sections. For the impatient ones, here is the &lt;a href=&quot;https://github.com/mmuller88/ddb-quicksight&quot;&gt;code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But before we got to the next section I would like to thank the sponsor for this blogpost and the exciting project to perform analysis of DynamoDB tables using QuickSight. Thanks to &lt;a href=&quot;https://www.take2.co/&quot;&gt;TAKE2&lt;/a&gt; for letting me be part of your agile and motivated team to work on exciting AWS CDK tasks like these.&lt;/p&gt;
&lt;h1&gt;AWS DynamoDB&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html&quot;&gt;AWS DynamoDB&lt;/a&gt; is a managed NoSQL database with very good performance and scaling. Managing the database from AWS eliminates tedious administrative tasks such as installation or maintenance. DynamoDB also has backup features like on demand or point-in-time recovery.&lt;/p&gt;
&lt;p&gt;In DynamoDB, the inserted data does not have to follow a fixed schema like in relational databases. This is super flexible and very useful, but can also lead to problems like confusion or inconsistencies in column names. Therefore I recommend to allow only certain columns in the table. This can be achieved for example by schema validation in Api Gateway or using a GraphQL schema in AWS AppSync.&lt;/p&gt;
&lt;h1&gt;AWS Athena&lt;/h1&gt;
&lt;p&gt;AWS Athena allows data to be queried. To access the data, the developer uses standard SQL as the query language. The data source can be various AWS services such as S3, RedShift and most recently DynamoDB. The advantage to Athena is that it is serverless, so you can focus directly on querying the data.&lt;/p&gt;
&lt;p&gt;To set DynamoDB as data source for Athena you need a Lambda Connector. The connector writes all items from the table into an S3 bucket. Fortunately, AWS already provides a SAM Lambda that does the job. This lambda is called &lt;a href=&quot;https://github.com/awslabs/aws-athena-query-federation/blob/master/athena-dynamodb&quot;&gt;AthenaDynamoDBConnector&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;AWS QuickSight&lt;/h1&gt;
&lt;p&gt;AWS QuickSight is a service for creating and analyzing visualizations of customer data. The customer data can reside in AWS services like S3, RedShift or as in our case in DynamoDB.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/mmuller88/ddb-quicksight/main/misc/QS.png&quot; alt=&quot;pic&quot;&gt;&lt;/p&gt;
&lt;p&gt;QuickSight cannot directly read data from DynamoDB at this time and a small intermediate step must be taken. The DynamoDB data has to be exported in a S3 bucket e.g. as JSON. Then QuickSight can read the data located in the S3.&lt;/p&gt;
&lt;p&gt;To push the data into the S3 bucket the approach of using an AthenaDynamoDBConnector Lambda is suitable. You can read more about this in the next section.&lt;/p&gt;
&lt;p&gt;Quicksight offers many cool functions for processing and visualizing data that can come from DynamoDB for example. You can also define them as code with CDK.&lt;/p&gt;
&lt;p&gt;I am working on storing the QuickSight analyses in templates via CDK in order to make them cross account accessible. This will allow me to create and test analyses on a dev account and then deploy them automatically to the prod account via CDK. How exactly this should work will be explained in the next blogpost.&lt;/p&gt;
&lt;h1&gt;AWS CDK&lt;/h1&gt;
&lt;p&gt;AWS CDK](&lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;https://github.com/aws/aws-cdk&lt;/a&gt;) is an open source framework for creating and managing AWS resources. By using languages familiar to the developer such as TypeScript or Python, the infrastructure is described as code. In doing so, CDK synthesizes the code into AWS Cloudformation Templates and can optionally deploy them right away.&lt;/p&gt;
&lt;p&gt;AWS CDK has been experiencing a steady increase in enthusiastic developers since 2019 and already has a strong and helpful community that is very active on &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt;. There is of course much more to say about AWS CDK and I recommend you explore it. Drop me a line if you have any questions.&lt;/p&gt;
&lt;p&gt;With AWS CDK, I have achieved a high level of automation in creating and managing the DynamoDB QuickSight deployment. This involves defining the required AWS resources and its configurations nicely as code and then simply executing them. And here you can see a component diagram:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/mmuller88/ddb-quicksight/main/misc/ddb-quicksight.png&quot; alt=&quot;pic&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can find the AWS CDK code for the DynamoDB Athena deployment in my &lt;a href=&quot;https://github.com/mmuller88/ddb-quicksight/blob/main/src/ddb-athena-stack.ts&quot;&gt;repo&lt;/a&gt;. Be sure to check out the readme there as well since it contains a lot of important instructions and information. Unfortunately I couldn&apos;t write everything in AWS CDK because e.g. the SAM Lambda AthenaDynamoDBConnector is not or only difficult to translate in AWS CDK and it has to be deployed manually until now.&lt;/p&gt;
&lt;h1&gt;Outlook&lt;/h1&gt;
&lt;p&gt;It would be super cool if the AthenaDynamoDBConnector was also available in AWS CDK. Also, the QuickSight Cloudformation resources still seem very immature to me as some things are not supported at all like the DataSet. A &lt;a href=&quot;https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/274&quot;&gt;GitHub Issue&lt;/a&gt; has already been created.&lt;/p&gt;
&lt;p&gt;As mentioned in the QuickSight section, I am working on persisting the analytics from QuickSight using CDK and then making them available cross account wise. I will show my findings in the next blogpost.&lt;/p&gt;
&lt;h1&gt;Summary.&lt;/h1&gt;
&lt;p&gt;AWS QuickSight is an exciting analytics tool for evaluating data in a DynamoDB table. Data is the new gold and therefore it is extremely important to be able to process data that is difficult to process, for example in a DynamoDB table. If you can use familiar mechanisms like SQL queries and aggregate functions, that&apos;s great. Also QuickSight offers cool graphical solutions for displaying analyses and dashboards. I am very excited to be able to work with it more.&lt;/p&gt;
&lt;p&gt;Thanks also to Jared Donboch for the extremely helpful BlogPost &lt;a href=&quot;https://dev.to/jdonboch/finally-dynamodb-support-in-aws-quicksight-sort-of-2lbl&quot;&gt;Using Athena data connectors to visualize DynamoDB data with AWS QuickSight&lt;/a&gt; . Based on that, I was able to automate as much as possible by composing it into an AWS CDK stack.&lt;/p&gt;
&lt;p&gt;Thanks again to &lt;a href=&quot;https://www.take2.co/&quot;&gt;TAKE2&lt;/a&gt; for sponsoring this blog post.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/a4e6419a5e300000378c2c3add7afcda/ddb-quicksight.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/a4e6419a5e300000378c2c3add7afcda/ddb-quicksight.jpeg" medium="image"/></item><item><title><![CDATA[A very cool DevOps AWS CDK Todolist]]></title><description><![CDATA[Hi. For a long time I've been dreaming of building a platform with a great DevOps experience. I want to have cool stuff in it like…]]></description><link>https://martinmueller.dev/cdk-appsync-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-appsync-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[projen]]></category><category><![CDATA[cdk]]></category><category><![CDATA[aws]]></category><category><![CDATA[appsync]]></category><pubDate>Tue, 23 Feb 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/e0e2c1119cbd004c5e7abd6f79093655/pipeline.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;For a long time I&apos;ve been dreaming of building a platform with a great DevOps experience. I want to have cool stuff in it like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Infrastructure as Code (IAC)&lt;/li&gt;
&lt;li&gt;CI / CD (Continuous Integration / Continuous Deployment)&lt;/li&gt;
&lt;li&gt;A staging e.g. dev, qa, prod&lt;/li&gt;
&lt;li&gt;automated tests&lt;/li&gt;
&lt;li&gt;all this with as little TypeScript code as necessary&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have found that now with the use of the following technologies. AWS CDK to manage the infrastructure as code. AWS AppSync as implementation of GraphQL, AWS Amplify for the frontend website and managing users. Furthermore AWS CodePipeline extended with my library &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-staging-pipeline&quot;&gt;AWS CDK Staging Pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With my Todolist deployment I want to show you how much power is in my deployment. But first I will explain what AWS CDK is.&lt;/p&gt;
&lt;h1&gt;AWS CDK&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt; is an open source framework for creating and managing AWS resources. By using languages familiar to the developer such as TypeScript or Python, Infrastructure as Code is described. In doing so, CDK synthesizes the code into AWS Cloudformation Templates and can optionally deploy them right away.&lt;/p&gt;
&lt;p&gt;AWS CDK has been experiencing a steady increase in usage for developers since 2019 and already has a strong and helpful community that is very active like on &lt;a href=&quot;https://cdk-dev.slack.com&quot;&gt;Slack&lt;/a&gt;. There is of course much more to say about AWS CDK and I recommend you explore it. Drop me a line if you have any questions.&lt;/p&gt;
&lt;h1&gt;Backend AWS AppSync, AWS DynamoDB and AWS Cognito&lt;/h1&gt;
&lt;p&gt;The code for the backend is in &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-todolist&quot;&gt;GitHub aws-cdk-todolist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;AWS AppSync is a GraphQL api implementation. GraphQL is an interesting new API technology. Since GraphQL is still new for me, I don&apos;t dare to make any big statements now. What I do like is that the connection to databases like AWS DynamoDB feels very native. I&apos;ve always been annoyed by the necessary Lambda implementations with AWS Api Gateway and the creation of new endpoints. All of that seems no longer necessary with the use of AWS AppSync.&lt;/p&gt;
&lt;p&gt;For storing items in the todo list I use DynamoDB. Each item gets its own ID, which is assigned by the AppSync resolver. In addition, each item has a body and a username.&lt;/p&gt;
&lt;p&gt;AWS Cognito is a service for user management and user authentication via Oauth. This service makes it very easy to implement a professional and scalable identity service with all the bells and whistles.&lt;/p&gt;
&lt;p&gt;A deployment pipeline deployed all these resources to AWS accounts. The AWS resources for the backend and the deployment pipeline itself, are deployed using AWS CDK as Infrastructure as Code.&lt;/p&gt;
&lt;h1&gt;Front-end React, AWS Amplify, S3 Static Website.&lt;/h1&gt;
&lt;p&gt;The code for the frontend is in &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-todolist-ui&quot;&gt;GitHub aws-cdk-todolist-ui&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The frontend stack consists of a React build with AWS Amplify UI extensions like @aws-amplify/auth @aws-amplify/ui-components @aws-amplify/ui-react. These extensions help massively with user management. For example, it is easy to create new users via the login screen or change the password in case you forget it.&lt;/p&gt;
&lt;p&gt;The React build is copied to an S3 bucket via the deployment pipeline (see next section). The S3 bucket is configured as a static website. All required AWS resources for the S3 bucket and the deployment pipeline are also provided with AWS CDK.&lt;/p&gt;
&lt;h1&gt;DevOps Pipelines&lt;/h1&gt;
&lt;p&gt;Any deployments today should have a decent deployment pipeline that has cool features like automated builds, deploys, tests, linting, versioning and so on. With this you achieve an incredible speed in development and the work is much more fun because annoying manual tasks like deploying to production or manual testing are simply omitted.&lt;/p&gt;
&lt;p&gt;My Todolisten deployment has such a deployment pipeline. Each of the &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-todolist-ui&quot;&gt;frontend&lt;/a&gt; and &lt;a href=&quot;https://github.com/mmuller88/aws-cdk-todolist&quot;&gt;backend&lt;/a&gt; have their own pipeline which is based on AWS CodePipeline and of course AWS CDK. For the pipeline I have developed a custom AWS CDK construct and also reported about it in a previous post which you can see &lt;a href=&quot;https://martinmueller.dev/cdk-pipeline-lib&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Outlook&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/&quot;&gt;AppSync Transformer&lt;/a&gt; looks very interesting. With it it is possible to use the &lt;a href=&quot;https://docs.amplify.aws/cli/graphql-transformer/overview&quot;&gt;AWS Amplify GraphQL Transformer&lt;/a&gt; more easily. Thus many lines of code can be saved by generating an extended GraphQL schema using cool labels like @model @connection.&lt;/p&gt;
&lt;p&gt;I do make a Udemy course about creating a platform like the Todolist. If you want a voucher for it, let me know and once it&apos;s done you&apos;ll get one.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;GraphQL is ultra exciting. I think it&apos;s a forward looking API technology and I can&apos;t wait to work with it more in a professional environment.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/e0e2c1119cbd004c5e7abd6f79093655/pipeline.png</featuredImage><media:content url="https://martinmueller.dev/static/e0e2c1119cbd004c5e7abd6f79093655/pipeline.png" medium="image"/></item><item><title><![CDATA[Scrum and GitHub]]></title><description><![CDATA[Hi. Our development team does an exciting experiment. We work in Scrum and organize ourselves mainly with GitHub. That works really great…]]></description><link>https://martinmueller.dev/github-scrum-eng/</link><guid isPermaLink="false">https://martinmueller.dev/github-scrum-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[github]]></category><pubDate>Thu, 11 Feb 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/e9e75f0f16063bb2c8e2898390177798/git.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;Our development team does an exciting experiment. We work in Scrum and organize ourselves mainly with GitHub. That works really great1. In this article I describe how we use GitHub for that.&lt;/p&gt;
&lt;p&gt;Even though I have experience with Scrum for about 5 years as a developer I give a little disclaimer here. I have never done a Scrum certification. So I will probably misrepresent or misclassify terms. I would then like to ask you to correct me.&lt;/p&gt;
&lt;p&gt;Also, our team has only been working together in Scrum for a little over a month. The team is relatively small with 4 people 3 fullstack developers and 1 product owner. Nevertheless I think this post can help you to improve your work process in your team.&lt;/p&gt;
&lt;p&gt;In the next section I&apos;ll tell you more about GitHub and how we use it to organize ourselves in Scrum.&lt;/p&gt;
&lt;h1&gt;GitHub and Scrum&lt;/h1&gt;
&lt;p&gt;My &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;GitHub account&lt;/a&gt; is active since 2016. GitHub is by far my favorite Git provider environment. Privately, I use GitHub a lot. I am very happy that I can now use GitHub for work as well. Our main motivations to use GitHub are the low costs and the fact that many developers are already used to GitHub.&lt;/p&gt;
&lt;p&gt;In the next section I explain how we use some GitHub features to manage our Scrum way of working.&lt;/p&gt;
&lt;h2 id=&quot;github-issues-as-tickets&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#github-issues-as-tickets&quot; aria-label=&quot;github issues as tickets permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GitHub Issues as Tickets&lt;/h2&gt;
&lt;p&gt;The issues on GitHub can be perfectly used as tickets for Scrum. Using labels it is even possible to give the tickets a size. A size in this context is a number to estimate the complexity of the ticket. Usually these are the Fibonacci numbers 1 3 5 8 13 .&lt;/p&gt;
&lt;p&gt;Labels can also be used to assign tickets to their respective components. Component means a kind of subcategory of the project like &quot;component: api&quot; or &quot;component: app&quot; .&lt;/p&gt;
&lt;h2 id=&quot;github-projects-as-scrum-boards&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#github-projects-as-scrum-boards&quot; aria-label=&quot;github projects as scrum boards permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;GitHub Projects as Scrum Boards&lt;/h2&gt;
&lt;p&gt;GitHub Projects are great for Scrum Boards. We have 3 Projects for 3 Boards. Each board represents its own time range and level of abstraction.&lt;/p&gt;
&lt;h3 id=&quot;current-sprint-board&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#current-sprint-board&quot; aria-label=&quot;current sprint board permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Current Sprint Board&lt;/h3&gt;
&lt;p&gt;The most important board is of course the &quot;Current Sprint Board&quot; (see in the middle of the cover image). We do a two-week sprint and with the &quot;Current Sprint Board&quot; we reflect on the work or the tickets we are currently working on and want to work on. It has three columns ToDo, In Progress and Done.&lt;/p&gt;
&lt;p&gt;Tickets from the Backlog Scrum Board, which will be introduced in the next section, end up here first in the ToDo column. At this point, the tickets should be understandable and sized. At the end of each Sprint, the Done column is emptied and the ToDo column is refilled.&lt;/p&gt;
&lt;h3 id=&quot;backlog-board&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#backlog-board&quot; aria-label=&quot;backlog board permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Backlog Board&lt;/h3&gt;
&lt;p&gt;The Backlog Board (see below in the title image) is intended for tasks in the period of 2 - 6 weeks and includes all tickets that are not yet in the current Sprint Board. Here they are collected and refined piece by piece. There are four columns from left to right: Backlog, Ready for Sizing, Ready for Sprint and Next Sprint.&lt;/p&gt;
&lt;p&gt;In each column, the ticket is refined, e.g. when the ticket is moved from Backlog to Ready for Sizing, it must be comprehensible to all developers so that it can be sized.&lt;/p&gt;
&lt;p&gt;When the ticket goes into the Ready for Spring column, it is now ready to potentially go into the next sprint. In the Next Sprint column we agree on which tickets we want to handle in the next sprint.&lt;/p&gt;
&lt;h3 id=&quot;future-board&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#future-board&quot; aria-label=&quot;future board permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Future Board&lt;/h3&gt;
&lt;p&gt;The Future Board is for ideas / tasks that are still relatively unclear and are in a time interval of about 6 weeks to a year. So far we hardly use this board and have ideas in a separated &lt;a href=&quot;https://miro.com&quot;&gt;Miro&lt;/a&gt; board.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I am still totally flashed how well it works with the tools on GitHub to work in Scrum. The UI of GitHub seems very sophisticated and allows a great Scrum experience. Just give it a try :) !&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/e9e75f0f16063bb2c8e2898390177798/git.jpg</featuredImage><media:content url="https://martinmueller.dev/static/e9e75f0f16063bb2c8e2898390177798/git.jpg" medium="image"/></item><item><title><![CDATA[Docker Hub release with Projen]]></title><description><![CDATA[Hi Projen folks. Projen is becoming popular. I've been using it myself for about half a year now and I'm still totally hooked. Recently I…]]></description><link>https://martinmueller.dev/projen-eng/</link><guid isPermaLink="false">https://martinmueller.dev/projen-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[projen]]></category><category><![CDATA[docker]]></category><pubDate>Mon, 01 Feb 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/91a64c6f688208ef362e26cd2d97b900/projen.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi Projen folks.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt; is becoming popular. I&apos;ve been using it myself for about half a year now and I&apos;m still totally hooked. Recently I even managed to build a Docker Image Release Cycle to Docker Hub with it. My &lt;a href=&quot;https://github.com/mmuller88/influxdb-s3-backup&quot;&gt;Docker InfluxDB Repo&lt;/a&gt; now automatically pushes an image to Docker Hub on every release.&lt;/p&gt;
&lt;p&gt;But what is Projen and how I use it? That and more I&apos;ll explain in the next sections.&lt;/p&gt;
&lt;h1&gt;Projen&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt; allows sophisticated management of project configuration through code. With just a few lines of TypeScript, an entire repository can be configured. Here is an example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; JsiiProject &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;projen&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; project &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsiiProject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alps-unified-ts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  authorAddress&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;damadden88@googlemail.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  authorName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Martin Mueller&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;synth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These few lines are creating all the GitHub project files you need. Among them the package.json, .gitignore, tsconfig.json and many more.&lt;/p&gt;
&lt;p&gt;What&apos;s cool is that Projen also comes with GitHub workflows that can for example publish new versions to registries like NPM or PYPI which I used for an other projen which I describe &lt;a href=&quot;https://martinmueller.dev/alps-unified-eng&quot;&gt;here&lt;/a&gt;. For my Docker image release to Docker Hub I extended the Projen GitHub release workflow. You can see how exactly in the next section.&lt;/p&gt;
&lt;h1&gt;Projen Setup&lt;/h1&gt;
&lt;p&gt;Below you can see my current Projen setup which is stored in the file .projenrc.js.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NodeProject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ProjectType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DockerCompose &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;projen&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; project &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodeProject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  authorAddress&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;damadden88@googlemail.de&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  authorName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Martin Mueller&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;influxdb-s3-backup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  releaseBranches&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;main&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  projectType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ProjectType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LIB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;releaseWorkflow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addJobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  publish_docker_hub&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    needs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;build&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;runs-on&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ubuntu-latest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;CI&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;steps&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Check out the repo&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;actions/checkout@v2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Set up QEMU&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;docker/setup-qemu-action@v1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Set up Docker Buildx&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;docker/setup-buildx-action@v1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Login to DockerHub&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;docker/login-action@v1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          username&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;${{ secrets.DOCKER_USERNAME }}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;${{ secrets.DOCKER_PASSWORD }}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;get_version&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;get_version&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        run&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&apos;DVERSION=$(jq .version version.json -r)&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&apos;echo &quot;::set-output name=dversion::$DVERSION&quot;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Build and push&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;docker/build-push-action@v2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          file&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./Dockerfile&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          platforms&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;linux/amd64,linux/arm64&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          push&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          tags&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;damadden88/influxdb-s3-backup:${{ steps.get_version.outputs.dversion }},damadden88/influxdb-s3-backup:latest&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;synth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;nodeproject&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#nodeproject&quot; aria-label=&quot;nodeproject permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;NodeProject&lt;/h2&gt;
&lt;p&gt;My project is from type NodeProject:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NodeProject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ProjectType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DockerCompose &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;projen&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; project &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NodeProject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  authorAddress&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;damadden88@googlemail.de&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  authorName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Martin Mueller&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;influxdb-s3-backup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  releaseBranches&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;main&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  projectType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ProjectType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;LIB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This means that it is a typical node deployment, which requires nodejs as environment and contains additional libraries and project information in the package.json. Also, Node projects come with a changelog.md which can list all changes since the last release.&lt;/p&gt;
&lt;p&gt;It also has a GitHub release workflow which automatically makes GitHub releases on commits using GitHub Actions and follows the &lt;a href=&quot;https://semver.org&quot;&gt;semver&lt;/a&gt;. I have now extended this release workflow to also push Docker images to Docker Hub in the same tag version as it is done during the GitHub release. To extend the release workflow I have extended the releaseWorkflow object as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;releaseWorkflow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addJobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  publish_docker_hub&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    needs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;build&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;runs-on&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ubuntu-latest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token constant&quot;&gt;CI&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;steps&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Check out the repo&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;actions/checkout@v2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Set up QEMU&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;docker/setup-qemu-action@v1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Set up Docker Buildx&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;docker/setup-buildx-action@v1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Login to DockerHub&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;docker/login-action@v1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          username&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;${{ secrets.DOCKER_USERNAME }}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;${{ secrets.DOCKER_PASSWORD }}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;get_version&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;get_version&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        run&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&apos;DVERSION=$(jq .version version.json -r)&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&apos;echo &quot;::set-output name=dversion::$DVERSION&quot;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Build and push&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        uses&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;docker/build-push-action@v2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          file&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./Dockerfile&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          platforms&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;linux/amd64,linux/arm64&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          push&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          tags&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;damadden88/influxdb-s3-backup:${{ steps.get_version.outputs.dversion }},damadden88/influxdb-s3-backup:latest&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So this GitHub workflow releases my image to Docker Hub with the same tag version and latest:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;tags: &apos;damadden88/influxdb-s3-backup:${{ steps.get_version.outputs.dversion }},damadden88/influxdb-s3-backup:latest&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;New releases to GitHub and Docker Hub are now completely managed by Projen automatically. This is extremely cool and saves me a lot of time :).&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;I love the Projen framework as it is a great abstraction and default for a setup of projects. I encourage you to give Projen a try and very soon you will experience the beauty of this framework yourself.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/91a64c6f688208ef362e26cd2d97b900/projen.png</featuredImage><media:content url="https://martinmueller.dev/static/91a64c6f688208ef362e26cd2d97b900/projen.png" medium="image"/></item><item><title><![CDATA[IOT - Gasmeter goes digital]]></title><description><![CDATA[Before it begins. Affiliates regarding the IOT devices are in the post Hi. A few weeks ago I presented my new IOT deployment here. It…]]></description><link>https://martinmueller.dev/nodered-eng/</link><guid isPermaLink="false">https://martinmueller.dev/nodered-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[nodered]]></category><category><![CDATA[raspberry]]></category><category><![CDATA[iot]]></category><pubDate>Mon, 25 Jan 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/1a808032dd7cf2199bc08dcf606e4110/gasmeter.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;&lt;em&gt;Before it begins. Affiliates regarding the IOT devices are in the post&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Hi.&lt;/p&gt;
&lt;p&gt;A few weeks ago I presented my new IOT deployment &lt;a href=&quot;https://martinmueller.dev/rasp4&quot;&gt;here&lt;/a&gt;. It consists of a &lt;a href=&quot;https://amzn.to/3a0Xjsd&quot;&gt;Raspberry 4 DE&lt;/a&gt; &lt;a href=&quot;https://amzn.to/3iEHyuD&quot;&gt;US&lt;/a&gt; &lt;a href=&quot;https://amzn.to/2Y8FOQZ&quot;&gt;UK&lt;/a&gt;, &lt;a href=&quot;https://amzn.to/2KEqsAz&quot;&gt;Zigbee Türsensor DE&lt;/a&gt; &lt;a href=&quot;https://amzn.to/2MeSmDM&quot;&gt;UK&lt;/a&gt; and the &lt;a href=&quot;https://amzn.to/2Y4aq63&quot;&gt;Zigbee Empfäger DE&lt;/a&gt; &lt;a href=&quot;https://amzn.to/3pjZrSk&quot;&gt;UK&lt;/a&gt;. The software that runs on the Raspberry 4 is Docker Compose. With the Docker Compose deployment, &lt;a href=&quot;https://github.com/node-red/node-red&quot;&gt;NodeRED&lt;/a&gt; is used for IOT management. For the charts which you can see in the picture I use &lt;a href=&quot;https://github.com/grafana/grafana&quot;&gt;Grafana&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First I want to explain how I made my analog gas meter digitally and then how I use NodeRED and Grafana to transform the received data and make it displayable in charts (see title image).&lt;/p&gt;
&lt;h1&gt;Gas meter extension&lt;/h1&gt;
&lt;p&gt;As shown in the picture above right I have an analog gas meter BK-G4. So how do I turn it into a digital gas meter that can even store values over time? Well the meter sends a magnetic pulse every 0.01 qm of consumed gas. On the picture you can see this as 1 imp 0,01 qm. So if you also have a gas meter with magnetic pulse, the instructions here should also work for you.&lt;/p&gt;
&lt;p&gt;I simply measure the magnetic pulse with the wireless &lt;a href=&quot;https://amzn.to/2KEqsAz&quot;&gt;Zigbee door sensor&lt;/a&gt; (also top right in picture) and send it to a &lt;a href=&quot;https://amzn.to/2Y4aq63&quot;&gt;Zigbee receiver&lt;/a&gt; which is connected to a &lt;a href=&quot;https://amzn.to/3a0Xjsd&quot;&gt;Raspberry 4&lt;/a&gt; &lt;a href=&quot;https://amzn.to/3iEHyuD&quot;&gt;US&lt;/a&gt; and record the values.&lt;/p&gt;
&lt;p&gt;The recording is not that easy because the signal has to be transformed. The transformation of the signal is done with NodeRED.&lt;/p&gt;
&lt;h1&gt;NodeRED&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/node-red/node-red&quot;&gt;NodeRED&lt;/a&gt; is an open source programming tool for connecting IOT devices together, APIs and online services. It provides a web browser based editor and supports JavaScript as a programming language. The runtime itself is &lt;a href=&quot;https://en.wikipedia.org/wiki/Node.js&quot;&gt;Nodejs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also find it very cool that NodeRED supports a connection to GitHub and the current state of the NodeRED project can be saved versioned using the Git protocol. NodeRED offers many other great features that you should definitely explore. But I only want to talk about the NodeRED Flow.&lt;/p&gt;
&lt;h2 id=&quot;nodered-flow&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#nodered-flow&quot; aria-label=&quot;nodered flow permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;NodeRED Flow&lt;/h2&gt;
&lt;p&gt;A NodeRED project can have several flows. A NodeRED Flow describes the interaction of the IOT devices with other devices, APIs or online services. You can see my flow in the upper left corner of the image. The flow is best read from left to right. On the far left are two inputs. The lower input is from an &lt;a href=&quot;https://openweathermap.org/appid&quot;&gt;Open Weather API&lt;/a&gt; that I use to collect the current outdoor temperature (also shown in yellow in the &quot;Gas Delta&quot; diagram).&lt;/p&gt;
&lt;p&gt;The upper input is from my Zigbee receiver which gets the signal from the Zigbee door sensor. The Zigbee door sensor and receiver work with the so called MQTT protocol. MQTT is a data saving, publish and subscribe protocol mainly for communication between IOT devices.&lt;/p&gt;
&lt;p&gt;On the right side of the flow you can see the outputs (a bit cut off). The blue output is a NodeRED UI element. NodeRED also offers the possibility to render UI elements with e.g. sensor values. This is then accessible e.g. at &lt;a href=&quot;https://localhost:1880/ui&quot;&gt;https://localhost:1880/ui&lt;/a&gt; . The brown outputs send data to an InfluxDB which is then displayed with Grafana.&lt;/p&gt;
&lt;h1&gt;InfluxDB &amp;#x26; Grafana&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/influxdata/influxdb&quot;&gt;InfluxDB&lt;/a&gt; is an open source time series database . It is written in GO and optimized for fast, high availability storage and query of stored data. It is great for IOT data.&lt;/p&gt;
&lt;p&gt;For my flow, I store the current gas value and temperature in InfluxDB. InfluxDB then calculates the timestamp on its own. Then I can simply use the graphical analysis tool &lt;a href=&quot;https://github.com/grafana/grafana&quot;&gt;Grafana&lt;/a&gt; to get the data from InfluxDB and display it flexibly (see diagrams in title image).&lt;/p&gt;
&lt;p&gt;At the bottom right I see the current and yesterday&apos;s daily consumption. You can not see it in the picture because only yellow is displayed but I have set different colors for color ranges. From 0 - 7 qm is green. Then from 7 - 14 qm is yellow and everything above 14 qm is red. For a family of three the average daily consumption is about 7 qm, which varies by a factor of 2 at most in summer and winter. Extremely cool ^^.&lt;/p&gt;
&lt;p&gt;At the very bottom left, the total consumption of the gas is displayed and above it how the consumption changes relatively over the day. A pretty cool feature of Grafana is that the time range can be changed comfortably. As default I have set &quot;Today&quot; which shows me all values from 0 to now. But there are other time ranges like yesterday, the day before yesterday, 12 hrs etc. Also start and end time can be entered directly. Extremely cool!&lt;/p&gt;
&lt;h1&gt;InfluxDB AWS S3 Backup&lt;/h1&gt;
&lt;p&gt;In the meantime, I even added a data backup feature. With this I compress my InfluxDB data and store it in AWS S3. AWS S3 is a cheap long term cloud storage. I prefer this method because I don&apos;t have to buy external storage and can leave the physical management of the storage to AWS.&lt;/p&gt;
&lt;p&gt;For backup, I built my own &lt;a href=&quot;https://github.com/mmuller88/influxdb-s3-backup&quot;&gt;Docker image and release&lt;/a&gt;. This was necessary as there was no Docker Image on Docker Hub yet which supported InfluxDB + AWS CLI + arm64. I now consume these in my &lt;a href=&quot;https://github.com/mmuller88/rasp4&quot;&gt;rasp4 repo&lt;/a&gt; in docker-compose.yaml. Backup is done by default every morning at 1am.&lt;/p&gt;
&lt;h1&gt;Outlook&lt;/h1&gt;
&lt;p&gt;Next I would like to digitallise my electricity meter to be able to read it as well and show nice charts.&lt;/p&gt;
&lt;p&gt;I also want to migrate more IOT devices to NodeRED because I currently have some things running in the cloud with the app &quot;Smart Life&quot;. But the functionality there is very limited. E.g. I can already turn my boiler on and off and I would like to be able to control that with NodeRED.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;If you have any cool ideas how to transform or visualize my sensor data to generate more useful information, let me know.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/1a808032dd7cf2199bc08dcf606e4110/gasmeter.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/1a808032dd7cf2199bc08dcf606e4110/gasmeter.jpeg" medium="image"/></item><item><title><![CDATA[Long term investing with Trading212]]></title><description><![CDATA[Before it starts! The Trading212 link is an affiliate where you and I get each a share for free. Hi, I started with stocks in November 202…]]></description><link>https://martinmueller.dev/trading212-eng/</link><guid isPermaLink="false">https://martinmueller.dev/trading212-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[trading]]></category><pubDate>Sun, 17 Jan 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/f076440af195b1acef0fb2885b2108aa/trading.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;&lt;em&gt;Before it starts! The Trading212 link is an affiliate where you and I get each a share for free&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I started with stocks in November 2020 and since them I am an active user of the trading app &lt;a href=&quot;https://trading212.com/invite/GvP8w4UF&quot;&gt;Trading212&lt;/a&gt;. The main reason is that I do not see a bank account as an ideal form of storage for my money since it loses value there over time.&lt;/p&gt;
&lt;p&gt;The exact explanation why I invest in stocks and how my strategy looks like, you will see in the next sections. Only so much is said, it was a great decision and I have already created after a few weeks a higher value than it would be possible in a bank in a year.&lt;/p&gt;
&lt;h1&gt;Why?&lt;/h1&gt;
&lt;p&gt;Banks nowadays only offer a very low interest rate up to a maximum of 2% per year. This can hardly or not at all keep up with the inflation rate of money. In other words, you lose financial strength. To better understand the word financial strength, I&apos;ll give a small example. Lets imagine in year 2020 you could afford 100 buns of 100€, in 2021 it only are 90 buns you can buy with 100€.&lt;/p&gt;
&lt;p&gt;So if you leave your money in the bank, you lose financial strength. So other options should be considered when it comes to storing money. An investment in shares with a low risk strategy sounds very tempting at first. At this point, however, it should be said that every investment carries a risk, and this of course also applies to shares. Even banks can go bankrupt at the expense of investors, see Greece.&lt;/p&gt;
&lt;p&gt;I also find the idea of supporting certain companies by buying shares very exciting. For companies, the stock market is a good opportunity to get interest-free capital to invest. Alternatively, the company would have to apply for an interest-bearing loan from a bank. To a certain extent, I can invest in companies that I find great. I like companies with the topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Green Energy: Companies that promote the expansion and development of renewable energies such as solar panels or wind turbines.&lt;/li&gt;
&lt;li&gt;Quality Food: I am a strong supporter of high quality food and I like the topics like organic, regional, fair trade.&lt;/li&gt;
&lt;li&gt;US Tech Companies: As a software developer, I naturally know a lot about tech companies and how useful and valuable they are to humanity.&lt;/li&gt;
&lt;li&gt;Non-US Tech Companies: Being from Germany myself, I would specifically like to support tech companies in the EU area.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And I can actively decide against companies with certain topics like fossil fuels or alcohol as a fun drink. These were my personal topics and they can look completely different for you, which is also ok.&lt;/p&gt;
&lt;p&gt;In the next section I explain how I invest in stocks with &lt;a href=&quot;https://trading212.com/invite/GvP8w4UF&quot;&gt;Trading212&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Trading212&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://trading212.com/invite/GvP8w4UF&quot;&gt;Trading212&lt;/a&gt; is an internet platform for investing in stocks. Trading212 advertises that it does not charge a commission, which makes the platform very attractive. If you use a broker, they usually charge a commission. Trading212 also have an iOS and Android app and of course a web interface.&lt;/p&gt;
&lt;p&gt;I myself use the Trading212 ios app as well as the web interface and am very satisfied. It makes it very easy to invest in stocks and track their performance over the long term. Depositing and withdrawing from my bank account to my Trading212 account is also very easy and fast.&lt;/p&gt;
&lt;p&gt;Last year (2020) a great feature called &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;Pie&lt;/a&gt; was released. With this it is possible to create so called Pies in which you can create up to 50 shares. Each share can then be assigned to a certain percentage value. In the sum all percentage values result then naturally again 100%. If you want to know what else the Pies can do just click &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I find the Pies great because they help with my low risk strategy and give me a great overview of how my broad portfolio is developing. I also like the &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;AutoInvest&lt;/a&gt; feature where I can pay a certain amount into the Pie every month.&lt;/p&gt;
&lt;p&gt;Quite recently, the &quot;Share Pie&quot; feature has been added. With this feature you can share the created pies and others can see how my pie looks like, i.e. in which shares and how many percent I have invested. Concrete amounts of money are not revealed. And this &lt;a href=&quot;https://trading212.com/pies/l7iYcKopcsn4QkND915c7ISopbU5&quot;&gt;here&lt;/a&gt; is my Pie with a diverse choice of stocks and companies I want to support.&lt;/p&gt;
&lt;p&gt;Even though the range of available stocks to invest in at Trading212 is very large, it happened once or twice that my desired stock was not available. In such a case, however, you can ask in the &lt;a href=&quot;https://community.trading212.com/&quot;&gt;Trading212 Community Forum&lt;/a&gt; to include the respective share in the portfolio of Trading212.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://community.trading212.com/&quot;&gt;Trading212 Forum Community&lt;/a&gt; is the perfect place if you want to learn more about trading with Trading212 and in general. The community there has been very supportive in my investment strategy for which I am very grateful. Recently Trading212 has also added a &lt;a href=&quot;https://discord.gg/yWy9scvP&quot;&gt;Discord Channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also great is that Trading212 offers free webinars on trading on their platform (so apps too) as well as on &lt;a href=&quot;https://youtube.com/user/Trading212&quot;&gt;YouTube&lt;/a&gt;. In the next section I explain my investment strategy.&lt;/p&gt;
&lt;h1&gt;My strategy&lt;/h1&gt;
&lt;p&gt;I want to invest long term (more than 10 years) in many different sectors like IT, materials, energy etc. What sectors there are and what they mean you can find &lt;a href=&quot;https://corporatefinanceinstitute.com/resources/knowledge/finance/the-sp-sectors/&quot;&gt;here&lt;/a&gt;. Investing money in many different sectors instead of one specific sector reduces the risk of loss because these sectors are more independent from each other than one sector would be. If you look at the Corona crisis, for example, you see that the IT sector did not suffer as much as real estate, for example.&lt;/p&gt;
&lt;p&gt;Modern internet platforms like &lt;a href=&quot;https://trading212.com/invite/GvP8w4UF&quot;&gt;Trading212&lt;/a&gt; allow to do without the middle man like the broker, who usually charges a commission, because well designed platforms make it very easy to take care of your portfolio yourself.&lt;/p&gt;
&lt;p&gt;Furthermore, I would like to deposit a part of my monthly income automatically with &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;AutoInvest&lt;/a&gt; into my &lt;a href=&quot;https://helpcentre.trading212.com/hc/en-us/articles/360009313957-Pies-AutoInvest-Introduction&quot;&gt;Pie&lt;/a&gt;. This way I can build up a good reserve over the years without much effort.
I start with 100€ which will be transferred automatically every month and increase this amount in the future if necessary.&lt;/p&gt;
&lt;p&gt;Since I am still quite new in the subject of shares, I will invest about 20-30% of the portfolio into &lt;a href=&quot;https://en.wikipedia.org/wiki/Exchange-traded_fund&quot;&gt;ETFs&lt;/a&gt;. And as my experience increases over time, swap out the ETFs for regular stocks. ETFs are managed by professional traders and this management of course costs something. My long term goal is to do without ETFs completely, because Trading212 with the Pies allows me to manage my own ETFs and I can save the costs.&lt;/p&gt;
&lt;h1&gt;Outlook&lt;/h1&gt;
&lt;p&gt;I am already very satisfied with my current selection of stocks and will probably only make minimal improvements. Then I would swap stocks and ETFs that are not performing so well for more promising ones. Let&apos;s see.&lt;/p&gt;
&lt;p&gt;My investments are so far mainly concentrated on the American, German and British stock market and I should think about making my portfolio even more diverse and invest in other stock markets and how exactly I split into these.&lt;/p&gt;
&lt;p&gt;I am very excited about the &quot;Pies in Pie&quot; feature that would simplify the management of my portfolio even more. Currently I still need an Excel spreadsheet to keep track of how much I have invested in which sectors. With Pies in Pie this would be directly readable.&lt;/p&gt;
&lt;p&gt;Also an export feature should come soon, where I can export the investments e.g. into an Excel sheet. With this I can then feed other visualization tools to make interesting analyses. But I don&apos;t have any concrete ideas yet.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Trading212 makes investing in stocks fun. It gives me all the tools I need to manage my stock portfolio myself. It&apos;s a great alternative to holding money in accounts and you learn a lot of useful things about the stock market. I think it is important and right to develop your financial intelligence. Trading212 can be your start to do just that!&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href=&quot;https://DeepL.com/Translator&quot;&gt;DeepL translater (free version)&lt;/a&gt; for helping with translating to english and saving me tons of time :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;https://github.com/mmuller88&quot;&gt;https://github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/f076440af195b1acef0fb2885b2108aa/trading.jpg</featuredImage><media:content url="https://martinmueller.dev/static/f076440af195b1acef0fb2885b2108aa/trading.jpg" medium="image"/></item><item><title><![CDATA[RC3 Summary]]></title><description><![CDATA[Hi friends of the chaos, The 37th Congress has taken place from 27 - 30 December 2020 and due to the pandemic everything was remote. So the…]]></description><link>https://martinmueller.dev/rc3-eng/</link><guid isPermaLink="false">https://martinmueller.dev/rc3-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[ccc]]></category><category><![CDATA[chaos]]></category><category><![CDATA[congress]]></category><pubDate>Tue, 05 Jan 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/468ee77a304e7901e07d5ae9dd3fb32b/rc3.JPG" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi friends of the chaos,&lt;/p&gt;
&lt;p&gt;The 37th Congress has taken place from 27 - 30 December 2020 and due to the pandemic everything was remote. So the Chaos Congress got the name RC3. This was my very first Chaos Computer Club event that I attended. How great the days were and what I experienced, I describe in the next paragraphs.&lt;/p&gt;
&lt;h1&gt;Tag 1&lt;/h1&gt;
&lt;p&gt;Visited streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;12:20 &lt;a href=&quot;https://media.ccc.de/v/rc3-11583-rc3_eroffnung&quot;&gt;#rc Eröffnung&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;13:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-729538-die_geschichte_der_corona_warn_app&quot;&gt;Die Geschichte der Corona-Warn-App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;14:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-695961-flutter_introduction_into_performant_cross_platform_development&quot;&gt;Flutter - Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;14:30 &lt;a href=&quot;https://media.ccc.de/v/rc3-578923-wie_gruende_ich_eine_genossenschaft&quot;&gt;Wie gründe ich eine Genossenschaft?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;16:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-891673-rage_against_the_machine_learning&quot;&gt;Rage Against The Machine Learning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;19:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-11337-what_the_cyberoptimists_got_wrong_-_and_what_to_do_about_it&quot;&gt;What the cyberoptimists got wrong-and what to do about it&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&apos;s December 27th, 2020, and RC3 starts at 12:20. The intro was very cool. There was a summary of the year 2020 and besides Corona many interesting and unfortunately also sad things happened to which attention was drawn. It was also shown and made clear how much effort and how many people are actually involved in making the RC3 possible. Extremely cool.&lt;/p&gt;
&lt;p&gt;The first talk I attended was 1pm &quot;The History of the Corona Warning App&quot;. It was really exciting to follow how the German Corona Warn app has evolved, as I had barely followed it. I found it very cool that the conference was remote and I was partly in 3 streams at the same time to pick the best one. That would not work in reality ^^&lt;/p&gt;
&lt;p&gt;At 14:30 my highlight stream was about &quot;How to start a cooperative?&quot;. The topic of starting a cooperative interests me a lot, as I&apos;m in the process of starting one with a few other developers. So it was really cool to learn in detail what a cooperative is and to hear about the experiences of people who have already founded one. For me it was very interesting to hear that cooperatives can probably help to save taxes in some areas and that cooperatives are probably underestimated in the general public, although they are something very great.&lt;/p&gt;
&lt;p&gt;I attended many other streams on the day and it&apos;s always great to see people so excited to present about their topics.&lt;/p&gt;
&lt;p&gt;Also extremely cool and fun and awesome was RC3 World which is a digitized two-dimensional world of the RC3 fairgrounds and more. You create a little avatar there and walk around with many others in a 2 d world. You can also talk to the others and gaze at each other via webcam if you get close enough. Extremely funny and cool. Among other things, the Chaos Spaces of Germany were modeled in the world and the &lt;a href=&quot;https://hacklabor.de&quot;&gt;Hacklabor&lt;/a&gt; is very well done (see cover picture).&lt;/p&gt;
&lt;h1&gt;Tag 2&lt;/h1&gt;
&lt;p&gt;Visited streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;11:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-110705-datenkanal&quot;&gt;Daten : IT bei der Polizei&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;12:20 &lt;a href=&quot;https://media.ccc.de/v/rc3-11430-scientific_literacy_101&quot;&gt;Scientific Literacy 101&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;13:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-4-mundhalle&quot;&gt;Mundhalle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;14:20 &lt;a href=&quot;https://media.ccc.de/v/rc3-518497-flutter_an_advanced_view_on_cross_platform_app_development&quot;&gt;Flutter - An advanced view on cross-platform app development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;15:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-990369-hackergenossenschaft_als_plattform_chaosnahen_wirtschaftens&quot;&gt;Hackergenossenschaft Plattform chaosnahen Wirtschaftens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;19:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-10-gesundheit_ist_eine_soziale_frage&quot;&gt;Gesundheit ist eine soziale Frage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today is Monday and the second day of rC3. My highlight stream today was the 15:00 &quot;Hacker cooperative as a platform for chaos-related business&quot; . Being in the process of starting a cooperative myself, it&apos;s highly exciting to hear about it. I found it a bit disturbing that the hacker cooperative presented there took a year to found the cooperative. I think that has a lot to do with the bureaucracy in Germany. However, I am optimistic that our cooperative will be founded more quickly.&lt;/p&gt;
&lt;p&gt;Also very exciting was the 19:00 &quot;Health is a social question&quot; talks, which showed very nicely how the current German health system is ailing. E.g. that prevention plays a rather subordinate role. It also made me think about why patients are actually released back into their environment, which has made them so ill. This is exactly where one should actually start and address the environment / the living conditions of the patient.&lt;/p&gt;
&lt;h1&gt;Tag 3&lt;/h1&gt;
&lt;p&gt;Visited streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;11:05 Digitales Ehrenamt meets Deutsche Stiftung fuer Engagement und Ehrenamt met&lt;/li&gt;
&lt;li&gt;13:00 &lt;a href=&quot;https://media.ccc.de/v/rc3-2020-157-offene-daten-fr-viele-nutzbar-machen&quot;&gt;Offene Daten für Viele Nutzbar machen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today I didn&apos;t have that much time to watch streams because I was working on projects. In the evening I did some socialising at the rC3 World. I met some cool dudes from the Rostock Space. I realized that I know some of them from my time as a student in Rostock. The rC3 World collapsed at some point and it took a long time until it was available again.&lt;/p&gt;
&lt;h1&gt;Day 4&lt;/h1&gt;
&lt;p&gt;Today I couldn&apos;t visit any streams because I had to do a lot at work. But I was able to spend some time with friends in the world and watch some streams.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Many thanks to the organizers and contributors of rC3. It was my very first Chaos Computer Club event and it just knocked my socks off. There were many exciting streams and the world was awesome. For the fact that this was the first rC3, the relatively frequent technical marbles / failures are definitely forgivable.&lt;/p&gt;
&lt;p&gt;Anyhow I hope for 2021 the C3 will take place in person again, but if not the rC3 is a great alternative! Thanks also to my buddy and experienced C3 congress visitor for all the little tips and the fun get-togethers that made my rC3 experience great :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/468ee77a304e7901e07d5ae9dd3fb32b/rc3.JPG</featuredImage><media:content url="https://martinmueller.dev/static/468ee77a304e7901e07d5ae9dd3fb32b/rc3.JPG" medium="image"/></item><item><title><![CDATA[Raspberry 4 IOT with AWS CDK Pipeline automated Deployment]]></title><description><![CDATA[Hi Raspberry Friends. Note: I have used commission links in this article and marked them with "*". Since recently I can call myself owner of…]]></description><link>https://martinmueller.dev/rasp4-eng/</link><guid isPermaLink="false">https://martinmueller.dev/rasp4-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2021]]></category><category><![CDATA[aws]]></category><category><![CDATA[raspberry]]></category><category><![CDATA[cdk]]></category><pubDate>Sat, 02 Jan 2021 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/e6278e400326b820a0c166be700e27e0/rasp.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi Raspberry Friends.&lt;/p&gt;
&lt;p&gt;Note: I have used commission links in this article and marked them with &quot;*&quot;.&lt;/p&gt;
&lt;p&gt;Since recently I can call myself owner of a Raspberry. On Cyber Monday I bought a *&lt;a href=&quot;https://amzn.to/3rD3HOf&quot;&gt;Raspberry 4 with 4 GB&lt;/a&gt;. I have had previous experiences with Home IOT and summarized them in a &lt;a href=&quot;https://martinmueller.dev/smart-home&quot;&gt;blogpost&lt;/a&gt;. However, these experiences were tied to ready-made IOT solutions and therefore give only a limited feature set. A good friend of mine, who has a lot of experience with Home IOT (Internet of Things), showed me what more is possible.&lt;/p&gt;
&lt;p&gt;So I aimed for the next IOT level with building cool solutions using MQTT and NodeRED. My first use case is that I want to read the gas meter digitally and get nice evaluation graphics displayed in relation to time. On the internet I found a tutorial how to read my gas meter, digitally supported &lt;a href=&quot;https://forum.iobroker.net/topic/27960/gasz%C3%A4hler-bk-g4-auslesen-mit-zigbee-fensterkontakt&quot;&gt;BK-G4&lt;/a&gt;. But this solution required a complex NodeRED deployment with the use of a Raspberry.&lt;/p&gt;
&lt;p&gt;The Raspberry can be treated like a normal VM. That means it is loaded with an operating system like Ubuntu. Then necessary programs are installed and afterwards the NodeRED Deployment is executed. If needed, the VM can simply be thrown away and everything run again. This is a lot of manual steps which can be very time consuming and error prone.&lt;/p&gt;
&lt;p&gt;Therefore, I decided to automate the entire deployment to a high degree using the following technologies GitHub, Docker, Docker Compose, AWS CodeDeploy Agent, AWS CodePipeline with CDK Pipeline. Basically, then all you need to do is push to the main branch and the entire Docker deployment builds and launches itself.&lt;/p&gt;
&lt;p&gt;I will describe how this all works in the next sections.&lt;/p&gt;
&lt;h1&gt;Setup&lt;/h1&gt;
&lt;p&gt;First, however, I would like to describe my setup. As mentioned before, I bought a Raspberry 4 (Rasp4 for short) with 4GB for Cyber-Monday *&lt;a href=&quot;https://amzn.to/3rD3HOf&quot;&gt;https://amzn.to/3rD3HOf&lt;/a&gt;. Furthermore there was a 64GB microSSD in the set.&lt;/p&gt;
&lt;p&gt;The installation of Ubuntu 20.04.1 was very easy and is very well documented on &lt;a href=&quot;https://ubuntu.com/download/raspberry-pi&quot;&gt;ubuntu.com&lt;/a&gt; . I chose the Ubuntu server because I want to use the Rasp4 as a headless remote VM.&lt;/p&gt;
&lt;p&gt;To read the gas meter I needed two more components. A *&lt;a href=&quot;https://amzn.to/37Vsm8S&quot;&gt;Zigbee door/window sensor&lt;/a&gt; and a &lt;a href=&quot;https://amzn.to/3hrc7nd&quot;&gt;Zigbee USB stick as receiver&lt;/a&gt;. The sensor sends a signal to the Zigbee receiver every time the meter measures 0.1 sq ft of gas consumption. This is a specific solution for my gas meter &lt;a href=&quot;https://forum.iobroker.net/topic/27960/gasz%C3%A4hler-bk-g4-auslesen-mit-zigbee-fensterkontakt&quot;&gt;BK-G4&lt;/a&gt;. It may not be possible for your gas meter.&lt;/p&gt;
&lt;h2 id=&quot;installation-of-the-environment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#installation-of-the-environment&quot; aria-label=&quot;installation of the environment permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Installation of the environment&lt;/h2&gt;
&lt;p&gt;The IOT programs are to be run using Docker Compose and deployed from my &lt;a href=&quot;https://github.com/mmuller88/rasp4&quot;&gt;GitHub Repo&lt;/a&gt; the Docker Compose YAML file. Furthermore, the Docker Compose deployment should be automatically rebuilt and redeployed as soon as something is pushed to the main branch.&lt;/p&gt;
&lt;p&gt;To make all this possible many programs like Docker, Docker Compose, Git, AWS CLI, AWS CodeDeploy Agent etc, are needed. To simplify the installation of the required programs I created a script &lt;a href=&quot;https://github.com/mmuller88/rasp4/blob/master/misc/init.sh&quot;&gt;./misc/init.sh&lt;/a&gt;. This is then simply executed on the Rasp4:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;sudo chmod +x ./init.sh
./init.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Important to mention. The Rasp4 has only a one way internet connection. That means it has no public IP and is not reachable from outside. It is only reachable in the local network.&lt;/p&gt;
&lt;h2 id=&quot;automated-deployment-with-aws-codedeploy--aws-codepipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#automated-deployment-with-aws-codedeploy--aws-codepipeline&quot; aria-label=&quot;automated deployment with aws codedeploy  aws codepipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Automated Deployment with AWS CodeDeploy &amp;#x26; AWS CodePipeline&lt;/h2&gt;
&lt;p&gt;To reduce manual effort as much as possible, I decided to automate the Docker Compose deployment. For this I use an AWS CodeDeploy agent that automatically registers changes on the main branch and executes them on the Rasp4. The installation of the AWS CodeDeploy agent was a bit tricky but worked out in the end. The agent is also installed with the init.sh.&lt;/p&gt;
&lt;p&gt;To have the agent perform actions on the Rasp4 when commits happen on the main branch, an AWS CodePipeline must be created. The AWS CodePipeline is configured and managed with &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt; . AWS CDK is an open source framework for creating and managing AWS resources using high level languages like TypeScript or Python. The AWS CDK code can also be found in my GitHub repo and &lt;a href=&quot;https://github.com/mmuller88/rasp4/blob/master/src&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If I made you curious about AWS CDK, you can find countless other blogposts about &lt;a href=&quot;https://martinmueller.dev/tags/cdk&quot;&gt;AWS CDK&lt;/a&gt; on my blog page.&lt;/p&gt;
&lt;h2 id=&quot;iot-docker-compose-stack&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#iot-docker-compose-stack&quot; aria-label=&quot;iot docker compose stack permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;IOT Docker Compose Stack&lt;/h2&gt;
&lt;p&gt;My IOT stack consists of the following containers NodeRED, InfluxDB, Grafana, Mosquitto and Zigbee. The exact settings are in the &lt;a href=&quot;https://github.com/mmuller88/rasp4/blob/master/docker-compose.yml&quot;&gt;docker-compose&lt;/a&gt; file . I assembled the stack using the Docker Compose Builder from &lt;a href=&quot;https://github.com/gcgarner/IOTstack&quot;&gt;IOTstack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I recommend you use one of the forks from IOTstack as the user gcgarner doesn&apos;t seem to maintain the builder anymore.&lt;/p&gt;
&lt;h1&gt;What did I enjoy the most?&lt;/h1&gt;
&lt;p&gt;Extremely cool was the easy installation of Ubuntu on my Rasp4. This even worked without an extra keyboard and monitor and is called remote installation. You just have to enter the wifi credentials during the image creation on the microSSD card. This simple process reminded me somehow of Docker images, which are also very light on their feet. Extremely cool!&lt;/p&gt;
&lt;p&gt;It also happened a few times that I reloaded the entire OS to solve configuration issues. Since I had all the steps of the installation in init.sh, that was no problem.&lt;/p&gt;
&lt;p&gt;Also, creating the AWS CodePipeline with AWS CDK was extremely cool. Since I already have a lot of experience with AWS CDK, it was very easy to do. Infrastructure as code is just great!&lt;/p&gt;
&lt;h1&gt;Difficulties&lt;/h1&gt;
&lt;p&gt;Setting up the AWS CodeDeploy agent was very time consuming and annoying, as it only works with certain program versions of awscli or ruby. To this day I&apos;m not sure why the agent always bitched so much. Well it works now and that&apos;s what counts.&lt;/p&gt;
&lt;h1&gt;Outlook&lt;/h1&gt;
&lt;p&gt;I have already started with the NodeRED Flow and can successfully read out the Zigbee door sensor and increase the digital meter reading with every signal. What is missing now is feeding into InfluxDB and configuring Grafana to get nice evaluation graphs for desired time periods.&lt;/p&gt;
&lt;p&gt;Also, in the future I want to work on even more exciting IOT stuff with cool use cases. I&apos;m thinking about migrating some IOT processes from my Smart Life app to my NodeRED.&lt;/p&gt;
&lt;p&gt;The Rasp4 itself offers even more possibilities than just being used as an IOT server. For example, I already use it as a DNS server with &lt;a href=&quot;https://github.com/pi-hole/pi-hole&quot;&gt;Pi-Hole&lt;/a&gt;. With this it blocks e.g. nervice DNS queries like telemetry data or advertisements. For sure I will find more cool use cases for my Rasp4.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;IOT is an exciting topic. Ready-made solutions like Smart Life, Alexa and co are easy to install and promise early the desired success. However, such ready-made solutions are mostly very limited in functionality. So far, I have made good progress with Smart Life.&lt;/p&gt;
&lt;p&gt;However, the task of reading the gas meter automatically has called for a more complex IOT solution with a Raspberry and NodeRED Flow. I described how this solution looks like here. I had an incredible amount of fun working on this IOT project and I am extremely grateful to my IOT buddy :D for spending the time to bring me closer to the IOT topic.&lt;/p&gt;
&lt;p&gt;Did you find the article interesting or do you have any questions? Feel free to write me :) .&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/e6278e400326b820a0c166be700e27e0/rasp.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/e6278e400326b820a0c166be700e27e0/rasp.jpeg" medium="image"/></item><item><title><![CDATA[ALPS Helper Library]]></title><description><![CDATA[Hi :). The new ALPS Converter I developed makes it possible to convert an ALPS specification (spec short) to OpenApi, GraphQL or other APIs…]]></description><link>https://martinmueller.dev/alps-unified-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alps-unified-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[swagger]]></category><category><![CDATA[cdk]]></category><category><![CDATA[alps]]></category><category><![CDATA[openapi]]></category><category><![CDATA[projen]]></category><pubDate>Sat, 19 Dec 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c004f8ddcfefc759aafb44af4071674e/alps-u.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi :).&lt;/p&gt;
&lt;p&gt;The new &lt;a href=&quot;https://github.com/mmuller88/alps-unified-ts&quot;&gt;ALPS Converter&lt;/a&gt; I developed makes it possible to convert an ALPS specification (spec short) to OpenApi, GraphQL or other APIs.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Alps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FormatType &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alps-unified-ts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// loaded from a YAML file&lt;/span&gt;
Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadYaml&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;todo-alps.yaml&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; formatType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FormatType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;OPENAPI&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Other great features of my ALPS unified library are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;automatic versioned releasing to &lt;a href=&quot;https://npmjs.com&quot;&gt;NPM&lt;/a&gt;, &lt;a href=&quot;https://pypi.com&quot;&gt;PyPi&lt;/a&gt;, &lt;a href=&quot;https://maven-central.com&quot;&gt;Maven&lt;/a&gt; and &lt;a href=&quot;https://nuget.com&quot;&gt;Nuget&lt;/a&gt; (for .NET).&lt;/li&gt;
&lt;li&gt;Type support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The GitHub project were created using &lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt;. I will discuss what the ALPS Api and Projen is in more details in the next sections.&lt;/p&gt;
&lt;h1&gt;ALPS API&lt;/h1&gt;
&lt;p&gt;ALPS is a specification for describing the context of a service. ALPS can be used as specification input to generate low abstracted specifications like OpenApi / Swagger, WSDL, RAML, WADL.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/mmuller88/alps-unified-ts&quot;&gt;ALPS Converter&lt;/a&gt; converts an ALPS Api Spec into lower abstracted Api specifications. An example of such a conversion follows in the next section.&lt;/p&gt;
&lt;h2 id=&quot;alps-api-spec-example&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#alps-api-spec-example&quot; aria-label=&quot;alps api spec example permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ALPS API Spec Example&lt;/h2&gt;
&lt;p&gt;The following example is a simple TODO ALPS API Spec.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;
&lt;span class=&quot;token key atrule&quot;&gt;alps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1.0&apos;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Simple Todo list example&apos;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;####################################&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# metadata&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; metadata
      &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; title
      &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; simpleTodo
      &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;oas&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; metadata
      &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; id
      &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; http&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//alps.io/profiles/mamund/simpleTodo
      &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;oas&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; metadata
      &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; root 
      &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; http&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//api.example.org/todo
      &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;oas&apos;&lt;/span&gt;
  
  &lt;span class=&quot;token key atrule&quot;&gt;descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# properties&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# - these are the data elements&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; id
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; semantic
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; storage id of todo item
      
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; body
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; semantic
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; content of todo item

    &lt;span class=&quot;token comment&quot;&gt;# groupings&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# - these are the storage objects&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoItem
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; group
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todo item
      &lt;span class=&quot;token key atrule&quot;&gt;descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#id&apos;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#body&apos;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# actions&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# - these are the operations&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoList
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; safe
      &lt;span class=&quot;token key atrule&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoItem
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; return list of todo items
            
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoAdd
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unsafe
      &lt;span class=&quot;token key atrule&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoItem
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; create a new todo item
      &lt;span class=&quot;token key atrule&quot;&gt;descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#todoItem&apos;&lt;/span&gt;
      
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoRemove
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; idempotent
      &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; delete
      &lt;span class=&quot;token key atrule&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoItem
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; remove a single todo item
      &lt;span class=&quot;token key atrule&quot;&gt;descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#id&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The element &lt;strong&gt;todoItem&lt;/strong&gt; consists of an &lt;strong&gt;id&lt;/strong&gt; and a todo string &lt;strong&gt;body&lt;/strong&gt; . Three actions are defined &lt;strong&gt;todoList&lt;/strong&gt; to list the todo items, &lt;strong&gt;todoAdd&lt;/strong&gt; to insert new todos and &lt;strong&gt;todoRemove&lt;/strong&gt; to delete todo items.&lt;/p&gt;
&lt;p&gt;From these, the Unified Convertor can generate this OpenApi specification:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;openapi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3.0.1

&lt;span class=&quot;token comment&quot;&gt;# *******************************************************************&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# generated by &quot;unified&quot; from src/todo-alps.yaml&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# date: Wed Nov 25 2020 18:47:05 GMT+0100 (Central European Standard Time)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# http://github.com/mamund/2020-11-unified&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# *******************************************************************&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; simpleTodo
  &lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Simple Todo list example
  &lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.0.0

&lt;span class=&quot;token key atrule&quot;&gt;servers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http://api.example.org/todo&apos;&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;/todoList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;return list of todo items&apos;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;operationId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoList
      &lt;span class=&quot;token key atrule&quot;&gt;responses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoList
          &lt;span class=&quot;token key atrule&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token key atrule&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; array
                &lt;span class=&quot;token key atrule&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                  &lt;span class=&quot;token key atrule&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#/components/schemas/todoItem&apos;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;/todoAdd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;create a new todo item&apos;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;operationId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoAdd
      &lt;span class=&quot;token key atrule&quot;&gt;requestBody&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token key atrule&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#/components/schemas/todoItem&apos;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;responses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; add todoAdd
          &lt;span class=&quot;token key atrule&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token key atrule&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; array
                &lt;span class=&quot;token key atrule&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                  &lt;span class=&quot;token key atrule&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#/components/schemas/todoItem&apos;&lt;/span&gt;
  /todoRemove/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;remove a single todo item&apos;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;operationId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoRemove
      &lt;span class=&quot;token key atrule&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; id
          &lt;span class=&quot;token key atrule&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; path
          &lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; id of todoRemove
          &lt;span class=&quot;token key atrule&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string
      &lt;span class=&quot;token key atrule&quot;&gt;responses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;204&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; delete todoRemove

&lt;span class=&quot;token key atrule&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;schemas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;todoItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todo item
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; object
      &lt;span class=&quot;token key atrule&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string
            &lt;span class=&quot;token key atrule&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4572&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string
            &lt;span class=&quot;token key atrule&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; jn1ov7axj4kv560d0921xf&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or in GraphQL schema:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ql&quot;&gt;&lt;pre class=&quot;language-ql&quot;&gt;&lt;code class=&quot;language-ql&quot;&gt;# *******************************************************************
# generated by &amp;quot;unified&amp;quot;
# date: Fri Dec 11 2020 16:51:00 GMT+0100 (Central European Standard Time)
# http://github.com/mamund/2020-11-unified
# *******************************************************************

type todoItem {
  id: String!
  body: String!
}

type Query {
  todoList: [todoItem]
}

type Mutation {
  todoAdd(todoItem: String!): todoItem
  todoRemove(id: String!): todoItem
}

schema {
  query: Query,
  mutation: Mutation
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Projen&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt; allows sophisticated management of project configuration files through code. With just a few lines of TypeScript code, an entire repository can be configured. Here is an example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; JsiiProject &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;projen&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; project &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsiiProject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alps-unified-ts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  authorAddress&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;damadden88@googlemail.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  authorName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Martin Mueller&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

project&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;synth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These few lines create all the GitHub project files your heart desires. Among them the package.json, .gitignore, tsconfig.json and many many more.&lt;/p&gt;
&lt;p&gt;What&apos;s really cool is that Projen also comes with GitHub workflows that can publish new versions to registries like NPM or PYPI.&lt;/p&gt;
&lt;p&gt;I fell in love with the Projen framework as it is a great abstraction and default for a setup of projects. I encourage you to give Projen a try and very soon you will experience the beauty of this framework yourself.&lt;/p&gt;
&lt;h1&gt;ALPS Library in Action&lt;/h1&gt;
&lt;p&gt;Here I would like to briefly introduce my new ALPS Unified Library. The TypeScript package can be used like this&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Alps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FormatType &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alps-unified-ts&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// loaded from a YAML file&lt;/span&gt;
Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadYaml&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./spec/todo-alps.yaml&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; formatType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FormatType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;OPENAPI&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// or directly via TypeScript Object&lt;/span&gt;
Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    alps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      version&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1.0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      doc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Simple Todo list example&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;Alps.unified(...)&lt;/strong&gt; function always returns a string. Depending on the &lt;strong&gt;formType&lt;/strong&gt; the returned string contains the desired format. In our example this is &lt;strong&gt;FormType.OPENAPI&lt;/strong&gt; which is OpenApi in YAML. If you would now like to have OpenAPI returned in JSON, FormatType.OPENAPI_JSON would also work. For rendering the Graph QL schema you would have to use FormatType.DSL.&lt;/p&gt;
&lt;p&gt;In Python, the library can be used like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; alps_unified_ts &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; alps

alps_def &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AlpsDef&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  version&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;1.0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
  descriptor&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DescriptorDef&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;semantic&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;sotrage id of todo item&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
  doc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DocDef&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    value&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Simple Todo list example&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
    ext&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ExtDef&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
        tags&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;oas&quot;&lt;/span&gt; 
        &lt;span class=&quot;token builtin&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
        value&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;http://api.example.org/todo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ExtDef&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
        tags&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;oas&quot;&lt;/span&gt; 
        &lt;span class=&quot;token builtin&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
        value&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;simpleTodo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

alps_converted &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;unified&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;alps_document&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;spec&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;alps&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;alps_def&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; format_type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;FormatType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OPENAPI&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using it in Java and .NET should look similar.&lt;/p&gt;
&lt;p&gt;In my previous blogpost &lt;a href=&quot;https://martinmueller.dev/alps-cdk-eng&quot;&gt;ALPS combined with CDK&lt;/a&gt;, I explain how to optionally create an AWS Api Gateway or AWS Appsync from an ALPS Spec using the ALPS Todo example and the ALPS unified library.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Building a library with &lt;a href=&quot;https://github.com/projen/projen&quot;&gt;Projen&lt;/a&gt; was super fun! I used it to build a new, improved version of the alps unified library. It now comes with super cool new features that I introduced here.&lt;/p&gt;
&lt;p&gt;By the way, one more info. If you are also interested in the ALPS topic, with the &lt;a href=&quot;https://alps.io&quot;&gt;ALPS Community&lt;/a&gt; we regularly organize community meetings online. There you can meet exciting people from all over the world. Feel free to come by :) .&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/c004f8ddcfefc759aafb44af4071674e/alps-u.png</featuredImage><media:content url="https://martinmueller.dev/static/c004f8ddcfefc759aafb44af4071674e/alps-u.png" medium="image"/></item><item><title><![CDATA[ALPS API combined with AWS CDK]]></title><description><![CDATA[Hi :). AWS offers many exciting Api technologies. Those include the AWS Api Gateway which is an implementation of a REST Api or AWS Appsync…]]></description><link>https://martinmueller.dev/alps-cdk-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alps-cdk-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[swagger]]></category><category><![CDATA[cdk]]></category><category><![CDATA[alps]]></category><category><![CDATA[openapi]]></category><pubDate>Mon, 14 Dec 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/a94dab226046a9ef49446f469d7a3a5c/alps.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi :).&lt;/p&gt;
&lt;p&gt;AWS offers many exciting Api technologies. Those include the AWS Api Gateway which is an implementation of a REST Api or AWS Appsync which implements a GRAPH QL Api.&lt;/p&gt;
&lt;p&gt;Each of these AWS Api implementations has its advantages and disadvantages. For example, Appsync can be faster to build than the Api Gateway, but then again it gets more complicated when creating queries to the Graph QL. Admittedly, I don&apos;t know enough to weigh the pros and cons of the different Api implementations in AWS, but I don&apos;t have to anymore!&lt;/p&gt;
&lt;p&gt;With my exciting work with ALPS in combination with AWS CDK, I can make the Api freely selectable or even interchangeable and all based on an ALPS specification (Spec for short). As AWS says itself. Choice Matter! :)&lt;/p&gt;
&lt;p&gt;What exactly an ALPS Spec is and how Api implementations like Api Gateway or Appsync can be created from it, I will explain in the next sections.&lt;/p&gt;
&lt;h1&gt;ALPS Api&lt;/h1&gt;
&lt;p&gt;ALPS is a specification to describe the context of a service. ALPS can be used as specification input to generate low abstracted specifications like OpenApi / Swagger, WSDL, RAML, WADL.&lt;/p&gt;
&lt;p&gt;When I saw the &lt;a href=&quot;https://www.youtube.com/watch?v=oG6-r3UdenE&quot;&gt;YouTube video&lt;/a&gt; with &lt;a href=&quot;https://twitter.com/mamund&quot;&gt;Mike Amundsen&lt;/a&gt;, I immediately thought the idea of ALPS was cool and exciting. Like any good developer I love abstractions and ALPS seems to be an extremely cool abstraction. I immediately had the idea to connect the ALPS Api with an AWS CDK construct. That&apos;s exactly what I did and I tell more in details about it in the next section.&lt;/p&gt;
&lt;h1&gt;AWS CDK ALPS Constructs&lt;/h1&gt;
&lt;p&gt;AWS CDK Constructs are, in short, source code for deploying resources or services in AWS. For this it uses abstract languages like TypeScript or Python and generates cloudformation templates from the code which are then also applied. If you are interested in the topic of AWS CDK, I have written a lot of posts about &lt;a href=&quot;https://martinmueller.dev/tags/cdk&quot;&gt;CDK here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So my goal was to have targeted AWS Apis like Api Gateway and Appsync built using an ALPS specs. Below, I first show an ALPS Spec example. Then I describe the construct where I generate an AWS Api Gateway from an ALPS Spec. After that, an Appsync is built from the same ALPS Spec.&lt;/p&gt;
&lt;p&gt;The two subsequent libraries are automatically released after &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;NPM&lt;/a&gt; (for JavaScript and TypeScript) and &lt;a href=&quot;https://pypi.org/&quot;&gt;PYPI&lt;/a&gt; (for Python). In the future I also plan to publish to a public Maven repository and .Net package repository.&lt;/p&gt;
&lt;h2 id=&quot;alps-spec-example&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#alps-spec-example&quot; aria-label=&quot;alps spec example permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ALPS Spec Example&lt;/h2&gt;
&lt;p&gt;The following example is a simple TODO list api.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;
&lt;span class=&quot;token key atrule&quot;&gt;alps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1.0&apos;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Simple Todo list example&apos;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;####################################&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;# metadata&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; metadata
      &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; title
      &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; simpleTodo
      &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &apos;oas
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; metadata
      &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; id
      &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; http&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//alps.io/profiles/mamund/simpleTodo
      &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;oas&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; metadata
      &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; root 
      &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; http&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//api.example.org/todo
      &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;oas&apos;&lt;/span&gt;
  
  &lt;span class=&quot;token key atrule&quot;&gt;descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# properties&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# - these are the data elements&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; id
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; semantic
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; storage id of todo item
      
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; body
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; semantic
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; content of todo item

    &lt;span class=&quot;token comment&quot;&gt;# groupings&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# - these are the storage objects&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoItem
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; group
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todo item
      &lt;span class=&quot;token key atrule&quot;&gt;descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#id&apos;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#body&apos;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# actions&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# - these are the operations&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoList
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; safe
      &lt;span class=&quot;token key atrule&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoItem
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; return list of todo items
            
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoAdd
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; unsafe
      &lt;span class=&quot;token key atrule&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoItem
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; create a new todo item
      &lt;span class=&quot;token key atrule&quot;&gt;descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#todoItem&apos;&lt;/span&gt;
      
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoRemove
      &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; idempotent
      &lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; delete
      &lt;span class=&quot;token key atrule&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todoItem
      &lt;span class=&quot;token key atrule&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; remove a single todo item
      &lt;span class=&quot;token key atrule&quot;&gt;descriptor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#id&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;todoItem&lt;/strong&gt; element consists of an &lt;strong&gt;id&lt;/strong&gt; and a todo string &lt;strong&gt;body&lt;/strong&gt; . Three actions are defined &lt;strong&gt;todoList&lt;/strong&gt; to list the todo items, &lt;strong&gt;todoAdd&lt;/strong&gt; to insert new todos and &lt;strong&gt;todoRemove&lt;/strong&gt; to delete todo items.&lt;/p&gt;
&lt;h2 id=&quot;cdk-alps-rest-api-construct-library&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-alps-rest-api-construct-library&quot; aria-label=&quot;cdk alps rest api construct library permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CDK ALPS REST Api Construct Library&lt;/h2&gt;
&lt;p&gt;The first ALPS CDK Construct I implemented is the CDK ALPS REST Api Construct in my &lt;a href=&quot;https://github.com/mmuller88/cdk-alps-Spec-rest-api&quot;&gt;github repo&lt;/a&gt; . It creates an AWS Api Gateway using the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-apigateway.SpecRestApi.html&quot;&gt;CDK SpecRestApi Construct&lt;/a&gt;. This then just needs to be passed an openApi Spec generated from the ALPS:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; api &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;apigw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SpecRestApi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SpecRestApi&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  apiDefinition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; apigw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ApiDefinition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromInline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;oasSpecJSON&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;cdk-alps-graph-ql-api-construct-library&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-alps-graph-ql-api-construct-library&quot; aria-label=&quot;cdk alps graph ql api construct library permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CDK ALPS Graph QL Api Construct Library&lt;/h2&gt;
&lt;p&gt;The second ALPS CDK Construct was much more exciting for me, because I used AWS Appsync as Graph QL Api and it was completely new for me. But against all expectations it was very easy and I was able to finish the construct in a few hours here on &lt;a href=&quot;https://github.com/mmuller88/cdk-alps-graph-ql&quot;&gt;github&lt;/a&gt;. The ALPS compiler translates the ALPS spec into the Graph QL schema and passes it to the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-appsync.GraphqlApi.html&quot;&gt;CDK GraphqlApi Construct&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AlpsGraphQL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;appsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;GraphqlApi &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cdk&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AlpsGraphQLProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// convert ALPS yaml to graph ql schema file in tmp/schema.graphql&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sdl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadYaml&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alpsSpecFile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; formatType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FormatType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SDL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tmp/schema.graphql&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sdl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      schema&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; appsync&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tmp/schema.graphql&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;cdk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CfnOutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GraphQlUrl&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;graphqlUrl &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;cdk-demo-deployment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#cdk-demo-deployment&quot; aria-label=&quot;cdk demo deployment permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;CDK Demo Deployment&lt;/h2&gt;
&lt;p&gt;Sweet! We now have these two constructs which can generate AWS Apis from an ALPS Spec. Now we just need to do that :). For this I created a new &lt;a href=&quot;https://github.com/mmuller88/cdk-alps-constructs-demo&quot;&gt;Demo Github Repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The demo deployment uses the same ALPS Spec TODO example I already presented. DynamoDB is used to store the TODO items:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; todoTable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Table&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;TodoTable&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  removalPolicy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RemovalPolicy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DESTROY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  partitionKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AttributeType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;STRING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then the Api Gateway and Appsync are created&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AlpsSpecRestApi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;AlpsSpecRestApi&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; alpsSpecFile&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;src/todo-alps.yaml&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; graphQlApi &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AlpsGraphQL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;AlpsGraphQL&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; alpsSpecFile&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;src/todo-alps.yaml&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&apos;s it. Now just apply the CDK stack with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn build
yarn deploy [--profile X]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yeahh. So we have created an Api Gateway and an Appsync based on the ALPS Api.&lt;/p&gt;
&lt;h1&gt;Use Cases&lt;/h1&gt;
&lt;p&gt;Of course I thought about what use cases there could be for the ALPS spec abstraction. Some of them came to my mind while I was creating the CDK ALPS Constructs.&lt;/p&gt;
&lt;p&gt;I see it as an easy and safe way to migrate from Api Gateway to Appsync. For example, the resolvers for the Graph QL could use the Lambda integrations from the Rest Api, or possibly even do away with them entirely and map directly to a DB for CRUD operations.&lt;/p&gt;
&lt;p&gt;Since the ALPS spec is an abstraction of e.g. Rest Api, it should be possible for domain experts to write it themselves. It would be great if the domain specific context could be abstracted better and this could be possible with ALPS. So while the domain expert takes care of the domain specificity, the developer can work on the concrete api and its implementation. Thus, a better modular work is made possible.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;ALPS Api is a fascinating idea about abstraction from other apis like REST, Graph QL etc. Personally, it helped me understand Graph QL better as I had a common denominator by going back through the ALPS spec. Also the auto-generation of Graph QL schema is super great to understand the api better as well.&lt;/p&gt;
&lt;p&gt;I myself realized while creating the three repos that I still don&apos;t know much about the ALPS syntax and want to learn more about it. If you are also interested in the ALPS topic, please write me. With the &lt;a href=&quot;https://alps.io&quot;&gt;ALPS Community&lt;/a&gt; we regularly organize community meetings online from all over the world. There you can meet exciting people and get involved if you want :).&lt;/p&gt;
&lt;p&gt;I am already working on a refreshed library to convert the ALPS spec to the lower abstracted Apis &lt;a href=&quot;https://github.com/mmuller88/alps-unified-ts&quot;&gt;here&lt;/a&gt;. This will make it even easier to use ALPS unified as a library in your code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ts&quot;&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// loaded from a YAML file&lt;/span&gt;
Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadYaml&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; formatType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FormatType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OPENApi &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// or directly via TypeScript object&lt;/span&gt;
Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unified&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Alps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Spec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    alps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      version&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1.0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      doc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Simple Todo list example&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In addition, the library should work in JavaScript, TypeScript, Python, Java and .NET and be available through public registries. More about this will come in a separate blog post. Until then stay tuned!&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/a94dab226046a9ef49446f469d7a3a5c/alps.png</featuredImage><media:content url="https://martinmueller.dev/static/a94dab226046a9ef49446f469d7a3a5c/alps.png" medium="image"/></item><item><title><![CDATA[Thankfulness]]></title><description><![CDATA[A warm welcome, As we are now approaching the end of 2020, I would like to take this opportunity to show my gratitude. For this I would like…]]></description><link>https://martinmueller.dev/thankful-eng/</link><guid isPermaLink="false">https://martinmueller.dev/thankful-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[notech]]></category><pubDate>Tue, 08 Dec 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/968572e3c16ad0b39f871262cf34bfec/fam.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;A warm welcome,&lt;/p&gt;
&lt;p&gt;As we are now approaching the end of 2020, I would like to take this opportunity to show my gratitude. For this I would like to dedicate a whole blog post :). Even if it was different for many, for us 2020 was the best year as a family. Why this is so, you will find out when you read the whole post.&lt;/p&gt;
&lt;p&gt;In the next sections I list my thanks chronologically by my life.&lt;/p&gt;
&lt;h1&gt;God&lt;/h1&gt;
&lt;p&gt;The first and greatest thanks goes to God. He is merciful and generous. He has blessed me with a healthy mind and body, which is by no means for granted. He has accompanied me on my path of life and saved me from greater harm.&lt;/p&gt;
&lt;p&gt;Thank you God and I humbly ask you to continue to watch over me and especially over my family, friends and humanity. Just saying thanks is not enough for me! In 2021 I would like to become more involved in your church.&lt;/p&gt;
&lt;p&gt;Even if it is not always easy, you give me the strength to do so. I want to thank you my God.&lt;/p&gt;
&lt;h1&gt;Parents&lt;/h1&gt;
&lt;p&gt;Many thanks also to my mom and dad. They are two incredibly great people. And above all they are kindhearted. They have given me great values. My childhood as an outsider was certainly not easy, but with the help and affection of my family it was no problem to get through this relatively difficult time of my life.&lt;/p&gt;
&lt;p&gt;I would especially like to thank my mother, who was instrumental in my development. For her, education has always been a top priority for me and my brother. I am extremely grateful to her for this, because without this high value I might never have found my dream job as a software developer.&lt;/p&gt;
&lt;p&gt;She is a kind and strong woman. I think this has influenced me in the choice of my wife who is also kind and strong. Thanks a lot mom and dad.&lt;/p&gt;
&lt;h1&gt;Woman&lt;/h1&gt;
&lt;p&gt;For the thanks to my wife. I don&apos;t know where to begin. I have so much to be grateful for when it comes to my wife. I got to know her in England. I was there for almost two years. After an internship at Alfresco, I got a permanent position there and decided to stay in England for a longer.&lt;/p&gt;
&lt;p&gt;My wife was in England for almost a year. She is from Brazil and was eager to get to know England. When we met we immediately had a connection. Love at first sight!&lt;/p&gt;
&lt;p&gt;Then everything went relatively quickly. We moved into an apartment together and got engaged only a few months after. Since then we have been together for 3 wonderful years. Our relationship is very harmonious and I am looking forward to the many years ahead of us.&lt;/p&gt;
&lt;p&gt;Many thanks to my beautiful, smart and wonderful wife, for always being at my side and walking through the adventure of life with me. I don&apos;t want to be a day without you anymore. And also many thanks that you are such a great mother. Our daughter is so lucky that she has such a great mommy.&lt;/p&gt;
&lt;h1&gt;Child&lt;/h1&gt;
&lt;p&gt;A special thanks goes to my daughter. She is not yet able to understand this text. Let&apos;s see, maybe this blog still exists, if she can and she is perhaps happy about it. Anyway I am very proud and happy to be your father.&lt;/p&gt;
&lt;p&gt;You give me your trust every day and I accept this precious gift every day and promise to always act for your best. Thank you so much for letting me be your father.&lt;/p&gt;
&lt;h1&gt;To all Others&lt;/h1&gt;
&lt;p&gt;Here I would like to thank everyone who deserves an own section but then the mail would be extremely long.&lt;/p&gt;
&lt;p&gt;A special thanks goes to my brother. He played and plays an important role in my life. We grew up together and were best friends. We went through thick and thin together during kindergarten and sometimes even at school. Many thanks.&lt;/p&gt;
&lt;p&gt;Many thanks also to my non core family like my aunts and uncles and my grandparents. We owe you so incredibly much. You have helped my wife and me a lot with the move to Germany. You have supported us so much in buying a house. Furthermore, the many small supports like clothes for Rebecca and the many small gifts were extremely helpful. Thanks a lot for your help.&lt;/p&gt;
&lt;p&gt;I would also like to thank my family from Brazil. I had the luck to visit them in Brazil in 2018 and hope to do so again in 2021.&lt;/p&gt;
&lt;p&gt;As well thank you to my former colleagues from Alfresco and Object. They have shaped me a lot and made me a better developer.&lt;/p&gt;
&lt;p&gt;We have only recently started living in the beautiful city called Ludwigslust. Not far from us we have found a great young family with whom we like to spend time. They are kind people and loving parents. Thank you very much that you are here and that we can have you as friends.&lt;/p&gt;
&lt;p&gt;At the very beginning I thanked God. I also want to thank God&apos;s church here in Ludwigslust. For me, the Landeskirchliche Gemeinschaft Ludwigslust  (church community) is a valuable community with the goal of doing good and proclaiming God&apos;s word. Thank you very much for letting me be your member.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Gratitude is a great thing and makes life more beautiful. It creates a positive feeling for the person to whom the gratitude is directed and for the one who expresses it. I hope you liked this slightly different stem anyway. Write me what you are thankful for.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/968572e3c16ad0b39f871262cf34bfec/fam.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/968572e3c16ad0b39f871262cf34bfec/fam.jpeg" medium="image"/></item><item><title><![CDATA[Optimised Fasting]]></title><description><![CDATA[Hi Low Carber :) In the last few months I have successfully lost a lot of weight with Optimised Fasting. Per week I have lost about 50…]]></description><link>https://martinmueller.dev/optimised-fasting-eng/</link><guid isPermaLink="false">https://martinmueller.dev/optimised-fasting-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[optimised]]></category><category><![CDATA[water]]></category><category><![CDATA[fasting]]></category><category><![CDATA[ketosis]]></category><pubDate>Sat, 28 Nov 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/bb32897db8ddbbe22af9c5aeeff2a071/opt.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi Low Carber :)&lt;/p&gt;
&lt;p&gt;In the last few months I have successfully lost a lot of weight with &lt;strong&gt;Optimised Fasting&lt;/strong&gt;. Per week I have lost about 500 grams, that is half a kilo. I have already gained a lot of experience with fasting like water fasting. Optimised Fasting is a variation of water fasting. Since this diet works so successfully for me, I wanted to introduce it to you.&lt;/p&gt;
&lt;h1&gt;Disclaimer&lt;/h1&gt;
&lt;p&gt;You should only try this diet if you have some experience with low carb or even ketosis. Low carb means a massive reduction in the intake of any kind of sugar. The human being has essentially two metabolisms to produce energy. One is the sugar metabolism and the other is the fat metabolism. In sugar metabolism, the body primarily uses sugar to produce energy and in fat metabolism, the body primarily uses fat.&lt;/p&gt;
&lt;p&gt;However, if the fat metabolism is hardly used, it atrophies or is never properly developed. With the Optimised Fasting we need a strongly trained fat metabolism, otherwise the two days of fasting can be physically and mentally difficult, because the body longs for sugar and has never learned to deal with its own body fat through fat metabolism. So it would be a bit like jumping into cold water. Side effects can then be headaches and extreme hunger.&lt;/p&gt;
&lt;p&gt;So if you think you don&apos;t have a well developed fat metabolism, I recommend to try a low carb diet and to experience a day of water fasting at the weekend. Here is still an older post of me over the &lt;a href=&quot;https://martinmueller.dev/waterfasting&quot;&gt;water chamfered&lt;/a&gt; which I can recommend you warmly.&lt;/p&gt;
&lt;p&gt;In the next sections I would like to tell you more about my new diet form of the Optimised Fasting. With this it concerns primarily to decrease over many weeks continuously with minimum expenditure.&lt;/p&gt;
&lt;h1&gt;Optimised Fasting instructions&lt;/h1&gt;
&lt;p&gt;Optimised Fasting consists of approx. 2 days long water fasting. Around the training it is allowed to add vitamins, salts and minimal proteins. By the supply of protein before and after the training, an anabolic signal for the body is virtually released, which helps to carry out the training better and above all more intensive.&lt;/p&gt;
&lt;p&gt;The amount of protein must not be too high, otherwise the digestive system is stressed too much and this becomes a hindrance to training. About 25g before and after training should be enough.&lt;/p&gt;
&lt;p&gt;The vitamins are generally important for humans to maintain the body functions. The body can store little or no salt in the body and therefore it is necessary to replenish salt during fasting. The easiest way to do this is to consume a food with a high salt content.&lt;/p&gt;
&lt;p&gt;An exact example of the foods I eat before and after training is listed in the next chapter.&lt;/p&gt;
&lt;p&gt;The goal is to continue fasting until you have reached 500 grams less than last week. For me this was always the third day, the day after the two days of Optimised Fasting. When I have reached 500 grams, I always make a picture of the dare with my smartphone. So I know then how many KG I want to reach next week.&lt;/p&gt;
&lt;h1&gt;Optimised Fasting Example&lt;/h1&gt;
&lt;p&gt;I work as a software developer for 4 days a week. So from Monday to Thursday. Therefore I start the Optimised Fasting already on Thursday. Wednesday evening is the last time I eat something.&lt;/p&gt;
&lt;p&gt;Already on Wednesday I reduce food with high sugar content. I then mainly eat only protein and fat. This helps me to prepare my fat metabolism for the next 2 days of fasting and makes it easier to start.&lt;/p&gt;
&lt;p&gt;Thursday and Friday we fast and only eat a little something for my morning training.&lt;/p&gt;
&lt;h2 id=&quot;before-the-training&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#before-the-training&quot; aria-label=&quot;before the training permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Before the Training&lt;/h2&gt;
&lt;p&gt;I make myself a green tea with a hot chilli sauce and pressed lemon juice. I hope that this will have a stimulating effect and burn more calories due to the increased caffeine content and spicy substances in the chili. Afterwards it goes to the training.&lt;/p&gt;
&lt;p&gt;My training in the morning is broad and very varied. Depending on my body condition I do some strength training, endurance training or a short high intensity training. Warming up and subsequent stretching is also part of my training program. If you want to know more about my training, let me know :).&lt;/p&gt;
&lt;h2 id=&quot;after-the-training&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#after-the-training&quot; aria-label=&quot;after the training permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;After the Training&lt;/h2&gt;
&lt;p&gt;I eat a small bowl full of nuts (walnut, pumpkin seeds, Brazil nut), Omega 3 and vitamin D capsules, a piece of black chocolate, gummi bears (about 8) and two eggs. In the cover picture you can also see this meal. If you are wondering why the gummi bears. They contain a lot of gelatine which is a healthy and important protein for the body. They are also delicious and the sugar in them is too little to get me out of ketosis.&lt;/p&gt;
&lt;h1&gt;What I find so great about Optimised Fasting&lt;/h1&gt;
&lt;p&gt;Any diet is only successful if it is easy to implement and Optimised Fasting is very easy to implement. It must be fasted only two days and on the remaining days one can eat as one would like. There is no need for time-consuming preparation of meals, because you are fasting.&lt;/p&gt;
&lt;p&gt;When water fasting, I have always been annoyed by drinking a lot of salt water. By Optimised Fasting enough salt can be supplied to the body by the snack after training. It is then no longer necessary to drink extra salt in the form of salt water.&lt;/p&gt;
&lt;p&gt;I also find it cool that the 500 grams I reach every weekend is a very reliable value, since my bowels are mostly empty after two days of fasting and the water, which was caused by sugar deposits in the muscles, is out. Thus I am subject to fewer water fluctuations during the weight admission after the second chamfering day.&lt;/p&gt;
&lt;h1&gt;Simplified Entrance&lt;/h1&gt;
&lt;p&gt;The implementation of my previous Optimised Fasting was very easy for me because I am used to fasting and I generally eat low carb. I am also very disciplined when it comes to sports and I usually do short and crisp workouts in the morning and evening. But I can imagine that you might find it a bit harder to get started.&lt;/p&gt;
&lt;p&gt;For this case I have thought of a simplified variant. Start the first two weeks with an Optimised Fasting Day. This gives your body the opportunity to get used to the fasting slowly. Maybe one fasting day is enough for you and the next day you have already lost 500 grams of weight compared to last week. That would be great :).&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Optimised Fasting is an easy way to lose weight continuously. It is extremely easy to implement since only about two days must be chamfered and in the remaining week you can eat what you want. No annoying preparation of the meals. No counting the calories.&lt;/p&gt;
&lt;p&gt;If fasting or low carb in general is something for you, I can only recommend you to try this kind of weight reduction. Write me your experiences. I am very curious :) !&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/bb32897db8ddbbe22af9c5aeeff2a071/opt.jpg</featuredImage><media:content url="https://martinmueller.dev/static/bb32897db8ddbbe22af9c5aeeff2a071/opt.jpg" medium="image"/></item><item><title><![CDATA[Alfresco 6.2 with OCR]]></title><description><![CDATA[Hi Alfrescans. Object Character Recognition (short OCR) is a cool tool as it allows you to make your scanned documents incredible useful as…]]></description><link>https://martinmueller.dev/alf-ocr-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alf-ocr-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[addon]]></category><category><![CDATA[acs]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[ocr]]></category><pubDate>Tue, 24 Nov 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/7f12d45b5943409bbeedde13a2aa8796/digital.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;Object Character Recognition (short OCR) is a cool tool as it allows you to make your scanned documents incredible useful as it recognizes characters and words and makes those accessible in your document like through a PDF sandwich. A PDF sandwich contains text which you can select, copy or search through it. That&apos;s the case like when you export a word document into PDF.&lt;/p&gt;
&lt;p&gt;But when you just scan a text and save it as PDF, the text is not selectable anymore and you only have some less useful pictures in your PDF document. And here the power of OCR comes in. With OCR you can transform those dumb PDF document to PDF sandwich. Than you can again select and copy text or search for it in the document.&lt;/p&gt;
&lt;p&gt;Even better as Alfresco uses Solr to make a full text search, you can search for documents containing certain words across you documents. Thats extremely powerful. But yeah Alfresco doesn&apos;t come ootb with OCR so how you can enhance Alfresco with such a cool feature? In the next sections I will explain how!&lt;/p&gt;
&lt;h1&gt;OCR as a Service&lt;/h1&gt;
&lt;p&gt;As a quick way of developing, I implemented my solution as a Docker Compose deployment. The OCR service itself is implemented as a Docker container which shares the ocr input and output volumes with the Alfresco container. The underlying OCR engine is &lt;a href=&quot;https://github.com/jbarlow83/OCRmyPDF&quot;&gt;OCRmyPDF&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;ocrmypdf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ocrmypdf
    &lt;span class=&quot;token key atrule&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ocrmypdf
    &lt;span class=&quot;token key atrule&quot;&gt;mem_limit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 512m
    &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ocr&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/usr/local/tomcat/ocr_input
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ocr&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;output&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/usr/local/tomcat/ocr_output&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The full Docker Compose git code can be found in my GitHub repo &lt;a href=&quot;https://github.com/mmuller88/alfresco-ocr&quot;&gt;alfresco-ocr&lt;/a&gt;. I describe in the next section how I did the setup with Alfresco.&lt;/p&gt;
&lt;h1&gt;Alfresco Setup&lt;/h1&gt;
&lt;p&gt;The Alfresco Docker Compose deploy is created using the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt; with the ACS Community 6.2 option. All other options are the defaults.&lt;/p&gt;
&lt;p&gt;Additionally the repo and share OCR amps &lt;a href=&quot;https://github.com/keensoft/alfresco-simple-ocr&quot;&gt;alfresco-simple-ocr&lt;/a&gt; are installed by simply dropping the addon jar files into &lt;strong&gt;alfresco-ocr/alfresco/modules/jars&lt;/strong&gt; and &lt;strong&gt;alfresco-ocr/share/modules/jars&lt;/strong&gt; . Easy peasy.&lt;/p&gt;
&lt;h1&gt;Run it with AWS CDK&lt;/h1&gt;
&lt;p&gt;I enhanced the Docker Compose deployment to make it easy runnable in AWS. For that I use &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt;. Is use a little library which hides a lot complexity using the AWS CDK stuff. The CDK Pipeline App in ./cdk/app.ts will create a sophisticated pipeline to deploy the instance in one or more accounts. For more information please read the Readme.&lt;/p&gt;
&lt;p&gt;Your Alfresco will become available in AWS und links like&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://ec2-3-92-227-231.compute-1.amazonaws.com:8080/&quot;&gt;http://ec2-3-92-227-231.compute-1.amazonaws.com:8080/&lt;/a&gt; for Alfresco Content App or&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ec2-3-92-227-231.compute-1.amazonaws.com:8080/share&quot;&gt;http://ec2-3-92-227-231.compute-1.amazonaws.com:8080/share&lt;/a&gt; for Share of course&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I personally like that way of deploying Alfresco into the Cloud as AWS CDK is a lovely abstraction on top of CloudFormation which makes creating infrastructure such as for Alfresco (Ec2, Loadbalancer, Kubernetes, Docker) a piece of cake. If you want to know more about deploying Alfresco into AWS have a look through &lt;a href=&quot;https://martinmueller.dev/tags/alfresco&quot;&gt;my posts&lt;/a&gt; where you find many more topics around it.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;OCR in Alfresco is a cool and useful feature. It enhances an Alfresco repository to make better use of documents which lost text information like scanned ones. It&apos;s incredibly useful it is to encapsulate the OCR engine as its own service like I did here as Docker Container.&lt;/p&gt;
&lt;p&gt;Potentially you could enhance that setup to offer a REST API to the OCR service and for example choose between difference OCR engines and pick the best result yourself. All that is very exciting. Tell me what you think about OCR together with Alfresco.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/7f12d45b5943409bbeedde13a2aa8796/digital.png</featuredImage><media:content url="https://martinmueller.dev/static/7f12d45b5943409bbeedde13a2aa8796/digital.png" medium="image"/></item><item><title><![CDATA[AWS Cognito Auth Mock]]></title><description><![CDATA[Ahoi AWS'ler In my AWS project, where I can start, stop and schedule instances of Alfresco via REST API, I use AWS Cognito as identity…]]></description><link>https://martinmueller.dev/cdk-cognito-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-cognito-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><category><![CDATA[postman]]></category><category><![CDATA[cognito]]></category><pubDate>Mon, 16 Nov 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/cc6c9fefa9f99ff2cd69bfe359b73339/cognito.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Ahoi AWS&apos;ler&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&quot;https://martinmueller.dev/alf-provisioner-eng&quot;&gt;AWS project&lt;/a&gt;, where I can start, stop and schedule instances of Alfresco via REST API, I use AWS Cognito as identity provider for user management. Cognito makes it easy for me to create new users and give them the rights to access the REST API.&lt;/p&gt;
&lt;p&gt;The REST API is implemented using AWS API Gateway and a Cognito Authorizer allows users from the Cognito Identity Pool to access the endpoints.&lt;/p&gt;
&lt;p&gt;The Cognito Authorizer is especially important because I have implemented a permission layer that prevents users from manipulating Alfresco instances of other users. Basically the Permission Layer works with the User ID returned by the Cognito Authorization process if the authorization was successful.&lt;/p&gt;
&lt;p&gt;This works great, but I would like to have automated tests to test the functionality of the permission layer. It would be great if I could use Postman for this. Unfortunately this is not possible because the authentication process with Cognito requires user interaction to retrieve the credentials.&lt;/p&gt;
&lt;p&gt;The solution for me was to write a Mock Authentication Layer which simulates the exact behavior of the Cognito Authorizer. For this I used Middy. What Middy is and how exactly my solution looks like I will describe in the next sections.&lt;/p&gt;
&lt;h1&gt;Middy as Mock Auth Layer&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/middyjs/middy&quot;&gt;Middy&lt;/a&gt; is a simple framework for building layers in Lambda functions. With this framework it is possible to encapsulate all features that are not directly related to business logic in layers. In my case I want to implement a Mock Auth Layer that simulates the Cognito authorization. This layer should be optionally switchable by environmental variables.&lt;/p&gt;
&lt;p&gt;The complete code for the Auth Layer can be found on &lt;a href=&quot;https://github.com/mmuller88/alf-cdk/blob/master/src/util/mockAuthLayer.ts&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;mockAuthLayer&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MockAuthLayerConfig&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handler&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockHeaderPrefix &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; config&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;mockHeaderPrefix &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;MOCK_AUTH_&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;headerKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; headerKey&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockHeaderPrefix&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;headerKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headerValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;headerKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;martin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claims &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claims &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claims&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            headerKey&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockHeaderPrefix&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; headerValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;shifted header &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ok let&apos;s have a look at the code.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockHeaderPrefix &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; config&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;mockHeaderPrefix &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;MOCK_AUTH_&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;headerKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; headerKey&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockHeaderPrefix&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So I filter all headers that start with a certain prefix. If none is set I use &lt;strong&gt;MOCK_AUTH&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; headerValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;headerKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;martin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claims &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claims &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;requestContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authorizer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;claims&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    headerKey&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockHeaderPrefix&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; headerValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then the headers are copied into the Authorizer Claims area which would also contain the Cognito Values. This way my Lambda has access to the authenticated user and role. How to set the &lt;strong&gt;MOCK_AUTH_&lt;/strong&gt; headers is shown in the next section.&lt;/p&gt;
&lt;p&gt;At the end with &lt;strong&gt;.replace(/&amp;#x26;/g, &apos;:&apos;)&lt;/strong&gt; there is a small symbol replacement because Postman does not allow to use double colons &lt;strong&gt;:&lt;/strong&gt; in the header key.&lt;/p&gt;
&lt;h1&gt;Lambda Unit Tests&lt;/h1&gt;
&lt;p&gt;For my Lambdas I have written unit tests which should also take the authorization into account. From my code I pick a unit test file on &lt;a href=&quot;https://github.com/mmuller88/alf-cdk/blob/master/test/get-all-conf-api.spec.ts&quot;&gt;GitHub&lt;/a&gt; and explain it in more detail.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;from himself will success&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;done&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  awsSdkPromiseResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mockReturnValueOnce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Items&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; instanceId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;i123&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;martin&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;MOCK_AUTH_cognito:username&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;martin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;MOCK_AUTH_cognito:groups&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Admin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      queryStringParameters&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;martin&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; Context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;statusCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So as we can see here I use the mock header &lt;strong&gt;MOCK_AUTH_cognito:username&apos;: &apos;martin&apos;&lt;/strong&gt; and &lt;strong&gt;&apos;MOCK_AUTH_cognito:groups&apos;: &apos;Admin&apos;&lt;/strong&gt; . With this I simply simulate the authorization behavior of Cognito and make the username and user groups known to the Lambda at runtime. Fair enough.&lt;/p&gt;
&lt;h1&gt;Postman Tests&lt;/h1&gt;
&lt;p&gt;Of course my Postman tests should also be able to use the new Auth Mock Layer. On &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-api-gw/blob/master/test/alf-cdk.postman_collection.json&quot;&gt;GitHub&lt;/a&gt; I have a Postman Collection with over 40 requests. The whole collection is executed by Newman after building the DEV environment as an integration test:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;testCommands&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stageAccount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stageAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dev&quot;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;npx newman run test/alf-cdk.postman_collection.json --env-var baseUrl=$RestApiEndPoint -r cli,json --reporter-json-export tmp/newman/report.json --export-environment tmp/newman/env-vars.json --export-globals tmp/newman/global-vars.json; RESULT=$? || \,
          ./scripts/cleanup.sh
          exit $RESULT&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To use the Mock Auth Layer you just have to set the headers, like you did with the unit tests in the previous section:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;MOCK_AUTH_cognito&amp;amp;username = martin
MOCK_AUTH_cognito&amp;amp;groups = Admin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But I had to make one change. Postman does not allow to have a double colon in the header key. So I had to add a symbol replacement. The AND character &lt;strong&gt;&amp;#x26;&lt;/strong&gt; is translated to the double colon &lt;strong&gt;:&lt;/strong&gt; in the code.&lt;/p&gt;
&lt;p&gt;If you are interested in testing with CDK, I can recommend my blog post from &lt;a href=&quot;https://martinmueller.dev/pipeline-testing-eng&quot;&gt;last week&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;AWS Cognito is mega cool and fast to set up. It offers a range of great user management functions. Unfortunately, it is not possible to run the Cognito authorization process completely automated, e.g. for automated tests. But that doesn&apos;t matter because I simply simulate the Cognito authorization with my Auth Mock Layer. Now to you. Did you like the article? Do you want to know more? Let me know.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/cc6c9fefa9f99ff2cd69bfe359b73339/cognito.jpg</featuredImage><media:content url="https://martinmueller.dev/static/cc6c9fefa9f99ff2cd69bfe359b73339/cognito.jpg" medium="image"/></item><item><title><![CDATA[AWS CDK - PipelineApp Library - Automated Testing]]></title><description><![CDATA[Hi CDK Fans, Recently I published a blog post about the AWS CDK PipelineApp Library I'm working on. If you are interested in the AWS CDK…]]></description><link>https://martinmueller.dev/pipeline-testing-eng/</link><guid isPermaLink="false">https://martinmueller.dev/pipeline-testing-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><category><![CDATA[testing]]></category><category><![CDATA[postman]]></category><pubDate>Mon, 09 Nov 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/f3f0000cdb65bfb0a2b9e0afe7d49982/testing.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi CDK Fans,&lt;/p&gt;
&lt;p&gt;Recently I published a blog post about the &lt;a href=&quot;https://martinmueller.dev/cdk-pipeline-lib-eng&quot;&gt;AWS CDK PipelineApp Library&lt;/a&gt; I&apos;m working on. If you are interested in the AWS CDK Pipeline you should read that one! Meanwhile I have used the library dozens of times in my projects and have developed it further.&lt;/p&gt;
&lt;p&gt;In this post I would like to explain how to use my library to run automated tests with the pipeline.&lt;/p&gt;
&lt;p&gt;By the way, my &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-app-pipeline&quot;&gt;CDK Library&lt;/a&gt; can be used directly via npm dependency and does not require an npm repository. Just specify the dependency as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt; &lt;span class=&quot;token property&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;alf-cdk-app-pipeline&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &quot;github&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;mmuller88/alf-cdk-app-pipeline#v0.&lt;span class=&quot;token number&quot;&gt;0.8&lt;/span&gt;
    ...
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;What are we testing for?&lt;/h1&gt;
&lt;p&gt;In the age of fast releases to production, it is essential to perform automated tests during the release process in the pipeline. This ensures that old and new features still work.&lt;/p&gt;
&lt;h1&gt;Cloudformation stack testing&lt;/h1&gt;
&lt;p&gt;In the last blogpost I already introduced my Ec2 stack. Now I would like to go into more detail about the test part in the &lt;strong&gt;testCommands&lt;/strong&gt; property.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pipelineAppProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PipelineAppProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  branch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;master&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;testCommands&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stageAccount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;curl -Ssf $InstancePublicDnsName
    aws cloudformation delete-stack --stack-name itest123 --region &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;stageAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the command &lt;code&gt;curl -Ssf $InstancePublicDnsName&lt;/code&gt; I test if the Ec2 instance is started successfully. Afterwards a cleanup is performed using the AWS CLI. Because the commands are passed as a list of strings &lt;code&gt;string[]&lt;/code&gt; and are processed sequentially, the cleanup can take place after the curl command before the test days process the next command or return a fail.&lt;/p&gt;
&lt;p&gt;The variable &lt;strong&gt;$InstancePublicDnsName&lt;/strong&gt; was defined in the Ec2 stack and explicitly rendered into the test command. How it was defined you can see here:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; instancePublicDnsName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CfnOutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;InstancePublicDnsName&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; instance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instancePublicDnsName
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cfnOutputs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;InstancePublicDnsName&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; instancePublicDnsName&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;API GW Tests&lt;/h1&gt;
&lt;p&gt;In my AWS API GW stack I run Postman tests. There are now more than 40 requests running against the API GW and testing the backend extensively. If you are interested in Postman Tests you can find a lot of articles about the topic on my blog page on &lt;a href=&quot;https://martinmueller.dev/tags/postman&quot;&gt;https://martinmueller.dev/tags/postman&lt;/a&gt; .&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pipelineAppProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PipelineAppProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  branch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;master&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;testCommands&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stageAccount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stageAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;npx newman run test/alf-cdk.postman_collection.json --env-var baseUrl=$RestApiEndPoint -r cli,json --reporter-json-export tmp/newman/report.json --export-environment tmp/newman/env-vars.json --export-globals tmp/newman/global-vars.json
      aws cloudformation describe-stacks --query &quot;Stacks[?Tags[?Key == &apos;alfInstanceId&apos;][]].StackName&quot; --region &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;stageAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; --output text |
      awk &apos;{print $1}&apos; |
      while read line;
      do aws cloudformation delete-stack --stack-name $line --region &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;stageAccount&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
      done&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the CLI tool &lt;strong&gt;newman&lt;/strong&gt; the Postman Collection, which contains more than 40 requests tests, can be executed. From &lt;code&gt;aws cloudformation ...&lt;/code&gt; on there is also a cleanup of all remaining cloudformation stacks.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;It feels like my AWS CDK pipeline library is becoming more useful and robust. With every new project of mine I add something to it and so it becomes a bit more sophisticated. I am very excited to see where the journey with my library will lead.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/f3f0000cdb65bfb0a2b9e0afe7d49982/testing.jpg</featuredImage><media:content url="https://martinmueller.dev/static/f3f0000cdb65bfb0a2b9e0afe7d49982/testing.jpg" medium="image"/></item><item><title><![CDATA[AWS CDK - PipelineApp - A Library for Staging Pipelines]]></title><description><![CDATA[Hi CDK Fans, Building AWS CDK pipelines is fun. Since the middle of this year (2020) there is even a high level CDK pipeline which brings…]]></description><link>https://martinmueller.dev/cdk-pipeline-lib-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-pipeline-lib-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[cdk]]></category><pubDate>Sat, 24 Oct 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/d76a89a0bc3763460ff79d5b46f05d7c/staging.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi CDK Fans,&lt;/p&gt;
&lt;p&gt;Building AWS CDK pipelines is fun. Since the middle of this year (2020) there is even a high level CDK pipeline which brings many advantages like self-mutate, a simplified cross-account deployment and a better abstraction from the required code build projects.&lt;/p&gt;
&lt;p&gt;I have developed a &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-app-pipeline&quot;&gt;CDK Library&lt;/a&gt; which solves some annoying problems. If you encounter only one of the following, you should read the whole post :) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maintaining CDK dependencies between multiple repositories&lt;/li&gt;
&lt;li&gt;Repetition of code for building CDK apps only to deploy e.g. an arbitrary stack&lt;/li&gt;
&lt;li&gt;Repetition of CDK pipeline code&lt;/li&gt;
&lt;li&gt;Missing a uniform CDK pipeline standard over e.g. an interface&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the next sections I will talk about this general library and how I solve those problems. First of all I will describe why you need a pipeline at all. Then I explain the idea behind the library and finally I show some examples of my projects which already use the library.&lt;/p&gt;
&lt;p&gt;By the way my &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-app-pipeline&quot;&gt;CDK Library&lt;/a&gt; can be used directly via npm depedency and does not require an npm repository. Just specify the dependency as follow:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt; &lt;span class=&quot;token property&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;alf-cdk-app-pipeline&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &quot;github&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;mmuller88/alf-cdk-app-pipeline#v0.&lt;span class=&quot;token number&quot;&gt;0.7&lt;/span&gt;
    ...
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Why a Pipeline at all?&lt;/h1&gt;
&lt;p&gt;In times of modern DevOps practices it is important to make changes in production as fast and easy as possible. Ideally this is done based on git commits and a staging pipeline. A Staging Pipeline executes changes on Stages.&lt;/p&gt;
&lt;p&gt;In my company we have four stages DEV, QA, PROD. The DEV Stage is intended as a development environment for the developers. The QA Stage is a test environment that is as similar as possible to the PROD environment. And PROD itself is of course the production environment which is actively used by the company and our customers.&lt;/p&gt;
&lt;p&gt;For a better understanding I will use only one DEV, PROD Stage in the next sections. The PipelineApp library can be extended by any number of stages.&lt;/p&gt;
&lt;h1&gt;Requirements&lt;/h1&gt;
&lt;p&gt;My CDK Pipeline Library should fulfill some requirements which are implemented externally via an interface. Here the interface is implemented with the &lt;strong&gt;PipelineAppProps&lt;/strong&gt; for the &lt;strong&gt;PipelineApp&lt;/strong&gt; class in the library:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pipelineAppProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PipelineAppProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  branch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;master&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  repositoryName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-cdk-ui&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  stageAccounts&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;987...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  buildAccount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;555...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;customStack&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; alfCdkSpecifics &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Z08...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;i.dev.alfpro.net&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;arn:aws:acm:eu-central-1:123...:certificate/d40cd852-5bbf-4c1d-9a18-2d96e5307b4c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
       &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// prod&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Z003...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;i.alfpro.net&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;arn:aws:acm:eu-central-1:987...:certificate/4fe684df-36da-4516-bd01-7fcc22337dff&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AlfCdkEc2Stack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      gitRepo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-ec2-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      tags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      customDomain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;certArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stackName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;itest12&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;testCommands&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;sleep 240&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;curl -Ssf $InstancePublicDnsName &amp;amp;&amp;amp; aws cloudformation delete-stack --stack-name itest123 --region &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// tslint:disable-next-line: no-unused-expression&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PipelineApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pipelineAppProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the next subsections I will explain the individual properties in more detail.&lt;/p&gt;
&lt;h2 id=&quot;git-repository&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#git-repository&quot; aria-label=&quot;git repository permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Git Repository&lt;/h2&gt;
&lt;p&gt;The PipelineApp will deploy its stages based on Git repositories. Therefore it is necessary to define the repository and the branch:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pipelineAppProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PipelineAppProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  branch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;master&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  repositoryName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-cdk-ui&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;repositoryName&lt;/strong&gt; refers to the name in my repository on Github e.g. &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ui&quot;&gt;https://github.com/mmuller88/alf-cdk-ui&lt;/a&gt; . Via the pipeline this repository will be pulled by a token and defined as source.&lt;/p&gt;
&lt;h2 id=&quot;manage-stages&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#manage-stages&quot; aria-label=&quot;manage stages permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Manage Stages&lt;/h2&gt;
&lt;p&gt;It should be possible to connect to specific AWS accounts on the respective stage. The specification about the account and the stage should be given as parameter. I developed the following interface:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;stageAccounts&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123..&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;987...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A list of stage accounts is passed to which the pipeline will deploy the stacks. Additionally the &lt;strong&gt;stage&lt;/strong&gt; property defines the name of the stage. The order of the accounts also determines the order in which the staging is performed. In this example the DEV Stage is run through first and then the PROD Stage.&lt;/p&gt;
&lt;p&gt;The build account defines the account where the CDK pipeline will be deployed.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;buildAccount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;555...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the build account you can also define important secrets with the Secret Manager or the parameter store like the GitHub token. In the pipeline stack these secrets can be accessed there.&lt;/p&gt;
&lt;h2 id=&quot;one-or-more-stacks&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#one-or-more-stacks&quot; aria-label=&quot;one or more stacks permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;One or more Stacks&lt;/h2&gt;
&lt;p&gt;The pipeline should be able to deploy and integrate one or more stacks. The stack definition should be located in the respective repository and can then simply be passed to the Library as a Higher Order Function:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;customStack&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; alfCdkSpecifics &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Z08...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;i.dev.alfpro.net&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;arn:aws:acm:eu-central-1:123...:certificate/d40cd852-5bbf-4c1d-9a18-2d96e5307b4c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
       &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// prod&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Z00371764UBVAUANTU0U&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;i.alfpro.net&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;arn:aws:acm:eu-central-1:987...:certificate/4fe684df-36da-4516-bd01-7fcc22337dff&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AlfCdkEc2Stack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      gitRepo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-cdk-ec2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      tags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      customDomain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;certArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stackName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;itest12&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The stack shown here is located in the &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ec2&quot;&gt;alf-cdk-ec2&lt;/a&gt; repo with alf-cdk-ec2-stack.ts as file. The stack is called in app.ts along with the PipelineApp Library.&lt;/p&gt;
&lt;p&gt;Thanks to the High Order Function, account information can easily be integrated as a parameter into the respective Stage Stack using &lt;strong&gt;account&lt;/strong&gt;.&lt;/p&gt;
&lt;h1&gt;Library Examples&lt;/h1&gt;
&lt;p&gt;In this section, I will show some of the consumers of the PipelineApp library.&lt;/p&gt;
&lt;h2 id=&quot;alf-cdk-ui-react-frontend&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#alf-cdk-ui-react-frontend&quot; aria-label=&quot;alf cdk ui react frontend permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Alf CDK UI React Frontend&lt;/h2&gt;
&lt;p&gt;The first example is about a frontend stack which builds a static website. The technologies I use here are React in TypeScript Flavor. The static site is hosted in a S3 bucket with a cloud front distribution.&lt;/p&gt;
&lt;p&gt;All code is on GitHub &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ui&quot;&gt;alf-cdk-ui&lt;/a&gt;. The root directory contains the React App. The cdk folder contains all relevant CDK parts. Among them the UIStack in ui-stack.ts Construct and the PipelineApp in app.ts. The PipelineApp is called as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; UIStack &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./ui-stack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./package.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; PipelineApp &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-cdk-app-pipeline/pipeline-app&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sharedProdAccountProps &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-cdk-app-pipeline/accountConfig&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token comment&quot;&gt;// tslint:disable-next-line: no-unused-expression&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PipelineApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  branch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;master&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  repositoryName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  stageAccounts&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;us-east-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  buildAccount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;customStack&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; stageProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        acmCertRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;acmCertRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        subDomain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        zoneName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// prod stage&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        acmCertRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;acmCertRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        subDomain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        zoneName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// console.log(&apos;echo = &apos; + JSON.stringify(account));&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UIStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      stackName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; stageProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      acmCertRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; stageProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;acmCertRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      subDomain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; stageProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; stageProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      zoneName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; stageProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  buildCommand&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;make distcdk&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;manualApprovals&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;testCommands&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Use &apos;curl&apos; to GET the given URL and fail if it returns an error&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;curl -Ssf $domainName&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;echo done!!!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see here I use the same account for the two stages dev and prod. It would also be possible to use different accounts. You only have to make sure that the CDK bootstrap command trusts the respective account! Interesting is that I overwrite the default &lt;strong&gt;buildCommand&lt;/strong&gt; here. The motivation for this is to fine-tune the React App during build to get it faster.&lt;/p&gt;
&lt;p&gt;The most interesting part is the &lt;strong&gt;customStack&lt;/strong&gt; property and the High Order Function. Here you can define the stack which should be managed by the PipelineApp. That&apos;s pretty cool because it allows me to keep the stack definition in the UI repo but I only have to import minimal code for the pipeline app library.&lt;/p&gt;
&lt;p&gt;This is an important point for stacks like the &lt;strong&gt;UIStack&lt;/strong&gt;. These are only allowed the aws-cdk dependencies like&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; StackProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CfnOutput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; RemovalPolicy &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;only indirectly from the PipelineApp Library. This is more of an advantage than a disadvantage because only the aws-cdk dependencies have to be managed in the pipeline app library itself. And with a reasonable tagging strategy you can avoid aws-cdk update problems!&lt;/p&gt;
&lt;p&gt;The build command can optionally be overwritten. Here I do this for example with &lt;strong&gt;make distcdk&lt;/strong&gt; . In the projects I use Makefiles because they are excellent for encapsulating commands. With Makefiles I also have a nice overview of the possible and desired commands.&lt;/p&gt;
&lt;p&gt;At the end I do a reachability test with the &lt;strong&gt;testCommands&lt;/strong&gt; property. The parameter $domainName was defined in the stack like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CfnOutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;domainName&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; route&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cfnOutputs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;domainName&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This notation must be followed so that the PipelineApp Library can retrieve the stack output variables after stack deployment.&lt;/p&gt;
&lt;h2 id=&quot;alf-cdk-ec2-backend&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#alf-cdk-ec2-backend&quot; aria-label=&quot;alf cdk ec2 backend permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Alf CDK Ec2 Backend&lt;/h2&gt;
&lt;p&gt;The next example is in Github on &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ec2&quot;&gt;alf-cdk-ec2&lt;/a&gt;. Here I create an Alfresco deployment based on Docker Compose, Ec2 and CDK as infrastructure orchestrator. You can read more in the blog post &lt;a href=&quot;https://martinmueller.dev/alf-cdk&quot;&gt;ACS infrastructure creation made easy with AWS CDK&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pipelineAppProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PipelineAppProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  branch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;master&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  repositoryName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  stageAccounts&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  buildAccount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;customStack&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// console.log(&apos;echo = &apos; + JSON.stringify(account));&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tags &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tags &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; alfCdkSpecifics &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Z08...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;i.dev.alfpro.net&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;certArn &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;arn:aws:acm:eu-central-1:123...:certificate/d40cd852-5bbf-4c1d-9a18-2d96e5307b4c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
       &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// prod&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Z003...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;i.alfpro.net&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;certArn &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;arn:aws:acm:us-east-1:123...:certificate/09d5c91e-6579-4189-882b-798301fb8fba&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AlfCdkEc2Stack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      gitRepo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;gitRepo &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-cdk-ec2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      tags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      customDomain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;certArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stackName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stackName &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;itest123&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;testCommands&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aws ec2 get-console-output --instance-id $InstanceId --region &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; --output text&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;sleep 180&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;curl -Ssf $InstancePublicDnsName &amp;amp;&amp;amp; aws cloudformation delete-stack --stack-name itest123 --region &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// tslint:disable-next-line: no-unused-expression&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PipelineApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pipelineAppProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this example only one staging account is defined&lt;/p&gt;
&lt;h2 id=&quot;alf-cdk-backend&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#alf-cdk-backend&quot; aria-label=&quot;alf cdk backend permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Alf CDK Backend&lt;/h2&gt;
&lt;p&gt;The next example is also in Github &lt;a href=&quot;https://github.com/mmuller88/alf-cdk&quot;&gt;alf-cdk&lt;/a&gt;. It is a very large stack consisting of Cognito, API GW, Lambdas, StepFunction, DynamoDB and more. This stack also creates other CDK stacks using a Lambda function.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; name &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./package.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; PipelineApp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PipelineAppProps &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-cdk-app-pipeline/pipeline-app&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; AlfInstancesStack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; AlfInstancesStackProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; alfTypes &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./lib/alf-instances-stack&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sharedProdAccountProps &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;alf-cdk-app-pipeline/accountConfig&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pipelineAppProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PipelineAppProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  branch&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;master&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  repositoryName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  stageAccounts&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;987...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;us-east-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  buildAccount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;123...&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-central-1&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;customStack&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// values that are differs from the stages&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; alfCdkSpecifics &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;api.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          zoneName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          certificateArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:acm:us-east-1:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:certificate/f605dd8c-4ae3-4c1b-9471-4b152e0f8846&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        createInstances&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          enabled&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          imageId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ami-0ea3405d2d2522162&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          minutes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          maxPerUser&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          maxInstances&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;i.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Z0847928PFMOCU700U4U&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:acm:eu-central-1:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:certificate/d40cd852-5bbf-4c1d-9a18-2d96e5307b4c&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        swagger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            certificateArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedDevAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;acmCertRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        auth&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// prod stage&lt;/span&gt;
        domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;api.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &apos;api.alfpro.net&apos;,&lt;/span&gt;
          zoneName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hostedZoneId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          certificateArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:acm:us-east-1:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:certificate/62010fca-125e-4780-8d71-7d745ff91789&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        createInstances&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          enabled&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          imageId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ami-01a6e31ac994bbc09&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          minutes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          maxPerUser&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          maxInstances&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;i.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zoneName&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Z00371764UBVAUANTU0U&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            certArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:acm:eu-central-1:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:certificate/4fe684df-36da-4516-bd01-7fcc22337dff&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        swagger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            certificateArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; sharedProdAccountProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;acmCertRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        auth&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          cognito&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            userPoolArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:cognito-idp:us-east-1:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:userpool/us-east-1_8c1pujn9g&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;aws.cognito.signin.user.admin&apos;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// console.log(&apos;echo = &apos; + JSON.stringify(account));&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; alfInstancesStackProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AlfInstancesStackProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      stackName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      createInstances&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        enabled&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createInstances&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enabled&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        imageId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createInstances&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;imageId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        alfTypes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        automatedStopping&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          minutes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createInstances&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;minutes
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        allowedConstraints&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          maxPerUser&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createInstances&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxPerUser&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          maxInstances&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createInstances&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxInstances&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createInstances&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      executer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        rate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rate(1 minute)&apos;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      swagger&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        file&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;templates/swagger_validations.yaml&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;swagger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          subdomain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;openapi&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          certificateArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;swagger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;certificateArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      auth&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; alfCdkSpecifics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AlfInstancesStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; alfInstancesStackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;manualApprovals&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;testCommands&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stage&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;npx newman run test/alf-cdk.postman_collection.json --env-var baseUrl=$RestApiEndPoint -r cli,json --reporter-json-export tmp/newman/report.json --export-environment tmp/newman/env-vars.json --export-globals tmp/newman/global-vars.json&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;echo done! Delete all remaining Stacks!&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aws cloudformation describe-stacks --query &quot;Stacks[?Tags[?Key == &apos;alfInstanceId&apos;][]].StackName&quot; --region &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; --output text |
      awk &apos;{print $1}&apos; |
      while read line;
      do aws cloudformation delete-stack --stack-name $line --region &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;account&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;region&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;;
      done&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// tslint:disable-next-line: no-unused-expression&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PipelineApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pipelineAppProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see this is a very large stack with many input properties. In the future I might break down this huge stack into smaller ones. This example is interesting because it does a lot of testing with Postman and the AWS CLI at the end. The property &lt;strong&gt;testCommands&lt;/strong&gt; performs tests for the DEV Stage Postman:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npx newman run test/alf-cdk.postman_collection.json --env-var baseUrl=$RestApiEndPoint -r cli,json --reporter-json-export tmp/newman/report.json --export-environment tmp/newman/env-vars.json --export-globals tmp/newman/global-vars.json`&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then it deletes any remaining CDK stacks resulting from the tests:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;aws cloudformation describe-stacks --query &quot;Stacks[?Tags[?Key == &apos;alfInstanceId&apos;][]].StackName&quot; --region ${account.region} --output text |
awk &apos;{print $1}&apos; |
while read line;
  do aws cloudformation delete-stack --stack-name $line --region ${account.region};
done`,&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;CDK code pipelines are super cool. But they are also super complicated or complex. You don&apos;t want to deal with all this complexity every time just to squeeze stacks into a staging pipeline. So there should be a good abstraction to these staging pipelines.&lt;/p&gt;
&lt;p&gt;In this article I presented such an abstraction in form of a library. I am already using it to run some CDK stacks, which are presented here.&lt;/p&gt;
&lt;p&gt;This library can only access repositories in my github account. It would be possible to make the library more general sophisticated in order to be able to access any git repositories. If you find this useful, let me know. But now I&apos;m curious. What do you think of my PipelineApp library? What can I improve? Let me know.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/d76a89a0bc3763460ff79d5b46f05d7c/staging.png</featuredImage><media:content url="https://martinmueller.dev/static/d76a89a0bc3763460ff79d5b46f05d7c/staging.png" medium="image"/></item><item><title><![CDATA[AWS CDK Let's build a Platform - Api Gateway]]></title><description><![CDATA[Hi CDK Fans, Welcome back to my little series "AWS CDK Let's build a platform". In the previous episode AWS CDK Let's build a Platform…]]></description><link>https://martinmueller.dev/cdk-platform-api-gw-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-platform-api-gw-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[react]]></category><category><![CDATA[cdk]]></category><pubDate>Sun, 13 Sep 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/8cd7f6e7377d2b3b2fe415061876e745/api-gw.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi CDK Fans,&lt;/p&gt;
&lt;p&gt;Welcome back to my little series &quot;AWS CDK Let&apos;s build a platform&quot;. In the previous episode &lt;a href=&quot;https://martinmueller.dev/cdk-platform-frontend&quot;&gt;AWS CDK Let&apos;s build a Platform - Frontend&lt;/a&gt; I explained how we build a cool static React Web App with AWS CDK for my company &lt;a href=&quot;https://unimed.de&quot;&gt;unimed.de&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;AWS CDK is a framework for creating and using Cloudformation templates. You can choose between common programming languages like Java, Python or TypeScript. We have decided to use TypeScript. If you want to know more about AWS CDK I recommend my other posts here in my blog like &lt;a href=&quot;https://martinmueller.dev/cdk-example-eng&quot;&gt;cdk-example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this episode I will talk about the AWS Api Gateway which is used by the frontend application to retrieve or store internal data.&lt;/p&gt;
&lt;h1&gt;Api Gateway&lt;/h1&gt;
&lt;p&gt;The AWS Api Gateway is the heart of many AWS deployments. It is a rest api for processing requests and the following responses. For example, if internal data is to be requested, this could be done with this request:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;GET https://example.com/users&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The response body could then look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bob&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So the Api Gateway receives a request, forwards it to an integration and then returns a response. The integration can be chosen from different technologies like Mock, HTTP Proxy, Lambda Proxy or other AWS services. When creating the API gateway, we decided to use the variant with the openApi specification. I already wrote about this in a &lt;a href=&quot;https://martinmueller.dev/cdk-swagger-eng&quot;&gt;previous post&lt;/a&gt; and recommend you to read it.&lt;/p&gt;
&lt;p&gt;In short, using an openApi specification offers some advantages like schema validation of the request parameters and a great documentation about the expected responses and possible error messages. Especially when using a NoSQL database like DynamoDB the validation of the request parameters is extremely important because the database itself does not provide a schema! And this is how an openApi Api Gateway looks like in CDK:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; api &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SpecRestApi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stackName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    apiDefinition&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ApiDefinition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./path/to/api-gw.yaml&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The openApi specification here called api-gw.yaml could look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;openapi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &quot;3.0.1
&lt;span class=&quot;token key atrule&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;example-endpoints&quot;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2020-09-01T13:03:56Z&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;/enumerations&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;security&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;x-amazon-apigateway integration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;aws_proxy&quot;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:apigateway:${AWS::region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::region}:${AWS::AccountId}:function:example/invocations&quot;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;passthroughBehavior&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &quot;when_no_match
        &lt;span class=&quot;token key atrule&quot;&gt;httpMethod&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &quot;POST
        &lt;span class=&quot;token key atrule&quot;&gt;credentials&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:iam::@@ACCOUNT_ID@@@:role/apiRole&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;responses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;200 responses&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you use Lambdas for your integrations you can also allow the Api Gateway to access your Lambdas right here:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; apiRole &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;apiRole&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    assumedBy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ServicePrincipal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;apigateway.amazonaws.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

apiRole&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PolicyStatement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;lambda:InvokeFunction&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Alternatively, the Lambdas themselves could give the Api Gateway permission to call them.&lt;/p&gt;
&lt;p&gt;Part of our staging pipeline, which I will explain in one of the following parts, are integration tests that are executed after each commit. At the moment it is &quot;only&quot; postmant tests that are executed via Newman:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npx newman run test/postman/example-com.postman_collection.json --env-var baseUrl=http://example.com --env-var keycloakUrl=http://keycloak-dev.example.com --env-var user=${testUserName} --env-var pass=${testUserPassword} -r cli,json --reporter-json-export tmp/newman/report.json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The user credentials are previously set in the build via secure environment variables, which are loaded from AWS SecurityManager.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;In this part of the &quot;AWS CDK Let&apos;s build a Platform&quot; series I have explained how the backend stack could look rough. What I left out on purpose is the information what comes behind the Api Gateway or Lambdas. Usually you access data from memory like maybe DynamoDB or RDS. But you might also want to trigger more complex processing with AWS Step Functions.&lt;/p&gt;
&lt;p&gt;A great example how to do a CRUD implementation with API Gateway, Lambda and DynamoDB is described in another post (&lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;https://martinmueller.dev/cdk-example&lt;/a&gt;). Did you like the next part of my &quot;AWS CDK Let&apos;s build a Platform&quot; series? What do you want to know next? Let me know.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/8cd7f6e7377d2b3b2fe415061876e745/api-gw.png</featuredImage><media:content url="https://martinmueller.dev/static/8cd7f6e7377d2b3b2fe415061876e745/api-gw.png" medium="image"/></item><item><title><![CDATA[AWS CDK Let's build a Platform - Frontend]]></title><description><![CDATA[Hi CDK fans, Since I have the great opportunity to help building a platform for my company unimed.de, I want to explain how it looks like…]]></description><link>https://martinmueller.dev/cdk-platform-frontend-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-platform-frontend-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[react]]></category><category><![CDATA[cdk]]></category><pubDate>Sun, 06 Sep 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/56fb0d6cd0d3762a7428c35543018cb3/frontend.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi CDK fans,&lt;/p&gt;
&lt;p&gt;Since I have the great opportunity to help building a platform for my company &lt;a href=&quot;https://unimed.de&quot;&gt;unimed.de&lt;/a&gt;, I want to explain how it looks like. At the moment we are working on an exciting platform for efficient storage and retrieval of internal data. My main responsibility is the AWS infrastructure.&lt;/p&gt;
&lt;p&gt;Our DevOps team wants to leverage as much as possible to AWS. We use AWS CDK to manage the resources in AWS. AWS CDK is a framework for creating and using Cloudformation Templates. You can choose between common programming languages. We decided to use TypeScript because our frontend is also written in TypeScript and offers the advantage of strong type definition without loosing much flexibility. If you want to know more about AWS CDK I recommend my other posts here in my blog like &lt;a href=&quot;https://martinmueller.dev/cdk-example-eng&quot;&gt;cdk-example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The above mentioned frontend is implemented in TypeScript flavour with React. I&apos;m planning a multi-part series about &quot;AWS CDK Let&apos;s build a Platform&quot; and this episode is specifically about the frontend.&lt;/p&gt;
&lt;h1&gt;React Frontend&lt;/h1&gt;
&lt;p&gt;As already mentioned our frontend is a React Browser App in TypeScript flavor. It uses the material design wherever possible. Authentication is done via Keycloak which is connected to our internal Active Directory. After entering the access data, relevant data can be searched for and new data can be added. The static app is built with &lt;code&gt;npm run build&lt;/code&gt; in the build folder.&lt;/p&gt;
&lt;p&gt;At this point I would like to make a cut and tell more about the used infrastructure. The React Browser App is a Static Web App and needs a couple of AWS resources. I will list these in the next section and how they can be managed using CDK.&lt;/p&gt;
&lt;h1&gt;CDK Stack&lt;/h1&gt;
&lt;p&gt;To display the static React App an S3 Bucket is required, which serves as a static Web App Bucket:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bucket &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AutoDeleteBucket&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  bucketName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  websiteIndexDocument&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;index.html&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  websiteErrorDocument&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;index.html&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  removalPolicy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RemovalPolicy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DESTROY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I use a CDK highlevel construct called &lt;a href=&quot;https://www.npmjs.com/package/@mobileposse/auto-delete-bucket&quot;&gt;AutoDeleteBucket&lt;/a&gt; which can delete itself if necessary. The normal &lt;a href=&quot;_COPY19@aws-cdk_aws-s3.Bucket.html&quot;&gt;S3Bucket Construct&lt;/a&gt; can only delete the bucket if there is no data in it. So the AutDeleteBucket first deletes all data contained and then removes itself. This flexible behavior is useful for buckets that are only used as static Web App containers. The name of the static Web App Bucket &lt;code&gt;bucketName: ${props.subDomain}.${props.domainName}&lt;/code&gt; is usually given after the domain e.g. example.com .&lt;/p&gt;
&lt;p&gt;The S3 bucket stores the static build and is connected to Cloudfront:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cloudFrontOAI &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OriginAccessIdentity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;OAI&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  comment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;OAI for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; website.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cloudFrontDistProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CloudFrontWebDistributionProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  aliasConfiguration&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      acmCertRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;acmCertRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      names&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      sslMethod&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SSLMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SNI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      securityPolicy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SecurityPolicyProtocol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TLS_V1_1_2016&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  originConfigs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      s3OriginSource&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        s3BucketSource&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; bucket&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        originAccessIdentity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cloudFrontOAI&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      behaviors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; isDefaultBehavior&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  errorConfigurations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      errorCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      errorCachingMinTtl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      responseCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      responsePagePath&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/index.html&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cloudfrontDistribution &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CloudFrontWebDistribution&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-cfd&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  cloudFrontDistProps
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cloudfront is a Cloud Distribution Network (CDN) from AWS that cascades static Web Apps all over the world in the respective regions. This keeps latency during loading to a minimum.&lt;/p&gt;
&lt;p&gt;To load the static Web App Build into the S3 Bucket you have to create a BucketDeployment Construct:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BucketDeployment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DeployApp-${new Date().toString()}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  sources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Source&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;../build&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  destinationBucket&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; bucket&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  distribution&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cloudfront distribution&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  distributionPaths&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The path for invalidating the Cloudfront distribution is also specified here in the BucketDeployment. This then ensures that the cash is reloaded if a new app is deployed. The static Web App build folder contains the build of the React App and was previously created with &lt;code&gt;npm run build&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Furthermore a Route 53 Record Resource is required to point a custom domain (e.g. &lt;a href=&quot;http://www.example.com&quot;&gt;www.example.com&lt;/a&gt;) to the cloudfront endpoint to make the static web app accessible via URL:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; zone &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; HostedZone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromLookup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Zone&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ARecord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SiteAliasRecord&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  recordName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AddressRecordTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromAlias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CloudFrontTarget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cloudfrontDistribution&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  zone
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And here is the whole code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; StackProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Construct &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; AutoDeleteBucket &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@mobileposse/auto-delete-bucket&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; BucketDeployment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Source &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-s3-deployment&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  CloudFrontWebDistribution&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  CloudFrontWebDistributionProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  OriginAccessIdentity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  SSLMethod&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  SecurityPolicyProtocol
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-cloudfront&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ARecord&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; AddressRecordTarget&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HostedZone &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-route53&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; CloudFrontTarget &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-route53-targets&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// @ts-ignore&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; codedeploy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-codedeploy&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// @ts-ignore&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; lambda &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// @ts-ignore&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; core &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FrontendStackProps&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StackProps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  acmCertRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  subDomain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FrontendStack&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stack &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Construct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; FrontendStackProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bucket &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AutoDeleteBucket&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      bucketName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      websiteIndexDocument&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;index.html&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      websiteErrorDocument&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;index.html&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      removalPolicy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RemovalPolicy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DESTROY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cloudFrontOAI &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OriginAccessIdentity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;OAI&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      comment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;OAI for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; website.&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cloudFrontDistProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CloudFrontWebDistributionProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      aliasConfiguration&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          acmCertRef&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;acmCertRef&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          names&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          sslMethod&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SSLMethod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SNI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          securityPolicy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SecurityPolicyProtocol&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TLS_V1_1_2016&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      originConfigs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          s3OriginSource&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            s3BucketSource&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; bucket&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            originAccessIdentity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cloudFrontOAI&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          behaviors&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; isDefaultBehavior&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      errorConfigurations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          errorCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          errorCachingMinTtl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          responseCode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          responsePagePath&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/index.html&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cloudfrontDistribution &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CloudFrontWebDistribution&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;-cfd&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      cloudFrontDistProps
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BucketDeployment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;DeployApp-${new Date().toString()}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      sources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Source&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;../build&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      destinationBucket&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; bucket&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      distribution&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; cloudfront distribution&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      distributionPaths&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; zone &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; HostedZone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromLookup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Zone&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ARecord&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SiteAliasRecord&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      recordName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subDomain&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;domainName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AddressRecordTarget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromAlias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CloudFrontTarget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cloudfrontDistribution&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      zone
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Pipeline&lt;/h1&gt;
&lt;p&gt;We deploy the static React app via a staging pipeline. This means the app runs through the different stages Dev, QA and Prod. All stages are separate accounts. This way we achieve increased security by separating the resources. The dev account is used to test new features. The QA environment serves as the next stage.&lt;/p&gt;
&lt;p&gt;I would like to report in more detail about our Staging Pipeline in the next part of the series.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Building a platform using AWS is exciting and fun. Having the complete infrastructure as code is extremely beneficial. It allows a sophisticated staging from e.g. a Dev environment to QA and then to Prod. Furthermore the code serves as documentation about what exactly has been and will be deployed in AWS. It is also much less error-prone than having to click everything together manually.&lt;/p&gt;
&lt;p&gt;Here I presented the first part of my &quot;AWS CDK Let&apos;s build a Platform&quot; series. I explain which resources our static Web App needs in AWS and how they are managed with CDK. In the next part I will talk in more detail about our staging pipeline which is reused almost everywhere to get CDK apps through the different stages Dev, QA and Prod. I hope you liked the article and if you have any questions, just write me.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/56fb0d6cd0d3762a7428c35543018cb3/frontend.png</featuredImage><media:content url="https://martinmueller.dev/static/56fb0d6cd0d3762a7428c35543018cb3/frontend.png" medium="image"/></item><item><title><![CDATA[Alfresco Signatures with Sinadura]]></title><description><![CDATA[Sponsored by PMGA Tech Hi Alfrescans. Digital signatures are one of the most used forms of integrity checks on the Internet. Integrity check…]]></description><link>https://martinmueller.dev/alf-sinadura-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alf-sinadura-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[addon]]></category><category><![CDATA[acs]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[docker-compose]]></category><pubDate>Fri, 14 Aug 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/3328d033c3462e7cd7cb65aba05960c5/sig.png" length="0" type="image/png"/><content:encoded>&lt;h1&gt;Sponsored by &lt;a href=&quot;www.pmga.tech&quot;&gt;PMGA Tech&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;Digital signatures are one of the most used forms of integrity checks on the Internet. Integrity check here means whether the document in question is the original and therefore not a fake or a modified version. An example are the SSL certificates which are needed to call HTTPS urls. There you have to check if the SSL certificate is not tampered with and this is done with a digital signature.&lt;/p&gt;
&lt;p&gt;Alfresco does not offer a document signing function out of the box, but with the open source addon &lt;a href=&quot;https://github.com/zylklab/alfresco-sinadura&quot;&gt;Sinadura&lt;/a&gt; (Repo and Share) this feature can be added. On YouTube there is a short &lt;a href=&quot;https://www.youtube.com/watch?feature=player_embedded&amp;#x26;v=MCTpOKZtTgw&quot;&gt;Video&lt;/a&gt; about the signing function of Sinadura. A signing feature in Alfresco has two major advantages. The first would be increased security, as it would make it almost impossible to forge documents in Alfresco, e.g. by an attacker entering the system.&lt;/p&gt;
&lt;p&gt;Second, it would allow the normal Use Case Scope, i.e. to stay within a company, to be abandoned and people who do not work in the company, such as customers, to be included in the content management system. By using signatures, an improved relationship of trust can be achieved.&lt;/p&gt;
&lt;p&gt;In the next sections, I would like to tell you more about the Sinadura addon.&lt;/p&gt;
&lt;h1&gt;Sinadura Addon&lt;/h1&gt;
&lt;p&gt;Sinadura.net is an open source project for digital signature software. For this purpose a Sinadura server is normally running for signature check and creation. A client then connects to the Sinadura server.&lt;/p&gt;
&lt;p&gt;Sinadura has an Alfresco addon repo in GitHub &lt;a href=&quot;https://github.com/zylklab/alfresco-sinadura&quot;&gt;https://github.com/zylklab/alfresco-sinadura&lt;/a&gt; which only works with ACS Community and Enterprise version 5. Of course it would be great to support newer Alfresco versions with Docker. So I made it my business to make this great addon compatible with ACS 6.2.&lt;/p&gt;
&lt;h1&gt;ACS 6.2 Compatible&lt;/h1&gt;
&lt;p&gt;Currently the Alfresco Sinadura addon in &lt;a href=&quot;https://github.com/zylklab/alfresco-sinadura&quot;&gt;https://github.com/zylklab/alfresco-sinadura&lt;/a&gt; is still based on SDK 2.2.0 and ACS 5. It seems that SDK 2.2.0 does not work ootb. anymore and some necessary artifacts are not available in the Alfresco Nexus. Only with a lot of efforts would it be possible to compile the Sinadura amps with SDK 2.2.0. So I decided to use the latest SDK version 4.1.0.&lt;/p&gt;
&lt;p&gt;The migration, which you can find in my Git Repo at &lt;a href=&quot;https://github.com/mmuller88/alfresco-sinadura-6X-pmgatech&quot;&gt;https://github.com/mmuller88/alfresco-sinadura-6X-pmgatech&lt;/a&gt;, worked great. How to build an Alfresco SDK 4.1.0 build is very well described in the official &lt;a href=&quot;https://github.com/Alfresco/alfresco-sdk&quot;&gt;Alfresco SDK Repo&lt;/a&gt;. SDK 4.1.0 is heavily based on Docker and uses Docker Compose as a container orchestrator.&lt;/p&gt;
&lt;p&gt;A bit more challenging was the migration of the AMP structure to 4.1.0 as some files have to be placed in a different location than in 2.2.0. Also I had to put the sinaduraCloud war file in its own Tomcat running with Java 8 as Alfresco uses Java 11.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Digital signatures are an exciting topic and enable an Alfresco document management system to have completely new use cases. The process of signing in conjunction with Alfresco Process Service could also be interesting.&lt;/p&gt;
&lt;p&gt;Many thanks to my sponsor &lt;a href=&quot;www.pmga.tech&quot;&gt;www.pmga.tech&lt;/a&gt; for the migration work on Sinadura. Do you have exciting Alfresco projects you are working on? Let me know :) !&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/3328d033c3462e7cd7cb65aba05960c5/sig.png</featuredImage><media:content url="https://martinmueller.dev/static/3328d033c3462e7cd7cb65aba05960c5/sig.png" medium="image"/></item><item><title><![CDATA[Create ACS Infrastructure easy with AWS CDK]]></title><description><![CDATA[Hi Alfrescans. Infrastructure as code has been popular in DevOps for quite some time. One of the first pioneers of IaC (Infrastructure as…]]></description><link>https://martinmueller.dev/alf-cdk-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alf-cdk-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[acs]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[cdk]]></category><category><![CDATA[docker-compose]]></category><pubDate>Sun, 26 Jul 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/32789ee4453cba38cb29d1c145d52c1f/alfcdk.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;Infrastructure as code has been popular in DevOps for quite some time. One of the first pioneers of IaC (Infrastructure as Code) is AWS with Cloudformation. For this, cloudformation templates must be written in JSON or YAML. This works very well but is a time consuming and complex work.&lt;/p&gt;
&lt;p&gt;With AWS CDK, a new level of abstraction has been created above the cloudformation templates, which makes it easier than ever to provide the infrastructure for a running ACS. In the next sections I will explain what AWS CDK actually is and how it can help to build AWS infrastructure for ACS.&lt;/p&gt;
&lt;h1&gt;What is AWS CDK?&lt;/h1&gt;
&lt;p&gt;CDK stands for Cloud Development Kit and is an open software development framework for modeling and managing Cloudformation resources and thus AWS infrastructure. AWS CDK synthesizes to Cloudformation Templates. This means that Cloudformation Templates are being created from the CDK code. A so-called CDK App consists of one or more Cloudformation Stacks. It supports well-known languages like Java, Python, JavaScript or TypeScript. For the rest of this article I use TypeScript.&lt;/p&gt;
&lt;h1&gt;Why is CDK so great?&lt;/h1&gt;
&lt;p&gt;The great thing about CDK in the TypeScript flavor are the type definitions which allow for fast progress when developing with an IDEA, since it virtually brings documentation with it thanks to the types. Also, the years of experience with cloud formation have already resulted in excellent defaults, which rarely need to be overwritten. CDK also takes care of the upload of the synthesized cloudformation template and assets into an S3. Also, the CDK framework is open source and if you want to take a closer look at how CDK works, you can do so in &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So AWS CDK is an excellent way to provide the infrastructure for an ACS deployment. In the following section, I&apos;ll explain the two stacks Ec2 stack and EKS stack created with CDK.&lt;/p&gt;
&lt;h1&gt;CDK Constructs&lt;/h1&gt;
&lt;p&gt;Constructs can be either low level or high level. Low level constructs represent a Cloudformation resource. High level constructs are a combination of several low level constructs. The whole CDK app represents a tree with the app itself as root. After that come the high level constructs and the leaves are the low level constructs. For completeness, I should add that low level constructs are getting auto generated from existing Cloudformation resources.&lt;/p&gt;
&lt;p&gt;A good example is the high level construct Vpc from the package @aws-cdk/aws-ec2 which is a combination of resources like Vpc, InternetGateway, Cidr or VpC Iam Role. The creation of the high level VPC Construct looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Vpc &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-ec2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; App&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@aws-cdk/aws-ec2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VpcStack&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Stack&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vpc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;vpc&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// just this line&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VpcStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;VpcStack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;synth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Only the line &lt;code&gt;new Vpc(this, &apos;vpc&apos;);&lt;/code&gt; is required to define a complete public VPC. Doing the same in a Cloudformation template would be 200 lines long! This is made possible because CDK has extremely useful default settings. You can see how well this framework benefits from years of experience with Cloudformation. If you would like to create a private VPC you only need to pass a third parameter object:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vpc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;CustomVPC&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cidr&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;10.0.0.0/16&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  maxAzs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  subnetConfiguration&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cidrMask&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;isolatedSubnet&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    subnetType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SubnetType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ISOLATED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  natGateways&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Ec2 Stack&lt;/h1&gt;
&lt;p&gt;The code is public and in my &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-ec2&quot;&gt;GitHub Repo&lt;/a&gt;. The ACS deployment was generated using the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt; and uses Docker Compose to orchestrate the ACS deployment services. The CDK app is defined in the file index.ts. If no CDK Apps have been deployed yet, the CDK Toolkit Stack must be created in the target region with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cdk bootstrap aws://&amp;lt;ACCOUNT-NUMBER&gt;/&amp;lt;REGION&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then the stack is deployed with the following command:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm run build &amp;amp;&amp;amp; cdk deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If everything went well, the Alfresco Content App should be available on the public DNS Url for a short ACA. For example, ec2-34-201-46-76.compute-1.amazonaws.com. You can get that URL directly from the AWS browser in the Ec2 section or define an Output resource and your CDK stack.&lt;/p&gt;
&lt;p&gt;The CDK app creates a cloudformation stack that deploys an Ec2 instance behind an application load balancer. The ACS Deploy Code, which is also contained in the same repo, is copied to the Ec2 instance and ACS is started. Docker Compose serves as a container orchestrator.&lt;/p&gt;
&lt;p&gt;This is ideal for simple developer environments, as Docker Compose templates can be created quickly and are easily extensible. However, if you want to create a production-like ACS deployment, you should use Kubernetes as a container orchestrator.&lt;/p&gt;
&lt;h1&gt;EKS Stack&lt;/h1&gt;
&lt;p&gt;EKS stands for Elastic Kubernetes Service and provides a Kubernetes Masternode when used. The Ec2 worker nodes are also configured. In contrast to the Ec2 stack, the EKS stack uses Kubernetes to orchestrate the ACS deployment services. There are already some good examples how to create an EKS deployment with CDK. &lt;a href=&quot;https://github.com/mmuller88/alf-cdk-eks&quot;&gt;Here&lt;/a&gt; you can find my GitHub code. The following properties are needed to create the cluster:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; eksCluster &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;cluster&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  clusterName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stackName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mastersRole&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; eksClusterAdmin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  vpc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vpc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  kubectlEnabled&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// we want to be able to manage k8s resources using CDK&lt;/span&gt;
  defaultCapacity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// we want to manage capacity our selves&lt;/span&gt;
  version&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CubernetesVersion&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;V1_17&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I overwrite the cluster name generated by the CDK with &lt;strong&gt;clusterName&lt;/strong&gt; because it is not reader-friendly. The &lt;strong&gt;masterRole&lt;/strong&gt; allows my IAM User Admin access to the cluster. The workernode is then defined as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; onDemandASG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AutoScalingGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;OnDemandASG&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  vpc&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; vpc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; workerRole&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  minCapacity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  maxCapacity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  instanceType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InstanceType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;t2.large&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  machineImage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;EksOptimizedImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    cybernetic version&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1.17&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    nodeType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; NodeType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;STANDARD&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// without this, incorrect SSM parameter for AMI is resolved&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  updateType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; UpdateType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ROLLING_UPDATE&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make Alfresco accessible via URLs, you need to define the address as well. I use a Nginx Ingress in AWS Flavour:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HelmChart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;NginxIngress&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  cluster&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; eksCluster&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  chart&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;nginx-ingress&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  repository&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https://helm.nginx.com/stable&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  namespace&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;kube-system&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  values&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;rbac&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;create&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&apos;controller&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;scope&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;enabled&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        namespace&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; acsNamespace
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;config&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;force-ssl-redirect&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        server tokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;service&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&apos;targetPorts&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string-property property&quot;&gt;&apos;https&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        annotations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string-property property&quot;&gt;&apos;service.beta.kubernetes.io/aws-load-balancer-backend-protocol&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token string-property property&quot;&gt;&apos;service.beta.kubernetes.io/aws-load-balancer-ssl-ports&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;https&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token string-property property&quot;&gt;&apos;service.beta.kubernetes.io/aws-load-balancer-ssl-cert&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; awsCertArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token string-property property&quot;&gt;&apos;external-dns.alpha.kubernetes.io/hostname&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;acsNamespace&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.eks.alfpro.net&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token string-property property&quot;&gt;&apos;service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; awsCertPolicy
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        publishService&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token string-property property&quot;&gt;&apos;enabled&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After successful deployment with&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm run build &amp;amp;&amp;amp; cdk deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;the following output appears:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt; ✅ AcsEksCluster

Outputs:
AcsEksCluster.ClusterConfigCommand43AAE40F = aws eks update-kubeconfig --name AcsEksCluster --region us-east-1 --role-arn arn:aws:iam::1111122223333:role/AcsEksCluster-eksClusterAdminE955DB57-1H9KJVEE241KS
AcsEksCluster.clusterGetTokenCommand06AE992E = aws eks get-token --cluster-name AcsEksCluster --region us-east-1 --role-arn arn:aws:iam::1111122223333:role/AcsEksCluster-eksClusterAdminE955DB57-1H9KJVEE241KS&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The aws eks update-config command can be used to connect to the cluster and apply cluster configurations using kubectl.&lt;/p&gt;
&lt;h2 id=&quot;helm-3-issue&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#helm-3-issue&quot; aria-label=&quot;helm 3 issue permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Helm 3 Issue&lt;/h2&gt;
&lt;p&gt;Unfortunately none of the ACS Charts, i.e. Community and Enterprise, are compatible with Helm 3 at this time. This means we can not use the existing HelmChart CDK Constructor to install ACS. Alternatively, ACS must be installed with Helm 2.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;AWS CDK is an exciting framework for building Alfresco infrastructure in AWS. CDK synthesizes into cloud formation templates, so there is little or no need to change existing CI CD pipelines. The gain from using CDK is huge. E.g. the type definition prevents bugs already in the editor. Many lines of code are saved and there is no or hardly any need to template YAML. For me CDK is the next logical step for IaC in AWS. There are even the first efforts to integrate CDK into the &lt;a href=&quot;https://github.com/hashicorp/terraform-cdk/&quot;&gt;Terraform&lt;/a&gt; ecosystem, which I find very exciting. I would be really interested to hear of you experiences with CDK :)!&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/32789ee4453cba38cb29d1c145d52c1f/alfcdk.jpg</featuredImage><media:content url="https://martinmueller.dev/static/32789ee4453cba38cb29d1c145d52c1f/alfcdk.jpg" medium="image"/></item><item><title><![CDATA[AWS CDK Apps deployed with Lambda]]></title><description><![CDATA[Ahoy AWS CDK Fans Creating any number of Ec2 instances with a Lambda is no problem. But if you want to create more complex deployments such…]]></description><link>https://martinmueller.dev/cdk-lambda-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-lambda-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[lambda]]></category><category><![CDATA[cdk]]></category><category><![CDATA[cfd]]></category><pubDate>Sat, 11 Jul 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/9c25429249986d6533534522130d3bbb/cloud.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Ahoy AWS CDK Fans&lt;/p&gt;
&lt;p&gt;Creating any number of Ec2 instances with a Lambda is no problem. But if you want to create more complex deployments such as LoadBalancer, Securitygroups, Scalingroups, etc. with a Lambda that is tricky! CDK Apps are a good choice to manage those stacks. Deploying CDK Apps with a Lambda is not that easy and there is less information about it in the web.&lt;/p&gt;
&lt;p&gt;During a CDK Meetup I got the suggestion to use a CodeBuild project to create the CDK App via Lambda. And yes that worked out great. In the next sections I will explain why this is useful for me and how I did it.&lt;/p&gt;
&lt;h1&gt;Use Case&lt;/h1&gt;
&lt;p&gt;I already mentioned several times in my blogs that I use CDK to deploy my &lt;a href=&quot;https://martinmueller.dev/alf-provisioner-eng&quot;&gt;Alfresco Provisioner&lt;/a&gt;(also: &lt;a href=&quot;https://martinmueller.dev/cdk-solutions-constructs-2-eng&quot;&gt;CDK Construct Solutions&lt;/a&gt;). Running Alfresco only on an EC2 VM works, but is not the best solution in long terms. I also want to be able to run a load balancer and multiple EC2 instances for an Alfresco stack. Even more I would like to integrate a Kubernetes cluster in the stack to orchestrate the instances and pods. So it was necessary to manage this kind of complex deployments and CDK Apps are perfect for that.&lt;/p&gt;
&lt;p&gt;Another use case is for a customer who wants to be able to deploy CDK stacks in different stage accounts like Dev, QA, Prod. The deployment should be supervised by CodePipeline written in CDK. This use case differs in that the stack is not deployed via Lambda, but via CodePipeline and CodeBuild. For deploying CDK stacks using CodePipeline a CodeBuild project must be created.&lt;/p&gt;
&lt;h1&gt;CDK Deploy via CodeBuild and Lambda&lt;/h1&gt;
&lt;p&gt;To deploy stacks using CDK, a CodeBuild project must be created. The project looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createInstanceBuild &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;LambdaBuild&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; createInstanceBuildRole&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// role needs all permission for deploying Stacks, accessing S3, logs ...&lt;/span&gt;
    source&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; gitHubSource&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
    buildSpec&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; codebuild&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;BuildSpec&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    version&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;0.2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    phases&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        install&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            commands&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;cd src&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;npm install -g aws-cdk&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;npm install&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        build&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            commands&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;npm run build&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;cdk deploy --require-approval never&apos;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        buildImage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; codebuild&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LinuxBuildImage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;STANDARD_4_0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And it&apos;s that easy! CDK Apps with CodeBuild can be deployed within an account. But if you want to do cross deployment, you only have to adjust the commands section slightly:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
phases&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        install&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            commands&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aws --profile dev configure set aws_access_key_id $AWS_ACCESS_KEY_ID_DEV&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aws --profile dev configure set aws_secret_access_key $AWS_ACCESS_KEY_ID_DEV&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aws --profile dev configure set region $AWS_ACCESS_KEY_ID_DEV&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aws --profile prod configure set aws_access_key_id $AWS_ACCESS_KEY_ID_PROD&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aws --profile prod configure set aws_secret_access_key $AWS_ACCESS_KEY_ID_PROD&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aws --profile prod configure set region $AWS_ACCESS_KEY_ID_PROD&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;cd src&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;npm install -g aws-cdk&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;npm install&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        build&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            commands&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;npm run build&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&apos;cdk deploy --require-approval never --profile dev&apos;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you would like to take a look at the required stack changes beforehand, you can easily do that with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cdk diff --profile dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What&apos;s missing now is the Lambda implementation to run the CodeBuild project. First the Lambda must be created:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; createInstanceLambdaRole &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;createInstanceLambdaRole&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      assumedBy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ServicePrincipal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;lambda.amazonaws.com&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      managedPolicies&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ManagedPolicy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromAwsManagedPolicyName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;service-role/AWSLambdaBasicExecutionRole&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    createInstanceLambdaRole&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addToPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PolicyStatement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      resources&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      actions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;codebuild:StartBuild&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;logs:*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token builtin&quot;&gt;Function&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scope&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;createCdkApp&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    code&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AssetCode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    handler&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;create-cdk-stack.handler&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    runtime&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODEJS_12_X&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token constant&quot;&gt;PROJECT_NAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; createInstanceBuild&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;projectName
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    role&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; createInstanceLambdaRole
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As the Lambda CDK code already indicates, the Lambda function is located in the folder ./lambda:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// lambeda/create-cdk-stack.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aws-sdk&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; CodeBuild &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;aws-sdk&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; codebuild &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CodeBuild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PROJECT_NAME&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PROJECT_NAME&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; handler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;create-cdk-stack event: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; params&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CodeBuild&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Types&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StartBuildInput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    projectName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PROJECT_NAME&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;params: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; startBuildResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; codebuild&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;startBuild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;startBuildResult: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;startBuildResult&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;E voila and can independently deploy the Lambda CDK Apps.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;CDK makes stack creation and management easy. This is also useful in dynamically created (e.g. with a Lambda) stacks! With previous solutions, cloudformation templates had to be created first and then uploaded to an S3 which could then be used as the source for a cloudformation deployment.&lt;/p&gt;
&lt;p&gt;With this new approach I presented that is no longer necessary and you can concentrate more on the creation of the CDK app itself. Another advantage I appreciate is that I can test the CDK apps deployed via Lambda separately without having to deploy the complete CDK Parent Stack. This combined with CI CD Pipeline is the DevOps dream comes true!&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/9c25429249986d6533534522130d3bbb/cloud.jpg</featuredImage><media:content url="https://martinmueller.dev/static/9c25429249986d6533534522130d3bbb/cloud.jpg" medium="image"/></item><item><title><![CDATA[Optimise Infrastructure with CDK Solutions Constructs Part II.]]></title><description><![CDATA[Hi CDK Fans In the previous Part I I have built the DynamoDB Stream to Lambda Solution Construct into my Alfresco Provisioner CDK Deployment…]]></description><link>https://martinmueller.dev/cdk-solutions-constructs-2-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-solutions-constructs-2-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[lambda]]></category><category><![CDATA[cdk]]></category><category><![CDATA[github]]></category><pubDate>Sat, 04 Jul 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/6b62e1973fc6935c99da7d4857d42df6/part2.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi CDK Fans&lt;/p&gt;
&lt;p&gt;In the previous &lt;a href=&quot;https://martinmueller.dev/cdk-solutions-constructs-eng&quot;&gt;Part I&lt;/a&gt; I have built the DynamoDB Stream to Lambda Solution Construct into my &lt;a href=&quot;https://martinmueller.dev/alf-provisioner-eng&quot;&gt;Alfresco Provisioner CDK Deployment&lt;/a&gt; and discussed the benefits of doing so. This week I integrated more CDK Solutions Constructs. CDK Solutions Constructs are CDK Constructs which encapsulate often used Cloudformation Patterns. You can read more about them in &lt;a href=&quot;https://martinmueller.dev/cdk-solutions-constructs&quot;&gt;Part I&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Cloudfront S3&lt;/h1&gt;
&lt;p&gt;In GitHub, this is the &lt;a href=&quot;https://github.com/awslabs/aws-solutions-constructs/tree/master/source/patterns/%40aws-solutions-constructs/aws-cloudfront-s3&quot;&gt;Cloudfront S3&lt;/a&gt; Solution Construct. It implements a Cloudfront in front of an S3 bucket. This allows for a higher performance distribution of files because they are cached and distributed on the edge using a content delivery network. With the Cloudfront S3 Solution Pattern comes some great well-architected aspects like HTTP security headers and buckets for CDN and S3 access logs.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; CloudFrontToS3 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@aws-solutions-constructs/aws-cloudfront-s3&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CloudFrontToS3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;test-cloudfront-s3&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    deployBucket&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I planed to use this pattern to extend the S3 Static website, because it already has a cloudfront as well. However, the Cloudfront S3 Solution Construct does not support static websites. Therefore I cannot use it for my stack. What matters is that I learned a lot about this solution construct and now I know what I can&apos;t use it for, which is useful!&lt;/p&gt;
&lt;h1&gt;SQS Lambda&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/awslabs/aws-solutions-constructs/tree/master/source/patterns/%40aws-solutions-constructs/aws-sqs-lambda&quot;&gt;SQS Lambda&lt;/a&gt; Solution Construct is an exciting pattern that connects a queue from the Simple Queue Service (SQS for short) to a Lambda and thus forwards the queue messages to the Lambda for further processing. The queue and the Lambda only receive the required permissions. In addition, the SQS Lambda Solution Construct also deploys a Dead Letter Queue that is used to store and process failed messages.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; SqsToLambda &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@aws-solutions-constructs/aws-sqs-lambda&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SqsToLambda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SqsToLambdaPattern&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    deployLambda&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    lambdaFunctionProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        runtime&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODEJS_12_X&lt;/span&gt;
        handler&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;index.handler&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        code&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;__dirname&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/lambda&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I need this Solution Construct because the DynamoDB Stream to Lambda Solution Construct mentioned in &lt;a href=&quot;https://martinmueller.dev/cdk-solutions-constructs-eng&quot;&gt;Part I&lt;/a&gt; showed a strange behaviour by occasionally duplicating event messages. With the SQS Lambda Solution Construct I was able to create a FIFO SQS which now has the additional advantages mentioned in the previous paragraph.&lt;/p&gt;
&lt;h1&gt;Lambda DynamoDB&lt;/h1&gt;
&lt;p&gt;A simple but nevertheless great Solution Construct is the &lt;a href=&quot;https://github.com/awslabs/aws-solutions-constructs/tree/master/source/patterns/%40aws-solutions-constructs/aws-lambda-dynamodb&quot;&gt;Lambda DynamoDB&lt;/a&gt;. It perfectly standardizes the connection of a Lambda to a DynamoDB. If required, an existing DynamoDB table can be used or a new one created:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; LambdaToDynamoDB &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@aws-solutions-constructs/aws-lambda-dynamodb&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LambdaToDynamoDB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;test-lambda-dynamodb-stack&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    deployLambda&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    lambdaFunctionProps&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        code&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;__dirname&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/lambda&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        runtime&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; lambda&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODEJS_12_X&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        handler&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;index.handler&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;//optionally pass existing table&lt;/span&gt;
    existingTableObj&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ddbTable
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As part of the solution construct the DynamoDB access privileges are granted to the Lambda. Also, after the table is created or forwarded, an environment variable is passed to the Lambda, which contains the name of the table. This way the table is easy accessible with the Lambda:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Copied from Solution Construct Repo&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lambdaFunction&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEnvironment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;DDB_TABLE_NAME&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dynamoTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tableName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Usage within the Lambda&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DDB_TABLE_NAME&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DDB_TABLE_NAME&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;The next CDK Solutions Constructs could be successfully integrated. When working with the CDK Solution Constructs I ask myself if it makes sense to build own Solution Constructs. This would have the advantage of abstracting the infrastructure. However, the disadvantages are that not much consideration is given to the &lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;well-architected Framework&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A further disadvantage would be that the self-created Solution Constructs should of course be maintained and further developed, which would require an additional efforts. The Use Case will decide about the sense of creating your own Solutions Constructs. Until then, you can and should use the existing AWS CDK Solution Constructs, because they are open source on Git and the strong AWS community maintains and develops them further. I could even contribute back to fix a bug. Let me know about your experience with CDK Solutions Constructs :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/6b62e1973fc6935c99da7d4857d42df6/part2.png</featuredImage><media:content url="https://martinmueller.dev/static/6b62e1973fc6935c99da7d4857d42df6/part2.png" medium="image"/></item><item><title><![CDATA[Optimize Infrastructure with CDK Solutions Constructs Part I.]]></title><description><![CDATA[Ahoy AWS'ler Recently the first CDK Solution Constructs were released. It promise a new level of abstraction for CDK Constructs by combining…]]></description><link>https://martinmueller.dev/cdk-solutions-constructs-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-solutions-constructs-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[lambda]]></category><category><![CDATA[cdk]]></category><category><![CDATA[github]]></category><pubDate>Sun, 28 Jun 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/b14d8595a054e40eaf70d8dea5988a41/cdkpattern.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Ahoy AWS&apos;ler&lt;/p&gt;
&lt;p&gt;Recently the first &lt;a href=&quot;https://github.com/awslabs/aws-solutions-constructs&quot;&gt;CDK Solution Constructs&lt;/a&gt; were released. It promise a new level of abstraction for CDK Constructs by combining often used Cloudformation patterns into their own CDK Constructs. For example, if you want to use an API GateWay with a lambda proxy, you can use the &lt;a href=&quot;https://github.com/awslabs/aws-solutions-constructs/tree/master/source/patterns/%40aws-solutions-constructs/aws-apigateway-lambda&quot;&gt;aws-apigateway-lambda Solution Construct&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A great &lt;a href=&quot;https://aws.amazon.com/blogs/aws/aws-solutions-constructs-a-library-of-architecture-patterns-for-the-aws-cdk/&quot;&gt;AWS Blogpost&lt;/a&gt; demonstrates the combination of two such Solution Constructs very well. Furthermore, the CDK Solution Constructs promise to align on the &lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;well-architected Framework&lt;/a&gt;, in order to include the five pillars Operational Excellence, Security, Reliability, Performance Efficiency and Cost Optimization best as possible in the CDK deployment. This and the reduction in CDK code lines has led me to investigate whether my &lt;a href=&quot;https://martinmueller.dev/alf-provisioner-eng&quot;&gt;Alfresco Provisioner CDK Deployment&lt;/a&gt; could benefit from some CDK Solution Constructs. In the next few sections I will describe the CDK Solution Pattern that I have successfully incorporated into my deployment so far.&lt;/p&gt;
&lt;h1&gt;AWS DynamoDB Stream to Lambda&lt;/h1&gt;
&lt;p&gt;This pattern, also to be seen in &lt;a href=&quot;https://github.com/awslabs/aws-solutions-constructs/tree/master/source/patterns/%40aws-solutions-constructs/aws-dynamodb-stream-lambda&quot;&gt;Github&lt;/a&gt;, describes the often used intention to call a DynamoDB table with changes in the items via a stream to a Lambda in order to be able to react to changes like creating, editing or deleting of the item itself. An example could be if the item is deleted from the table, it can be persisted elsewhere at a lower cost.&lt;/p&gt;
&lt;p&gt;In my deployment I use it directly to map the EC2 instances according to the desired configuration in the table. For example, if the EC2 instance needs to be stopped, only &lt;strong&gt;stopped&lt;/strong&gt; is written to the &lt;strong&gt;expectedStatus&lt;/strong&gt; column of the table. If the instance is to be running again you simply write &lt;strong&gt;running&lt;/strong&gt;. If the instance is to be completely terminated, the item can simply be deleted and the streamed lambda will ensure that the instance is deleted.&lt;/p&gt;
&lt;p&gt;My previous solution was to use StepFunction alone, but using streams is much more advantageous and saves many lines of code. I also like the fact that the pattern abstracts the stream away and I only have to worry about the table and the lambda.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;The CDK Solution Constructs are great patterns that simplify the creation of the AWS infrastructure massively and even take the well-architected framework into account. Next week I will try to integrate the next pattern &lt;a href=&quot;https://github.com/awslabs/aws-solutions-constructs/tree/master/source/patterns/%40aws-solutions-constructs/aws-cloudfront-s3&quot;&gt;Cloudfront S3&lt;/a&gt;. Be curious!&lt;/p&gt;
&lt;p&gt;With great excitement I follow the development of the CDK Solution Constructs. Do you already have experience with CDK or even with the CDK Solution Constructs? If so for what? If you have any questions or suggestions, let me know!&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/b14d8595a054e40eaf70d8dea5988a41/cdkpattern.png</featuredImage><media:content url="https://martinmueller.dev/static/b14d8595a054e40eaf70d8dea5988a41/cdkpattern.png" medium="image"/></item><item><title><![CDATA[ACS and APS Integration]]></title><description><![CDATA[Hi Alfrescans. Some months ago I reported about an exciting project with the customer where we used the latest ACS and APS version. So far…]]></description><link>https://martinmueller.dev/alf-acs-aps-integration-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alf-acs-aps-integration-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[acs]]></category><category><![CDATA[aps]]></category><category><![CDATA[process]]></category><pubDate>Sun, 14 Jun 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/50478aa4ca7db03fc0f4e7880a7018cd/handshake.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;Some months ago I reported about an exciting project with the customer where we used the latest &lt;a href=&quot;https://martinmueller.dev/alf-acs-aps-integration-eng&quot;&gt;ACS and APS version&lt;/a&gt;. So far everything has been running smoothly. But now we were facing an exciting challenge. We wanted to start processes in APS from ACS. But without using the Share Connector, which normally facilitates such integrations between ACS and APS. Since ACS 6.0 the Share Connector is no longer supported by Alfresco.&lt;/p&gt;
&lt;h1&gt;Problem&lt;/h1&gt;
&lt;p&gt;ACS and APS are two independent services that are able to communicate with each other via CMIS or REST APIs. For a long time it has been possible to set ACS as a content management system and thus store and retrieve data directly in ACS (content and properties). This works great as long as the processes are started from APS. But you can also perfectly imagine the use case that processes should be started from ACS. An example would be if a document is uploaded in a certain ACS folder, a process in APS should be started with this document.&lt;/p&gt;
&lt;p&gt;For ACS 5.2 this problem could be solved with the Share Connector. This extends ACS with webscripts which can start processes via REST with APS. Additionally the Share Connector offers some Share UI extensions for the APS integration. It could be still possible to use the Share Connector for newer ACS versions, but then Alfresco would no longer offer support if you are running in any problems with it. In the following I explain two methods how to start a process in APS from a URL without using the Share Connector. Then I explain how to call this URL in ACS as part of an action webhook.&lt;/p&gt;
&lt;h1&gt;Custom Endpoint for Starting a Process&lt;/h1&gt;
&lt;p&gt;APS offers the possibility to implement custom endpoints via Java code. This can then be used to start processes and transfer variables to the process. You can find the Alfresco documentation &lt;a href=&quot;https://docs.alfresco.com/process-services1.11/topics/custom_rest_endpoints.html&quot;&gt;here&lt;/a&gt;. If such a custom endpoint is implemented, it can be used as a WebHook in ACS to start a process from ACS. As described in the documentation, the endpoint is defined using Java and then packed into a jar. The configuration of this was a bit complex because some dependencies are only available in the private Alfresco Nexus. I needed the following dependencies to build the JAR:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;maven&quot;&gt;&lt;pre class=&quot;language-maven&quot;&gt;&lt;code class=&quot;language-maven&quot;&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.alfresco&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;alfresco repository
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;com.activiti&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;activiti-app-rest&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.11.0&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-web&amp;gt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;4.1.6.RELEASE&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;
...
&amp;lt;repositories&amp;gt;
    &amp;lt;repository&amp;gt;
        &amp;lt;id&amp;gt;enterprise-releases&amp;lt;/id&amp;gt;
        &amp;lt;url&amp;gt;https://artifacts.alfresco.com/nexus/content/repositories/activiti-enterprise-releases&amp;lt;/url&amp;gt;
    &amp;lt;/repository&amp;gt;
&amp;lt;/repositories&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Access to the private Alfresco Nexus repository is required. These can be obtained from support.alfresco.com . Afterwards the JAR can be copied into the container using a docker. Below I show the Docker Compose and Docker Settings for loading the JAR into the Tomcat webapp lib.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ./process
    &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The following Docker file is located in the ./process folder.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;FROM alfresco/process&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;services&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;1.11.0

ARG TOMCAT_DIR=/usr/local/tomcat

COPY target/acsaps&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;1.0.0&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;SNAPSHOT.jar $TOMCAT_DIR/webapps/activiti&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;app/WEB&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;INF/lib&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Better you test the custom endpoint with Postman before you try to call it with ACS Url Webhook. I&apos;m not sure yet what the advantages of this method are compared to the APS Signals method in the next section. But I suspect that with Java programming a more complex process call might be possible.&lt;/p&gt;
&lt;h1&gt;APS Signal for Starting the Process&lt;/h1&gt;
&lt;p&gt;The use of start signals in APS is a different way of connecting ACS and APS. The big advantage compared to the custom endpoint method is that no Java code has to be created and everything can be configured via UI in /activiti-app. Another advantage is that the so called Start Signals can start several independent processes. In our example I will stick to one process. jtsmith describes the procedure very well in his blog post &lt;a href=&quot;https://hub.alfresco.com/t5/alfresco-process-services/using-rest-call-with-a-start-signal-event-in-aps/ba-p/288943&quot;&gt;Start Signal Event with REST example&lt;/a&gt;. In short, a Basic Auth Endpoint is created using APS. Afterwards a signal process is modeled, which will intercept the signal and map it to the endpoint. It is important that the request mapping has the following form:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;APS Signal Payload&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;signalName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mysignal&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;tenantId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tenant_1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;async&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token property&quot;&gt;&quot;variables&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;document&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;${document.nodeRef}&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Please read the exact functions of the properties in the linked original post. Next you can create processes that can use the &lt;strong&gt;mysignal&lt;/strong&gt; signal as start event to start the process. The model for the signal process can then be easily exported and reused.&lt;/p&gt;
&lt;h1&gt;ACS Webhook Action&lt;/h1&gt;
&lt;p&gt;The previous sections explained how to start an APS process from a URL. Now the only thing missing is the possibility to do exactly that with ACS. I consider the use case that a user wants to start a process when a file in a folder is uploaded to ACS. Two elements are necessary for this. For the folder we have to create a rule that is activated when a new document is created. Then a WebHook action must be executed.&lt;/p&gt;
&lt;p&gt;Unfortunately Alfresco does not offer a Webhook action ootb. There are two possibilities to archive that. Either you create an Alfresco Webhook action yourself or use the sophisticated Webhook action from &lt;a href=&quot;https://github.com/Acosix/alfresco-actions&quot;&gt;Acosix GmBH&lt;/a&gt;. That comes with a lot of great features like FreeMarker text input fields to define the payload or the Webhook URL, which is pretty cool. The Webhook Action works with payload templates that can be created / customized at runtime.&lt;/p&gt;
&lt;p&gt;I have provided an APS Payload Template which already provides the &lt;strong&gt;APS Signal Payload&lt;/strong&gt; mentioned above. If you want to transfer more variables like Alfresco properties using the Webhook, you only have to extend the payload template in the &lt;strong&gt;variables&lt;/strong&gt; section. The Webhook Action from Axel also offers excellent debugging options to find possible bugs.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;ACS and APS are powerful tools that combine to help companies finally find the long awaited, optimal digital solution. The integration of ACS with APS presents challenges for many Alfresco engineers. I&apos;ve listed two ways in which this integration can be accomplished and hope it helps you achieve your ECM BPM goals using ACS and APS. Our ACS to APS integration at the customer site is far from complete as we plan to write complex processes in APS and are already thinking about the integrity between ACS and APS, which presents us with exciting problems. Write me how your ACS APS integration looks like :) .&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/50478aa4ca7db03fc0f4e7880a7018cd/handshake.png</featuredImage><media:content url="https://martinmueller.dev/static/50478aa4ca7db03fc0f4e7880a7018cd/handshake.png" medium="image"/></item><item><title><![CDATA[OpenApi generated Restic REST Server]]></title><description><![CDATA[Hello folks :). In this article I want to tell you how easy it can be to create a backend REST server using OpenApi specifications. My…]]></description><link>https://martinmueller.dev/openapi-server-eng/</link><guid isPermaLink="false">https://martinmueller.dev/openapi-server-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[openapi]]></category><category><![CDATA[automate]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[postman]]></category><pubDate>Sat, 06 Jun 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/30cafd579699d68dbc586ebed03534bf/swagger.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hello folks :).&lt;/p&gt;
&lt;p&gt;In this article I want to tell you how easy it can be to create a backend REST server using OpenApi specifications. My ultimate goal is to make backups and the restore process of Alfresco data as easy as possible. After much research I decided to use &lt;a href=&quot;https://github.com/restic/restic&quot;&gt;Restic&lt;/a&gt; as my backup and restore engine. In my previous deployments all Alfresco data, i.e. blob data, DB data, Solr data etc. is stored in the /data folder. The automated backup works fine so far. Many thanks at this point &lt;a href=&quot;https://github.com/lobaro/restic-backup-docker&quot;&gt;lobaro&lt;/a&gt; and his brilliant restic backup work which helped me a lot in the part automated backup.&lt;/p&gt;
&lt;p&gt;But now the restoring part is still to be done. And as it seems there is no tooling for it yet. So the administrator would have to do the restoring manually with restic. That means logging into the machine and executing the necessary Restic Restore commands, which restore the desired snapshot. I want to simplify this process and provide the administrator with a convenient UI for restoring. For this I use the OpenApi technologies. In the next sections I will tell you more about OpenApi and what exactly I did.&lt;/p&gt;
&lt;h1&gt;OpenApi&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://swagger.io/docs/specification/about/&quot;&gt;OpenApi&lt;/a&gt; which was formerly called Swagger is a YAML or JSON template language for describing RESTful APIs. In the following I describe what is great about OpenApi. First of all, the templates are extremely well suited as documentation about the API itself, because a nice looking HTML UI can be generated from the template, which describes the API endpoints very well. Such a UI can be seen on the cover of this blog post. Even more ingenious is the UI can be used directly to test the endpoints, i.e. to send and receive requests and responses. Many API interfaces, such as AWS API Gateway, offer to do the parameter validation of requests via OpenApi files. What is meant by parameter validation I will try to explain with the following example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; query
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; userId
    &lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Get items of that user
    &lt;span class=&quot;token key atrule&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here you can see a parameter of type Query. This means it would look like this in the URL&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;http://&amp;lt;url&gt;/items?userId=martin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the parameter validation I can then define certain properties of the parameter, like here the name &lt;strong&gt;userId&lt;/strong&gt; if it is required and what type the value should have, in our case as of type string.&lt;/p&gt;
&lt;p&gt;Also very powerful is the property that it is possible to generate from OpenApi files &lt;a href=&quot;https://swagger.io/tools/swagger-codegen/&quot;&gt;client libraries and server stubs&lt;/a&gt;. For example, Alfresco generates JavaScript clients using the &lt;a href=&quot;https://api-explorer.alfresco.com/api-explorer/&quot;&gt;API Explorer&lt;/a&gt; (see &lt;a href=&quot;https://github.com/Alfresco/rest-api-explorer&quot;&gt;GitHub Api-Explorer&lt;/a&gt;) and &lt;a href=&quot;https://www.alfresco.com/abn/adf/&quot;&gt;ADF&lt;/a&gt; (or &lt;a href=&quot;https://github.com/Alfresco/alfresco-js-api&quot;&gt;ADF JS Github&lt;/a&gt;). There you can create a JavaScript API library from the &lt;a href=&quot;https://github.com/Alfresco/rest-api-explorer/blob/master/src/main/webapp/definitions/alfresco-core.yaml&quot;&gt;Swagger File&lt;/a&gt; which can be used as a wrapper for the API requests in the &lt;a href=&quot;https://github.com/Alfresco/alfresco-ng2-components&quot;&gt;ADF Components Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also cool is, &lt;a href=&quot;https://www.postman.com/automated-testing&quot;&gt;Postman&lt;/a&gt; offers an import function for OpenApi files. Then a collection is created from it. This is very handy if you want to start writing the requests in Postman.&lt;/p&gt;
&lt;h1&gt;Server generation&lt;/h1&gt;
&lt;p&gt;In this part I tell you more about my implementation in &lt;a href=&quot;https://github.com/mmuller88/restic-backup-restore-docker/&quot;&gt;Github&lt;/a&gt;. The &lt;a href=&quot;https://github.com/OpenAPITools/openapi-generator-cli&quot;&gt;OpenApi Generator&lt;/a&gt; is a powerful tool for creating client libs and server stubs of OpenApi specifications like the one I have in repo ./restic.yaml . But at the moment I&apos;m only interested in the server stub generation. It can be chosen from a variety of different server technologies like Go, Kotlin, Java, JavaScript. I have specifically chosen the NodeJS Express Server. To generate the server the following command is executed in ./build_server:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;&lt;span class=&quot;token environment constant&quot;&gt;PWD&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; run &lt;span class=&quot;token parameter variable&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${&lt;span class=&quot;token environment constant&quot;&gt;PWD&lt;/span&gt;}&lt;/span&gt;:/local openapitools/openapi-generator-cli generate &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; /local/restic.yaml &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; nodejs-express-server &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; local/server&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;An additional bonus. The NodeJS Express Server also generates a Swagger UI which is then accessible on /api-doc . Since I don&apos;t want to implement the handlers for the endpoints again and again when generating the server, I have placed them in a designated folder ./handlers . Then you only have to refer to it in the OpenApi Spec:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;operationId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; getSnapshots
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; List all snapshots
&lt;span class=&quot;token key atrule&quot;&gt;x-eov operation handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; handlers/default controller&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The x-eov-operation-handler property refers to the handler function. The ./handlers folder then only needs to be copied to the Docker image.&lt;/p&gt;
&lt;h1&gt;Testing&lt;/h1&gt;
&lt;p&gt;For testing, I&apos;m using the new GitHub build engine GitHub Actions to generate workflows. In my previous project, I tested GitHub Actions extensively with a &lt;a href=&quot;https://martinmueller.dev/alf-lets-encrypt-eng&quot;&gt;Let&apos;s Encrypt SSL Docker Companion&lt;/a&gt; and found it to be good. In my test workflow under ./.github/workflows/action.yml the image is started with Docker Compose and tested extensively with the help of Postman. If you are more interested in automated testing with Postman just click &lt;a href=&quot;https://martinmueller.dev/tags/postman&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Building REST servers is usually a complex process that requires writing a lot of code. Request parameters in the path or body must be validated for correctness. Or Url mapping algorithms must be equipped with request and response handler logic. And so that the user of the REST server does not despair, the REST API should be well documented. All these tasks and many more can be solved by the OpenApi approach.&lt;/p&gt;
&lt;p&gt;With great works like the &lt;a href=&quot;https://github.com/OpenAPITools/openapi-generator-cli&quot;&gt;OpenApi Generator&lt;/a&gt; you can easily generate rest servers and document them with Swagger HTML UI. Also the REST server can be tested without any problems in the Swagger HTML UI with the try out function and postman tests can be generated directly from the OpenApi Spec File. Working with OpenApi specs is very exciting for me and I hope I could animate you to try OpenApi technologies. Let me hear how it went for you!&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/30cafd579699d68dbc586ebed03534bf/swagger.png</featuredImage><media:content url="https://martinmueller.dev/static/30cafd579699d68dbc586ebed03534bf/swagger.png" medium="image"/></item><item><title><![CDATA[Alfresco meets Let's Encrypt]]></title><description><![CDATA[Hi Alfrescans. During the Alfresco Hackathon in May 2020 I implemented a Docker Companion extension for the Docker Alfresco Installer to…]]></description><link>https://martinmueller.dev/alf-lets-encrypt-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alf-lets-encrypt-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[acs]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[docker]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[ssl]]></category><category><![CDATA[github-actions]]></category><category><![CDATA[postman]]></category><pubDate>Sat, 30 May 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/5c02d1b313de471f395bf8947d525307/lets.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;During the Alfresco Hackathon in May 2020 I implemented a Docker Companion extension for the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Docker Alfresco Installer&lt;/a&gt; to manage SSL certificates. These certificates can be used for HTTPS connections. The SSL certificates are issued and regularly renewed by &lt;a href=&quot;https://letsencrypt.org/de/&quot;&gt;Let&apos;s Encrypt&lt;/a&gt;. Let&apos;s Encrypt also serves as the authorizer of the certificates. Pretty cool, right? So I don&apos;t have to worry about a secure, encrypted and maintained connection to my Alfresco proxy.&lt;/p&gt;
&lt;p&gt;Unfortunately, the pull request was denied because the Alfresco Installer docker should remain in focus demo and trial. To make this feature more accessible for you, I decided to implement it into my GitHub repo and present it to you here. Additionally, I&apos;ve written automated tests that use the new build engine GitHub Actions to test the Let&apos;s Encrypt Docker Companion. In the next sections I will explain the extension and the automated tests.&lt;/p&gt;
&lt;h1&gt;Docker Companion&lt;/h1&gt;
&lt;p&gt;The code for the Let&apos;s Encrypt extension is at &lt;a href=&quot;https://github.com/mmuller88/alf-lets-encrypt&quot;&gt;me on GitHub&lt;/a&gt;. The Docker Compose deployment is started with the script ./start.sh. If you want Lets Encrypt to request an SSL certificate, you need a server where Docker Compose Deployment is running and a domain that redirects to this server. I have taken EC2 VM from AWS and created a CNAME record which points from my domain to the Public DNS name of the EC2 VM. The CNAME record then looks something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;a.notreal.net. CNAME ec2-3-8-139-83.eu-west-2.compute.amazonaws.com&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Alfresco Docker Compose Deployment can then be launched as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;./start.sh &lt;span class=&quot;token parameter variable&quot;&gt;-spr&lt;/span&gt; https &lt;span class=&quot;token parameter variable&quot;&gt;-sh&lt;/span&gt; a.notreal.net &lt;span class=&quot;token parameter variable&quot;&gt;-sp&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thus the entire ACS Docker Compose Deployment is specifically switched to https and the domain a.notreal.net. The Docker Compose Deployment could also be started without using the ./start.sh script. However, the variables in the Docker Compose file would then have to be set correctly!&lt;/p&gt;
&lt;p&gt;The SSL specific adjustments in the Docker Compose File only include the three following services:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; nginx&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;alpine
      &lt;span class=&quot;token key atrule&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; alfresco
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; solr6
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; share
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; content app
      &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# redirect Alfresco Apps to port 80&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ./config/nginx.conf&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/etc/nginx/nginx.conf
      &lt;span class=&quot;token key atrule&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;VIRTUAL_PORT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;VIRTUAL_HOST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;SERVER_HOST&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;LETSENCRYPT_HOST&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;SERVER_HOST&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;LETSENCRYPT_EMAIL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; admin@$&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;SERVER_HOST&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;


    &lt;span class=&quot;token key atrule&quot;&gt;nginx-proxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; jwilder/nginx&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;proxy
      &lt;span class=&quot;token key atrule&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;80:80&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;443:443&quot;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/etc/nginx/vhost.d&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/usr/share/nginx/html&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/var/run/docker.sock:/tmp/docker.sock:ro&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/etc/nginx/certs&quot;&lt;/span&gt;

    &lt;span class=&quot;token key atrule&quot;&gt;letsencrypt-nginx-proxy-companion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; jrcs/letsencrypt&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;nginx&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;proxy&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;companion
      &lt;span class=&quot;token key atrule&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/var/run/docker.sock:/var/run/docker.sock:ro&quot;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;volumes_from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nginx-proxy&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first service called &lt;strong&gt;proxy&lt;/strong&gt; is the Alfresco Proxy which is used to access Alfresco applications such as Share or Alfresco Content App. The following two services together form the Docker Companion Images for SSL certificate management with Let&apos;s Encrypt.&lt;/p&gt;
&lt;h1&gt;Testing&lt;/h1&gt;
&lt;p&gt;I had a great desire to try out the new build engine GitHub Actions to test the issuance of the SSL certificate for the domain a.notreal.com I thought it should be possible to run the GitHub Action Runner directly on AWS instead of GitHub itself. I could then use the CNAME record to point to the Public DNS name of the AWS Runner. And yes, that actually worked. A lot of help was given to me &lt;a href=&quot;https://www.lotharschulz.info/2019/12/09/github-action-self-hosted-runners-on-aws-incl-spot-instances/&quot;&gt;this blog post by Lothar Schulz&lt;/a&gt; which describes exactly how I can use AWS Ec2 VMs as GitHub Actions Runner. My GitHub workflow looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Test Deployment

&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; master &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;pull_request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; master &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

  &lt;span class=&quot;token key atrule&quot;&gt;linux-build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# runs-on: ubuntu-latest&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;hosted
    &lt;span class=&quot;token key atrule&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;fail-fast&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Checkout
      &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@v2.1.1
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Setup Node.js environment
      &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/setup&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;node@v1.4.2
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Execute start.sh
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
        mkdir -p data/solr-data
        mkdir -p logs/postgres
        sudo chown -R 33007 data/solr-data
        sudo chown -R 999 logs/postgres
        chmod +x start.sh &amp;amp;&amp;amp; ./start.sh -spr https -sh a.notreal.net -sp 443&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Docker Compose deployment has failed
      &lt;span class=&quot;token key atrule&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; failure() &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
        docker-compose config
        docker-compose logs&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Execute Postman Tests
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
        npx newman run test/alf-ec2.postman_collection.json -e test/alf-ec2.postman_environment.json -r cli,json --reporter-json-export tmp/newman/report.json&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Postman has failed&lt;span class=&quot;token tag&quot;&gt;!&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; failure() &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token scalar string&quot;&gt;
        echo &quot;Postman Failed!&quot;
        cat tmp/newman/report.json
        docker-compose config
        docker-compose logs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the workflow file of GitHub Actions we see that Alfresco is started with the domain that points to the EC2 Runner via the CNAME record. By executing &apos;start.sh&apos; Alfresco is started and at the end the availability is checked. Now we should just make sure that the index engine Solr is also working. Using Newman, which is a CLI tool from Postman, a request with subsequent validation is used as a test:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;protocol=https
host=a.notreal.net
port=443
POST {{protocol}}://{{host}}:{{port}}/alfresco/api/-default-/public/search/versions/1/search&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This tests the accessibility of Solr. At this time I don&apos;t see much point in more request tests with Postman. But it would be no problem to do this at a later time. Are you more interested in the possibilities with Postman? Some time ago I wrote an interesting article where I also &lt;a href=&quot;https://martinmueller.dev/cdk-example&quot;&gt;use Postman&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Encrypted connections to the Alfresco proxy are essential for a production environment using Alfresco. It requires a lot of manual effort to create, authorize and renew the required SSL certificates. With the great and free offer from &lt;a href=&quot;https://letsencrypt.org/de/&quot;&gt;Let&apos;s Encrypt&lt;/a&gt; this effort can be reduced to almost zero. If you find Kubernetes as exciting as I do, you might consider creating small Let&apos;s Encrypt charts which can be used in a Kubernetes deployment to achieve SSL certificate management in a cluster.&lt;/p&gt;
&lt;p&gt;If you use Let&apos;s Encrypt for a production environment, please consider making a donation and Let&apos;s Encrypt. This way we can guarantee that this service will remain free in the future. Thank you for your attention and I hope for a lot of feedback :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/5c02d1b313de471f395bf8947d525307/lets.png</featuredImage><media:content url="https://martinmueller.dev/static/5c02d1b313de471f395bf8947d525307/lets.png" medium="image"/></item><item><title><![CDATA[The Alfresco Provisioner]]></title><description><![CDATA[Hi Alfrescans. Have you ever installed Alfresco on an AWS Ec2 instance? Maybe even with Docker Compose? Even though Docker has made…]]></description><link>https://martinmueller.dev/alf-provisioner-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alf-provisioner-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[acs]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[docker]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[ec2]]></category><category><![CDATA[swagger]]></category><category><![CDATA[cdk]]></category><category><![CDATA[postman]]></category><pubDate>Tue, 19 May 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/60201aa138fb718b95f2d983b06eb5e5/prov.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;Have you ever installed Alfresco on an AWS Ec2 instance? Maybe even with Docker Compose? Even though Docker has made installing Alfresco easier, it is still a lot of work! First af all you have to create an Ec2 instance. To do this, you have to log into AWS, select an Ec2 type and start it. Then connect it there, install Docker and then you have to do an Alfresco Docker Compose installation. How great would it be if we had a Managed Service that did all this for us for us?&lt;/p&gt;
&lt;p&gt;Good news! That&apos;s exactly what I&apos;ve been working on in the past few weeks. As a result of my work, all you will have to do in the future is to enter the desired Ec2 type and choose the Alfresco Docker Compose Deployment and the Alfresco Provisioner does the rest and installs Alfresco for you! This allows everyone to quickly and easily create Alfresco backends for themselves and their community. In the next sections, I will explain in more details how it works and which technologies I used.&lt;/p&gt;
&lt;h1&gt;For Whom?&lt;/h1&gt;
&lt;p&gt;I see a clear need for the Alfresco Provisioner amongst smaller groups who could profit from the use of Alfresco products I already have a good real life example from my local area. I am a member of a little church community. Now the church community would like to modernize, also towards digitalisation. For example, videos of church services are uploaded to YouTube or pictures taken end up somewhere in Dropbox. Community projects are mainly planned only on pen and paper, because of the right digital tools are simply missing. I see Alfresco products being able to help a group like my church community to manage content more efficiently. You are also likely to know groups such as clubs in your area that could benefit from Alfresco.&lt;/p&gt;
&lt;p&gt;The rapid provision of the Alfresco backend for such communities could also help with the mandatory digitalisation during the corona crisis. It should be avoided as much as possible to exchange real documents from person to person or to work on them face to face together. I would like to do my part to help with the pandemic and maybe the Alfresco Provisioner is a possibility.&lt;/p&gt;
&lt;p&gt;It will be challenging to keep the costs as low as possible and to pass on the cost advantages of the cloud to the user in the best possible way. A few ideas that I already have in this regard are the use of Reserved Instances, Spot Instances, S3 as object storage, Pay as you go for the Alfresco instances and the possibility to use your own Ec2 instances.&lt;/p&gt;
&lt;p&gt;Another possibility would be to create the Docker Compose and use easily expandable backends for demo purposes and thus show potential users what Alfresco products are capable of.&lt;/p&gt;
&lt;h1&gt;Technologies&lt;/h1&gt;
&lt;p&gt;The Alfresco Provisioner uses a variety of modern technologies. I describe them below in the categories - backend, frontend, and DevOps Pipeline.&lt;/p&gt;
&lt;h2 id=&quot;backend&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#backend&quot; aria-label=&quot;backend permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Backend&lt;/h2&gt;
&lt;p&gt;The Alfresco instances are operated with the help of Docker Compose, which I created with the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt;. These then run on AWS Ec2 instances. The use of Ec2 instances for an Alfresco backend has become very common. However, I make this creation of the instances as dynamic and simple as possible. I have created an AWS Api GateWay which is autonomously able to start, stop and terminate Ec2 instances using API requests from the user.&lt;/p&gt;
&lt;p&gt;After the instance is started, the user receives a url that brings him to the Alfresco backend. A number of lambdas, step functions, dynamo DB tables and S3 buckets also work behind the Api Gateway to make them possible. All of this is written with infrastructure as code in the AWS CDK. I use TypeScript as the programming language for the CDK and the Lambdas. I began to love TypeScript during this project and it enables me to develop the Alfresco Provisioner very quickly. A Swagger file is also created using CDK, which is used as the UI and client library for the front end. I have more detailed information on how to seamlessly integrate Swagger / OpenApi in CDK &lt;a href=&quot;https://martinmueller.dev/cdk-swagger-eng&quot;&gt;described in this article&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;frontend&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#frontend&quot; aria-label=&quot;frontend permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Frontend&lt;/h2&gt;
&lt;p&gt;The frontend is still very modest compared to the backend. This is partly due to the fact that I still have a lot to learn in the frontend area, but also because the backend is developing quickly and I don&apos;t want to readjust UI components every time. My choice of technologies are React and TypeScript. React impresses with a rich selection of beautiful components and TypeScript is an ingenious language. To briefly describe TypeScript it only takes the best out of Java and JavaScript. What I like most on TypeScript is the usage of Types. This serves as documentation and I create order in the rather typeless jungle of JavaScript. TypeScript&apos;s zero handling or undefined handling is also great.&lt;/p&gt;
&lt;p&gt;In addition, I decided to use the OpenAPI UI Explorer as my UI. This simply has the great advantage that the UI components are only rendered based on the Swagger file and I don&apos;t have to do it myself. Quasi automatically generated components. You can find out more from my previous posts and on the Swagger UI page in &lt;a href=&quot;https://github.com/swagger-api/swagger-ui&quot;&gt;GitHub&lt;/a&gt; and on &lt;a href=&quot;https://swagger.io/tools/swagger-ui/&quot;&gt;Swagger.io&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;devops-pipeline&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#devops-pipeline&quot; aria-label=&quot;devops pipeline permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;DevOps Pipeline&lt;/h2&gt;
&lt;p&gt;By DevOps Pipeline I mean the process from implementing new features to bringing those into production. There is a huge variety for archiving that!. In general, however, it has been set to be automated as much as possible. I have achieved a very high degree of automation in my pipeline. I just have to push to the master branch, then a test stack is set up and postman tests are carried out against the API GateWay. If the tests were successful, the production stack will be updated automatically. I can easily influence this behavior in the code itself by setting the following variables:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  destroyBefore&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
  deploy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
  updateProduction&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
  destroyAfter&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I also use AWS CDK which allows me to define the test and production stack using TypeScript. More about this can be found in my previous post &lt;a href=&quot;https://martinmueller.dev/cdk-multistack-eng&quot;&gt;CDK Multistack&lt;/a&gt; or &lt;a href=&quot;http://martinmueller.dev/cdk-example-eng&quot;&gt;CDK in general&lt;/a&gt;. I find Travis and AWS CDK a brilliant combination&lt;/p&gt;
&lt;h1&gt;How does it work?&lt;/h1&gt;
&lt;p&gt;The provisioning of the Alfresco instances takes place via the REST API. The user logs in to the website of the managed service, then receives an OAUTH token and can then use it to create new Alfresco instances, call up and change old ones. By using the OpanAPI UI Explorer, the user can explore the very detailed information on how to use the REST API, i.e. which parameters in the requests and response are to be set or expected.&lt;/p&gt;
&lt;p&gt;Below I list how the body in the POST request is for creating a new instance:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;alfresco&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;&quot;alfType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;ec2InstanceType&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;t2.large&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;gitRepo&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;alf-ec2-1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;&quot;customName&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alf Backend 1&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;userId&lt;/strong&gt; is just the username in the system and &lt;strong&gt;customName&lt;/strong&gt; a nickname for the Alfresco backend created with the provisioner. &lt;strong&gt;AlfType&lt;/strong&gt; describes the type of Alfresco backend. This consists of the type Ec2 VM &lt;strong&gt;ec2InstanceType&lt;/strong&gt; and an Alfresco Docker Compose Repository &lt;strong&gt;gitRepo&lt;/strong&gt;. The GitHub repository is on my account and private. I currently only support one github repo:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;alf-ec-1&lt;/strong&gt;: ACS 6.2 Community, ACA&lt;/p&gt;
&lt;p&gt;All components were installed with the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt;. Of course, this offer is planned to be expanded widely in the future. It would also be conceivable to use Alfresco Git repositories from other users who are not from my GitHub realm. You just have to meet a certain standard and then there is nothing to be said against it.&lt;/p&gt;
&lt;p&gt;A detailed description of all REST endpoints as well as their requests and response parameters can be found on the Alfresco Provisioner UI page.&lt;/p&gt;
&lt;h1&gt;Planned Features&lt;/h1&gt;
&lt;p&gt;Already many features are planned, which enable the user to save money, facilitate the handling of Alfresco products and make the backend more secure. The user should be able to stop and start the instances. If the instance is stopped, the user no longer has to pay for the computer, but only for the storage or possibly no longer. An extension for the automatic creation of backups would also be useful. For this I will look at Tony&apos;s interesting work with &lt;a href=&quot;https://github.com/toniblyx/alfresco-backup-and-recovery-tool&quot;&gt;Alfresco BART&lt;/a&gt;. This would also make it easier to upgrade to other alfTypes. At the moment I have made good progress by writing a tool in Go that can create backups. Now the only thing missing is the possibility to import them back into Alfresco.&lt;/p&gt;
&lt;p&gt;No HTTPS has yet been set up for the proxy of the instances. I plan to use the certificates provided by Let&apos;s Encrypt. For this you simply have to create a Docker Companion, which takes over the certificate management. It should also be possible to have the certificates renewed automatically before expiry. So far only ACS Community is set up, but I plan to offer other Alfresco products such as ACS Enterprise or APS. I&apos;m also thinking about an onboarding layer for ACA.&lt;/p&gt;
&lt;p&gt;Another useful feature would be if the user can simply redirect the url instance to his own domain url.&lt;/p&gt;
&lt;h1&gt;Closed Alpha&lt;/h1&gt;
&lt;p&gt;I will soon make the Alfresco Provisioner available to the public. For that I thought to organize a closed alpha first. Interested people can try out the Alfresco Instance Provisioner and provide feedback and more.&lt;/p&gt;
&lt;p&gt;If you are interested, write to me and I will then create your access accounts. All I need is the email address and the desired user name. I don&apos;t have a specific launch date for the Closed Alpha yet, but I am confident that I will do it in May.&lt;/p&gt;
&lt;h2 id=&quot;brief-instructions-on-how-to-use-the-alfresco-provisioner&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#brief-instructions-on-how-to-use-the-alfresco-provisioner&quot; aria-label=&quot;brief instructions on how to use the alfresco provisioner permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Brief instructions on how to use the Alfresco Provisioner&lt;/h2&gt;
&lt;p&gt;I decided to make a short video about how to use the Alfresco Provisioner. The video can be viewed here: &lt;a href=&quot;https://www.youtube.com/watch?v=OOEOE_ncsx4&quot;&gt;https://www.youtube.com/watch?v=OOEOE_ncsx4&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;more-about-the-alfresco-products&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#more-about-the-alfresco-products&quot; aria-label=&quot;more about the alfresco products permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More about the Alfresco Products&lt;/h2&gt;
&lt;p&gt;To give you a quicker&lt;/p&gt;
&lt;h1&gt;From a Personal Perspective&lt;/h1&gt;
&lt;p&gt;What I like most about this project is the fact that most of the implementation, testing, development and documentation is done or supported using the Swagger definition. This goes from the validation of the request parameters, implementation of the REST interface, documentation, visualization with Swagger UI and automated tests in Postman. I love the approach with the Swagger definition, which I can preview using the Swagger plugin in Visual Studio Code, to use for almost everything. For sure, that&apos;s the future of server implementations.&lt;/p&gt;
&lt;p&gt;Furthermore, I&apos;m just still overwhelmed with what a single developer is able to do with AWS CDK, especially in the TypeScript flavor. I have already described my enthusiasm for &lt;a href=&quot;http://martinmueller.dev/cdk-example-eng&quot;&gt;CDK&lt;/a&gt; here and do not want to repeat it here. Please catch up.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;What started as a simple AWS CDK experiment quickly developed into a great new service that I called the Alfresco Provisioner. This makes it easy to provide Alfresco backends that were developed with Docker Compose. In the closed alpha phase I cordially invite you to use the service.&lt;/p&gt;
&lt;h1&gt;Kudos&lt;/h1&gt;
&lt;p&gt;A big thank you to the &lt;a href=&quot;https://gitter.im/awslabs/aws-cdk&quot;&gt;AWS CDK Community in Gitter&lt;/a&gt;. I have rarely seen a community so in love with technology.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/60201aa138fb718b95f2d983b06eb5e5/prov.png</featuredImage><media:content url="https://martinmueller.dev/static/60201aa138fb718b95f2d983b06eb5e5/prov.png" medium="image"/></item><item><title><![CDATA[Alfresco Virtual Hack-a-thon May 2020 Summary]]></title><description><![CDATA[Hi Alfhackas. The Alfresco hack-a-thon was great. What I liked most were the personal conversations with many great ex-colleagues and other…]]></description><link>https://martinmueller.dev/alf-hackathon-after/</link><guid isPermaLink="false">https://martinmueller.dev/alf-hackathon-after/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[acs]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[docker]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[hackathon]]></category><pubDate>Fri, 15 May 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c5ea648a4bafcba102488588ee4533d0/hack.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi Alfhackas.&lt;/p&gt;
&lt;p&gt;The Alfresco hack-a-thon was great. What I liked most were the personal conversations with many great ex-colleagues and other Alfresco folks. In addition, I was able to learn valuable information about planned projects within Alfresco. For example, I am very excited to see where Digital Workspace, the beautiful webapp for ACS Enterprise, will develop. Very soon it will get UI elements to display APS elements like tasks and processes. I was also advised that as an Alfresco partner I could get access to the Digital Workspace Repository, which I gratefully will do.&lt;/p&gt;
&lt;h1&gt;Lets Encrypt&lt;/h1&gt;
&lt;p&gt;My project for the Hack-a-thon was to give the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Docker Alfresco Installer&lt;/a&gt; a Docker extension, which would enable Lets Encrypt to use authorized certificates for the HTTPS connection. Even the extension would manage the entire life cycle of the certificate. I haven&apos;t completely finished with it, but I was able to implement a good bit and I&apos;m guaranteed to finish it this weekend.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Many thanks to the organizers of the Alfresco Hack-a-thon and to the great Alfresco community. I will definitely be back at the next Hack-a-thon. Cheers.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/c5ea648a4bafcba102488588ee4533d0/hack.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/c5ea648a4bafcba102488588ee4533d0/hack.jpeg" medium="image"/></item><item><title><![CDATA[Alfresco Virtual Hack-a-thon May 2020]]></title><description><![CDATA[Hi Alfrescans. On May 11, 2020, Alfresco will host a virtual hackathon. You can find the current project ideas here at hub.alfresco.com…]]></description><link>https://martinmueller.dev/alf-hackathon-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alf-hackathon-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[acs]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[docker]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[hackathon]]></category><pubDate>Fri, 08 May 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c5ea648a4bafcba102488588ee4533d0/hack.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;On May 11, 2020, Alfresco will host a virtual hackathon. You can find the current project ideas here at &lt;a href=&quot;https://hub.alfresco.com/t5/news-announcements/alfresco-virtual-hack-a-thon-may-2020-project-ideas/ba-p/298030&quot;&gt;hub.alfresco.com&lt;/a&gt;. With this post I want to invite you to participate.&lt;/p&gt;
&lt;h1&gt;Why Participate?&lt;/h1&gt;
&lt;p&gt;There can be several reasons why you should participate. If you like the Alfresco products, it&apos;s great to help develop the products further or even create completely new ones. For example, I would like an SSL Companion Container for the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt;. Without further ado, I simply registered the project to help organize and implement it.&lt;/p&gt;
&lt;p&gt;It is also a great opportunity to make contacts with motivated developers from all over the world. During my time at Alfresco, I got to know smart and helpful developers, from whom I learned a lot. I am always looking for opportunities to learn and the hackathon is the perfect opportunity for that.&lt;/p&gt;
&lt;p&gt;My company would also like to organize a hackathon in the future and the Alfresco Hackathon could be a perfect opportunity to learn how to organize such hackathons.&lt;/p&gt;
&lt;p&gt;The best reason: why not? It could be an interesting new experience for you and if you don&apos;t like it you can go at any time and just don&apos;t take part next time.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;The Alfresco Hackathon on May 11, 2020 is just around the corner. In the starting blocks my friends :)! After the event I will report in the form of a post here how I liked the hackathon. By 11 then and stays healthy :D!&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/c5ea648a4bafcba102488588ee4533d0/hack.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/c5ea648a4bafcba102488588ee4533d0/hack.jpeg" medium="image"/></item><item><title><![CDATA[AWS CDK Multistacks for Test and Produktion]]></title><description><![CDATA[Hi AWS Fans, Last time I described how well AWS CDK is suited for describing infrastructure as code. This article is about how CDK could…]]></description><link>https://martinmueller.dev/cdk-multistack-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-multistack-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[lambda]]></category><category><![CDATA[cdk]]></category><category><![CDATA[production]]></category><category><![CDATA[github]]></category><category><![CDATA[travis]]></category><pubDate>Sun, 19 Apr 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/af0d68d5c53d93dd998ef9f7a7e4135f/cloud.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi AWS Fans,&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://martinmueller.dev/cdk-example-eng&quot;&gt;Last time&lt;/a&gt; I described how well AWS CDK is suited for describing infrastructure as code. This article is about how CDK could look in a test and production environment. In my private project I have already implemented something like a production environment and I am very enthusiastic about it. In short, I use CDK&apos;s &lt;a href=&quot;https://docs.aws.amazon.com/cdk/latest/guide/stack_how_to_create_multiple_stacks.html&quot;&gt;Multistack&lt;/a&gt;. In the next sections I describe how my deployment looks like.&lt;/p&gt;
&lt;h1&gt;CDK Multistack&lt;/h1&gt;
&lt;p&gt;A CDK multistack is a CDK deployment that manages multiple stacks. These stacks can be in the same or different regions, or even in a different AWS account. The different stacks can then be easily initialized with different parameters before creation. Here is an example with two stacks:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MultiStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EuWest2Prod&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;prod&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eu-west-2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ABC&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// disable create ec2 instance&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// createInstances: {&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;//   imageId: &apos;ami-04d5cc9b88f9d1d39&apos;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// },&lt;/span&gt;
    cognito&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;true&apos;&lt;/span&gt;
    domain&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      domainName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;api.nope.dev&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      zoneName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;api.nope.dev.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      hostedZoneId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;AA&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      certificateArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;arn:aws:acm:eu-west-2:ABC:certificate/xyz&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MultiStack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;EuWest2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  environment&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;dev&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    region&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;eu-west-2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    account&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;XYZ&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  createInstances&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    imageId&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ami-0cb790308f7591fa6&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a small excerpt from my project. The first stack called EuWest2Prod describes the production stack, which is even in another account. The second stack EuWest2 is the test stack. This type of parameterization can be used to turn features on and off. In the production stack, by commenting out createInstances, I disabled the feature to create Ec2 instances in order to save costs. The parameterization also supports simple migration from one AWS account to another.&lt;/p&gt;
&lt;p&gt;In the next sections, I want to talk more about my test stack and production stack. But I have to mention fairly that I don&apos;t have a real production yet. So to speak real customers who use my service. I hope to be able to change this soon in a closed beta version. At the moment I am trying to gain experience on how I could keep a real production running as good as possible, i.e. implement seamlessly new features. AWS ChangeSets for cloud formation stacks are very suitable for that. These only change the respective stack with the necessary updates. Before you continue reading, I definitely recommend to learn about AWS ChangeSets for CloudFormations.&lt;/p&gt;
&lt;h1&gt;Test Stack&lt;/h1&gt;
&lt;p&gt;Test stacks should be primarily cheap. The tests are carried out and the log result should be easily accessible to the developer. Shortly afterwards, the stack should destroy the resources to save money. If a manual assessment of the test stack is still desired afterwards, a delay in destruction can be implemented. I did that for the Ec2 instances which terminate themself after 55 minutes.&lt;/p&gt;
&lt;p&gt;And of course the test stack should test. What exactly that is depends on your use case. I test against an API GateWay and its endpoints. In the background, several DynamoDB tables and EC2 instances are created or terminated using step functions. I do that with Postman. If you are more interested in testing, I have already written about it in one of my &lt;a href=&quot;https://martinmueller.dev/cdk-example-eng&quot;&gt;previous post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In itself, that&apos;s it. If the test phase was successful, the update can be applied to production. This is described in the next section.&lt;/p&gt;
&lt;h1&gt;Production Stack&lt;/h1&gt;
&lt;p&gt;The production stack is intended for customers. Everything has to work as well as possible there and new features should only be implemented after they have been proven in the test stack. It can also make sense to operate the production stack with slightly changed service settings. An example of this would be that I don&apos;t really need user administration with Cognito in the test stack, but I do in the production stack. This keeps the complexity in the test stack lower. In the snippet above, I defined cognito in production. Another example would be EC2 instances. In the test stack, low cost EC2 types are fine, but stronger and therefore more expensive instances are required in production, usually.&lt;/p&gt;
&lt;p&gt;The question now is where the production stack should be deployed. Fortunately, CDK gives us every freedom there. It is possible to deploy the stack in the same or in a different region, in the same account. The production stack can also be deployed in another account. Profiles have to be used for this. Here is an example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;cdk deploy &lt;span class=&quot;token string&quot;&gt;&quot;$ STACK_NAME_PRODUCTION&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--profile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; prod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This stack is now deployed in another AWS account. So far I have had a good experience with this type of deployments. However, this type of deployment has one disadvantage. Since I am now dependent on the Profile parameter, I cannot use the same cdk deploy command for the test stack and I have to execute two CDK commands:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;cdk deploy &lt;span class=&quot;token string&quot;&gt;&quot;$ STACK_NAME_TEST&quot;&lt;/span&gt;
cdk deploy &lt;span class=&quot;token string&quot;&gt;&quot;$ STACK_NAME_PRODUCTION&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--profile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; prod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It would be great if I could simply specify the profile name when defining it in the multistack. This disadvantage is of course not really bad, since in a proper pipeline the test stack should run first and after passed test an a manual approval the production stack is deployed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; I received feedback that there is already a workaround for this in the npm registry: &lt;a href=&quot;https://github.com/hupe1980/cdk-multi-profile-plugin&quot;&gt;https://github.com/hupe1980/cdk-multi-profile-plugin&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;DevOps Travis Pipeline&lt;/h1&gt;
&lt;p&gt;Every developer should be familiar with Travis. The Travis Free Tier allows you to use VMs from Travis if your GitHub project is public. These then only have to be defined and configured in the .travis file. That&apos;s exactly what I&apos;m doing. To be honest, I use Travis a lot. I just briefly describe my workflow when I create a new feature:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write code adjustments of new feature in master.&lt;/li&gt;
&lt;li&gt;If necessary add new test in Postman.&lt;/li&gt;
&lt;li&gt;master commit -&gt; Travis build is triggered.&lt;/li&gt;
&lt;li&gt;Travis fails or passes.&lt;/li&gt;
&lt;li&gt;If it failed, the stack reverted automatically and I evaluated the logs to see what went wrong. Back to step 1).&lt;/li&gt;
&lt;li&gt;If it passed, the new feature is on all stacks and I can now test it manually.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is very awesome because I have to do fewer interactions to implement this new feature. The entire build takes about 10 minutes and then I can just do something else for 10 minutes. This type of pipeline has brought me very quick iterations of new features. I am literally flabbergasted what is possible today with just a DevOps. What I can do alone would have required about 10 people 5 years ago instead of just one.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;CDK&apos;s multistacks are a great way to manage multiple stacks like a test stack and production stack. For my small project I have great experiences with this type of stack management and described it here. So far, a relatively small Travis build has been sufficient to create a useful pipeline. I am considering looking into AWS CodePipeline to see if it could benefit me. I hope you enjoyed my little summary :)&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/af0d68d5c53d93dd998ef9f7a7e4135f/cloud.jpg</featuredImage><media:content url="https://martinmueller.dev/static/af0d68d5c53d93dd998ef9f7a7e4135f/cloud.jpg" medium="image"/></item><item><title><![CDATA[ACS and APS Deployment with Docker Compose]]></title><description><![CDATA[Hi Alfrescans. It is time again to report about an exciting Alfresco partner project from me. For a customer here in Germany I am developing…]]></description><link>https://martinmueller.dev/alf-acs-aps-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alf-acs-aps-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[acs]]></category><category><![CDATA[aps]]></category><category><![CDATA[docker]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[ec2]]></category><pubDate>Sun, 12 Apr 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/f47b6c2e94925b7c19457ec716647b6b/compose.jpeg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi Alfrescans.&lt;/p&gt;
&lt;p&gt;It is time again to report about an exciting Alfresco partner project from me. For a customer here in Germany I am developing a POC which should use ACS 6.2 and APS 1.10. After a bit of persuasion, I was able to convince those involved to use Docker for ACS 6.2. My plan was to create a Docker Compose Deployment which included ACS, APS and openLDAP as an identity provider. The complete deployment can be viewed &lt;a href=&quot;https://github.com/mmuller88/alf-acs-aps&quot;&gt;in GitHub&lt;/a&gt;. One thing should be mentioned in advance. Alfresco officially recommends &lt;a href=&quot;https://github.com/Alfresco/alfresco-dbp-deployment&quot;&gt;to use Kubernetes&lt;/a&gt; for such deployments, but the cloud is a taboo topic for my customers so far. I am also excited to see how far I will get with Docker Compose for such a deployment.&lt;/p&gt;
&lt;h1&gt;Docker Compose Setup&lt;/h1&gt;
&lt;p&gt;To start, I will describe in more detail the technologies used in my deployment. As indicated at the beginning, ACS 6.2 should be installed. The most recently released version is 6.2.0.3. So that has to be reflected in the alfresco Dockerfile at /alfresco/Dockerfile. Share remains on version 6.2.0 since no newer version has been released. ACS is to be connected with an openLDAP DB for user provisioning. Fortunately, there are already great images for creating and managing an &lt;a href=&quot;https://github.com/osixia/docker-openldap&quot;&gt;openLDAP DB&lt;/a&gt;. For the visual administration of the openLDAP DB I use &lt;a href=&quot;http://phpldapadmin.sourceforge.net/wiki/index.php/Main_Page&quot;&gt;phpldapadmin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.alfresco.com/process-services1.10/concepts/welcome.html&quot;&gt;APS 1.10&lt;/a&gt; should be used to model the workflows. The fact that Alfresco no longer offers Docker Compose Reference Deployments for APS 1.10 is somewhat unfortunate. I guess that is because of the Kubernetes deployments and that there is a stronger focus on those. Fortunately, there are still a few old &lt;a href=&quot;https://github.com/AlfrescoLabs/aps-docker-library/tree/master/docker-compose&quot;&gt;Docker Compose templates&lt;/a&gt; and with a few modifications they work too!&lt;/p&gt;
&lt;p&gt;Since it is very memory intensive to run ACS and APS at the same time, I decided to split the complex deployment into three separable deployments. So I can continue to work efficiently on my 16 GB memory laptop. The division is done using Docker Compose files. The first is the ACS deployment, followed by the second with the APS deployment. Finally, there is ACS and APS deployment. I think that&apos;s a brilliant idea because if I just want to work on ACS or APS alone, I don&apos;t have to start up the entire stack. In addition, I am considering deploying the third deployment ACS and APS in EC2 using a good looking DevOps pipeline.&lt;/p&gt;
&lt;h1&gt;Prerequisites&lt;/h1&gt;
&lt;p&gt;It is clear that you need Docker. If you are working on a Windows or Mac, I recommend the &lt;a href=&quot;https://www.docker.com/products/docker-desktop&quot;&gt;Docker Desktop&lt;/a&gt;. After the installation please remember to make more memory available to the Docker environment as the default 2 GB are far too little to get ACS up and running. At least 12 GB would is recommended!&lt;/p&gt;
&lt;p&gt;The ACS Docker Compose File also uses private images hosted by Alfresco in quay.io. For these, it would be important to request access data from Alfresco Support. If you have this, just run the following command and enter the credentials:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker login quay.io&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;More or less optional but my example in the GitHub repository uses Node&apos;s NPM for a CLI script tool to wait until Alfresco has finished booting. So it&apos;s best to install the node and NPM as well.&lt;/p&gt;
&lt;h1&gt;Git Prepare&lt;/h1&gt;
&lt;p&gt;Of course, a git repo has to be created first. I called mine &lt;a href=&quot;https://github.com/mmuller88/alf-acs-aps&quot;&gt;alf-acs-aps&lt;/a&gt;. As in my last &lt;a href=&quot;https://martinmueller.dev/start-script-eng&quot;&gt;Alfresco Docker Project&lt;/a&gt; I recommend using the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Docker Alfresco Installer&lt;/a&gt; to prepare the empty Git repository. I describe exactly how the Docker Alfresco Installer can be used &lt;a href=&quot;https://github.com/mmuller88/alfresco-docker-installer-eng&quot;&gt;here&lt;/a&gt;. When installing, make sure that LDAP and an SMTP server are also selected. If you are not using my GithUb Repo, you should now integrate the APS 1.10 services into the Docker Compose Deployment. I recommend that you split the deployment into three parts. All three are explained in the next sections.&lt;/p&gt;
&lt;h2 id=&quot;acs-deployment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#acs-deployment&quot; aria-label=&quot;acs deployment permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ACS Deployment&lt;/h2&gt;
&lt;p&gt;First a docker-compose-base.yml file is created which contains all the services required for all three deployments. In my case this is an openLDAP and postgres database. As well as a mail server. Then the ACS Docker Compose File is created. The entire deployment can now be started as:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-ACS.yml up -d --build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and so stop:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-ACS.yml stop&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If a complete ACS restart with empty databases and other storage is desired, simply execute these commands:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-ACS.yml down
rm -rf data
rm -rf logs&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;aps-deployment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#aps-deployment&quot; aria-label=&quot;aps deployment permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;APS Deployment&lt;/h2&gt;
&lt;p&gt;The APS deployment is started as:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-APS.yml up -d --build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and it is stopped like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-APS.yml stop&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To erase just do the following:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-APS.yml down
rm -rf data
rm -rf logs&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;acs-and-aps-deployment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#acs-and-aps-deployment&quot; aria-label=&quot;acs and aps deployment permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;ACS and APS Deployment&lt;/h2&gt;
&lt;p&gt;Warning a warning in advance! This deployment is very memory intensive. Your laptop or PC should have at least 16Gb. Alternatively, I plan to deploy this variant in the cloud on EC2.&lt;/p&gt;
&lt;p&gt;And this is how all services are started:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-ACS.yml -f docker-compose-APS.yml -f docker-compose-Proxy.yml up -d --build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and so stopped&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-ACS.yml -f docker-compose-APS.yml -f docker-compose-Proxy.yml stop&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And just type to tear it down:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose -f docker-compose-base.yml -f docker-compose-ACS.yml -f docker-compose-APS.yml -f docker-compose-Proxy.yml down
rm -rf data
rm -rf logs&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Outlook&lt;/h1&gt;
&lt;p&gt;As indicated, I would like to bring the third deployment ACS and APS to AWS EC2. Preferably even in a nice DevOps pipeline, i.e. commit after master triggered and deploy to EC2, where automated tests are then carried out, such as whether ACS and APS have successfully booted.&lt;/p&gt;
&lt;p&gt;SSO (Single Sign On) allows you to only have to register once for Alfresco products. That means if I log in to Share for example and then open Alfresco Digital Workspace or the Ativiti app, I don&apos;t have to log in again. To do this, AIMS (Alfresco Identify Manager Service) would have to be configured with ACS and, in addition, the SAML amp.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;You don&apos;t always have to shoot with the Kubernetes shotgun when it comes to container orchestration. Docker Compose can also be used to orchestrate containers in a simplified manner. There is even the option of dividing complex deployments like that into smaller pieces. This not only saves memory footprint, but is also excellent for fast iterations during development. So feel free to try it out yourself and deploy ACS and APS using Docker Compose. If there are any questions, just write to me.&lt;/p&gt;
&lt;h1&gt;Kudos&lt;/h1&gt;
&lt;p&gt;To Thijs from the amazing &lt;a href=&quot;https://discord.gg/XGQjUU&quot;&gt;Alfrescan Discord Channel&lt;/a&gt; for suggesting this kind of Docker Compose deployment split.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/f47b6c2e94925b7c19457ec716647b6b/compose.jpeg</featuredImage><media:content url="https://martinmueller.dev/static/f47b6c2e94925b7c19457ec716647b6b/compose.jpeg" medium="image"/></item><item><title><![CDATA[AWS CDK Api Gateway with Swagger]]></title><description><![CDATA[Ahoi AWS'ler and Swagger fans In the last post I showed how AWS CDK can be used as a welcome alternative to YAML for describing your cloud…]]></description><link>https://martinmueller.dev/cdk-swagger-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-swagger-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[swagger]]></category><category><![CDATA[cdk]]></category><category><![CDATA[cfd]]></category><category><![CDATA[github]]></category><category><![CDATA[travis]]></category><category><![CDATA[postman]]></category><pubDate>Sun, 05 Apr 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/f1aa4c6cb8a88964c80c6e6f5ba9ffef/swagger.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Ahoi AWS&apos;ler and Swagger fans&lt;/p&gt;
&lt;p&gt;In the last post I showed how &lt;a href=&quot;https://martinmueller.dev/cdk-example-eng&quot;&gt;AWS CDK&lt;/a&gt; can be used as a welcome alternative to YAML for describing your cloud infrastructure. Working on my CDK project from I encountered a problem handling Swagger files. But first I want to explain what the Swagger definitions are. It should also be said that the new version of Swagger has been called OpenApi since 2018. When using AWS API Gateway, it is convenient to use Swagger for parameter validation such as Query, Path and Body Parameter. What exactly Swagger is and why I think it&apos;s so great I describe in the next section.&lt;/p&gt;
&lt;h1&gt;What is Swagger&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://swagger.io/docs/specification/2-0/what-is-swagger/&quot;&gt;Swagger&lt;/a&gt; is a YAML or JSON template language for describing RESTful APIs. Following I describe what is great about Swagger. First of all, the templates are extremely suitable as documentation about the API itself, because a stylish looking HTML UI can be generated out of the template, which describes the API endpoints very well. Such an UI can be seen in the cover of this blog post. Even more brilliant is the UI that can be used directly to test the endpoints, i.e. to send and receive requests and responses. Many API interfaces, like the AWS API Gateway, offer the parameter validation of requests with using Swagger. I give a little example for what I mean by parameter validation using the following example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; query
    name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; userId
    description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Get items of that user
    required&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here you can see a parameter of the type query. That means it would look something like this in the URL&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;http://&amp;lt;url&gt;/items?userId=martin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With parameter validation, I can then define certain properties of the parameter, such as the name &lt;strong&gt;userId&lt;/strong&gt;, whether it is required and what type the value should be, in our case as of the type string.&lt;/p&gt;
&lt;p&gt;Another very powerful feature is that it is possible to generate client libaries from the Swagger definition (&lt;a href=&quot;https://swagger.io/tools/swagger-codegen/&quot;&gt;https://swagger.io/tools/swagger-codegen/&lt;/a&gt;). For example, Alfresco does this with the &lt;a href=&quot;https://api-explorer.alfresco.com/api-explorer/&quot;&gt;API Explorer&lt;/a&gt; (For more information, see &lt;a href=&quot;https://github.com/Alfresco/rest-api-explorer&quot;&gt;GitHub Api-Explorer&lt;/a&gt;) and &lt;a href=&quot;https://www.alfresco.com/abn/adf/&quot;&gt;ADF&lt;/a&gt; (or &lt;a href=&quot;https://github.com/Alfresco/alfresco-js-api&quot;&gt;ADF JS Github&lt;/a&gt;). There, for example, the &lt;a href=&quot;https://github.com/Alfresco/rest-api-explorer/blob/master/src/main/webapp/definitions/alfresco-core.yaml&quot;&gt;Swagger File&lt;/a&gt; becomes the JavaScript API Library generated, which can be used as a wrapper for the API requests and is also in &lt;a href=&quot;https://github.com/Alfresco/alfresco-ng2-components&quot;&gt;ADF Components Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&apos;s also cool, &lt;a href=&quot;https://www.postman.com/automated-testing&quot;&gt;Postman&lt;/a&gt; offers an import feature for Swagger definitions. Then a collection is created immediately. This is very handy if you want to start writing the requests in Postman.&lt;/p&gt;
&lt;h1&gt;AWS Api Gatway with Swagger&lt;/h1&gt;
&lt;p&gt;All the features from the previous section sound very tempting, don&apos;t they? How nice that AWS API Gateway also offers to &lt;a href=&quot;https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-export-api.html&quot;&gt;extract&lt;/a&gt; Swagger definitions from its deployments and also to import it using CloudFormation or CDK. Unfortunately in connection with &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;AWS CDK&lt;/a&gt;, extracted Swagger files are not so easy to reuse for their description. The biggest problem is that if, for example, a lambda is updated, its ARN also changes. However, the Swagger Files extracted from the API Gateway use exactly these ARNs when Lambda is used as a backend implementation for an endpoint. And since the ARN changes, they are outdated in the swagger file. Below is a Swagger Snippet and there you can see the Arn I&apos;m talking about behind the &lt;strong&gt;uri&lt;/strong&gt; keyword.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  / items&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    get&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      responses&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &apos;200&apos;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Ok
          content&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &apos;401&apos;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Authorization information is missing or invalid
          content&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      x&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token key atrule&quot;&gt;amazon-apigateway-integration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        uri&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;
          arn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;apigateway&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;path/2015-03-31/functions/arn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ApiLambdaCrudDynamoDBExam&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;getAllItemsFunction0B7A9&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;1KKCGIJ01C3NI/invocations
        passthroughBehavior&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; when_no_match
        httpMethod&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; POST
        type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; aws_proxy
      parameters&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;$ ref&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#/parameters/alfUserIdParam&apos;&lt;/span&gt;
      x&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token key atrule&quot;&gt;amazon-apigateway-request-validator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Validator&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The AWS CDK team knows about this problem and it is on the roadmap. So hopefully if you read this post the following workaround is no longer necessary. For completeness, I list the related issues here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aws/aws-cdk/issues/723&quot;&gt;https://github.com/aws/aws-cdk/issues/723&lt;/a&gt;
&lt;a href=&quot;https://github.com/aws/aws-cdk/issues/1461&quot;&gt;https://github.com/aws/aws-cdk/issues/1461&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Workaround&lt;/h1&gt;
&lt;p&gt;To solved the problem with deploying CDK twice. The first deploy does not use a swagger definition but the second does. It is really interesting how I generated the Swagger file. In the following I try to describe the process, but please also look into &lt;a href=&quot;https://github.com/mmuller88/cdk-swagger&quot;&gt;my GitHub repo&lt;/a&gt; (there in .travis) for how I implemented this workaround.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I deploy or Swagger File with:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export WITH_SWAGGER = &apos;false&apos; &amp;amp;&amp;amp; cdk deploy --require-approval never&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;WITH_SWAGGER is an env variable in the CDK Deployment File index.ts. This means that no swagger file is used programmatically for the deployment.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Now I can use the AWS CLI to extract the swagger file from the API gateway:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;aws apigateway get-export --parameters extensions = &apos;integrations&apos; --rest-api-id $ REST_API_ID --stage-name prod --export-type swagger --accepts application/yaml tmp/swagger_new.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The generated Swagger File tmp/swagger_new.yaml looks something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;swagger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2.0&apos;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    version&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2020-03-29T16: 59: 22Z&apos;&lt;/span&gt;
    title&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Items Service
&lt;span class=&quot;token key atrule&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hjtiuj2ou1.execute&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;api. &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; .amazonaws.com
basePath&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/prod
&lt;span class=&quot;token key atrule&quot;&gt;schemes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; https
&lt;span class=&quot;token key atrule&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    / items&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        get&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            responses&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &apos;200&apos;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Ok
                &apos;401&apos;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Authorization information is missing or invalid
            x&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token key atrule&quot;&gt;amazon-apigateway-integration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                uri&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;
                arn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;apigateway&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;path/2015-03-31/functions/arn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ApiLambdaCrudDynamoDBExam&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;getAllItemsFunction0B7A9&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;1MLKSKO1RUL3I/invocations
                passthroughBehavior&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; when_no_match
                httpMethod&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; POST
                type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; aws_proxy
            x&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token key atrule&quot;&gt;amazon-apigateway-request-validator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Validator
        post Office&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;It looks very good. However, the parameter validation is still missing. For this a second Swagger definition has to be created manually templates/swagger_validations.yaml and looks something like this:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    / items&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        get&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        parameters&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; alfUserId
            in&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; query
            required&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;
            type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string
            $ ref&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#/parameters/alfUserIdParam&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;What we want now is a merge of both swagger files. NPM offers a useful tool for merging YAML files:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm i -g merge-yaml-cli&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Swagger definition tmp/swagger_full.yaml now contains the current LambdaUri and the parameter validation:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;swagger&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2.0&apos;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  version&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;2020-03-29T16: 59: 22Z&apos;&lt;/span&gt;
  title&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Items Service
&lt;span class=&quot;token key atrule&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; hjtiuj2ou1.execute&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;api. &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; .amazonaws.com
basePath&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;/prod
&lt;span class=&quot;token key atrule&quot;&gt;schemes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; https
&lt;span class=&quot;token key atrule&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  / items&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    get&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        parameters&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; alfUserId
            in&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; query
            required&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;false&lt;/span&gt;
            type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; string
            $ ref&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#/parameters/alfUserIdParam&apos;&lt;/span&gt;
        responses&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &apos;200&apos;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Ok
            &apos;401&apos;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Authorization information is missing or invalid
        x&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token key atrule&quot;&gt;amazon-apigateway-integration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            uri&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;
            arn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;apigateway&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;path/2015-03-31/functions/arn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;secure&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ApiLambdaCrudDynamoDBExam&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;getAllItemsFunction0B7A9&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;1MLKSKO1RUL3I/invocations
            passthroughBehavior&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; when_no_match
            httpMethod&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; POST
            type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; aws_proxy
        x&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token key atrule&quot;&gt;amazon-apigateway-request-validator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Validator
    post Office&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Now this swagger file can be used in the second CDK deployment:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export WITH_SWAGGER = &apos;true&apos; &amp;amp;&amp;amp; cdk deploy --require-approval never&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Attention!: Always take care with creating a new stage deployment in AWS API Gateway. I do this in Travis with the AWS CLI:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;aws apigateway create-deployment --rest-api-id $ REST_API_ID --stage-name prod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Swagger Definitions are ideal for creating, editing, documenting and testing APIs such as those from AWS Api Gateway. They are not only useful directly in the backend. As well they are suited in the frontend because Swagger can generate amazing looking and useful Swagger UI to understand the backend better in a way shorter time.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/f1aa4c6cb8a88964c80c6e6f5ba9ffef/swagger.png</featuredImage><media:content url="https://martinmueller.dev/static/f1aa4c6cb8a88964c80c6e6f5ba9ffef/swagger.png" medium="image"/></item><item><title><![CDATA[AWS CDK Tutorial with Travis Deployment]]></title><description><![CDATA[Ahoy AWS folks For a private project I have been working on an AWS CDK example in the past few days. AWS offers a range of great AWS CDK…]]></description><link>https://martinmueller.dev/cdk-example-eng/</link><guid isPermaLink="false">https://martinmueller.dev/cdk-example-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[aws]]></category><category><![CDATA[lambda]]></category><category><![CDATA[cdk]]></category><category><![CDATA[cfd]]></category><category><![CDATA[github]]></category><category><![CDATA[travis]]></category><category><![CDATA[postman]]></category><pubDate>Sun, 29 Mar 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/5b8afc2cc792f34647192a89cff02f22/cloud.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Ahoy AWS folks&lt;/p&gt;
&lt;p&gt;For a private project I have been working on an AWS CDK example in the past few days. AWS offers a range of great &lt;a href=&quot;https://github.com/aws-samples/aws-cdk-examples&quot;&gt;AWS CDK examples&lt;/a&gt;. The experience I had was so good that I decided to write a blog post about it. I was fortunate to work with CloudFormation very early in my AWS career. It was a lot of fun and amazing to experience infrastructure as code at first hand. Now there seems to be a new kid on the block called AWS CDK (Cloud Development Kit), which can preferably being used as a language to describe the infrastructure in AWS. CDK promises to be a welcome alternative to CloudFormation, instead of writing rather complex YAML, the CDK supports programming languages ​​such as Java, Python, JS or Typescript to define the infrastructure. I think that&apos;s a great idea because if you are using like already Typescript to write your Lambdas, you can use it as well for CDK.
My example code &lt;a href=&quot;https://github.com/mmuller88/cdk-example&quot;&gt;CDK Example Repo&lt;/a&gt; is on GitHub. So feel free to use it. In the next sections I will briefly describe the steps I took to create that Repo.&lt;/p&gt;
&lt;h1&gt;The Requirements&lt;/h1&gt;
&lt;p&gt;If you want to try AWS CDK, you need an AWS account. You also need AWS CLI credentials that allows your deployment to use resources in your AWS account. Usually you create an &lt;a href=&quot;https://docs.aws.amazon.com/de_de/IAM/latest/UserGuide/id_users_create.html#id_users_create_cliwpsapi&quot;&gt;IAM User&lt;/a&gt;. It is important that you save the access data, i.e. the access key ID and the secret access key. These will later be required in the deployment.
The AWS example uses NPM as the package manager. That means it takes care of the dependencies such as the aws-cdk which is installed with the following command:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm install -g aws-cdk&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;NPM is available &lt;a href=&quot;https://nodejs.org/en/download/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Prepare the Git Repo&lt;/h1&gt;
&lt;p&gt;So now lets start. First we create our GitHub repository which is still completely empty. For me I called it &lt;strong&gt;cdk-example&lt;/strong&gt;. Then the &lt;a href=&quot;https://github.com/aws-samples/aws-cdk-examples&quot;&gt;AWS CDK Examples&lt;/a&gt; repo should be forked and checked out locally. With the intention that we can do cherry picking more easily this way and simply copy over example code to our repository.&lt;/p&gt;
&lt;p&gt;If you look at the AWS CDK Examples Repository you might are a bit overwhelmed of the choices. I myself can recommend the examples from the Typescript category because they are many and Typescript seems to be becoming increasingly popular. I also recommend starting with the &lt;a href=&quot;https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/api-cors-lambda-crud-dynamodb&quot;&gt;Api Cors Lambda Crud DynamoDB&lt;/a&gt; Example because it already contains a lot of AWS services like API Gateway, Lambda and DynamoDB. That example is a simple CRUD storage which is backed up with DynamoDB. +&lt;/p&gt;
&lt;p&gt;It&apos;s best not to change the existing source code and first try to get it working. I myself had a little difficulty. The example has a missing dependency. The NPM uuid library, which is used to generate IDs, is missing. To do this, change to the src/ directory and execute the following commands:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm init
npm install uuid&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code also needs to be adjusted a bit, as the uuid has changed somewhat with the versions. Alternatively, you can simply copy from my &lt;a href=&quot;https://github.com/mmuller88/cdk-example&quot;&gt;published GitHub Repo&lt;/a&gt;. In the next section we will get the example up and running.&lt;/p&gt;
&lt;h1&gt;Manually Deploying CDK&lt;/h1&gt;
&lt;p&gt;In the previous section we have prepared the repo so far, now of course we want to deploy it! Since we have our deployment in AWS, it must be ensured that the access credentials are set correctly. In the &lt;strong&gt;This is required&lt;/strong&gt; we have already received the credentials. There are different ways to make these credentials available to your build. The automated deployment in Travis, explained in the next section, works with environment variables. For manual deployment it is more convenient to create the credentials in the aws config folder. simply insert the following files:&lt;/p&gt;
&lt;p&gt;~/.aws/conf and ~/.aws/credentials too! For Windows users simply use your user folder instead of the ~. Write done the following content:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[default]
aws_access_key_id = AKI ...
aws_secret_access_key = for you ...
region = eu-west-2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You should choose a region that is close to you and offers a lot of functionality. I am from Germany and the Frankfurt Region is more close, that region is often behind with new features, I chose the London region eu-west-2.&lt;/p&gt;
&lt;p&gt;Now switch to the repo and execute the following commands:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm install -g aws-cdk
npm install
npm run build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The npm install commands are loading the dependencies and just needed to be executed rarely. The run build command, however, whenever changes have been made. An interesting fact is that it converts the TypeScript files into JavaScript files. Since TypeScript is a superset of JavaScript, you do not have to reinvent TypeScript tooling and simply use the existing JavaScript tooling out there. Anyway take care and not get confused about those generated JS files. You might apply changes there and wondering why it is not reflected in the build, as I did.&lt;/p&gt;
&lt;p&gt;Next, CDK must be configured so that it knows which account and which region to use. I don&apos;t understand why CDK cannot generate this from the AWS folder. Then CDK can be deployed:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cdk bootstrab aws//{account}/{region}
cdk deploy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also interesting with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cdk synth &gt; cfn.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Can you look at the generated CloudFormation template.&lt;/p&gt;
&lt;h1&gt;Automation with Travis&lt;/h1&gt;
&lt;p&gt;The manual effort for deployment certainly is still low, but this will change as complexity increases. So I had great experiences to automate as much of it as possible. And now imagine how cool it is to change the production environment with just a push to master. I describe a little foretaste of what this could look like exactly here. Also, I would like to say again that you could look at my Travis definition here &lt;a href=&quot;https://github.com/mmuller88/cdk-example/blob/master/.travis.yml&quot;&gt;CDK Example Repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What I do there in Travis is explained quite simply. I just do the manual deploy steps from the previous section in Travis. Since Travis has my AWS credentials in the form of encrypted environmental variables, I allow it to be manipulated in my AWS account resources. The following environmental variables were required: AWS_ACCESS_KEY_ID, AWS_ACCOUNT_NUMBER, AWS_DEFAULT_REGION, AWS_SECRET_ACCESS_KEY, CDK_DEFAULT_ACCOUNT, CDK_DEFAULT_REGION.&lt;/p&gt;
&lt;p&gt;Just not having to do the manual deployment anymore may not seem very useful at first glance, but believe me, it&apos;s worth it! After the CDK deployment is finished, Postman tests are then carried out in the form of requests and response validations. I will describe more about this in the next section.&lt;/p&gt;
&lt;h1&gt;Stack Testing with Postman&lt;/h1&gt;
&lt;p&gt;I think everyone knows about &lt;a href=&quot;https://www.postman.com/automated-testing&quot;&gt;Postman&lt;/a&gt; now the days. It is a glorious tool for testing APIs that work with requests and responses. In my case it is a REST API using AWS API Gateway. In my GitHub repository I have put together a small collection of requests and response tests, which Postman calls collections. These can then simply be used with the CLI &lt;a href=&quot;https://github.com/postmanlabs/newman&quot;&gt;Newman&lt;/a&gt; to execute the collections created with Postman. Of course, Newman must then be installed on the build machine beforehand. In my repo I do this via NPM in package.json. Simply run the following command:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm install newman&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The creative process of writing collections is firstly you cerate a new collection in Postman and than you write request. The request runs against the REST API and returns a response. The response can then be validated. Postman offers a wide range of options for validating responses. So you can easily compare the status code in the response with an expected value, compare other expected values, create variables for next requests and much more. A tip from me, try to keep the amount of tests low.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;AWS quite new CDK is a great tool for creating AWS infrastructure. It is amazing that you can write in the same language that you would use for your Lambdas. Combined with automatic deployment and testing like with Travis, changes to a possible productions stack are easy and make fun. I also believe that this means that there is no need or less need to test Lambdas locally. If you need help with your AWS CDK project, don&apos;t hesitate to ask me or the helpful &lt;a href=&quot;https://gitter.im/awslabs/aws-cdk&quot;&gt;CDK Gitter community&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/5b8afc2cc792f34647192a89cff02f22/cloud.jpg</featuredImage><media:content url="https://martinmueller.dev/static/5b8afc2cc792f34647192a89cff02f22/cloud.jpg" medium="image"/></item><item><title><![CDATA[Bash Script Contribution for the Alfresco Docker Installer]]></title><description><![CDATA[Hi Alfrescans, I made great experiences in my last project with the Alfresco Docker Installer. You can read more about it in my previous…]]></description><link>https://martinmueller.dev/start-script-eng/</link><guid isPermaLink="false">https://martinmueller.dev/start-script-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[2020]]></category><category><![CDATA[ecm]]></category><category><![CDATA[docker]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[yeoman]]></category><pubDate>Sun, 22 Mar 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/24a8550d70bdb1314bc4abe873f5b42d/owl.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi Alfrescans,&lt;/p&gt;
&lt;p&gt;I made great experiences in my last project with the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt;. You can read more about it in my previous &lt;a href=&quot;http://martinmueller.dev/alfresco-docker-installer-eng&quot;&gt;blog post&lt;/a&gt;. Now I am of course excited to add valuable new features to it. One of them is the Start Script which can be used as a wrapper for the Docker Compose File. In my previous Alfresco Docker Compose projects I always implemented this script because it offers some nice additional functionality. The next section explains what these are.&lt;/p&gt;
&lt;h1&gt;Features&lt;/h1&gt;
&lt;p&gt;The most important feature is probably the built-in wait routine. This waits until ACS has finished booting. This is very useful, for example, if you want to run tests after starting ACS with tools like Postman. Data can also be pushed to ACS with the REST API when ACS finished booting. The wait routine is implemented with NPM&apos;s &lt;a href=&quot;https://www.npmjs.com/package/wait-on&quot;&gt;wait-on&lt;/a&gt;. It makes sense to use the wide range of tools in the public NPM repository, because I then do not have to implement them myself and they are usually well tested.&lt;/p&gt;
&lt;p&gt;The next feature is particularly important to me since I am working with Windows. If you try to run Docker Compose with Windows you may get a problem with defined volumes, since they do not support the Windows Path spelling ootb. Fortunately, the Docker Compose Community has provided a solution. Simply set the following environment variable before starting Docker Compose:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;export COMPOSE_CONVERT_WINDOWS_PATHS = 1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is now done beforehand if you start the start script with the -wp flag.&lt;/p&gt;
&lt;p&gt;The next features have not yet made it into the Alfresco Docker Installer, but this could change soon. I personally use them a lot in my deployments. It is possible to set the host IP and host port dynamically with the start script using -hi and -hp. I find this very practical when you are in environments that change their IP more often like for example your laptop. At the moment, however, the installer solves this by asking for the host IP and host port during installation. So it is already configurable but only during the installation.&lt;/p&gt;
&lt;p&gt;More features are possible but are not currently implemented. E.g. Loading test data with the REST API. In my &lt;a href=&quot;http://martinmueller.dev/adf-app-eng&quot;&gt;ADF AI prototype&lt;/a&gt; I also have a -b for build the Angular Webapp and an -aca so that only the ACA container is redeployed for fast development with the Ensure ACA web app. In the next section, I will show you how exactly I contributed the Start Script.&lt;/p&gt;
&lt;h1&gt;Contribution&lt;/h1&gt;
&lt;p&gt;First, a fork should be created by the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt;. Than you make your changes to your fork. In my case it is the start script with the file name start.sh. I saved the script in template/scripts directory and configured the Yeoman setup that the script can optionally be added, very similar to how the LDAP service is added. All changes should be saved to your fork in the form of a remote branch. To do this, a local branch must first be created and changes pushed:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git branch startscript
git add --all
git commit -m &quot;added startscript&quot;
git push -u origin HEAD: startscript&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once all changes have been made and extensively tested, a pull request to the Alfresco Docker Installer Repository can be created. To do this, simply go to the Installer Github page. A Create Pull Request button will appear there.&lt;/p&gt;
&lt;p&gt;Oh yeah one thing more. If you planning to contribute a new feature it would be very nice and best practice to add a test which tests the new feature as well. I did that in the .travis file which now tests the deployment and start of Alfresco with and without the new start script. With that it ensures it can work both ways.&lt;/p&gt;
&lt;h1&gt;Outlook&lt;/h1&gt;
&lt;p&gt;Next I would like to provide Alfresco&apos;s new Alfresco Identity Management Service, also called AIMS, as a contribution. For this, a Keycloak container is added and the Alfresco properties are adjusted. AIMS only makes sense if you also have an identity provider. So AIMS should only be added if LDAP is selected during installation.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;This article describes a brief overview of my first contribution to the Alfresco Docker Installer. I already use the Installer for my projects a lot and contributing to it gave me the perfect opportunity to understand the Yeoman template installer better. The Start Script offers many new additional functionalities. How to do such a contribution has also been described. Do you also have a great idea how to improve the installer? I&apos;m looking forward to hear about it.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/24a8550d70bdb1314bc4abe873f5b42d/owl.png</featuredImage><media:content url="https://martinmueller.dev/static/24a8550d70bdb1314bc4abe873f5b42d/owl.png" medium="image"/></item><item><title><![CDATA[Alfresco's Amps and Jars Testing with Docker]]></title><description><![CDATA[Hi Alfrescans, In this article I will describe how to use Docker to test Amps and Jars extensions for ACS. Share Customizations and Custom…]]></description><link>https://martinmueller.dev/alfresco-docker-installer-eng/</link><guid isPermaLink="false">https://martinmueller.dev/alfresco-docker-installer-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[2020]]></category><category><![CDATA[ecm]]></category><category><![CDATA[docker]]></category><category><![CDATA[docker-compose]]></category><category><![CDATA[Amp]]></category><category><![CDATA[Jar]]></category><pubDate>Tue, 17 Mar 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/bb6d986b940877fd90cc15c9ff53dcaf/docker.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;p&gt;Hi Alfrescans,&lt;/p&gt;
&lt;p&gt;In this article I will describe how to use Docker to test Amps and Jars extensions for ACS. Share Customizations and Custom Content Models were developed for a customer of &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt;, which I wanted further develop and test quickly and easily.&lt;/p&gt;
&lt;p&gt;Another interesting detail for my project was that the Amps were written for an ACS 5.2.6 deployment and Docker is only supported as a deployment starting with ACS 6.0. So it was relatively challenging to adjust Docker Deployment so that everything worked. If your extensions were written for ACS 6.0 or later, it should be a lot easier.&lt;/p&gt;
&lt;h1&gt;Why Docker Deployment?&lt;/h1&gt;
&lt;p&gt;The old fashioned way is to test the locally compiled Amps and Jars on a local ACS deployment, which is configured completely without or almost Docker. That means Tomcat must be installed and ACS with all its dependencies must also be available. Clearly the old-fashioned installer helps, but it is still a time-consuming and unsatisfactory task to install Alfresco like this. In addition, there is the fact that the Amps must always be installed by hand and possibly uninstalled. Not nice!&lt;/p&gt;
&lt;p&gt;Docker containers address precisely these problems. With the help of the Dockerfile I can write down which configuration steps should be taken. With Git, deployments can be versioned and reverted. The installation of the Tomcat as well as the configuration of ACS and much more can be written down in these Dockerfiles.&lt;/p&gt;
&lt;p&gt;Sounds like a lot of work? Nope! Alfresco maintains ACS Docker Deployments for ACS 6.0 or newer. Such a simple Docker deployment, whereby the containers are orchestrated with Docker Compose can be stowed here for &lt;a href=&quot;https://github.com/Alfresco/acs-deployment/tree/master/docker-compose&quot;&gt;ACS Enterprise&lt;/a&gt; and here for &lt;a href=&quot;https://github.com/Alfresco/acs-community-deployment/tree/master/docker-compose&quot;&gt;ACS Community&lt;/a&gt;. The Docker Image for this deployment you can find here &lt;a href=&quot;https://github.com/Alfresco/acs-packaging/tree/master/docker-alfresco&quot;&gt;ACS Enterprise Image&lt;/a&gt; and here for &lt;a href=&quot;https://github.com/Alfresco/acs-community-packaging/tree/master/docker-alfresco&quot;&gt;ACS Community Image&lt;/a&gt;. These deployments and images are quite limited in point of customizations as we would need for our Amps or Jars. While this is good for a quick start, it does not allow us to test things like our locally created Amps. I describe how this is made possible in the next chapter.&lt;/p&gt;
&lt;h1&gt;Prepare Git Repo&lt;/h1&gt;
&lt;p&gt;If the build code of your Amps and Jars are in different git repos, it makes sense to combine them into one to make Docker image creation easier. E.g. the repo and share Amp could be in the same subdirectories. If Maven was used as a build and packaging tool, this is easy to implement with parent poms. After the possible restructuring, the build must be tested if the Amps or Jars are also created. For me that was done with the following simple maven command:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;mvn clean install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the Docker backend needs to be installed. The orchestration of the containers should be done with Docker Compose. Fortunately, there is the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer&quot;&gt;Alfresco Docker Installer&lt;/a&gt; which is very easy to use Yeoman supported template installer and already has a wide range of install options such as the ACS version, whether LDAP to be used, etc. offers. I would suggest to first create a folder with the name docker in the Git Repo and to install the Docker Compose backend with the &lt;a href=&quot;https://github.com/Alfresco/alfresco-docker-installer#installation&quot;&gt;Alfresco Docker Installer as instructed&lt;/a&gt;. After installation, the deployment should start with&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;´&quot;&gt;&lt;pre class=&quot;language-´&quot;&gt;&lt;code class=&quot;language-´&quot;&gt;docker-compose up --build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and the urls can be tested which are:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;http://localhost:80  Alfresco Content App
http://localhost:80/alfresco 
http://localhost:80/share&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If everything worked, just shut down the deployment with:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;docker-compose down&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The next section explains how the share or repo Amp / Jar can be integrated into the image.&lt;/p&gt;
&lt;h1&gt;Customize Share and Repo Images&lt;/h1&gt;
&lt;p&gt;Now it is time to combine the share and repo modifications into the Docker image using your Amps or Jars. Ideally, the freshly compiled Amps / Jars from the target folder should be used for this. The easiest way to do this is to move the Dockerfile from docker/alfresco to repo/ and docker/share to share/. This allows Docker to access the target directory there when building the image. Now simply set the instruction in the repo and share Dockerfile that the Amps / Jars are copied from the target folder into the image, such as here:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;COPY modules/Amps $TOMCAT_DIR/Amps
COPY modules/Jars $TOMCAT_DIR/webapps/alfresco/WEB-INF/lib

COPY target/myAmp-62-repo-1.0-SNAPSHOT.Amp $TOMCAT_DIR/Amps/myAmp-62-repo-1.0-SNAPSHOT.Amp&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the docker/docker-compose.yaml file has to be changed and the directories for the repo and share image have to be adjusted. In my setup it looks like this for repo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;context: ./../repo&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that for Share:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;context: ./../share&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Amps / Jars for ACS 5.2&lt;/h1&gt;
&lt;p&gt;If you want to test Amps or Jars for an ACS 5.2 deployment like me, there are a few difficulties. It may happen that the dependencies used for the 5.2 Amp / Jar are no longer compatible with the ACS Docker Deployment. It will be noticed that errors are thrown at the booting time of ACS. The first step is to find out which dependencies (usually Jar files on the Tomcat classpath) are causing the problem. It is then recommended to create a Maven profile dedicated for the 6.2 Amp, which then reloads the dependencies with the correct version.&lt;/p&gt;
&lt;p&gt;Then the conflicted dependency must be also deleted in the Dockerfile. Don&apos;t be discouraged, it can be hair-raising and time-consuming! For me it looked something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;ARG POI_V = 4.0.1
RUN rm -f $ TOMCAT_DIR/webapps/alfresco/WEB-INF/lib/poi-$ {POI_V}.Jar
RUN rm -f $ TOMCAT_DIR/webapps/alfresco/WEB-INF/lib/poi-ooxml-${POI_V}.Jar
RUN rm -f $ TOMCAT_DIR/webapps/alfresco/WEB-INF/lib/poi-scratchpad-${POI_V}.Jar

ARG TIKA_V = 1.21-20190624
RUN rm -f $ TOMCAT_DIR/webapps/alfresco/WEB-INF/lib/tika-core-${TIKA_V}-alfresco-patched.Jar
RUN rm -f $ TOMCAT_DIR/webapps/alfresco/WEB-INF/lib/tika-parsers-${TIKA_V}-alfresco-patched.ja&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Amp / Jar built with the 6.2 profile can then be used for testing. But be careful for the 5.2 deployment, the Amp / Jar must be used without the 6.2 profile, otherwise there can be other dependency problems!&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Amps and Jars are still the most popular method of customizing ACS and Share. Testing them locally does not have to be time consuming when using Docker. I hope I have encouraged you to give Docker a try for your extensions in the future and share your experiences with me.&lt;/p&gt;
&lt;h1&gt;Kudos&lt;/h1&gt;
&lt;p&gt;Again to &lt;a href=&quot;https://twitter.com/freshwebs&quot;&gt;Eddie May&lt;/a&gt; the new awesome Digital Community Manager from Alfresco for helping improving my english :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/bb6d986b940877fd90cc15c9ff53dcaf/docker.jpg</featuredImage><media:content url="https://martinmueller.dev/static/bb6d986b940877fd90cc15c9ff53dcaf/docker.jpg" medium="image"/></item><item><title><![CDATA[My Smart Home Experience]]></title><description><![CDATA[Hi folks. As in October 2019 I had the amazing opportunity to buy a house in the beautiful town called Ludwigslust in Germany. It is an old…]]></description><link>https://martinmueller.dev/smart-home/</link><guid isPermaLink="false">https://martinmueller.dev/smart-home/</guid><category><![CDATA[eng]]></category><category><![CDATA[2020]]></category><category><![CDATA[smart-home]]></category><category><![CDATA[smart-life]]></category><category><![CDATA[amazon]]></category><pubDate>Fri, 06 Mar 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/02b2708475cc054bb90de6ba74ce46fd/house.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hi folks.&lt;/p&gt;
&lt;p&gt;As in October 2019 I had the amazing opportunity to buy a house in the beautiful town called Ludwigslust in Germany. It is an old but recently renovated lovely house. As I&apos;m much interested in tech I couldn&apos;t wait to try some cool Smart Home stuff.&lt;/p&gt;
&lt;p&gt;I made some amazing times with the following Smart Home gadgets:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Bulbs Teckin&lt;/strong&gt;: That are smart bulbs with integrated wifi. You can easily replace your existing ones with them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Sockets Teckin&lt;/strong&gt;: Pretty nice power sockets which you can plug between your electrical device and the socket in your wall to remote control it. It works with your wifi as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Garage Door&lt;/strong&gt;: A cool garage engine extension. It enhances your existing garage engine to be remote controllable via wifi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thermostats&lt;/strong&gt;: Very nice little gadget to time schedule your heaters. Those I tested didn&apos;t had wifi or bluetooth connection.&lt;/p&gt;
&lt;p&gt;Further done I have links to those gadgets if you would like to try them out yourself. My highest priorities were to save costs like electricity or gas in the long run and increase the living quality from me and my wife.&lt;/p&gt;
&lt;p&gt;There are dozens of Smart Home solutions out there and you need to be careful which one you take as often gadgets from different vendors are not playing nicely together.&lt;/p&gt;
&lt;p&gt;I decided to buy gadgets which can be controlled with the &apos;Smart Life&apos; app, as it has a huge offer on all kinds of Smart Home devices.&lt;/p&gt;
&lt;h1&gt;Which Wireless Frequency?&lt;/h1&gt;
&lt;p&gt;It is important to mention that all of my Smart Home gadgets only are working in a 2.4 GHz wireless network. It is unlikely that you find gadgets for the 5 GHz network. 2.4 as the length of the waves are longer compared to 5 GHz it reaches better through walls but it has a smaller maximum bandwidth. Actually Smart Home devices don&apos;t need a high bandwidth, so thats fine. Make sure to establish both of those network frequencies on your router!&lt;/p&gt;
&lt;h1&gt;Smart Light Bulbs Everywhere&lt;/h1&gt;
&lt;p&gt;I opted in buying the Smart wifi LED lights from Teckin. You can buy them in a bundle of for for saving a bit. What can I say, I really love those Smart bulbs. I already saved money with them just replacing the existing bulbs which ran on 40 W to use those Smart bulbs which just need 8 W to shine.&lt;/p&gt;
&lt;p&gt;As it is just natural to forget turning out the light and it already happened, I configured every replaced bulb to turn off at 1 am as usually no one is wake at this time. Anyway there are some places in the house, where the wifi signal is not strong enough. For that case I didn&apos;t installed a smart bulb. I only replaced the 40 W against a simple LED ones.&lt;/p&gt;
&lt;h1&gt;Smart Sockets&lt;/h1&gt;
&lt;p&gt;The next smart device were the Smart Sockets. I love those sockets as they have a bunch of nice features. First as we in Germany don&apos;t have manual on off switches integrated in the power sockets like I know from UK, it is very convenient that those smart sockets have an on off switch. Than you don&apos;t need to force pulling out if you want to cancel the power and your device doesn&apos;t have an on off switch itself.&lt;/p&gt;
&lt;p&gt;The next cool feature of those sockets is that you can configure a time schedule for switching off and on devices. I do use a schedule off switch on my TV station as there are a bunch of energy waster which I would like to cut off at night. So I configured the TV smart socket to turn off at 1 am. An other off schedule is on the microwave. As it is an old microwave it spends a lot of energy even just being in standby. That isn&apos;t acceptable so the microwave turns off at 7 pm and 1 am now. If you want to turn it on again, simply press the button on the socket.&lt;/p&gt;
&lt;p&gt;Last but not least the washing machine. It now has a smart socket between as well. Three reasons for that. As well the on off switch is practical. It saves energy because it turns off the machine completely. Really cool I configured the &quot;Smart Life&quot; app to send me a notification when the cloth is done washing. That is possible because you can trigger a notification event when the power level reaches a threshold . I love that!&lt;/p&gt;
&lt;h1&gt;Smart Garage Door&lt;/h1&gt;
&lt;p&gt;Imagine if you could open your door with just saying &quot;Hey Siri, Garage&quot;. Well thats the case for me. And still until now I feel like Batman when his cave opens kind of automatically when he approaches in his batmobile :D. So very very cool. How I did that? When I bought the house, there was already an electrical garage door which could be controlled with a simple infrared remote. Yes thats nice but it isn&apos;t handy to carry that remote with you all the time and it can&apos;t be voice controlled at all. So I wrote down the name of the door engine and bought on Amazon for a Smart Garage gadget which is compatible with that engine and the &apos;Smart Life&apos; app.&lt;/p&gt;
&lt;p&gt;The installation of the device was easy. I have the following enhancements. The old-fashioned remote control is still working but now I can open and close the door with my smart phone and the app &apos;Smart Life&apos; or using Siri. Furthermore I can check if the garage is open or closed on my phone and I do get an alarm when the door gets opened. And really cool I scheduled the power of the garage engine to turn off the electricity at night. That saves costs and increases the security.&lt;/p&gt;
&lt;h1&gt;Time Scheduled Thermostats&lt;/h1&gt;
&lt;p&gt;I am very happy with my &quot;Smart&quot; thermostats from Eqiva Radiator for most of my heaters. Though I am not sure if they are falling under the category of Smart Home devices as they are basically just configurable through the display and I am currently only using them for time scheduled heating and easily turning on and off. Anyway there were very easy to install and they do work like a charm.&lt;/p&gt;
&lt;h1&gt;Smart Home Gadgets&lt;/h1&gt;
&lt;p&gt;If you found something I mentioned here interesting, check it out those Affiliates links (I would get a little commission for supporting my blog post work):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Bulbs Teckin&lt;/strong&gt; (Amazon): &lt;a href=&quot;https://amzn.to/2xcvwFp&quot;&gt;UK&lt;/a&gt; &lt;a href=&quot;https://amzn.to/2xe1CAJ&quot;&gt;DE&lt;/a&gt; &lt;a href=&quot;https://amzn.to/3ax4pmR&quot;&gt;USA&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Sockets Teckin&lt;/strong&gt; (Amazon): &lt;a href=&quot;https://amzn.to/2xbZKZ5&quot;&gt;UK&lt;/a&gt; &lt;a href=&quot;https://amzn.to/3amBOAq&quot;&gt;DE&lt;/a&gt; &lt;a href=&quot;https://amzn.to/3cy1wnF&quot;&gt;USA&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Garage Door&lt;/strong&gt; (Amazon): &lt;a href=&quot;https://amzn.to/2PMt2DQ&quot;&gt;UK&lt;/a&gt; &lt;a href=&quot;https://amzn.to/2IiKzQ3&quot;&gt;DE&lt;/a&gt; &lt;a href=&quot;https://amzn.to/2x5NtoU&quot;&gt;USA&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thermostats&lt;/strong&gt; (Amazon): &lt;a href=&quot;https://amzn.to/2Tn3hwb&quot;&gt;UK&lt;/a&gt; &lt;a href=&quot;https://amzn.to/38lbyF5&quot;&gt;DE&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Future Ideas&lt;/h1&gt;
&lt;p&gt;I feel like that I just started my little Smart Home journey. Soon I would like to try more complex technologies like the Tado Smart Radiator system. As well I am thinking about to create my own private Smart Home Server running an a PI. I found some interesting articles regarding that in a german magazine.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Smart Home devices are not just tools for playing around with. They actually help you to save real coins which will add up over the years and will increase your living quality. If you think about peeking in the Smart Home devices world start with simple devices like those wifi Smart Bulbs and Smart Sockets which doesn&apos;t need any other devices to work and they are cheap! Be creative for how you can use them in a smart way. And yeah most important have fun!&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/02b2708475cc054bb90de6ba74ce46fd/house.png</featuredImage><media:content url="https://martinmueller.dev/static/02b2708475cc054bb90de6ba74ce46fd/house.png" medium="image"/></item><item><title><![CDATA[Build an ADF App from Scratch]]></title><description><![CDATA[Good day As mentioned in the previous Blog Post, I am working on an exciting AI prototype which uses ACS Community as a content management…]]></description><link>https://martinmueller.dev/ADF-App-eng/</link><guid isPermaLink="false">https://martinmueller.dev/ADF-App-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[ai]]></category><category><![CDATA[2020]]></category><category><![CDATA[ecm]]></category><category><![CDATA[adf]]></category><category><![CDATA[prototype]]></category><category><![CDATA[aca]]></category><category><![CDATA[object]]></category><pubDate>Sun, 01 Mar 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/8b4173afa1e1b6d3e61572f80ee2b733/robot.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Good day&lt;/p&gt;
&lt;p&gt;As mentioned in the previous &lt;a href=&quot;https://martinmueller.dev/First-Week-Object/&quot;&gt;Blog Post&lt;/a&gt;, I am working on an exciting AI prototype which uses ACS Community as a content management system. In addition, certain AI services are running and performing certain AI actions using the ACS interface such as CMIS and REST. Unfortunately, I have to remain unclear here to protect company secrets. So I am allowed to say &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt; and the partner company are planning a webinar where, among other things, this prototype will be shown. Back to the topic! We chose &lt;a href=&quot;https://www.alfresco.com/ecm-software/application-development-framework&quot;&gt;ADF&lt;/a&gt; for the webapp.&lt;/p&gt;
&lt;p&gt;In the next chapters I will explain how to create an ADF webapp project and how to change it. That shouldn&apos;t differ whether you are working with Windows 10, MacOS or Linux. I myself like all three operating systems.&lt;/p&gt;
&lt;h1&gt;This is Required&lt;/h1&gt;
&lt;p&gt;You should install &lt;a href=&quot;https://docs.docker.com/install/&quot;&gt;Docker&lt;/a&gt;, &lt;a href=&quot;https://docs.docker.com/compose/install/&quot;&gt;Docker Compose&lt;/a&gt;, &lt;a href=&quot;https://www.npmjs.com/get-npm&quot;&gt;NPM&lt;/a&gt; and &lt;a href=&quot;https://yarnpkg.com/lang/en/docs/install/&quot;&gt;YARN&lt;/a&gt;. I needed YARN because I am working on a Windows laptop and YARN is able to convert the Windows Paths into Unix Paths. Watch out at Docker! The standard installation at Docker only allows the use of 2 GB RAM for the Docker Compose Deployments, which is far too little for ACS Community and the other services! For this you need at least 10 GB and for ACS Enterprise at least 12 GB. Preferably more! In addition, if you want to set up your own amps, jars or other customizations for ACS deployment, I recommend installing Java and Maven.&lt;/p&gt;
&lt;h1&gt;Prepare the Git repository&lt;/h1&gt;
&lt;p&gt;I use the &lt;a href=&quot;https://github.com/Alfresco/alfresco-content-app&quot;&gt;ACA Git Repository&lt;/a&gt; as the base for the prototype. Firstly it has already integrated many &lt;a href=&quot;https://github.com/Alfresco/alfresco-ng2-components&quot;&gt;ADF Component and API Libaries&lt;/a&gt; and secondly it provides a shell that uses the ACS backend quite extensively. In addition, it will be easy to import updates from the ACA repository into my webapp. And pretty cool, I can directly contribute back.&lt;/p&gt;
&lt;p&gt;Now lets start with the Git repository. For me, the choice was a private Git repository in our &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt; GitLab. In your case, maybe you can take a public Git repository. The further instructions will not change regarding of choosing a private or public ones.&lt;/p&gt;
&lt;p&gt;As mentioned earlier, I would like to be able to import updates from the ACA repository without any problems. In addition, of course, I want to reuse as much of the ACA repository as possible. I therefore chose &lt;a href=&quot;https://git-scm.com/docs/git-submodule&quot;&gt;Git&apos;s submodules&lt;/a&gt;. With that I am able to contribute back easily. I created a fork from the ACA repo &lt;a href=&quot;https://github.com/mmuller88/alfresco-content-app&quot;&gt;https://github.com/mmuller88/alfresco-content-app&lt;/a&gt;. I advise you to do the same. Then simply switch to the project directory and load the fork as submodule:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git submodule add https://github.com/&amp;lt;USER&gt;/alfresco-content-app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The following command may also be useful to update the submodules, which in this case is only ACA:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git submodule update --init --remote&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I needed it because I changed the branch in the .gitmodules file to apply my fix branch.&lt;/p&gt;
&lt;h1&gt;Start ACA&lt;/h1&gt;
&lt;p&gt;We can test if the Docker Compose Deployment starts in the alfresco-content-app folder. In my previous position as a full stack developer at Alfresco I had the opportunity to work a lot with this ACA repository.&lt;/p&gt;
&lt;p&gt;The following commands are required to start ACA Deployment:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To load the necessary node dependencies.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn run build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For creating the ADF webapp in the dist/app directory. The command also creates the ADF extensions with the names @alfresco/aca-shared and @alfresco/adf-office-services-ext. As an early objective, the goal will be to write your own extension for your own ADF webapp. This has practical reasons such as modularization and distribution.&lt;/p&gt;
&lt;p&gt;The start.sh in the ACA directory is a sophisticated script. You should preferably use it to start the deployment. The individual parameters can be queried with the -h or --help flag. For my Windows laptop I have to use these parameter configuration:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.\start.sh -wp -hi 192.168.0.237&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The -wp flag converts the Linux file paths to Windows file paths and -hi stands for Host IP and transfers the IP of the computer to the deployment. If everything is all right the following addresses should be available:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;http://localhost:8080/alfresco/   ACS
http://localhost:8080/content-app/   ACA Webapp
http://localhost:8080/share/   Good old Share&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When I started writing this article I got a strange error because of the GoogleDocs module on my Windows PC. I&apos;m sure I didn&apos;t get it on my MacBook. I confidently ignore this error. If you dear reader, however, knows why, I would be happy to receive a private message with an explanation.&lt;/p&gt;
&lt;p&gt;To cleanly shutdown the deployment simply use the following command:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.\start.sh -d&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The stop and delete all containers that were started using start.sh. You will need to delete and start the deployment again to apply changes from the dist/app webapp. Alternatively you can use the -aca flag for the start.sh script as that only redeploys the webapp container.&lt;/p&gt;
&lt;h1&gt;Adjust the Deployment&lt;/h1&gt;
&lt;p&gt;This and the next section is probably the most difficult and requires a lot of patience. So far it was easy because we just took existing code that was already configured and tested by other developers. Now we have to do it ourselves, because we want to be able to integrate customizations like our own extension. So, grab a coffee, or like in my case a tea and get ready!&lt;/p&gt;
&lt;p&gt;To manipulate the Docker Compose Deployment, I copied all direct Docker related files from the ACA folder into the project folder. This includes, for example, &lt;strong&gt;docker-compose.yaml&lt;/strong&gt;, &lt;strong&gt;start.sh&lt;/strong&gt;, &lt;strong&gt;Dockerfile&lt;/strong&gt; and the &lt;strong&gt;docker&lt;/strong&gt; folder. It would now be advisable to test whether your Docker Compose Deployment is still working. Maybe just copy the ADF webapp in the alfresco-content-app/dist/app folder into the project dist/app folder and start the deployment with start.sh script. I described how to do this in the previous chapter.&lt;/p&gt;
&lt;p&gt;Now comes the most difficult part, at least that&apos;s how it was for me. You now have to copy the Angular related files into the project folder and configure them so that they use the components from alfresco-conten-app/src. In my case it was the following files:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;src\app\extensions.module.ts
src\assets\app.extensions.json
src\app.config.json
src\tsconfig.app.json&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I don&apos;t want to pretend here, the correct setting of the configuration actually took me two days. When I got stuck, I looked for advice from the wonderful &lt;a href=&quot;https://gitter.im/Alfresco/content-app&quot;&gt;ADF Community in Gitter&lt;/a&gt;. The boys and girls understand their craft. Special thanks to my friend and ex-colleague &lt;a href=&quot;https://twitter.com/pionnegru&quot;&gt;Bogdan&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now it is time to let Angular compile the dist/app folder yourself instead of just copying it from the aca project. If you have managed to make Docker Compose Deployment successful with the web app compiled in the parent folder in the dist folder, you can finally start customizing :)!&lt;/p&gt;
&lt;h1&gt;Create an Extension&lt;/h1&gt;
&lt;p&gt;Wohoo! You actually made it this far. To build a new extension, the following command is recommended:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;ng generate library my-ext&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I would highly recommend adding -ext to the extension name to make it more distinguishable from the webapp itself. In my project they have the same names, except that I added -ext to the extension. What you do now with the extension is totally open and there are many great Angular tutorials, pages or forums out there to help you.&lt;/p&gt;
&lt;p&gt;If you want to test the webapp in between or at the end of your changes, you simply have to compile the ADF webapp and start the Docker Compose Deployment. This looks similar to what is explained in &lt;strong&gt;Start ACA&lt;/strong&gt; section with the following commands:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;yarn install
yarn run build
.\start.sh -wp -hi 192.168.0.237&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Please don&apos;t forget that -wp is Windows specific. If you use MacOS or Linux you don&apos;t need this flag. You probably wouldn&apos;t even need -hi IP then.&lt;/p&gt;
&lt;h1&gt;New ACA Update Available&lt;/h1&gt;
&lt;p&gt;As the &lt;a href=&quot;https://github.com/Alfresco/alfresco-content-app&quot;&gt;ACA Git Repository&lt;/a&gt; evolves at an incredibly fast rate, the question arises how we can integrate these updates into our ADF web app in just a few steps. So far I have not had to do that but basically these steps are mentioned:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The alfresco-content-app Git submodule must be updated.&lt;/li&gt;
&lt;li&gt;The dependencies of the package.json file in the project folder must be synchronized with those in the alfresco-content-app/package.json&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Wow think about what we did here. We actually wrote our own ADF webapp which is based on ACA and can be easily updated at any time! For that we first had to create a new Git repo. Then integrate the ACA project as a submodule. Immediately afterwards we tested the Docker Compose Deployment in ACA. Then we rebuilt the repo so that we integrated our own Angular Extension into the ADF web app. That’s it! I hope you had fun and the article was helpful.&lt;/p&gt;
&lt;h1&gt;Kudos&lt;/h1&gt;
&lt;p&gt;To &lt;a href=&quot;https://twitter.com/freshwebs&quot;&gt;Eddie May&lt;/a&gt; the new awesome Digital Community Manager from Alfresco for doing some English quality check and offering more feedback for coming posts :).&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/8b4173afa1e1b6d3e61572f80ee2b733/robot.png</featuredImage><media:content url="https://martinmueller.dev/static/8b4173afa1e1b6d3e61572f80ee2b733/robot.png" medium="image"/></item><item><title><![CDATA[My First Exciting Week at OBJECT]]></title><description><![CDATA[Hello. In this article I briefly summarize the first week at OBJECT. For myself that has a couple of advantages. On one hand I practice…]]></description><link>https://martinmueller.dev/First-Week-Object/</link><guid isPermaLink="false">https://martinmueller.dev/First-Week-Object/</guid><category><![CDATA[eng]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[object]]></category><category><![CDATA[2020]]></category><category><![CDATA[ecm]]></category><category><![CDATA[2022]]></category><category><![CDATA[bpm]]></category><category><![CDATA[hamburg]]></category><category><![CDATA[onboarding]]></category><pubDate>Thu, 20 Feb 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/2e66d14a419be34b80eb2e64737c23fd/ham.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Hello.&lt;/p&gt;
&lt;p&gt;In this article I briefly summarize the first week at &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt;. For myself that has a couple of advantages. On one hand I practice writing articles and on the other hand it serves as a reflection on the previous days. As well for some of my family and friends it is hart to understand what I am doing in my dream profession as a Software Engineer. This kind of blog post may helps them to understand it better.&lt;/p&gt;
&lt;h1&gt;Day 1 Onboarding&lt;/h1&gt;
&lt;p&gt;It was originally planed that I should come to Zurich for onboarding. In short, onboarding usually means the company of the new employee makes you familiar with the hardware and the various software systems they are using, as well as the tasks you have to work on. At that time my wife was pregnant and I didn&apos;t wanted to let her alone.&lt;/p&gt;
&lt;p&gt;I was very happy when OBJECT offered me to do the onboarding in Hamburg. I love Hamburg because it is a beautiful city surrounded by water. In the article picture you can see the Church of St. Jacobi in Hamburg, which I noticed immediately on the way to the onboarding location. I was given three exciting main tasks. I can only write about these in very rough details.&lt;/p&gt;
&lt;p&gt;The first task is that I have my own project together with another partner. This project is about an exciting Alfresco deployment. In this deployment, ACS (Alfresco Content Service) and APS (Alfresco Process Service) should run together. It is super exciting that I am allowed to combine Alfresco&apos;s ECM and BPM products.&lt;/p&gt;
&lt;p&gt;The second project is about developing a prototype for discovering sensitive data. For that we also would like to create a beautiful ADF app. In this project, my own knowledge gained with Docker and ADF will be very useful.&lt;/p&gt;
&lt;p&gt;In the third and for me most exciting project it is about that OBJECT would like to be more in the social media world. That would go from platforms like Xing, LinkedIN to YouTube videos. Again, I have a great interest based on my knowledge of Alfresco and my existing social media skills, which can be improved though.&lt;/p&gt;
&lt;p&gt;For this day I can say that it was challenging, but also very productive and great. I am very happy that OBJECT has big plans for me.&lt;/p&gt;
&lt;h1&gt;Day 2 Project Launch&lt;/h1&gt;
&lt;p&gt;My great Brazilian colleague, also called Amigo by me, took the time to give me an overview about the current ACS 5.2 deployment. I devoured all the details and asked him a lot of questions. It took us about two hours. The most impressive fact was that the designing process for this deployment. I already have a few interesting ideas on how to improve the deployment in terms of maintainability, security and reliability.&lt;/p&gt;
&lt;h1&gt;Day 3 Developer Meeting&lt;/h1&gt;
&lt;p&gt;On Wednesday, and thus the third day, we had an approximately one hour meeting with all developers at OBJECT. In this round all of my developer colleagues summarized in short on what exciting tasks they are working on. In order to better digest this flood on information, I decided to write it down in my notepad. The introduction round was very nice and I think I left a first good impression of myself. I hope that I can soon work together with one or the other colleague because I feel I can learn a lot from them.&lt;/p&gt;
&lt;p&gt;I spent the rest of the day to learn more about the deployment I mentioned in the chapter before. I also made ready an improvement proposal for that deployment and I am excited to hear what they will think of it.&lt;/p&gt;
&lt;h1&gt;Day 4 Inspirational Conversation&lt;/h1&gt;
&lt;p&gt;Today on Thursday I had a super interesting and inspiring conversation with one of our partners. This is in the area of ​​AI (Artificial Intelligence) and the partner founded that company. Alfresco&apos;s Content Management System is just one of many platforms where that AI can extract valuable information. I was impressed as the founder told about the product with so much passion.&lt;/p&gt;
&lt;p&gt;My goal is to develop a prototype based on ADF in the next few weeks, which the using the AI capabilities I spoke of. I will use ADF for the prototype. As mentioned in the &lt;a href=&quot;https://martinmueller.dev/Object-CH-eng/&quot;&gt;Blog Post&lt;/a&gt; I love this framework. My idea is to include &lt;a href=&quot;https://github.com/Alfresco/alfresco-content-app&quot;&gt;Alfresco&apos;s ADF app with the name ACA&lt;/a&gt; as the base for the prototype. It might could be a cool idea to write an Artikel about that app too.&lt;/p&gt;
&lt;h1&gt;Day 5 AI Magic&lt;/h1&gt;
&lt;p&gt;When I started writing this article, I certainly didn&apos;t think that AI would become such an important part of this post. I am very interested in AI and today on Friday I got a cool life demonstration about an AI system that uses Alfresco&apos;s Content Management System as a data source to extract extremely interesting information. The system also warns the user if something suspicious happens.&lt;/p&gt;
&lt;p&gt;I find it impressive that a simple ACS Community version without any customization was sufficient. This demonstration gave me a good picture of how the ADF app should look like. On Monday I will start making small sketches of the prototype.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;The first week was intense with lots of new information. I was positively surprised that quite a lot colleagues seek my help regarding Alfresco stuff. I see very ambitioned and forward looking into the future from myself together with OBJECT.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/2e66d14a419be34b80eb2e64737c23fd/ham.png</featuredImage><media:content url="https://martinmueller.dev/static/2e66d14a419be34b80eb2e64737c23fd/ham.png" medium="image"/></item><item><title><![CDATA[From Alfresco to OBJECT]]></title><description><![CDATA[Dear reader. I am happy to announce that I will switch to OBJECT on February 14th. This is a partner company of my current company Alfresco…]]></description><link>https://martinmueller.dev/Object-CH-eng/</link><guid isPermaLink="false">https://martinmueller.dev/Object-CH-eng/</guid><category><![CDATA[eng]]></category><category><![CDATA[alfresco]]></category><category><![CDATA[object]]></category><category><![CDATA[2020]]></category><category><![CDATA[ecm]]></category><category><![CDATA[2022]]></category><category><![CDATA[vision]]></category><category><![CDATA[bpm]]></category><pubDate>Sun, 09 Feb 2020 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/c0803b9d82f4e4a89ac40f58d158805c/object.png" length="0" type="image/png"/><content:encoded>&lt;p&gt;Dear reader.&lt;/p&gt;
&lt;p&gt;I am happy to announce that I will switch to &lt;a href=&quot;https://www.object.ch&quot;&gt;OBJECT&lt;/a&gt; on February 14th. This is a partner company of my current company &lt;a href=&quot;https://www.alfresco.com&quot;&gt;Alfresco&lt;/a&gt;. OBJECT mainly operates in the German and Swiss ECM (Enterprise Content Management) market. Below I list my motives and at the end I explain my future visions of OBJECT and Alfresco for the year 2022.&lt;/p&gt;
&lt;h1&gt;Reasons for the Change&lt;/h1&gt;
&lt;p&gt;One of my biggest motivations is that I really like the Alfresco products. Alfresco Content System (ACS) is an genius and sophisticated content management system based on the Java VM. Even though I hardly had the opportunity to work with Alfresco Process Service (APS) so far, I recognize how great this product is and would like to work with it in the future. Last but not least, Alfresco Developer Framework (ADF). I find the new, Angular-based web interfaces very nice and glorios for the front end. Above all, the simple use of the graphical user interface and the impressive collection of ready-made components, such as the &lt;a href=&quot;https://www.alfresco.com/abn/adf/docs/content-services/components/document-list.component&quot;&gt;Document List&lt;/a&gt; affects me. In 2019 I had the opportunity to help the ADF teams with Alfresco backend know-how and was able to learn a lot about ADF, for which I am very grateful.&lt;/p&gt;
&lt;p&gt;The switch to OBJECT should also enable me to be closer to the customer. I want to develop solutions for and with the customer. I am convinced that Alfresco offers excellent solutions in the ECM and BPM area. In cooperation with the customer I will help to find the ideal solution. I would not shy away from considering other software products for solutions or partial solutions besides Alfresco. In fact, I love getting to know new and other software technologies.&lt;/p&gt;
&lt;p&gt;I have also discovered the possibilities of the cloud for myself in recent years and was simply overwhelmed. With such a simplicity with which infrastructure such as virtual servers or storage can be provided and operated inexpensively, it is second to none. Acting in the cloud was so much fun that I decided to take AWS certificates. In addition to other previous certificates, I obtained the &quot;AWS Solution Architect Professional&quot; certificate in July 2019, which I am very proud of. If you would like to know more about the certificate and the preparations for it, have a look at my blog post &lt;a href=&quot;https://martinmueller.dev/aws-architect-professional-2019-preparation&quot;&gt;SAP-C01&lt;/a&gt;. Therefore, I would be happy if I can promote the use of the cloud in German-speaking countries.&lt;/p&gt;
&lt;p&gt;I am also very interested in new IT technologies such as Docker and Kubernetes. I think working with Docker is so nice, because you can always provide clean environments and configure them with just a few lines of code. It is also simply incomparable how much easier it is to develop with Alfresco products if they are already defined in containers. Alfresco also offers reference images e.g. &lt;a href=&quot;https://github.com/Alfresco/acs-packaging/blob/master/docker-alfresco/Dockerfile&quot;&gt;acs-packaging&lt;/a&gt; as well as deployments e.g. &lt;a href=&quot;https://github.com/Alfresco/acs-deployment/blob/master/docker-compose/docker-compose.yml&quot;&gt;acs-deployment&lt;/a&gt; that are easy to use and customizable. I also don&apos;t want to leave out Kubernetes at this point. Kubernetes has a steep learning curve, but when used in production it is simply unbeatable. Alfresco also has a reference deployment &lt;a href=&quot;https://github.com/Alfresco/alfresco-dbp-deployment&quot;&gt;alfresco-dbp-deployment&lt;/a&gt;. I would be happy to further advance these technologies in German-speaking countries.&lt;/p&gt;
&lt;p&gt;Last but not least. The application process with OBJECT was a wonderful experience and really stood out from all of my applications before. The employees at OBJECT make a very happy and open-minded impression. I also think OBJECT&apos;s home office culture is great and contemporary. This is the ideal environment to develop myself further.&lt;/p&gt;
&lt;p&gt;In the next section I would like to give you an outlook on OBJECT together with Alfresco for 2022.&lt;/p&gt;
&lt;h1&gt;Outlook 2022&lt;/h1&gt;
&lt;p&gt;In the last year at Alfresco, I was able to observe the cloud trend and participate in it myself. I know that this will be expanded even more. Alfresco already offers a strong PaaS (Program as a Service) offering and will continue to expand it in the future. Realistically speaking, I believe that this offer will not be used in German-speaking countries until 2022, or will only be used to a limited extent, since countries like Germany are moving very carefully and therefore slowly in the cloud world.&lt;/p&gt;
&lt;p&gt;Even if the German-speaking region will hardly use the Alfresco&apos;s PaaS offer by 2022, we will experience a strong move towards the cloud with regard to Alfresco products. Already today many costs can be saved by using the cloud as storage e.g. the ACS S3 or Azure Connector makes it easy to use the BLOB storages of the respective cloud provider. OBJECT can provide advice and action as a trustworthy partner.&lt;/p&gt;
&lt;p&gt;Many Alfresco customers are already using the chic web applications created with ADF, and there will be more by 2022. I see OBJECT in the perfect position to develop customized ADF apps together with the customer.&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/c0803b9d82f4e4a89ac40f58d158805c/object.png</featuredImage><media:content url="https://martinmueller.dev/static/c0803b9d82f4e4a89ac40f58d158805c/object.png" medium="image"/></item><item><title><![CDATA[Water Fasting Experience]]></title><description><![CDATA[Water Fasting what is that? As the name describes, you are only allowed to drink water for the time of the fasting. No teas, coffee, sugar…]]></description><link>https://martinmueller.dev/waterfasting/</link><guid isPermaLink="false">https://martinmueller.dev/waterfasting/</guid><category><![CDATA[eng]]></category><category><![CDATA[water]]></category><category><![CDATA[fasting]]></category><category><![CDATA[ketosis]]></category><pubDate>Wed, 12 Jun 2019 00:00:00 GMT</pubDate><enclosure url="https://martinmueller.dev/static/7c1047b533fafd805e1cac338a11bef1/water.jpg" length="0" type="image/jpeg"/><content:encoded>&lt;h1&gt;Water Fasting what is that?&lt;/h1&gt;
&lt;p&gt;As the name describes, you are only allowed to drink water for the time of the fasting. No teas, coffee, sugar-less or sugar-free drinks except, of course water.&lt;/p&gt;
&lt;p&gt;As from personal experience it is much easier than juice fasting where you only drink fresh pressed juice from a big variety of vegetables like apples, oranges and cucumbers and so on.&lt;/p&gt;
&lt;h1&gt;Motivation?&lt;/h1&gt;
&lt;p&gt;You might think why on earth should someone should do something like this? Well there are some interesting health benefits when we abstain food for a while. And it makes sense when you think where we humans are coming from. Now the days food is every where at any time. Just some decades ago, food wasn&apos;t available everywhere all the time. Humans had to survive with less or even no food for days. An unpleasant relic from those time is the capability to store extra calories as body fat.&lt;/p&gt;
&lt;p&gt;So what are the health benefits I spoke about? There are a lot benefits and most of them are having scientific evidences. I will focus on my top three reasons to avoid eating for some days.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First: Autophagy.&lt;/strong&gt; A phase from the body where it self-eats its own body cells to cover the need of protein. Preferable the body starts to eat degenerated body cells first. Those degenerated cells otherwise could cause cancer in the worst case. A better explanation from a study 2010:&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2990190&quot;&gt;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2990190&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Autophagy also plays a housekeeping role in removing misfolded or aggregated proteins, clearing damaged organelles, such as mitochondria, endoplasmic reticulum and peroxisomes, as well as eliminating intracellular pathogens. Thus, autophagy is generally thought of as a survival mechanism.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So I really hope doing fasting once or twice a year to reduce the amount of those &quot;bad&quot; proteins to have a reduced likelihood for having certain diseases like cancer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Second: Reset of gut bacteria.&lt;/strong&gt; As a known fact our gut bacteria are very important for digestion and our immune system. But alongside the settlement of &quot;good&quot; gut bacteria we also can have less useful or even harmful gut bacteria. Those settlements normally following the rule first come, first served. Having a &quot;bad&quot; composition of gut bacteria can reduce not even your health, as well your live quality. A medical article describes it as the following:&lt;/p&gt;
&lt;p&gt;[&lt;a href=&quot;https://www.tandfonline.com/doi/full/10.1080/13102818.2018.1481350&quot;&gt;https://www.tandfonline.com/doi/full/10.1080/13102818.2018.1481350&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Gut microbiota dysbiosis may lead to a number of diseases, including gastrointestinal disorders, obesity, cardiovascular diseases, allergy and central nervous system-related diseases.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As all kind of bacteria, gut bacteria need food as source of energy to survive. Taking away food will reduce the total number of bacteria and allow the settlement of new &quot;good&quot; bacteria cultures after the fasting, assuming that you eat healthy food after the fasting period like vegetables or natural yoghurt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Third: Food detaching.&lt;/strong&gt; Less of physical health benefit that is more like a mental health benefit. In our modern time, food plays a big role in our life. Some of us are spending much time thinking and consuming food. Experiencing that you can survive without frequently eating, makes you less attached to food by becoming more independent of it.&lt;/p&gt;
&lt;h1&gt;Fasting experience&lt;/h1&gt;
&lt;p&gt;Just some years ago in March 2017 I tried my first fasting experience. I decided to do juice fasting for 7 days. For this I bought a juicer which separates the juice from the pulp and some big glass bottles. Every day I drank two bottles full of juice composed of fresh apples, oranges, cucumbers, beetroot, grapes and other vegetables. I had less side effects. What I remember of, I had some minor headache after the third day which disappeared shortly after they appeared. But more interestingly it became very hard, after the fourth day, to continue with drinking the juice because it started to taste very awful.&lt;/p&gt;
&lt;p&gt;In the next year 2018 I tried water fasting two times. Both times I skipped eating for three days. I only did three days because I tried to minimize the effect of loosing muscles during the fasting, but receive the full health benefits as described above. I did the water fasting on weekends to minimize the chance to affect my work as a software engineer.&lt;/p&gt;
&lt;h1&gt;3 Days Water Fasting Diary&lt;/h1&gt;
&lt;p&gt;In this section I will summarize my three days of water fasting including the day before as day 0 and the day after as day 4.&lt;/p&gt;
&lt;h2 id=&quot;day-0-thursday&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#day-0-thursday&quot; aria-label=&quot;day 0 thursday permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Day 0 Thursday:&lt;/h2&gt;
&lt;p&gt;I call it day 0 because it is the last day of eating. Knowing that I will not eat for the next three days I ate plenty of food until 9pm. That helped me to suppress my hunger the following first water fasting day.&lt;/p&gt;
&lt;h2 id=&quot;day-1-friday&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#day-1-friday&quot; aria-label=&quot;day 1 friday permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Day 1 Friday:&lt;/h2&gt;
&lt;p&gt;I woke up and drunk two big glasses full of water before I started my 30 minutes morning workout, which I do usually every morning at 8 am. The workout includes 8 minutes tabata. If you don&apos;t know what is tabata I explain it shortly. Tabata is a high intensive short workout which usually consist of at least 9 cycles where you perform at least 20 seconds a full body exercise like jumping jack or burpees. After the 20 seconds you rest for 10 seconds. These you repeat 9 times.&lt;/p&gt;
&lt;p&gt;After my daily morning workout I took a shower and measured my body weight with my impedance scale which I listed in the end of this article. It ca measure your body composition of body fat, muscle and water as well. In day three I will reveal how much kilos I finally lost. Please keep in mind that loosing weight is not my top priority for doing water fasting, as it is a much better and more secure to loose slowly weight over many weeks and month! But if you know what you do, it can be a nice short cut for losing some kilos.&lt;/p&gt;
&lt;p&gt;Additional to measuring my weight and body composition I was interested how fast my body can switch to mainly use the fat instead of sugar for its metabolism and produce ketones for compensating the missing sugar. There is a lot of information out about ketones and why they are healthy in many aspects. For finding out if my body produces ketones I used a simple alcohol breathalyzer. Cheap breathalyzer can not distinguish between alcohol or acetones in your breath, which makes them easy to use and perfect for figuring out if you are in ketose or not. This article (&lt;a href=&quot;https://www.fatforweightloss.com.au/measure-breath-ketones/&quot;&gt;https://www.fatforweightloss.com.au/measure-breath-ketones/&lt;/a&gt;) describes more in details about using a breathalyzer for measuring ketones. The following picture is taken from my alcohol tester which shows that I did not produce ketose so far.&lt;/p&gt;
&lt;p&gt;[picture Alcohol-tester Friday morning]&lt;/p&gt;
&lt;p&gt;I went to work. In the office I paid much attention to drink a lot water. Even it was Friday it was quite a busy day with a lot of meetings. Anyway the work day went on very smoothly and I felt no hunger. Even at home in the night the craving for eating something remained low. Remember I ate plenty food the day before which seemed to pay off! As well before I went to sleep I measured my ketose in my breath.&lt;/p&gt;
&lt;p&gt;[picture Alcohol-tester Friday evening]&lt;/p&gt;
&lt;h2 id=&quot;day-2-saturday&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#day-2-saturday&quot; aria-label=&quot;day 2 saturday permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Day 2 Saturday:&lt;/h2&gt;
&lt;p&gt;Hello lovely weekend! Day two was slightly more harder regarding hunger but overall the feeling remained low. As usually I made my 30 minutes morning workout at 8 am and after it I measure my weight again. I already lost almost 4 kilos in just on day which surprised me quite a lot. Though I know most of it is water which you are loosing as well when your body is burning the sugar reserves in your body. Even more excited I was about what the alcohol tester is saying and if I am in ketosis or not.&lt;/p&gt;
&lt;p&gt;[picture Alcohol-tester Saturday morning]&lt;/p&gt;
&lt;p&gt;A value over 0.030 would indicate that I am in ketosis and my body mainly burns fat to produce energy.&lt;/p&gt;
&lt;p&gt;It was a sunny day and most of the rest of the day my wife and me we spend outside in the park enjoying the sun. Of course I payed much attention to drink water. The hunger craving remained low, but it made me a bit jealous seeing my wife eating and smelling this delicious food she ate. Once more I measure the ketosis in my breath.&lt;/p&gt;
&lt;p&gt;[picture Alcohol-tester Saturday evening]&lt;/p&gt;
&lt;h2 id=&quot;day-3-sunday&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#day-3-sunday&quot; aria-label=&quot;day 3 sunday permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Day 3 Sunday:&lt;/h2&gt;
&lt;p&gt;Finally the last day. It was my favorite day, knowing that I can start soo eating again. I followed my normal morning routine. After the workout I measure my weight. I lost unbelievable 6 kg. The alcohol tester reached it maximum:&lt;/p&gt;
&lt;p&gt;[picture Alcohol-tester Sunday]&lt;/p&gt;
&lt;p&gt;At 1 pm I prepared a natural yoghurt with some healthy nuts in it. Remember one of my health benefits was to resettle good gut bacteria. Those bacteria normally come with healthy food like yoghurt. At 2 pm my wife prepared a healthy warm meal for us.&lt;/p&gt;
&lt;h2 id=&quot;day-4-monday&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#day-4-monday&quot; aria-label=&quot;day 4 monday permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Day 4 Monday:&lt;/h2&gt;
&lt;p&gt;For luck this day was a bank holiday in UK. I woke up with a feeling of endless energy which I directly could use in my morning workout. I felt stronger than never before. This is easy explainable. After abstaining carbs for some days your body becomes very sensitive for carbs and tries to store it even stronger in your body.&lt;/p&gt;
&lt;h1&gt;Summary:&lt;/h1&gt;
&lt;p&gt;As mentioned before it wasn&apos;t my first water fasting and my experiences were similar as the times before. I enjoyed the few days without eating and I really can recommend to try it yourself! In special after the first time you will be amazed for what your body is capable of for abstaining food.&lt;/p&gt;
&lt;p&gt;Just some advices from me if you plan to do water fasting as well. Reduce high intensive workouts but keep doing workouts! Do it when you are not working like on Weekend or during holidays. Observe and write down the experiences you made to reflect on them.&lt;/p&gt;
&lt;p&gt;Disclaimer: The following section contains affiliate links, which means that if you click on one of the product links, I’ll receive a small commission. This helps support this blog!&lt;/p&gt;
&lt;h2 id=&quot;my-amazing-equipment&quot; style=&quot;position:relative;&quot;&gt;&lt;a href=&quot;#my-amazing-equipment&quot; aria-label=&quot;my amazing equipment permalink&quot; class=&quot;heading-anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; height=&quot;20&quot; width=&quot;20&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;currentColor&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;My Amazing Equipment:&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Alcohol tester&lt;/strong&gt;: Great for figuring out if you are in ketosis or not. &lt;br&gt;
Amazon UK: &lt;a href=&quot;https://amzn.to/2IdwHGo&quot; target=&quot;_blank&quot;&gt;&lt;a href=&quot;https://amzn.to/2IdwHGo&quot;&gt;https://amzn.to/2IdwHGo&lt;/a&gt; (Amazon)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Omron Scale&lt;/strong&gt;: Measures not only your body weight. Can estimate your body fat, water and muscle composition as well. &lt;br&gt;
Amazon UK: &lt;a href=&quot;https://amzn.to/2EPEVUc&quot; target=&quot;_blank&quot;&gt;&lt;a href=&quot;https://amzn.to/2EPEVUc&quot;&gt;https://amzn.to/2EPEVUc&lt;/a&gt; (Amazon)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bare-Foot Shoes&lt;/strong&gt;: Perfect shoes for workouts like tabata, gym or running. Normal modern shoes are bad for your feet as they are overprotecting to your foot which will result in underdeveloped foot muscles and skeleton. A good developed foot is the basement of your body and prevents all kind of resulting issues like knee or back pain. There are many of expensive bare-foot shoes out but some cheap water shoes are completely sufficient. &lt;br&gt;
Amazon UK: &lt;a href=&quot;https://amzn.to/2ESuyiF&quot; target=&quot;_blank&quot;&gt;&lt;a href=&quot;https://amzn.to/2ESuyiF&quot;&gt;https://amzn.to/2ESuyiF&lt;/a&gt; (Amazon)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bluetooth Earphones&lt;/strong&gt;: I tested many different bluetooth earphones. I am sticking now with this one because they are cheap but are from very good quality regarding sound, battery and robustness. I can use them for weeks for my workouts without ever charging them! &lt;br&gt;
Amazon UK: &lt;a href=&quot;https://amzn.to/2IkCdqG&quot; target=&quot;_blank&quot;&gt;&lt;a href=&quot;https://amzn.to/2IkCdqG&quot;&gt;https://amzn.to/2IkCdqG&lt;/a&gt; (Amazon)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gymnastic Rings&lt;/strong&gt;: Perfect tool for upper body workout. I love it to train outside in the sun and fresh air. As well they are very light so you can take them with you wherever you go. &lt;br&gt;
Amazon UK: &lt;a href=&quot;https://amzn.to/2WLwKm4&quot; target=&quot;_blank&quot;&gt;&lt;a href=&quot;https://amzn.to/2WLwKm4&quot;&gt;https://amzn.to/2WLwKm4&lt;/a&gt; (Amazon)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stainless Steel Water Bottle&lt;/strong&gt;: That drinking water is crucial I don&apos;t need to explain. I prefer those steel water bottles because there is not risk of plastic in your water. &lt;br&gt;
Amazon UK: &lt;a href=&quot;https://amzn.to/2JYGyTL&quot; target=&quot;_blank&quot;&gt;&lt;a href=&quot;https://amzn.to/2JYGyTL&quot;&gt;https://amzn.to/2JYGyTL&lt;/a&gt; (Amazon)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To the wonderful readers of this article I&apos;m saying that feedback of any kind is welcome. In the future I will try to include a discussion and comment feature here. In the meantime, please feel free to send me feedback via my social media accounts such as &lt;a href=&quot;https://twitter.com/MartinMueller_&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.facebook.com/martin.muller.10485&quot;&gt;FaceBook&lt;/a&gt;. Thank you very much :).&lt;/p&gt;
&lt;p&gt;I love to work on Content Management Open Source projects. A lot from my stuff you can already use on &lt;a href=&quot;http://www.github.com/mmuller88&quot;&gt;www.github.com/mmuller88&lt;/a&gt; . If you like my work there and my blog posts, please consider supporting me on Patreon:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.patreon.com/bePatron?u=29010217&quot; data-patreon-widget-type=&quot;become-patron-button&quot;&gt;Become a Patreon!&lt;/a&gt;&lt;script async src=&quot;https://c6.patreon.com/becomePatronButton.bundle.js&quot;&gt;&lt;/script&gt;&lt;/p&gt;</content:encoded><featuredImage>https://martinmueller.dev/static/7c1047b533fafd805e1cac338a11bef1/water.jpg</featuredImage><media:content url="https://martinmueller.dev/static/7c1047b533fafd805e1cac338a11bef1/water.jpg" medium="image"/></item></channel></rss>